about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml6
-rw-r--r--Cargo.lock36
-rw-r--r--README.md2
-rw-r--r--RELEASES.md204
-rw-r--r--compiler/rustc_apfloat/src/ppc.rs4
-rw-r--r--compiler/rustc_ast/src/ast.rs39
-rw-r--r--compiler/rustc_ast/src/util/comments.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs63
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs5
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs53
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs668
-rw-r--r--compiler/rustc_ast_lowering/src/lifetime_collector.rs115
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs30
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs64
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs74
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs28
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs28
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs17
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs138
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs19
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs7
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs23
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs27
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs12
-rw-r--r--compiler/rustc_const_eval/src/util/alignment.rs28
-rw-r--r--compiler/rustc_const_eval/src/util/call_kind.rs9
-rw-r--r--compiler/rustc_error_messages/locales/en-US/passes.ftl3
-rw-r--r--compiler/rustc_errors/Cargo.toml2
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs6
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs20
-rw-r--r--compiler/rustc_errors/src/lib.rs4
-rw-r--r--compiler/rustc_hir/src/definitions.rs7
-rw-r--r--compiler/rustc_hir/src/hir.rs31
-rw-r--r--compiler/rustc_hir/src/intravisit.rs42
-rw-r--r--compiler/rustc_hir/src/lang_items.rs3
-rw-r--r--compiler/rustc_hir/src/target.rs90
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs17
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs9
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs20
-rw-r--r--compiler/rustc_lexer/src/cursor.rs4
-rw-r--r--compiler/rustc_lexer/src/lib.rs89
-rw-r--r--compiler/rustc_lexer/src/tests.rs50
-rw-r--r--compiler/rustc_lint/src/builtin.rs25
-rw-r--r--compiler/rustc_lint/src/context.rs17
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs4
-rw-r--r--compiler/rustc_lint/src/unused.rs14
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs27
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs14
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp7
-rw-r--r--compiler/rustc_macros/Cargo.toml2
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs28
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs38
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs48
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs6
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs6
-rw-r--r--compiler/rustc_middle/src/mir/patch.rs65
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs29
-rw-r--r--compiler/rustc_middle/src/query/mod.rs8
-rw-r--r--compiler/rustc_middle/src/thir.rs15
-rw-r--r--compiler/rustc_middle/src/traits/select.rs4
-rw-r--r--compiler/rustc_middle/src/traits/specialization_graph.rs2
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs4
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs63
-rw-r--r--compiler/rustc_middle/src/ty/context.rs7
-rw-r--r--compiler/rustc_middle/src/ty/error.rs5
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs124
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs11
-rw-r--r--compiler/rustc_middle/src/ty/util.rs20
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/lints.rs21
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs65
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs26
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs16
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs6
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs5
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs4
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs77
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs5
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs3
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs56
-rw-r--r--compiler/rustc_parse/src/parser/item.rs54
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs7
-rw-r--r--compiler/rustc_parse_format/src/lib.rs75
-rw-r--r--compiler/rustc_parse_format/src/tests.rs70
-rw-r--r--compiler/rustc_passes/src/check_attr.rs60
-rw-r--r--compiler/rustc_passes/src/check_const.rs2
-rw-r--r--compiler/rustc_passes/src/dead.rs129
-rw-r--r--compiler/rustc_passes/src/errors.rs7
-rw-r--r--compiler/rustc_privacy/src/errors.rs11
-rw-r--r--compiler/rustc_privacy/src/lib.rs32
-rw-r--r--compiler/rustc_query_system/src/query/job.rs14
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs6
-rw-r--r--compiler/rustc_resolve/src/late.rs43
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs7
-rw-r--r--compiler/rustc_resolve/src/lib.rs8
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs6
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs6
-rw-r--r--compiler/rustc_target/src/abi/call/x86.rs6
-rw-r--r--compiler/rustc_target/src/abi/mod.rs3
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs11
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs19
-rw-r--r--compiler/rustc_target/src/spec/apple_sdk_base.rs54
-rw-r--r--compiler/rustc_target/src/spec/tests/tests_impl.rs5
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs10
-rw-r--r--compiler/rustc_trait_selection/Cargo.toml1
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs89
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/on_unimplemented.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs25
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs55
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs359
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs65
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_match.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs9
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs39
-rw-r--r--compiler/rustc_traits/src/chalk/mod.rs2
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs5
-rw-r--r--compiler/rustc_transmute/Cargo.toml28
-rw-r--r--compiler/rustc_transmute/src/layout/dfa.rs184
-rw-r--r--compiler/rustc_transmute/src/layout/mod.rs71
-rw-r--r--compiler/rustc_transmute/src/layout/nfa.rs179
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs471
-rw-r--r--compiler/rustc_transmute/src/layout/tree/tests.rs80
-rw-r--r--compiler/rustc_transmute/src/lib.rs117
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/mod.rs320
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/query_context.rs93
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/tests.rs115
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs39
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs2
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs19
-rw-r--r--compiler/rustc_typeck/src/astconv/errors.rs6
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs6
-rw-r--r--compiler/rustc_typeck/src/check/_match.rs4
-rw-r--r--compiler/rustc_typeck/src/check/check.rs2
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs75
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs26
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs24
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs11
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs14
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs14
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs5
-rw-r--r--compiler/rustc_typeck/src/check/method/confirm.rs13
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/prelude2021.rs7
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs35
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs6
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs53
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs30
-rw-r--r--compiler/rustc_typeck/src/coherence/builtin.rs49
-rw-r--r--compiler/rustc_typeck/src/collect.rs6
-rw-r--r--compiler/rustc_typeck/src/collect/item_bounds.rs4
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs5
-rw-r--r--compiler/rustc_typeck/src/hir_wf_check.rs6
-rw-r--r--compiler/rustc_typeck/src/impl_wf_check.rs2
-rw-r--r--compiler/rustc_typeck/src/lib.rs47
-rw-r--r--compiler/rustc_typeck/src/outlives/implicit_infer.rs4
-rw-r--r--compiler/rustc_typeck/src/outlives/outlives_bounds.rs4
-rw-r--r--library/core/src/ffi/c_str.rs47
-rw-r--r--library/core/src/intrinsics.rs31
-rw-r--r--library/core/src/mem/mod.rs4
-rw-r--r--library/core/src/mem/transmutability.rs43
-rw-r--r--library/core/src/ptr/const_ptr.rs5
-rw-r--r--library/core/src/ptr/mut_ptr.rs5
-rw-r--r--library/core/src/slice/iter.rs24
-rw-r--r--library/core/src/str/mod.rs2
-rw-r--r--library/core/tests/slice.rs21
-rw-r--r--library/std/src/error.rs74
-rw-r--r--library/std/src/error/tests.rs5
-rw-r--r--library/std/src/sys/solid/fs.rs12
-rw-r--r--library/std/src/sys/solid/net.rs4
-rw-r--r--library/std/src/sys/unix/fs.rs10
-rw-r--r--library/std/src/sys/wasm/mod.rs6
-rw-r--r--library/std/src/sys/windows/c.rs24
-rw-r--r--library/std/src/sys/windows/compat.rs199
-rw-r--r--library/std/src/sys/windows/rand.rs68
-rw-r--r--library/std/src/sys/windows/thread_parker.rs31
-rw-r--r--src/bootstrap/builder/tests.rs2
-rw-r--r--src/bootstrap/check.rs8
-rw-r--r--src/bootstrap/flags.rs12
-rw-r--r--src/bootstrap/lib.rs20
-rw-r--r--src/bootstrap/native.rs40
-rw-r--r--src/bootstrap/test.rs7
-rw-r--r--src/bootstrap/tool.rs52
-rw-r--r--src/ci/docker/README.md38
-rw-r--r--src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile33
-rw-r--r--src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.config802
-rw-r--r--src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile95
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile15
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch24
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/002-newer-gcc.patch26
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config764
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile16
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-powerpc64-linux/build-powerpc64-toolchain.sh20
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch24
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/002-Prevent-inlining-in-PPC64-initfini.s.patch26
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/003-newer-gcc.patch26
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config761
-rw-r--r--src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile13
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh6
-rw-r--r--src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile9
-rw-r--r--src/ci/docker/host-x86_64/dist-riscv64-linux/crosstool-ng.sh13
-rw-r--r--src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.12.1/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch63
-rw-r--r--src/ci/docker/host-x86_64/dist-s390x-linux/s390x-linux-gnu.config68
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile95
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/build-binutils.sh19
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/build-cmake.sh17
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh31
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh5
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh16
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/build-python.sh22
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh10
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/llvm-project-centos.patch18
-rw-r--r--src/ci/github-actions/ci.yml2
-rwxr-xr-xsrc/ci/scripts/checkout-submodules.sh17
m---------src/doc/embedded-book0
-rw-r--r--src/doc/man/rustc.16
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.md6
-rw-r--r--src/doc/rustc/src/platform-support.md14
-rw-r--r--src/librustdoc/clean/auto_trait.rs7
-rw-r--r--src/librustdoc/clean/blanket_impl.rs2
-rw-r--r--src/librustdoc/clean/inline.rs16
-rw-r--r--src/librustdoc/clean/mod.rs443
-rw-r--r--src/librustdoc/clean/types.rs71
-rw-r--r--src/librustdoc/clean/utils.rs8
-rw-r--r--src/librustdoc/doctest.rs2
-rw-r--r--src/librustdoc/html/highlight.rs2
-rw-r--r--src/librustdoc/html/render/print_item.rs2
-rw-r--r--src/librustdoc/html/render/write_shared.rs33
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css10
-rw-r--r--src/librustdoc/html/static/js/main.js2
-rw-r--r--src/librustdoc/html/static/js/source-script.js18
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs2
-rw-r--r--src/librustdoc/scrape_examples.rs6
-rw-r--r--src/test/assembly/asm/riscv-types.rs2
-rw-r--r--src/test/codegen-units/item-collection/generic-drop-glue.rs4
-rw-r--r--src/test/codegen-units/item-collection/transitive-drop-glue.rs10
-rw-r--r--src/test/codegen-units/item-collection/unsizing.rs2
-rw-r--r--src/test/codegen/merge-functions.rs6
-rw-r--r--src/test/debuginfo/no_mangle-info.rs40
-rw-r--r--src/test/incremental/hashes/inherent_impls.rs8
-rw-r--r--src/test/incremental/hashes/trait_defs.rs44
-rw-r--r--src/test/incremental/hashes/trait_impls.rs26
-rw-r--r--src/test/mir-opt/derefer_complex_case.main.Derefer.diff4
-rw-r--r--src/test/mir-opt/derefer_terminator_test.main.Derefer.diff4
-rw-r--r--src/test/mir-opt/derefer_test.main.Derefer.diff4
-rw-r--r--src/test/mir-opt/derefer_test_multiple.main.Derefer.diff4
-rw-r--r--src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_cycle.one.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_cycle.two.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_diverging.f.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_diverging.g.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_diverging.h.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_options.main.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/inline_shims.clone.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_shims.drop.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_specialization.main.Inline.diff4
-rw-r--r--src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir4
-rw-r--r--src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir4
-rw-r--r--src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff4
-rw-r--r--src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff4
-rw-r--r--src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff4
-rw-r--r--src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff4
-rw-r--r--src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff4
-rw-r--r--src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff4
-rw-r--r--src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff4
-rw-r--r--src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff4
-rw-r--r--src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff4
-rw-r--r--src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff4
-rw-r--r--src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff4
-rw-r--r--src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff4
-rw-r--r--src/test/run-make-fulldeps/issues-41478-43796/a.rs2
-rw-r--r--src/test/run-make/native-link-modifier-whole-archive/Makefile19
-rw-r--r--src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_minus_whole_archive.rs7
-rw-r--r--src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_plus_whole_archive.rs7
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/Makefile11
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/driver.rs5
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/extern.c55
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/lib.rs76
-rw-r--r--src/test/run-make/raw-dylib-alt-calling-convention/output.msvc.txt11
-rw-r--r--src/test/run-make/raw-dylib-c/extern_1.c7
-rw-r--r--src/test/run-make/raw-dylib-c/lib.rs10
-rw-r--r--src/test/run-make/raw-dylib-c/output.txt2
-rw-r--r--src/test/run-make/raw-dylib-link-ordinal/exporter.c7
-rw-r--r--src/test/run-make/raw-dylib-link-ordinal/exporter.def2
-rw-r--r--src/test/run-make/raw-dylib-link-ordinal/lib.rs8
-rw-r--r--src/test/run-make/raw-dylib-link-ordinal/output.txt2
-rw-r--r--src/test/rustdoc-gui/item-info-width.goml8
-rw-r--r--src/test/rustdoc-gui/item-info.goml32
-rw-r--r--src/test/rustdoc-gui/src/lib2/lib.rs3
-rw-r--r--src/test/rustdoc-ui/check-doc-alias-attr-location.stderr2
-rw-r--r--src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs7
-rw-r--r--src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr14
-rw-r--r--src/test/rustdoc/auxiliary/issue-99734-aux.rs11
-rw-r--r--src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs16
-rw-r--r--src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs14
-rw-r--r--src/test/ui/align-with-extern-c-fn.rs2
-rw-r--r--src/test/ui/allocator/no_std-alloc-error-handler-custom.rs2
-rw-r--r--src/test/ui/allocator/no_std-alloc-error-handler-default.rs2
-rw-r--r--src/test/ui/argument-suggestions/issue-100154.rs7
-rw-r--r--src/test/ui/argument-suggestions/issue-100154.stderr35
-rw-r--r--src/test/ui/array-slice-vec/show-boxed-slice.rs2
-rw-r--r--src/test/ui/asm/aarch64/bad-options.stderr24
-rw-r--r--src/test/ui/asm/aarch64/parse-error.stderr12
-rw-r--r--src/test/ui/asm/x86_64/bad-options.stderr24
-rw-r--r--src/test/ui/asm/x86_64/parse-error.stderr12
-rw-r--r--src/test/ui/associated-consts/associated-const-type-parameters.rs2
-rw-r--r--src/test/ui/associated-type-bounds/enum-bounds.rs1
-rw-r--r--src/test/ui/associated-types/associated-types-method.rs1
-rw-r--r--src/test/ui/associated-types/associated-types-struct-field-numbered.rs2
-rw-r--r--src/test/ui/async-await/async-fn-size-moved-locals.rs2
-rw-r--r--src/test/ui/async-await/async-fn-size-uninit-locals.rs2
-rw-r--r--src/test/ui/async-await/no-const-async.stderr2
-rw-r--r--src/test/ui/attributes/issue-90873.stderr4
-rw-r--r--src/test/ui/auto-traits/auto-traits.rs2
-rw-r--r--src/test/ui/bench/issue-32062.rs4
-rw-r--r--src/test/ui/binding/match-tag.rs2
-rw-r--r--src/test/ui/binding/or-pattern.rs2
-rw-r--r--src/test/ui/binding/simple-generic-match.rs2
-rw-r--r--src/test/ui/borrowck/access-mode-in-closures.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr2
-rw-r--r--src/test/ui/borrowck/borrowck-move-error-with-note.stderr2
-rw-r--r--src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs2
-rw-r--r--src/test/ui/chalkify/builtin-copy-clone.rs2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed4
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs4
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed2
-rw-r--r--src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs2
-rw-r--r--src/test/ui/closures/issue-84128.stderr5
-rw-r--r--src/test/ui/closures/issue-90871.rs5
-rw-r--r--src/test/ui/closures/issue-90871.stderr23
-rw-r--r--src/test/ui/codegen/issue-16602-3.rs1
-rw-r--r--src/test/ui/coercion/issue-14589.rs2
-rw-r--r--src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs1
-rw-r--r--src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs1
-rw-r--r--src/test/ui/const-generics/const-argument-cross-crate.rs2
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/associated-consts.rs2
-rw-r--r--src/test/ui/consts/assoc-const.rs2
-rw-r--r--src/test/ui/consts/const-needs_drop.rs2
-rw-r--r--src/test/ui/consts/const-size_of_val-align_of_val.rs2
-rw-r--r--src/test/ui/consts/const_in_pattern/warn_corner_cases.rs2
-rw-r--r--src/test/ui/consts/issue-44415.stderr6
-rw-r--r--src/test/ui/consts/issue-70773-mir-typeck-lt-norm.rs2
-rw-r--r--src/test/ui/consts/rvalue-static-promotion.rs2
-rw-r--r--src/test/ui/consts/transmute-const.rs2
-rw-r--r--src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr18
-rw-r--r--src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr6
-rw-r--r--src/test/ui/deriving/deriving-clone-generic-tuple-struct.rs1
-rw-r--r--src/test/ui/deriving/deriving-copyclone.rs2
-rw-r--r--src/test/ui/deriving/issue-58319.rs1
-rw-r--r--src/test/ui/did_you_mean/use_instead_of_import.fixed8
-rw-r--r--src/test/ui/did_you_mean/use_instead_of_import.rs8
-rw-r--r--src/test/ui/did_you_mean/use_instead_of_import.stderr16
-rw-r--r--src/test/ui/drop/dropck-eyepatch-reorder.rs8
-rw-r--r--src/test/ui/drop/dropck-eyepatch.rs8
-rw-r--r--src/test/ui/drop/dynamic-drop.rs2
-rw-r--r--src/test/ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs2
-rw-r--r--src/test/ui/enum-discriminant/discriminant_value-wrapper.rs1
-rw-r--r--src/test/ui/enum-discriminant/discriminant_value.rs3
-rw-r--r--src/test/ui/expr/if/if-branch-types.stderr5
-rw-r--r--src/test/ui/expr/if/if-else-type-mismatch.stderr10
-rw-r--r--src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs3
-rw-r--r--src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr11
-rw-r--r--src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr12
-rw-r--r--src/test/ui/fmt/struct-field-as-captured-argument.fixed18
-rw-r--r--src/test/ui/fmt/struct-field-as-captured-argument.rs18
-rw-r--r--src/test/ui/fmt/struct-field-as-captured-argument.stderr79
-rw-r--r--src/test/ui/for-loop-while/break-while-condition.stderr8
-rw-r--r--src/test/ui/generator/size-moved-locals.rs2
-rw-r--r--src/test/ui/generator/type-mismatch-signature-deduction.stderr6
-rw-r--r--src/test/ui/generics/generic-default-type-params-cross-crate.rs2
-rw-r--r--src/test/ui/generics/generic-ivec-leak.rs2
-rw-r--r--src/test/ui/generics/generic-newtype-struct.rs2
-rw-r--r--src/test/ui/generics/generic-no-mangle.fixed4
-rw-r--r--src/test/ui/generics/generic-no-mangle.rs4
-rw-r--r--src/test/ui/generics/generic-recursive-tag.rs2
-rw-r--r--src/test/ui/generics/generic-tag-corruption.rs2
-rw-r--r--src/test/ui/generics/generic-tag-local.rs2
-rw-r--r--src/test/ui/generics/generic-tag.rs2
-rw-r--r--src/test/ui/hrtb/hrtb-perfect-forwarding.stderr42
-rw-r--r--src/test/ui/impl-trait/bounds_regression.rs2
-rw-r--r--src/test/ui/impl-trait/equality.stderr7
-rw-r--r--src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr4
-rw-r--r--src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr67
-rw-r--r--src/test/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs7
-rw-r--r--src/test/ui/issues/issue-12511.stderr6
-rw-r--r--src/test/ui/issues/issue-13027.rs2
-rw-r--r--src/test/ui/issues/issue-14382.rs2
-rw-r--r--src/test/ui/issues/issue-15858.rs2
-rw-r--r--src/test/ui/issues/issue-17905.rs1
-rw-r--r--src/test/ui/issues/issue-2063.rs2
-rw-r--r--src/test/ui/issues/issue-23491.rs2
-rw-r--r--src/test/ui/issues/issue-24308.rs2
-rw-r--r--src/test/ui/issues/issue-24805-dropck-itemless.rs2
-rw-r--r--src/test/ui/issues/issue-25089.rs2
-rw-r--r--src/test/ui/issues/issue-25679.rs1
-rw-r--r--src/test/ui/issues/issue-25700-1.rs2
-rw-r--r--src/test/ui/issues/issue-25700-2.rs3
-rw-r--r--src/test/ui/issues/issue-25700.rs2
-rw-r--r--src/test/ui/issues/issue-26127.rs2
-rw-r--r--src/test/ui/issues/issue-26641.rs2
-rw-r--r--src/test/ui/issues/issue-26709.rs2
-rw-r--r--src/test/ui/issues/issue-27240.rs5
-rw-r--r--src/test/ui/issues/issue-28498-must-work-ex1.rs2
-rw-r--r--src/test/ui/issues/issue-28498-must-work-ex2.rs2
-rw-r--r--src/test/ui/issues/issue-28498-ugeh-ex1.rs2
-rw-r--r--src/test/ui/issues/issue-29147-rpass.rs1
-rw-r--r--src/test/ui/issues/issue-29147.rs1
-rw-r--r--src/test/ui/issues/issue-29147.stderr4
-rw-r--r--src/test/ui/issues/issue-31267-additional.rs2
-rw-r--r--src/test/ui/issues/issue-31299.rs4
-rw-r--r--src/test/ui/issues/issue-34571.rs2
-rw-r--r--src/test/ui/issues/issue-36053.rs2
-rw-r--r--src/test/ui/issues/issue-36278-prefix-nesting.rs1
-rw-r--r--src/test/ui/issues/issue-40003.rs2
-rw-r--r--src/test/ui/issues/issue-4252.rs2
-rw-r--r--src/test/ui/issues/issue-46069.rs2
-rw-r--r--src/test/ui/issues/issue-5315.rs2
-rw-r--r--src/test/ui/issues/issue-61894.rs2
-rw-r--r--src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr14
-rw-r--r--src/test/ui/issues/issue-7911.rs2
-rw-r--r--src/test/ui/issues/issue-99838.rs40
-rw-r--r--src/test/ui/layout/unsafe-cell-hides-niche.rs4
-rw-r--r--src/test/ui/let-else/issue-100103.rs15
-rw-r--r--src/test/ui/lifetimes/elided-lifetime-in-path-in-type-relative-expression.rs17
-rw-r--r--src/test/ui/lint/dead-code/tuple-struct-field.rs35
-rw-r--r--src/test/ui/lint/dead-code/tuple-struct-field.stderr33
-rw-r--r--src/test/ui/lint/dead-code/with-impl.rs2
-rw-r--r--src/test/ui/lint/issue-99387.rs24
-rw-r--r--src/test/ui/lint/unaligned_references.rs53
-rw-r--r--src/test/ui/lint/unaligned_references.stderr58
-rw-r--r--src/test/ui/lint/unreachable_pub.stderr14
-rw-r--r--src/test/ui/lint/unused/issue-92751.rs9
-rw-r--r--src/test/ui/lint/unused/issue-92751.stderr32
-rw-r--r--src/test/ui/lint/unused/unused_attributes-must_use.stderr4
-rw-r--r--src/test/ui/list.rs2
-rw-r--r--src/test/ui/macros/html-literals.rs1
-rw-r--r--src/test/ui/macros/issue-98466.stderr36
-rw-r--r--src/test/ui/macros/issue-99265.stderr172
-rw-r--r--src/test/ui/macros/issue-99907.fixed24
-rw-r--r--src/test/ui/macros/issue-99907.rs24
-rw-r--r--src/test/ui/macros/issue-99907.stderr68
-rw-r--r--src/test/ui/macros/macro-tt-followed-by-seq.rs1
-rw-r--r--src/test/ui/methods/method-argument-inference-associated-type.rs2
-rw-r--r--src/test/ui/methods/method-probe-no-guessing-dyn-trait.rs4
-rw-r--r--src/test/ui/mir/mir_codegen_switch.rs4
-rw-r--r--src/test/ui/mir/mir_fat_ptr.rs2
-rw-r--r--src/test/ui/mir/mir_raw_fat_ptr.rs1
-rw-r--r--src/test/ui/mir/mir_refs_correct.rs4
-rw-r--r--src/test/ui/mismatched_types/E0409.stderr4
-rw-r--r--src/test/ui/mismatched_types/dont-point-return-on-E0308.rs18
-rw-r--r--src/test/ui/mismatched_types/dont-point-return-on-E0308.stderr19
-rw-r--r--src/test/ui/mismatched_types/issue-84976.stderr5
-rw-r--r--src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.fixed21
-rw-r--r--src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.rs21
-rw-r--r--src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.stderr49
-rw-r--r--src/test/ui/moves/issue-99470-move-out-of-some.rs9
-rw-r--r--src/test/ui/moves/issue-99470-move-out-of-some.stderr16
-rw-r--r--src/test/ui/moves/moves-based-on-type-block-bad.stderr2
-rw-r--r--src/test/ui/nll/issue-98589-closures-relate-named-regions.rs36
-rw-r--r--src/test/ui/nll/issue-98589-closures-relate-named-regions.stderr61
-rw-r--r--src/test/ui/nll/move-errors.stderr4
-rw-r--r--src/test/ui/nullable-pointer-iotareduction.rs2
-rw-r--r--src/test/ui/optimization-fuel-0.rs2
-rw-r--r--src/test/ui/optimization-fuel-1.rs2
-rw-r--r--src/test/ui/packed/packed-struct-drop-aligned.rs2
-rw-r--r--src/test/ui/packed/packed-struct-optimized-enum.rs2
-rw-r--r--src/test/ui/packed/packed-tuple-struct-layout.rs2
-rw-r--r--src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.fixed13
-rw-r--r--src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.rs13
-rw-r--r--src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.stderr8
-rw-r--r--src/test/ui/parser/issues/issue-70388-without-witness.fixed2
-rw-r--r--src/test/ui/parser/issues/issue-70388-without-witness.rs2
-rw-r--r--src/test/ui/parser/issues/issue-88770.rs2
-rw-r--r--src/test/ui/parser/issues/issue-88770.stderr16
-rw-r--r--src/test/ui/parser/issues/issue-89574.stderr4
-rw-r--r--src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr4
-rw-r--r--src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr8
-rw-r--r--src/test/ui/parser/removed-syntax-static-fn.stderr4
-rw-r--r--src/test/ui/parser/suggest-semi-in-array.rs5
-rw-r--r--src/test/ui/parser/suggest-semi-in-array.stderr10
-rw-r--r--src/test/ui/range_inclusive.rs2
-rw-r--r--src/test/ui/recursion/issue-26548-recursion-via-normalize.rs10
-rw-r--r--src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr12
-rw-r--r--src/test/ui/reify-intrinsic.stderr3
-rw-r--r--src/test/ui/resolve/issue-23305.stderr10
-rw-r--r--src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr8
-rw-r--r--src/test/ui/resolve/resolve-inconsistent-names.rs1
-rw-r--r--src/test/ui/resolve/resolve-inconsistent-names.stderr9
-rw-r--r--src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs2
-rw-r--r--src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs2
-rw-r--r--src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs2
-rw-r--r--src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs2
-rw-r--r--src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs2
-rw-r--r--src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs2
-rw-r--r--src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs2
-rw-r--r--src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs2
-rw-r--r--src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs2
-rw-r--r--src/test/ui/rfc-2294-if-let-guard/feature-gate.rs2
-rw-r--r--src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr24
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs12
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr542
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs4
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr8
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs3
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr10
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs3
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr10
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs3
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr14
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs25
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr29
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs3
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr10
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs3
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr10
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop.rs2
-rw-r--r--src/test/ui/rfcs/rfc-2151-raw-identifiers/attr.rs2
-rw-r--r--src/test/ui/rustdoc/check-doc-alias-attr-location.rs8
-rw-r--r--src/test/ui/rustdoc/check-doc-alias-attr-location.stderr22
-rw-r--r--src/test/ui/specialization/issue-43037.rs20
-rw-r--r--src/test/ui/specialization/issue-43037.stderr12
-rw-r--r--src/test/ui/specialization/issue-45814.rs12
-rw-r--r--src/test/ui/specialization/issue-45814.stderr14
-rw-r--r--src/test/ui/specialization/specialization-cross-crate.rs2
-rw-r--r--src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs2
-rw-r--r--src/test/ui/stdlib-unit-tests/raw-fat-ptr.rs1
-rw-r--r--src/test/ui/struct-ctor-mangling.rs2
-rw-r--r--src/test/ui/structs-enums/enum-null-pointer-opt.rs6
-rw-r--r--src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs2
-rw-r--r--src/test/ui/structs-enums/resource-in-struct.rs2
-rw-r--r--src/test/ui/structs-enums/tuple-struct-construct.rs1
-rw-r--r--src/test/ui/structs-enums/uninstantiable-struct.rs2
-rw-r--r--src/test/ui/suggestions/const-no-type.rs14
-rw-r--r--src/test/ui/suggestions/const-no-type.stderr28
-rw-r--r--src/test/ui/suggestions/dont-suggest-ref/simple.stderr48
-rw-r--r--src/test/ui/suggestions/unnamable-types.stderr20
-rw-r--r--src/test/ui/trailing-comma.rs4
-rw-r--r--src/test/ui/traits/augmented-assignments-trait.rs2
-rw-r--r--src/test/ui/traits/issue-91949-hangs-on-recursion.stderr9
-rw-r--r--src/test/ui/traits/negative-impls/negated-auto-traits-rpass.rs2
-rw-r--r--src/test/ui/traits/object/exclusion.rs2
-rw-r--r--src/test/ui/traits/object/generics.rs2
-rw-r--r--src/test/ui/traits/pointee-deduction.rs4
-rw-r--r--src/test/ui/traits/principal-less-objects.rs2
-rw-r--r--src/test/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr2
-rw-r--r--src/test/ui/transmutability/abstraction/abstracted_assume.rs73
-rw-r--r--src/test/ui/transmutability/abstraction/const_generic_fn.rs41
-rw-r--r--src/test/ui/transmutability/arrays/should_have_correct_length.rs44
-rw-r--r--src/test/ui/transmutability/arrays/should_inherit_alignment.rs55
-rw-r--r--src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs61
-rw-r--r--src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr99
-rw-r--r--src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs149
-rw-r--r--src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr323
-rw-r--r--src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs117
-rw-r--r--src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr99
-rw-r--r--src/test/ui/transmutability/enums/should_order_correctly.rs32
-rw-r--r--src/test/ui/transmutability/enums/should_pad_variants.rs40
-rw-r--r--src/test/ui/transmutability/enums/should_pad_variants.stderr19
-rw-r--r--src/test/ui/transmutability/enums/should_respect_endianness.rs33
-rw-r--r--src/test/ui/transmutability/enums/should_respect_endianness.stderr19
-rw-r--r--src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs9
-rw-r--r--src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr21
-rw-r--r--src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs21
-rw-r--r--src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr12
-rw-r--r--src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs21
-rw-r--r--src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr12
-rw-r--r--src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs22
-rw-r--r--src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr9
-rw-r--r--src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs40
-rw-r--r--src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr27
-rw-r--r--src/test/ui/transmutability/primitives/bool.rs25
-rw-r--r--src/test/ui/transmutability/primitives/bool.stderr19
-rw-r--r--src/test/ui/transmutability/primitives/numbers.rs128
-rw-r--r--src/test/ui/transmutability/primitives/numbers.stderr915
-rw-r--r--src/test/ui/transmutability/primitives/unit.rs24
-rw-r--r--src/test/ui/transmutability/primitives/unit.stderr19
-rw-r--r--src/test/ui/transmutability/references.rs20
-rw-r--r--src/test/ui/transmutability/references.stderr19
-rw-r--r--src/test/ui/transmutability/structs/repr/should_handle_align.rs36
-rw-r--r--src/test/ui/transmutability/structs/repr/should_handle_packed.rs35
-rw-r--r--src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs76
-rw-r--r--src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr195
-rw-r--r--src/test/ui/transmutability/structs/should_order_fields_correctly.rs31
-rw-r--r--src/test/ui/transmutability/unions/boolish.rs31
-rw-r--r--src/test/ui/transmutability/unions/repr/should_handle_align.rs40
-rw-r--r--src/test/ui/transmutability/unions/repr/should_handle_packed.rs41
-rw-r--r--src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs37
-rw-r--r--src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr35
-rw-r--r--src/test/ui/transmutability/unions/should_pad_variants.rs40
-rw-r--r--src/test/ui/transmutability/unions/should_pad_variants.stderr19
-rw-r--r--src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs39
-rw-r--r--src/test/ui/transmutability/unions/should_reject_contraction.rs36
-rw-r--r--src/test/ui/transmutability/unions/should_reject_contraction.stderr19
-rw-r--r--src/test/ui/transmutability/unions/should_reject_disjoint.rs36
-rw-r--r--src/test/ui/transmutability/unions/should_reject_disjoint.stderr35
-rw-r--r--src/test/ui/transmutability/unions/should_reject_intersecting.rs38
-rw-r--r--src/test/ui/transmutability/unions/should_reject_intersecting.stderr35
-rw-r--r--src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs38
-rw-r--r--src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs39
-rw-r--r--src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs46
-rw-r--r--src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs39
-rw-r--r--src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr12
-rw-r--r--src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs40
-rw-r--r--src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr15
-rw-r--r--src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs38
-rw-r--r--src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs39
-rw-r--r--src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs38
-rw-r--r--src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr12
-rw-r--r--src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs39
-rw-r--r--src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr15
-rw-r--r--src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs37
-rw-r--r--src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr19
-rw-r--r--src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs38
-rw-r--r--src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr19
-rw-r--r--src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs52
-rw-r--r--src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs39
-rw-r--r--src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr19
-rw-r--r--src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs42
-rw-r--r--src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr32
-rw-r--r--src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs2
-rw-r--r--src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr6
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-74280.stderr2
-rw-r--r--src/test/ui/type/missing-let-in-binding.fixed5
-rw-r--r--src/test/ui/type/missing-let-in-binding.rs5
-rw-r--r--src/test/ui/type/missing-let-in-binding.stderr16
-rw-r--r--src/test/ui/typeck/issue-100164.fixed9
-rw-r--r--src/test/ui/typeck/issue-100164.rs9
-rw-r--r--src/test/ui/typeck/issue-100164.stderr14
-rw-r--r--src/test/ui/typeck/issue-79040.stderr4
-rw-r--r--src/test/ui/typeck/issue-98982.rs9
-rw-r--r--src/test/ui/typeck/issue-98982.stderr24
-rw-r--r--src/test/ui/typeck/typeck_type_placeholder_item.stderr4
-rw-r--r--src/test/ui/unboxed-closures/type-id-higher-rank.rs2
-rw-r--r--src/test/ui/unsized-locals/unsized-exprs-rpass.rs2
-rw-r--r--src/test/ui/unsized/unchanged-param.rs4
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_all.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_restriction.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_style.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs4
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs1
-rw-r--r--src/tools/clippy/tests/ui/format.fixed1
-rw-r--r--src/tools/clippy/tests/ui/format.rs1
-rw-r--r--src/tools/clippy/tests/ui/format.stderr38
-rw-r--r--src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed2
-rw-r--r--src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs2
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.fixed2
-rw-r--r--src/tools/clippy/tests/ui/must_use_candidates.rs2
-rw-r--r--src/tools/clippy/tests/ui/numbered_fields.fixed1
-rw-r--r--src/tools/clippy/tests/ui/numbered_fields.rs1
-rw-r--r--src/tools/clippy/tests/ui/numbered_fields.stderr4
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed1
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs1
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr30
-rw-r--r--src/tools/clippy/tests/ui/unreadable_literal.fixed1
-rw-r--r--src/tools/clippy/tests/ui/unreadable_literal.rs1
-rw-r--r--src/tools/clippy/tests/ui/unreadable_literal.stderr22
-rw-r--r--src/tools/html-checker/Cargo.toml1
-rw-r--r--src/tools/html-checker/main.rs46
m---------src/tools/rls0
-rw-r--r--src/tools/rust-analyzer/.github/workflows/publish.yml17
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs48
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs56
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs314
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs23
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs55
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html51
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html50
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs46
-rw-r--r--src/tools/rust-analyzer/crates/limit/src/lib.rs15
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs13
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs16
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs38
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs2
-rw-r--r--src/tools/rust-analyzer/docs/dev/README.md7
-rw-r--r--src/tools/rust-analyzer/xtask/src/release.rs10
-rw-r--r--src/tools/rustc-workspace-hack/Cargo.toml7
-rw-r--r--src/tools/x/src/main.rs6
-rw-r--r--src/version2
759 files changed, 14671 insertions, 5380 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1f95c1bcab4..5410613548c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -79,7 +79,7 @@ jobs:
         uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
         with:
           github_token: "${{ secrets.github_token }}"
-        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
@@ -478,7 +478,7 @@ jobs:
         uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
         with:
           github_token: "${{ secrets.github_token }}"
-        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
@@ -588,7 +588,7 @@ jobs:
         uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
         with:
           github_token: "${{ secrets.github_token }}"
-        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+        if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'"
       - name: collect CPU statistics
         run: src/ci/scripts/collect-cpu-stats.sh
         if: success() && !env.SKIP_JOB
diff --git a/Cargo.lock b/Cargo.lock
index 058b6198dc4..11d57deb699 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -84,12 +84,6 @@ dependencies = [
 
 [[package]]
 name = "annotate-snippets"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5"
-
-[[package]]
-name = "annotate-snippets"
 version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c3b9d411ecbaf79885c6df4d75fff75858d5995ff25385657a28af47e82f9c36"
@@ -109,9 +103,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.51"
+version = "1.0.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
+checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
 
 [[package]]
 name = "array_tool"
@@ -525,9 +519,9 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.0.69"
+version = "1.0.73"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
+checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
 dependencies = [
  "jobserver",
 ]
@@ -1788,6 +1782,7 @@ dependencies = [
 name = "html-checker"
 version = "0.1.0"
 dependencies = [
+ "rayon",
  "walkdir",
 ]
 
@@ -3861,7 +3856,7 @@ dependencies = [
 name = "rustc_errors"
 version = "0.0.0"
 dependencies = [
- "annotate-snippets 0.8.0",
+ "annotate-snippets",
  "atty",
  "rustc_data_structures",
  "rustc_error_messages",
@@ -4113,7 +4108,7 @@ dependencies = [
 name = "rustc_macros"
 version = "0.1.0"
 dependencies = [
- "annotate-snippets 0.8.0",
+ "annotate-snippets",
  "fluent-bundle",
  "fluent-syntax",
  "proc-macro2",
@@ -4553,6 +4548,7 @@ dependencies = [
  "rustc_session",
  "rustc_span",
  "rustc_target",
+ "rustc_transmute",
  "smallvec",
  "tracing",
 ]
@@ -4578,6 +4574,20 @@ dependencies = [
 ]
 
 [[package]]
+name = "rustc_transmute"
+version = "0.1.0"
+dependencies = [
+ "itertools",
+ "rustc_data_structures",
+ "rustc_infer",
+ "rustc_macros",
+ "rustc_middle",
+ "rustc_span",
+ "rustc_target",
+ "tracing",
+]
+
+[[package]]
 name = "rustc_ty_utils"
 version = "0.0.0"
 dependencies = [
@@ -4713,7 +4723,7 @@ dependencies = [
 name = "rustfmt-nightly"
 version = "1.5.1"
 dependencies = [
- "annotate-snippets 0.9.1",
+ "annotate-snippets",
  "anyhow",
  "bytecount",
  "cargo_metadata 0.14.0",
diff --git a/README.md b/README.md
index 26613314a15..7f601d5ee58 100644
--- a/README.md
+++ b/README.md
@@ -233,7 +233,7 @@ Snapshot binaries are currently built and tested on several platforms:
 | Platform / Architecture                     | x86 | x86_64 |
 |---------------------------------------------|-----|--------|
 | Windows (7, 8, 10, ...)                     | ✓   | ✓      |
-| Linux (kernel 2.6.32, glibc 2.11 or later)  | ✓   | ✓      |
+| Linux (kernel 3.2, glibc 2.17 or later)     | ✓   | ✓      |
 | macOS (10.7 Lion or later)                  | (\*) | ✓      |
 
 (\*): Apple dropped support for running 32-bit binaries starting from macOS 10.15 and iOS 11.
diff --git a/RELEASES.md b/RELEASES.md
index 8154eab2059..e66bf60b7f7 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,207 @@
+Version 1.63.0 (2022-08-11)
+==========================
+
+Language
+--------
+- [Remove migrate borrowck mode for pre-NLL errors.][95565]
+- [Modify MIR building to drop repeat expressions with length zero.][95953]
+- [Remove label/lifetime shadowing warnings.][96296]
+- [Allow explicit generic arguments in the presence of `impl Trait` args.][96868]
+- [Make `cenum_impl_drop_cast` warnings deny-by-default.][97652]
+- [Prevent unwinding when `-C panic=abort` is used regardless of declared ABI.][96959]
+- [lub: don't bail out due to empty binders.][97867]
+
+Compiler
+--------
+- [Stabilize the `bundle` native library modifier,][95818] also removing the
+  deprecated `static-nobundle` linking kind.
+- [Add Apple WatchOS compile targets\*.][95243]
+- [Add a Windows application manifest to rustc-main.][96737]
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+   information on Rust's tiered platform support.
+
+Libraries
+---------
+- [Implement `Copy`, `Clone`, `PartialEq` and `Eq` for `core::fmt::Alignment`.][94530]
+- [Extend `ptr::null` and `null_mut` to all thin (including extern) types.][94954]
+- [`impl Read and Write for VecDeque<u8>`.][95632]
+- [STD support for the Nintendo 3DS.][95897]
+- [Make write/print macros eagerly drop temporaries.][96455]
+- [Implement internal traits that enable `[OsStr]::join`.][96881]
+- [Implement `Hash` for `core::alloc::Layout`.][97034]
+- [Add capacity documentation for `OsString`.][97202]
+- [Put a bound on collection misbehavior.][97316]
+- [Make `std::mem::needs_drop` accept `?Sized`.][97675]
+- [`impl Termination for Infallible` and then make the `Result` impls of `Termination` more generic.][97803]
+- [Document Rust's stance on `/proc/self/mem`.][97837]
+
+Stabilized APIs
+---------------
+
+- [`array::from_fn`]
+- [`Box::into_pin`]
+- [`BinaryHeap::try_reserve`]
+- [`BinaryHeap::try_reserve_exact`]
+- [`OsString::try_reserve`]
+- [`OsString::try_reserve_exact`]
+- [`PathBuf::try_reserve`]
+- [`PathBuf::try_reserve_exact`]
+- [`Path::try_exists`]
+- [`Ref::filter_map`]
+- [`RefMut::filter_map`]
+- [`NonNull::<[T]>::len`][`NonNull::<slice>::len`]
+- [`ToOwned::clone_into`]
+- [`Ipv6Addr::to_ipv4_mapped`]
+- [`unix::io::AsFd`]
+- [`unix::io::BorrowedFd<'fd>`]
+- [`unix::io::OwnedFd`]
+- [`windows::io::AsHandle`]
+- [`windows::io::BorrowedHandle<'handle>`]
+- [`windows::io::OwnedHandle`]
+- [`windows::io::HandleOrInvalid`]
+- [`windows::io::HandleOrNull`]
+- [`windows::io::InvalidHandleError`]
+- [`windows::io::NullHandleError`]
+- [`windows::io::AsSocket`]
+- [`windows::io::BorrowedSocket<'handle>`]
+- [`windows::io::OwnedSocket`]
+- [`thread::scope`]
+- [`thread::Scope`]
+- [`thread::ScopedJoinHandle`]
+
+These APIs are now usable in const contexts:
+
+- [`array::from_ref`]
+- [`slice::from_ref`]
+- [`intrinsics::copy`]
+- [`intrinsics::copy_nonoverlapping`]
+- [`<*const T>::copy_to`]
+- [`<*const T>::copy_to_nonoverlapping`]
+- [`<*mut T>::copy_to`]
+- [`<*mut T>::copy_to_nonoverlapping`]
+- [`<*mut T>::copy_from`]
+- [`<*mut T>::copy_from_nonoverlapping`]
+- [`str::from_utf8`]
+- [`Utf8Error::error_len`]
+- [`Utf8Error::valid_up_to`]
+- [`Condvar::new`]
+- [`Mutex::new`]
+- [`RwLock::new`]
+
+Cargo
+-----
+- [Stabilize the `--config path` command-line argument.][cargo/10755]
+- [Expose rust-version in the environment as `CARGO_PKG_RUST_VERSION`.][cargo/10713]
+
+Compatibility Notes
+-------------------
+
+- [`#[link]` attributes are now checked more strictly,][96885] which may introduce
+  errors for invalid attribute arguments that were previously ignored.
+
+Internal Changes
+----------------
+
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc
+and related tools.
+
+- [Prepare Rust for LLVM opaque pointers.][94214]
+
+[94214]: https://github.com/rust-lang/rust/pull/94214/
+[94530]: https://github.com/rust-lang/rust/pull/94530/
+[94954]: https://github.com/rust-lang/rust/pull/94954/
+[95243]: https://github.com/rust-lang/rust/pull/95243/
+[95565]: https://github.com/rust-lang/rust/pull/95565/
+[95632]: https://github.com/rust-lang/rust/pull/95632/
+[95818]: https://github.com/rust-lang/rust/pull/95818/
+[95897]: https://github.com/rust-lang/rust/pull/95897/
+[95953]: https://github.com/rust-lang/rust/pull/95953/
+[96296]: https://github.com/rust-lang/rust/pull/96296/
+[96455]: https://github.com/rust-lang/rust/pull/96455/
+[96737]: https://github.com/rust-lang/rust/pull/96737/
+[96868]: https://github.com/rust-lang/rust/pull/96868/
+[96881]: https://github.com/rust-lang/rust/pull/96881/
+[96885]: https://github.com/rust-lang/rust/pull/96885/
+[96959]: https://github.com/rust-lang/rust/pull/96959/
+[97034]: https://github.com/rust-lang/rust/pull/97034/
+[97202]: https://github.com/rust-lang/rust/pull/97202/
+[97316]: https://github.com/rust-lang/rust/pull/97316/
+[97652]: https://github.com/rust-lang/rust/pull/97652/
+[97675]: https://github.com/rust-lang/rust/pull/97675/
+[97803]: https://github.com/rust-lang/rust/pull/97803/
+[97837]: https://github.com/rust-lang/rust/pull/97837/
+[97867]: https://github.com/rust-lang/rust/pull/97867/
+[cargo/10713]: https://github.com/rust-lang/cargo/pull/10713/
+[cargo/10755]: https://github.com/rust-lang/cargo/pull/10755/
+
+[`array::from_fn`]: https://doc.rust-lang.org/stable/std/array/fn.from_fn.html
+[`Box::into_pin`]: https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.into_pin
+[`BinaryHeap::try_reserve_exact`]: https://doc.rust-lang.org/stable/alloc/collections/binary_heap/struct.BinaryHeap.html#method.try_reserve_exact
+[`BinaryHeap::try_reserve`]: https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html#method.try_reserve
+[`OsString::try_reserve`]: https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.try_reserve
+[`OsString::try_reserve_exact`]: https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.try_reserve_exact
+[`PathBuf::try_reserve`]: https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.try_reserve
+[`PathBuf::try_reserve_exact`]: https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.try_reserve_exact
+[`Path::try_exists`]: https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.try_exists
+[`Ref::filter_map`]: https://doc.rust-lang.org/stable/std/cell/struct.Ref.html#method.filter_map
+[`RefMut::filter_map`]: https://doc.rust-lang.org/stable/std/cell/struct.RefMut.html#method.filter_map
+[`NonNull::<slice>::len`]: https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.len
+[`ToOwned::clone_into`]: https://doc.rust-lang.org/stable/std/borrow/trait.ToOwned.html#method.clone_into
+[`Ipv6Addr::to_ipv4_mapped`]: https://doc.rust-lang.org/stable/std/net/struct.Ipv6Addr.html#method.to_ipv4_mapped
+[`unix::io::AsFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/trait.AsFd.html
+[`unix::io::BorrowedFd<'fd>`]: https://doc.rust-lang.org/stable/std/os/unix/io/struct.BorrowedFd.html
+[`unix::io::OwnedFd`]: https://doc.rust-lang.org/stable/std/os/unix/io/struct.OwnedFd.html
+[`windows::io::AsHandle`]: https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsHandle.html
+[`windows::io::BorrowedHandle<'handle>`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.BorrowedHandle.html
+[`windows::io::OwnedHandle`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedHandle.html
+[`windows::io::HandleOrInvalid`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.HandleOrInvalid.html
+[`windows::io::HandleOrNull`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.HandleOrNull.html
+[`windows::io::InvalidHandleError`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.InvalidHandleError.html
+[`windows::io::NullHandleError`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.NullHandleError.html
+[`windows::io::AsSocket`]: https://doc.rust-lang.org/stable/std/os/windows/io/trait.AsSocket.html
+[`windows::io::BorrowedSocket<'handle>`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.BorrowedSocket.html
+[`windows::io::OwnedSocket`]: https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedSocket.html
+[`thread::scope`]: https://doc.rust-lang.org/stable/std/thread/fn.scope.html
+[`thread::Scope`]: https://doc.rust-lang.org/stable/std/thread/struct.Scope.html
+[`thread::ScopedJoinHandle`]: https://doc.rust-lang.org/stable/std/thread/struct.ScopedJoinHandle.html
+
+[`array::from_ref`]: https://doc.rust-lang.org/stable/std/array/fn.from_ref.html
+[`slice::from_ref`]: https://doc.rust-lang.org/stable/std/slice/fn.from_ref.html
+[`intrinsics::copy`]: https://doc.rust-lang.org/stable/std/intrinsics/fn.copy.html
+[`intrinsics::copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/intrinsics/fn.copy_nonoverlapping.html
+[`<*const T>::copy_to`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_to
+[`<*const T>::copy_to_nonoverlapping`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_to_nonoverlapping
+[`<*mut T>::copy_to`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_to-1
+[`<*mut T>::copy_to_nonoverlapping`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_to_nonoverlapping-1
+[`<*mut T>::copy_from`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_from
+[`<*mut T>::copy_from_nonoverlapping`]: https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.copy_from_nonoverlapping
+[`str::from_utf8`]: https://doc.rust-lang.org/stable/std/str/fn.from_utf8.html
+[`Utf8Error::error_len`]: https://doc.rust-lang.org/stable/std/str/struct.Utf8Error.html#method.error_len
+[`Utf8Error::valid_up_to`]: https://doc.rust-lang.org/stable/std/str/struct.Utf8Error.html#method.valid_up_to
+[`Condvar::new`]: https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html#method.new
+[`Mutex::new`]: https://doc.rust-lang.org/stable/std/sync/struct.Mutex.html#method.new
+[`RwLock::new`]: https://doc.rust-lang.org/stable/std/sync/struct.RwLock.html#method.new
+
+Version 1.62.1 (2022-07-19)
+==========================
+
+Rust 1.62.1 addresses a few recent regressions in the compiler and standard
+library, and also mitigates a CPU vulnerability on Intel SGX.
+
+* [The compiler fixed unsound function coercions involving `impl Trait` return types.][98608]
+* [The compiler fixed an incremental compilation bug with `async fn` lifetimes.][98890]
+* [Windows added a fallback for overlapped I/O in synchronous reads and writes.][98950]
+* [The `x86_64-fortanix-unknown-sgx` target added a mitigation for the
+  MMIO stale data vulnerability][98126], advisory [INTEL-SA-00615].
+
+[98608]: https://github.com/rust-lang/rust/issues/98608
+[98890]: https://github.com/rust-lang/rust/issues/98890
+[98950]: https://github.com/rust-lang/rust/pull/98950
+[98126]: https://github.com/rust-lang/rust/pull/98126
+[INTEL-SA-00615]: https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00615.html
+
 Version 1.62.0 (2022-06-30)
 ==========================
 
diff --git a/compiler/rustc_apfloat/src/ppc.rs b/compiler/rustc_apfloat/src/ppc.rs
index 4ae8edf3157..65a0f66645b 100644
--- a/compiler/rustc_apfloat/src/ppc.rs
+++ b/compiler/rustc_apfloat/src/ppc.rs
@@ -30,7 +30,7 @@ pub type DoubleDouble = DoubleFloat<ieee::Double>;
 // FIXME: Implement all operations in DoubleDouble, and delete these
 // semantics.
 // FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
-pub struct FallbackS<F>(F);
+pub struct FallbackS<F>(#[allow(unused)] F);
 type Fallback<F> = ieee::IeeeFloat<FallbackS<F>>;
 impl<F: Float> ieee::Semantics for FallbackS<F> {
     // Forbid any conversion to/from bits.
@@ -45,7 +45,7 @@ impl<F: Float> ieee::Semantics for FallbackS<F> {
 // truncate the mantissa. The result of that second conversion
 // may be inexact, but should never underflow.
 // FIXME(eddyb) This shouldn't need to be `pub`, it's only used in bounds.
-pub struct FallbackExtendedS<F>(F);
+pub struct FallbackExtendedS<F>(#[allow(unused)] F);
 type FallbackExtended<F> = ieee::IeeeFloat<FallbackExtendedS<F>>;
 impl<F: Float> ieee::Semantics for FallbackExtendedS<F> {
     // Forbid any conversion to/from bits.
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index ac2328a5824..870a7c0be33 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -64,7 +64,7 @@ impl fmt::Debug for Label {
 
 /// A "Lifetime" is an annotation of the scope in which variable
 /// can be used, e.g. `'a` in `&'a i32`.
-#[derive(Clone, Encodable, Decodable, Copy)]
+#[derive(Clone, Encodable, Decodable, Copy, PartialEq, Eq)]
 pub struct Lifetime {
     pub id: NodeId,
     pub ident: Ident,
@@ -1111,10 +1111,6 @@ pub struct Expr {
     pub tokens: Option<LazyTokenStream>,
 }
 
-// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Expr, 104);
-
 impl Expr {
     /// Returns `true` if this expression would be valid somewhere that expects a value;
     /// for example, an `if` condition.
@@ -2883,9 +2879,6 @@ pub enum ItemKind {
     MacroDef(MacroDef),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ItemKind, 112);
-
 impl ItemKind {
     pub fn article(&self) -> &str {
         use ItemKind::*;
@@ -2957,9 +2950,6 @@ pub enum AssocItemKind {
     MacCall(MacCall),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(AssocItemKind, 72);
-
 impl AssocItemKind {
     pub fn defaultness(&self) -> Defaultness {
         match *self {
@@ -3009,9 +2999,6 @@ pub enum ForeignItemKind {
     MacCall(MacCall),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ForeignItemKind, 72);
-
 impl From<ForeignItemKind> for ItemKind {
     fn from(foreign_item_kind: ForeignItemKind) -> ItemKind {
         match foreign_item_kind {
@@ -3038,3 +3025,27 @@ impl TryFrom<ItemKind> for ForeignItemKind {
 }
 
 pub type ForeignItem = Item<ForeignItemKind>;
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    // These are in alphabetical order, which is easy to maintain.
+    rustc_data_structures::static_assert_size!(AssocItemKind, 72);
+    rustc_data_structures::static_assert_size!(Attribute, 152);
+    rustc_data_structures::static_assert_size!(Block, 48);
+    rustc_data_structures::static_assert_size!(Expr, 104);
+    rustc_data_structures::static_assert_size!(Fn, 192);
+    rustc_data_structures::static_assert_size!(ForeignItemKind, 72);
+    rustc_data_structures::static_assert_size!(GenericBound, 88);
+    rustc_data_structures::static_assert_size!(Generics, 72);
+    rustc_data_structures::static_assert_size!(Impl, 200);
+    rustc_data_structures::static_assert_size!(Item, 200);
+    rustc_data_structures::static_assert_size!(ItemKind, 112);
+    rustc_data_structures::static_assert_size!(Lit, 48);
+    rustc_data_structures::static_assert_size!(Pat, 120);
+    rustc_data_structures::static_assert_size!(Path, 40);
+    rustc_data_structures::static_assert_size!(PathSegment, 24);
+    rustc_data_structures::static_assert_size!(Stmt, 32);
+    rustc_data_structures::static_assert_size!(Ty, 96);
+}
diff --git a/compiler/rustc_ast/src/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs
index b4fff0022e2..c96474ccb42 100644
--- a/compiler/rustc_ast/src/util/comments.rs
+++ b/compiler/rustc_ast/src/util/comments.rs
@@ -194,7 +194,7 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
     }
 
     for token in rustc_lexer::tokenize(&text[pos..]) {
-        let token_text = &text[pos..pos + token.len];
+        let token_text = &text[pos..pos + token.len as usize];
         match token.kind {
             rustc_lexer::TokenKind::Whitespace => {
                 if let Some(mut idx) = token_text.find('\n') {
@@ -211,8 +211,10 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
             }
             rustc_lexer::TokenKind::BlockComment { doc_style, .. } => {
                 if doc_style.is_none() {
-                    let code_to_the_right =
-                        !matches!(text[pos + token.len..].chars().next(), Some('\r' | '\n'));
+                    let code_to_the_right = !matches!(
+                        text[pos + token.len as usize..].chars().next(),
+                        Some('\r' | '\n')
+                    );
                     let style = match (code_to_the_left, code_to_the_right) {
                         (_, true) => CommentStyle::Mixed,
                         (false, false) => CommentStyle::Isolated,
@@ -246,7 +248,7 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec<Comme
                 code_to_the_left = true;
             }
         }
-        pos += token.len;
+        pos += token.len as usize;
     }
 
     comments
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 983efa48a45..fb6715ff17e 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -864,22 +864,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
             (body_id, generator_option)
         });
 
-        self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
-            // Lower outside new scope to preserve `is_in_loop_condition`.
-            let fn_decl = this.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
-
-            let c = self.arena.alloc(hir::Closure {
-                binder: binder_clause,
-                capture_clause,
-                bound_generic_params,
-                fn_decl,
-                body: body_id,
-                fn_decl_span: this.lower_span(fn_decl_span),
-                movability: generator_option,
-            });
+        let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
+        // Lower outside new scope to preserve `is_in_loop_condition`.
+        let fn_decl = self.lower_fn_decl(decl, None, FnDeclKind::Closure, None);
+
+        let c = self.arena.alloc(hir::Closure {
+            binder: binder_clause,
+            capture_clause,
+            bound_generic_params,
+            fn_decl,
+            body: body_id,
+            fn_decl_span: self.lower_span(fn_decl_span),
+            movability: generator_option,
+        });
 
-            hir::ExprKind::Closure(c)
-        })
+        hir::ExprKind::Closure(c)
     }
 
     fn generator_movability_for_fn(
@@ -991,23 +990,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
             body_id
         });
 
-        self.with_lifetime_binder(closure_id, generic_params, |this, bound_generic_params| {
-            // We need to lower the declaration outside the new scope, because we
-            // have to conserve the state of being inside a loop condition for the
-            // closure argument types.
-            let fn_decl = this.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
-
-            let c = self.arena.alloc(hir::Closure {
-                binder: binder_clause,
-                capture_clause,
-                bound_generic_params,
-                fn_decl,
-                body,
-                fn_decl_span: this.lower_span(fn_decl_span),
-                movability: None,
-            });
-            hir::ExprKind::Closure(c)
-        })
+        let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
+
+        // We need to lower the declaration outside the new scope, because we
+        // have to conserve the state of being inside a loop condition for the
+        // closure argument types.
+        let fn_decl = self.lower_fn_decl(&outer_decl, None, FnDeclKind::Closure, None);
+
+        let c = self.arena.alloc(hir::Closure {
+            binder: binder_clause,
+            capture_clause,
+            bound_generic_params,
+            fn_decl,
+            body,
+            fn_decl_span: self.lower_span(fn_decl_span),
+            movability: None,
+        });
+        hir::ExprKind::Closure(c)
     }
 
     /// Destructure the LHS of complex assignments.
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index ddd54f7c208..d5af74d47fd 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -323,7 +323,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
         // Do not visit the duplicate information in TraitItemRef. We want to
         // map the actual nodes, not the duplicate ones in the *Ref.
-        let TraitItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
+        let TraitItemRef { id, ident: _, kind: _, span: _ } = *ii;
 
         self.visit_nested_trait_item(id);
     }
@@ -331,8 +331,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
         // Do not visit the duplicate information in ImplItemRef. We want to
         // map the actual nodes, not the duplicate ones in the *Ref.
-        let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _, trait_item_def_id: _ } =
-            *ii;
+        let ImplItemRef { id, ident: _, kind: _, span: _, trait_item_def_id: _ } = *ii;
 
         self.visit_nested_impl_item(id);
     }
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 7da49143b46..ee4c0036f76 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -80,7 +80,6 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
             generator_kind: None,
             task_context: None,
             current_item: None,
-            captured_lifetimes: None,
             impl_trait_defs: Vec::new(),
             impl_trait_bounds: Vec::new(),
             allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
@@ -755,17 +754,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let hir_id = self.lower_node_id(i.id);
         let trait_item_def_id = hir_id.expect_owner();
 
-        let (generics, kind) = match i.kind {
+        let (generics, kind, has_default) = match i.kind {
             AssocItemKind::Const(_, ref ty, ref default) => {
                 let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
                 let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
-                (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body))
+                (hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
             }
             AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
                 let names = self.lower_fn_params_to_names(&sig.decl);
                 let (generics, sig) =
                     self.lower_method_sig(generics, sig, i.id, FnDeclKind::Trait, None);
-                (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
+                (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
             }
             AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
                 let asyncness = sig.header.asyncness;
@@ -778,7 +777,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     FnDeclKind::Trait,
                     asyncness.opt_return_id(),
                 );
-                (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
+                (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
             }
             AssocItemKind::TyAlias(box TyAlias {
                 ref generics,
@@ -789,7 +788,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }) => {
                 let mut generics = generics.clone();
                 add_ty_alias_where_clause(&mut generics, where_clauses, false);
-                self.lower_generics(
+                let (generics, kind) = self.lower_generics(
                     &generics,
                     i.id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
@@ -805,7 +804,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             ty,
                         )
                     },
-                )
+                );
+                (generics, kind, ty.is_some())
             }
             AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
         };
@@ -817,28 +817,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
             generics,
             kind,
             span: self.lower_span(i.span),
+            defaultness: hir::Defaultness::Default { has_value: has_default },
         };
         self.arena.alloc(item)
     }
 
     fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
-        let (kind, has_default) = match &i.kind {
-            AssocItemKind::Const(_, _, default) => (hir::AssocItemKind::Const, default.is_some()),
-            AssocItemKind::TyAlias(box TyAlias { ty, .. }) => {
-                (hir::AssocItemKind::Type, ty.is_some())
-            }
-            AssocItemKind::Fn(box Fn { sig, body, .. }) => {
-                (hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }, body.is_some())
+        let kind = match &i.kind {
+            AssocItemKind::Const(..) => hir::AssocItemKind::Const,
+            AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
+            AssocItemKind::Fn(box Fn { sig, .. }) => {
+                hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
             }
             AssocItemKind::MacCall(..) => unimplemented!(),
         };
         let id = hir::TraitItemId { def_id: self.local_def_id(i.id) };
-        let defaultness = hir::Defaultness::Default { has_value: has_default };
         hir::TraitItemRef {
             id,
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
-            defaultness,
             kind,
         }
     }
@@ -849,6 +846,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
     }
 
     fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
+        // Since `default impl` is not yet implemented, this is always true in impls.
+        let has_value = true;
+        let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
+
         let (generics, kind) = match &i.kind {
             AssocItemKind::Const(_, ty, expr) => {
                 let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type));
@@ -903,19 +904,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
             kind,
             vis_span: self.lower_span(i.vis.span),
             span: self.lower_span(i.span),
+            defaultness,
         };
         self.arena.alloc(item)
     }
 
     fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
-        // Since `default impl` is not yet implemented, this is always true in impls.
-        let has_value = true;
-        let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
         hir::ImplItemRef {
             id: hir::ImplItemId { def_id: self.local_def_id(i.id) },
             ident: self.lower_ident(i.ident),
             span: self.lower_span(i.span),
-            defaultness,
             kind: match &i.kind {
                 AssocItemKind::Const(..) => hir::AssocItemKind::Const,
                 AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
@@ -1351,12 +1349,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         let mut predicates: SmallVec<[hir::WherePredicate<'hir>; 4]> = SmallVec::new();
         predicates.extend(generics.params.iter().filter_map(|param| {
-            let bounds = self.lower_param_bounds(&param.bounds, itctx);
             self.lower_generic_bound_predicate(
                 param.ident,
                 param.id,
                 &param.kind,
-                bounds,
+                &param.bounds,
+                itctx,
                 PredicateOrigin::GenericParam,
             )
         }));
@@ -1404,13 +1402,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
         ident: Ident,
         id: NodeId,
         kind: &GenericParamKind,
-        bounds: &'hir [hir::GenericBound<'hir>],
+        bounds: &[GenericBound],
+        itctx: ImplTraitContext,
         origin: PredicateOrigin,
     ) -> Option<hir::WherePredicate<'hir>> {
         // Do not create a clause if we do not have anything inside it.
         if bounds.is_empty() {
             return None;
         }
+
+        let bounds = self.lower_param_bounds(bounds, itctx);
+
         let ident = self.lower_ident(ident);
         let param_span = ident.span;
         let span = bounds
@@ -1451,11 +1453,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
             GenericParamKind::Lifetime => {
                 let ident_span = self.lower_span(ident.span);
                 let ident = self.lower_ident(ident);
-                let res = self.resolver.get_lifetime_res(id).unwrap_or_else(|| {
-                    panic!("Missing resolution for lifetime {:?} at {:?}", id, ident.span)
-                });
                 let lt_id = self.next_node_id();
-                let lifetime = self.new_named_lifetime_with_res(lt_id, ident_span, ident, res);
+                let lifetime = self.new_named_lifetime(id, lt_id, ident_span, ident);
                 Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
                     lifetime,
                     span,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index a1bf0f94964..a5b089b032d 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -45,7 +45,7 @@ use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
@@ -56,6 +56,7 @@ use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::span_bug;
 use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::MacroKind;
@@ -77,6 +78,7 @@ mod block;
 mod expr;
 mod index;
 mod item;
+mod lifetime_collector;
 mod pat;
 mod path;
 
@@ -110,9 +112,6 @@ struct LoweringContext<'a, 'hir> {
     is_in_trait_impl: bool,
     is_in_dyn_type: bool,
 
-    /// Used to handle lifetimes appearing in impl-traits.
-    captured_lifetimes: Option<LifetimeCaptureContext>,
-
     current_hir_id_owner: LocalDefId,
     item_local_id_counter: hir::ItemLocalId,
     local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
@@ -129,28 +128,6 @@ struct LoweringContext<'a, 'hir> {
     allow_into_future: Option<Lrc<[Symbol]>>,
 }
 
-/// When we lower a lifetime, it is inserted in `captures`, and the resolution is modified so
-/// to point to the lifetime parameter impl-trait will generate.
-/// When traversing `for<...>` binders, they are inserted in `binders_to_ignore` so we know *not*
-/// to rebind the introduced lifetimes.
-#[derive(Debug)]
-struct LifetimeCaptureContext {
-    /// parent def_id for new definitions
-    parent_def_id: LocalDefId,
-    /// Set of lifetimes to rebind.
-    captures: FxHashMap<
-        LocalDefId, // original parameter id
-        (
-            Span,        // Span
-            NodeId,      // synthetized parameter id
-            ParamName,   // parameter name
-            LifetimeRes, // original resolution
-        ),
-    >,
-    /// Traversed binders.  The ids in this set should *not* be rebound.
-    binders_to_ignore: FxHashSet<NodeId>,
-}
-
 trait ResolverAstLoweringExt {
     fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>>;
     fn get_partial_res(&self, id: NodeId) -> Option<PartialRes>;
@@ -159,6 +136,12 @@ trait ResolverAstLoweringExt {
     fn get_lifetime_res(&self, id: NodeId) -> Option<LifetimeRes>;
     fn take_extra_lifetime_params(&mut self, id: NodeId) -> Vec<(Ident, NodeId, LifetimeRes)>;
     fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind;
+    /// Record the map from `from` local def id to `to` local def id, on `generics_def_id_map`
+    /// field.
+    fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId);
+    /// Get the previously recorded `to` local def id given the `from` local def id, obtained using
+    /// `generics_def_id_map` field.
+    fn get_remapped_def_id(&self, local_def_id: LocalDefId) -> LocalDefId;
 }
 
 impl ResolverAstLoweringExt for ResolverAstLowering {
@@ -226,6 +209,28 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
     fn decl_macro_kind(&self, def_id: LocalDefId) -> MacroKind {
         self.builtin_macro_kinds.get(&def_id).copied().unwrap_or(MacroKind::Bang)
     }
+
+    /// Push a remapping into the top-most map.
+    /// Panics if no map has been pushed.
+    /// Remapping is used when creating lowering `-> impl Trait` return
+    /// types to create the resulting opaque type.
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn record_def_id_remap(&mut self, from: LocalDefId, to: LocalDefId) {
+        self.generics_def_id_map.last_mut().expect("no map pushed").insert(from, to);
+    }
+
+    fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId {
+        for map in &self.generics_def_id_map {
+            if let Some(r) = map.get(&local_def_id) {
+                debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`");
+                local_def_id = *r;
+            } else {
+                debug!("def_id_remapper: no remapping for `{local_def_id:?}` found in map");
+            }
+        }
+
+        local_def_id
+    }
 }
 
 /// Context of `impl Trait` in code, which determines whether it is allowed in an HIR subtree,
@@ -481,8 +486,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         start
     }
 
+    /// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
+    /// resolver (if any), after applying any remapping from `get_remapped_def_id`.
+    ///
+    /// For example, in a function like `fn foo<'a>(x: &'a u32)`,
+    /// invoking with the id from the `ast::Lifetime` node found inside
+    /// the `&'a u32` type would return the `LocalDefId` of the
+    /// `'a` parameter declared on `foo`.
+    ///
+    /// This function also applies remapping from `get_remapped_def_id`.
+    /// These are used when synthesizing opaque types from `-> impl Trait` return types and so forth.
+    /// For example, in a function like `fn foo<'a>() -> impl Debug + 'a`,
+    /// we would create an opaque type `type FooReturn<'a1> = impl Debug + 'a1`.
+    /// When lowering the `Debug + 'a` bounds, we add a remapping to map `'a` to `'a1`.
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
-        self.resolver.node_id_to_def_id.get(&node).copied()
+        self.resolver
+            .node_id_to_def_id
+            .get(&node)
+            .map(|local_def_id| self.resolver.get_remapped_def_id(*local_def_id))
     }
 
     fn local_def_id(&self, node: NodeId) -> LocalDefId {
@@ -542,6 +563,27 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         debug_assert!(_old.is_none())
     }
 
+    /// Installs the remapping `remap` in scope while `f` is being executed.
+    /// This causes references to the `LocalDefId` keys to be changed to
+    /// refer to the values instead.
+    ///
+    /// The remapping is used when one piece of AST expands to multiple
+    /// pieces of HIR. For example, the function `fn foo<'a>(...) -> impl Debug + 'a`,
+    /// expands to both a function definition (`foo`) and a TAIT for the return value,
+    /// both of which have a lifetime parameter `'a`. The remapping allows us to
+    /// rewrite the `'a` in the return value to refer to the
+    /// `'a` declared on the TAIT, instead of the function.
+    fn with_remapping<R>(
+        &mut self,
+        remap: FxHashMap<LocalDefId, LocalDefId>,
+        f: impl FnOnce(&mut Self) -> R,
+    ) -> R {
+        self.resolver.generics_def_id_map.push(remap);
+        let res = f(self);
+        self.resolver.generics_def_id_map.pop();
+        res
+    }
+
     fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> {
         let attrs = std::mem::take(&mut self.attrs);
         let mut bodies = std::mem::take(&mut self.bodies);
@@ -751,40 +793,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         })
     }
 
-    /// Setup lifetime capture for and impl-trait.
-    /// The captures will be added to `captures`.
-    fn while_capturing_lifetimes<T>(
-        &mut self,
-        parent_def_id: LocalDefId,
-        captures: &mut FxHashMap<LocalDefId, (Span, NodeId, ParamName, LifetimeRes)>,
-        f: impl FnOnce(&mut Self) -> T,
-    ) -> T {
-        let lifetime_stash = std::mem::replace(
-            &mut self.captured_lifetimes,
-            Some(LifetimeCaptureContext {
-                parent_def_id,
-                captures: std::mem::take(captures),
-                binders_to_ignore: Default::default(),
-            }),
-        );
-
-        let ret = f(self);
-
-        let ctxt = std::mem::replace(&mut self.captured_lifetimes, lifetime_stash).unwrap();
-        *captures = ctxt.captures;
-
-        ret
-    }
-
-    /// Register a binder to be ignored for lifetime capture.
-    #[tracing::instrument(level = "debug", skip(self, f))]
+    /// Lowers a lifetime binder that defines `generic_params`, returning the corresponding HIR
+    /// nodes. The returned list includes any "extra" lifetime parameters that were added by the
+    /// name resolver owing to lifetime elision; this also populates the resolver's node-id->def-id
+    /// map, so that later calls to `opt_node_id_to_def_id` that refer to these extra lifetime
+    /// parameters will be successful.
+    #[tracing::instrument(level = "debug", skip(self))]
     #[inline]
-    fn with_lifetime_binder<T>(
+    fn lower_lifetime_binder(
         &mut self,
         binder: NodeId,
         generic_params: &[GenericParam],
-        f: impl FnOnce(&mut Self, &'hir [hir::GenericParam<'hir>]) -> T,
-    ) -> T {
+    ) -> &'hir [hir::GenericParam<'hir>] {
         let mut generic_params: Vec<_> = self.lower_generic_params_mut(generic_params).collect();
         let extra_lifetimes = self.resolver.take_extra_lifetime_params(binder);
         debug!(?extra_lifetimes);
@@ -794,14 +814,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let generic_params = self.arena.alloc_from_iter(generic_params);
         debug!(?generic_params);
 
-        if let Some(ctxt) = &mut self.captured_lifetimes {
-            ctxt.binders_to_ignore.insert(binder);
-        }
-        let ret = f(self, generic_params);
-        if let Some(ctxt) = &mut self.captured_lifetimes {
-            ctxt.binders_to_ignore.remove(&binder);
-        }
-        ret
+        generic_params
     }
 
     fn with_dyn_type_scope<T>(&mut self, in_scope: bool, f: impl FnOnce(&mut Self) -> T) -> T {
@@ -1222,15 +1235,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 hir::TyKind::Rptr(lifetime, self.lower_mt(mt, itctx))
             }
             TyKind::BareFn(ref f) => {
-                self.with_lifetime_binder(t.id, &f.generic_params, |this, generic_params| {
-                    hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
-                        generic_params,
-                        unsafety: this.lower_unsafety(f.unsafety),
-                        abi: this.lower_extern(f.ext),
-                        decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
-                        param_names: this.lower_fn_params_to_names(&f.decl),
-                    }))
-                })
+                let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
+                hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
+                    generic_params,
+                    unsafety: self.lower_unsafety(f.unsafety),
+                    abi: self.lower_extern(f.ext),
+                    decl: self.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
+                    param_names: self.lower_fn_params_to_names(&f.decl),
+                }))
             }
             TyKind::Never => hir::TyKind::Never,
             TyKind::Tup(ref tys) => hir::TyKind::Tup(
@@ -1293,17 +1305,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             TyKind::ImplTrait(def_node_id, ref bounds) => {
                 let span = t.span;
                 match itctx {
-                    ImplTraitContext::ReturnPositionOpaqueTy { origin } => self
-                        .lower_opaque_impl_trait(span, origin, def_node_id, |this| {
-                            this.lower_param_bounds(bounds, itctx)
-                        }),
+                    ImplTraitContext::ReturnPositionOpaqueTy { origin } => {
+                        self.lower_opaque_impl_trait(span, origin, def_node_id, bounds, itctx)
+                    }
                     ImplTraitContext::TypeAliasesOpaqueTy => {
                         let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
                         self.lower_opaque_impl_trait(
                             span,
                             hir::OpaqueTyOrigin::TyAlias,
                             def_node_id,
-                            |this| this.lower_param_bounds(bounds, nested_itctx),
+                            bounds,
+                            nested_itctx,
                         )
                     }
                     ImplTraitContext::Universal => {
@@ -1343,13 +1355,43 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
     }
 
-    #[tracing::instrument(level = "debug", skip(self, lower_bounds))]
+    /// Lowers a `ReturnPositionOpaqueTy` (`-> impl Trait`) or a `TypeAliasesOpaqueTy` (`type F =
+    /// impl Trait`): this creates the associated Opaque Type (TAIT) definition and then returns a
+    /// HIR type that references the TAIT.
+    ///
+    /// Given a function definition like:
+    ///
+    /// ```rust
+    /// fn test<'a, T: Debug>(x: &'a T) -> impl Debug + 'a {
+    ///     x
+    /// }
+    /// ```
+    ///
+    /// we will create a TAIT definition in the HIR like
+    ///
+    /// ```
+    /// type TestReturn<'a, T, 'x> = impl Debug + 'x
+    /// ```
+    ///
+    /// and return a type like `TestReturn<'static, T, 'a>`, so that the function looks like:
+    ///
+    /// ```rust
+    /// fn test<'a, T: Debug>(x: &'a T) -> TestReturn<'static, T, 'a>
+    /// ```
+    ///
+    /// Note the subtlety around type parameters! The new TAIT, `TestReturn`, inherits all the
+    /// type parameters from the function `test` (this is implemented in the query layer, they aren't
+    /// added explicitly in the HIR). But this includes all the lifetimes, and we only want to
+    /// capture the lifetimes that are referenced in the bounds. Therefore, we add *extra* lifetime parameters
+    /// for the lifetimes that get captured (`'x`, in our example above) and reference those.
+    #[tracing::instrument(level = "debug", skip(self))]
     fn lower_opaque_impl_trait(
         &mut self,
         span: Span,
         origin: hir::OpaqueTyOrigin,
         opaque_ty_node_id: NodeId,
-        lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>,
+        bounds: &GenericBounds,
+        itctx: ImplTraitContext,
     ) -> hir::TyKind<'hir> {
         // Make sure we know that some funky desugaring has been going on here.
         // This is a first: there is code in other places like for loop
@@ -1359,70 +1401,108 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
         let opaque_ty_def_id = self.local_def_id(opaque_ty_node_id);
+        debug!(?opaque_ty_def_id);
 
-        let mut collected_lifetimes = FxHashMap::default();
-        self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
-            let hir_bounds = if origin == hir::OpaqueTyOrigin::TyAlias {
-                lower_bounds(lctx)
-            } else {
-                lctx.while_capturing_lifetimes(
-                    opaque_ty_def_id,
-                    &mut collected_lifetimes,
-                    lower_bounds,
-                )
-            };
-            debug!(?collected_lifetimes);
+        // Contains the new lifetime definitions created for the TAIT (if any).
+        let mut collected_lifetimes = Vec::new();
 
-            let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
-                |(_, &(span, p_id, p_name, _))| {
-                    let hir_id = lctx.lower_node_id(p_id);
-                    debug_assert_ne!(lctx.opt_local_def_id(p_id), None);
+        // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
+        // to capture the lifetimes that appear in the bounds. So visit the bounds to find out
+        // exactly which ones those are.
+        let lifetimes_to_remap = if origin == hir::OpaqueTyOrigin::TyAlias {
+            // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
+            Vec::new()
+        } else {
+            // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
+            // we only keep the lifetimes that appear in the `impl Debug` itself:
+            lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
+        };
+        debug!(?lifetimes_to_remap);
 
-                    let kind = if p_name.ident().name == kw::UnderscoreLifetime {
-                        hir::LifetimeParamKind::Elided
-                    } else {
-                        hir::LifetimeParamKind::Explicit
-                    };
+        self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
+            let mut new_remapping = FxHashMap::default();
+
+            // If this opaque type is only capturing a subset of the lifetimes (those that appear
+            // in bounds), then create the new lifetime parameters required and create a mapping
+            // from the old `'a` (on the function) to the new `'a` (on the opaque type).
+            collected_lifetimes = lctx.create_lifetime_defs(
+                opaque_ty_def_id,
+                &lifetimes_to_remap,
+                &mut new_remapping,
+            );
+            debug!(?collected_lifetimes);
+            debug!(?new_remapping);
+
+            // Install the remapping from old to new (if any):
+            lctx.with_remapping(new_remapping, |lctx| {
+                // This creates HIR lifetime definitions as `hir::GenericParam`, in the given
+                // example `type TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection
+                // containing `&['x]`.
+                let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
+                    |&(new_node_id, lifetime)| {
+                        let hir_id = lctx.lower_node_id(new_node_id);
+                        debug_assert_ne!(lctx.opt_local_def_id(new_node_id), None);
+
+                        let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
+                            (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+                        } else {
+                            (
+                                hir::ParamName::Plain(lifetime.ident),
+                                hir::LifetimeParamKind::Explicit,
+                            )
+                        };
 
-                    hir::GenericParam {
-                        hir_id,
-                        name: p_name,
-                        span,
-                        pure_wrt_drop: false,
-                        kind: hir::GenericParamKind::Lifetime { kind },
-                        colon_span: None,
-                    }
-                },
-            ));
-
-            debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs);
-
-            let opaque_ty_item = hir::OpaqueTy {
-                generics: self.arena.alloc(hir::Generics {
-                    params: lifetime_defs,
-                    predicates: &[],
-                    has_where_clause_predicates: false,
-                    where_clause_span: lctx.lower_span(span),
-                    span: lctx.lower_span(span),
-                }),
-                bounds: hir_bounds,
-                origin,
-            };
+                        hir::GenericParam {
+                            hir_id,
+                            name,
+                            span: lifetime.ident.span,
+                            pure_wrt_drop: false,
+                            kind: hir::GenericParamKind::Lifetime { kind },
+                            colon_span: None,
+                        }
+                    },
+                ));
+                debug!(?lifetime_defs);
+
+                // Then when we lower the param bounds, references to 'a are remapped to 'a1, so we
+                // get back Debug + 'a1, which is suitable for use on the TAIT.
+                let hir_bounds = lctx.lower_param_bounds(bounds, itctx);
+                debug!(?hir_bounds);
+
+                let opaque_ty_item = hir::OpaqueTy {
+                    generics: self.arena.alloc(hir::Generics {
+                        params: lifetime_defs,
+                        predicates: &[],
+                        has_where_clause_predicates: false,
+                        where_clause_span: lctx.lower_span(span),
+                        span: lctx.lower_span(span),
+                    }),
+                    bounds: hir_bounds,
+                    origin,
+                };
+                debug!(?opaque_ty_item);
 
-            trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_id);
-            lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+                lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+            })
         });
 
-        let lifetimes = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
-            |(_, (span, _, p_name, res))| {
+        // This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
+        // TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
+        let lifetimes =
+            self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(|(_, lifetime)| {
                 let id = self.next_node_id();
-                let ident = Ident::new(p_name.ident().name, span);
-                let l = self.new_named_lifetime_with_res(id, span, ident, res);
-                hir::GenericArg::Lifetime(l)
-            },
-        ));
+                let span = lifetime.ident.span;
 
-        debug!("lower_opaque_impl_trait: lifetimes={:#?}", lifetimes);
+                let ident = if lifetime.ident.name == kw::UnderscoreLifetime {
+                    Ident::with_dummy_span(kw::UnderscoreLifetime)
+                } else {
+                    lifetime.ident
+                };
+
+                let l = self.new_named_lifetime(lifetime.id, id, span, ident);
+                hir::GenericArg::Lifetime(l)
+            }));
+        debug!(?lifetimes);
 
         // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
         hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
@@ -1450,6 +1530,70 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
     }
 
+    /// Given a `parent_def_id`, a list of `lifetimes_in_bounds and a `remapping` hash to be
+    /// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the
+    /// new definition, adds it to the remapping with the definition of the given lifetime and
+    /// returns a list of lifetimes to be lowered afterwards.
+    fn create_lifetime_defs(
+        &mut self,
+        parent_def_id: LocalDefId,
+        lifetimes_in_bounds: &[Lifetime],
+        remapping: &mut FxHashMap<LocalDefId, LocalDefId>,
+    ) -> Vec<(NodeId, Lifetime)> {
+        let mut result = Vec::new();
+
+        for lifetime in lifetimes_in_bounds {
+            let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
+            debug!(?res);
+
+            match res {
+                LifetimeRes::Param { param: old_def_id, binder: _ } => {
+                    if remapping.get(&old_def_id).is_none() {
+                        let node_id = self.next_node_id();
+
+                        let new_def_id = self.create_def(
+                            parent_def_id,
+                            node_id,
+                            DefPathData::LifetimeNs(lifetime.ident.name),
+                        );
+                        remapping.insert(old_def_id, new_def_id);
+
+                        result.push((node_id, *lifetime));
+                    }
+                }
+
+                LifetimeRes::Fresh { param, binder: _ } => {
+                    debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
+                    let old_def_id = self.local_def_id(param);
+                    if remapping.get(&old_def_id).is_none() {
+                        let node_id = self.next_node_id();
+
+                        let new_def_id = self.create_def(
+                            parent_def_id,
+                            node_id,
+                            DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+                        );
+                        remapping.insert(old_def_id, new_def_id);
+
+                        result.push((node_id, *lifetime));
+                    }
+                }
+
+                LifetimeRes::Static | LifetimeRes::Error => {}
+
+                res => {
+                    let bug_msg = format!(
+                        "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+                        res, lifetime.ident, lifetime.ident.span
+                    );
+                    span_bug!(lifetime.ident.span, "{}", bug_msg);
+                }
+            }
+        }
+
+        result
+    }
+
     fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
         // Skip the `...` (`CVarArgs`) trailing arguments from the AST,
         // as they are not explicit in HIR/Ty function signatures.
@@ -1582,11 +1726,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     //
     //     type OpaqueTy<generics_from_parent_fn> = impl Future<Output = T>;
     //
-    // `inputs`: lowered types of parameters to the function (used to collect lifetimes)
     // `output`: unlowered output type (`T` in `-> T`)
     // `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition)
     // `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created
-    // `elided_lt_replacement`: replacement for elided lifetimes in the return type
     #[tracing::instrument(level = "debug", skip(self))]
     fn lower_async_fn_ret_ty(
         &mut self,
@@ -1643,90 +1785,126 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // by the opaque type. This should include all in-scope
         // lifetime parameters, including those defined in-band.
 
-        let mut captures = FxHashMap::default();
+        // Contains the new lifetime definitions created for the TAIT (if any) generated for the
+        // return type.
+        let mut collected_lifetimes = Vec::new();
+        let mut new_remapping = FxHashMap::default();
 
         let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
         debug!(?extra_lifetime_params);
         for (ident, outer_node_id, outer_res) in extra_lifetime_params {
-            let Ident { name, span } = ident;
             let outer_def_id = self.local_def_id(outer_node_id);
             let inner_node_id = self.next_node_id();
 
             // Add a definition for the in scope lifetime def.
-            self.create_def(opaque_ty_def_id, inner_node_id, DefPathData::LifetimeNs(name));
+            let inner_def_id = self.create_def(
+                opaque_ty_def_id,
+                inner_node_id,
+                DefPathData::LifetimeNs(ident.name),
+            );
+            new_remapping.insert(outer_def_id, inner_def_id);
 
-            let (p_name, inner_res) = match outer_res {
+            let inner_res = match outer_res {
                 // Input lifetime like `'a`:
                 LifetimeRes::Param { param, .. } => {
-                    (hir::ParamName::Plain(ident), LifetimeRes::Param { param, binder: fn_node_id })
+                    LifetimeRes::Param { param, binder: fn_node_id }
                 }
                 // Input lifetime like `'1`:
                 LifetimeRes::Fresh { param, .. } => {
-                    (hir::ParamName::Fresh, LifetimeRes::Fresh { param, binder: fn_node_id })
+                    LifetimeRes::Fresh { param, binder: fn_node_id }
                 }
                 LifetimeRes::Static | LifetimeRes::Error => continue,
                 res => {
-                    panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span)
+                    panic!(
+                        "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+                        res, ident, ident.span
+                    )
                 }
             };
 
-            captures.insert(outer_def_id, (span, inner_node_id, p_name, inner_res));
+            let lifetime = Lifetime { id: outer_node_id, ident };
+            collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
         }
 
-        debug!(?captures);
-
-        self.with_hir_id_owner(opaque_ty_node_id, |this| {
-            let future_bound =
-                this.while_capturing_lifetimes(opaque_ty_def_id, &mut captures, |this| {
-                    // We have to be careful to get elision right here. The
-                    // idea is that we create a lifetime parameter for each
-                    // lifetime in the return type.  So, given a return type
-                    // like `async fn foo(..) -> &[&u32]`, we lower to `impl
-                    // Future<Output = &'1 [ &'2 u32 ]>`.
-                    //
-                    // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
-                    // hence the elision takes place at the fn site.
-                    this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
-                });
-            debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
-            debug!("lower_async_fn_ret_ty: captures={:#?}", captures);
+        debug!(?collected_lifetimes);
 
-            let generic_params =
-                this.arena.alloc_from_iter(captures.iter().map(|(_, &(span, p_id, p_name, _))| {
-                    let hir_id = this.lower_node_id(p_id);
-                    debug_assert_ne!(this.opt_local_def_id(p_id), None);
+        // We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
+        // find out exactly which ones those are.
+        // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
+        // we only keep the lifetimes that appear in the `impl Debug` itself:
+        let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
+        debug!(?lifetimes_to_remap);
 
-                    let kind = if p_name.ident().name == kw::UnderscoreLifetime {
-                        hir::LifetimeParamKind::Elided
-                    } else {
-                        hir::LifetimeParamKind::Explicit
-                    };
+        self.with_hir_id_owner(opaque_ty_node_id, |this| {
+            // If this opaque type is only capturing a subset of the lifetimes (those that appear
+            // in bounds), then create the new lifetime parameters required and create a mapping
+            // from the old `'a` (on the function) to the new `'a` (on the opaque type).
+            collected_lifetimes.extend(
+                this.create_lifetime_defs(
+                    opaque_ty_def_id,
+                    &lifetimes_to_remap,
+                    &mut new_remapping,
+                )
+                .into_iter()
+                .map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
+            );
+            debug!(?collected_lifetimes);
+            debug!(?new_remapping);
+
+            // Install the remapping from old to new (if any):
+            this.with_remapping(new_remapping, |this| {
+                // We have to be careful to get elision right here. The
+                // idea is that we create a lifetime parameter for each
+                // lifetime in the return type.  So, given a return type
+                // like `async fn foo(..) -> &[&u32]`, we lower to `impl
+                // Future<Output = &'1 [ &'2 u32 ]>`.
+                //
+                // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
+                // hence the elision takes place at the fn site.
+                let future_bound =
+                    this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span);
+
+                let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
+                    |&(new_node_id, lifetime, _)| {
+                        let hir_id = this.lower_node_id(new_node_id);
+                        debug_assert_ne!(this.opt_local_def_id(new_node_id), None);
+
+                        let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
+                            (hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
+                        } else {
+                            (
+                                hir::ParamName::Plain(lifetime.ident),
+                                hir::LifetimeParamKind::Explicit,
+                            )
+                        };
 
-                    hir::GenericParam {
-                        hir_id,
-                        name: p_name,
-                        span,
-                        pure_wrt_drop: false,
-                        kind: hir::GenericParamKind::Lifetime { kind },
-                        colon_span: None,
-                    }
-                }));
-            debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
-
-            let opaque_ty_item = hir::OpaqueTy {
-                generics: this.arena.alloc(hir::Generics {
-                    params: generic_params,
-                    predicates: &[],
-                    has_where_clause_predicates: false,
-                    where_clause_span: this.lower_span(span),
-                    span: this.lower_span(span),
-                }),
-                bounds: arena_vec![this; future_bound],
-                origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
-            };
+                        hir::GenericParam {
+                            hir_id,
+                            name,
+                            span: lifetime.ident.span,
+                            pure_wrt_drop: false,
+                            kind: hir::GenericParamKind::Lifetime { kind },
+                            colon_span: None,
+                        }
+                    },
+                ));
+                debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
+
+                let opaque_ty_item = hir::OpaqueTy {
+                    generics: this.arena.alloc(hir::Generics {
+                        params: generic_params,
+                        predicates: &[],
+                        has_where_clause_predicates: false,
+                        where_clause_span: this.lower_span(span),
+                        span: this.lower_span(span),
+                    }),
+                    bounds: arena_vec![this; future_bound],
+                    origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+                };
 
-            trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
-            this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+                trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
+                this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
+            })
         });
 
         // As documented above, we need to create the lifetime
@@ -1744,13 +1922,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         //
         // For the "output" lifetime parameters, we just want to
         // generate `'_`.
-        let generic_args =
-            self.arena.alloc_from_iter(captures.into_iter().map(|(_, (span, _, p_name, res))| {
+        let generic_args = self.arena.alloc_from_iter(collected_lifetimes.into_iter().map(
+            |(_, lifetime, res)| {
                 let id = self.next_node_id();
-                let ident = Ident::new(p_name.ident().name, span);
+                let span = lifetime.ident.span;
+
+                let ident = if lifetime.ident.name == kw::UnderscoreLifetime {
+                    Ident::with_dummy_span(kw::UnderscoreLifetime)
+                } else {
+                    lifetime.ident
+                };
+
+                let res = res.unwrap_or(
+                    self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
+                );
                 let l = self.new_named_lifetime_with_res(id, span, ident, res);
                 hir::GenericArg::Lifetime(l)
-            }));
+            },
+        ));
 
         // Create the `Foo<...>` reference itself. Note that the `type
         // Foo = impl Trait` is, internally, created as a child of the
@@ -1820,8 +2009,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
         let span = self.lower_span(l.ident.span);
         let ident = self.lower_ident(l.ident);
-        let res = self.resolver.get_lifetime_res(l.id).unwrap_or(LifetimeRes::Error);
-        self.new_named_lifetime_with_res(l.id, span, ident, res)
+        self.new_named_lifetime(l.id, l.id, span, ident)
     }
 
     #[tracing::instrument(level = "debug", skip(self))]
@@ -1832,55 +2020,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         ident: Ident,
         res: LifetimeRes,
     ) -> hir::Lifetime {
-        debug!(?self.captured_lifetimes);
         let name = match res {
-            LifetimeRes::Param { mut param, binder } => {
+            LifetimeRes::Param { param, .. } => {
                 let p_name = ParamName::Plain(ident);
-                if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
-                    if !captured_lifetimes.binders_to_ignore.contains(&binder) {
-                        match captured_lifetimes.captures.entry(param) {
-                            Entry::Occupied(o) => param = self.local_def_id(o.get().1),
-                            Entry::Vacant(v) => {
-                                let p_id = self.next_node_id();
-                                let p_def_id = self.create_def(
-                                    captured_lifetimes.parent_def_id,
-                                    p_id,
-                                    DefPathData::LifetimeNs(p_name.ident().name),
-                                );
-
-                                v.insert((span, p_id, p_name, res));
-                                param = p_def_id;
-                            }
-                        }
-                    }
+                let param = self.resolver.get_remapped_def_id(param);
 
-                    self.captured_lifetimes = Some(captured_lifetimes);
-                }
                 hir::LifetimeName::Param(param, p_name)
             }
-            LifetimeRes::Fresh { param, binder } => {
+            LifetimeRes::Fresh { param, .. } => {
                 debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
-                let mut param = self.local_def_id(param);
-                if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
-                    if !captured_lifetimes.binders_to_ignore.contains(&binder) {
-                        match captured_lifetimes.captures.entry(param) {
-                            Entry::Occupied(o) => param = self.local_def_id(o.get().1),
-                            Entry::Vacant(v) => {
-                                let p_id = self.next_node_id();
-                                let p_def_id = self.create_def(
-                                    captured_lifetimes.parent_def_id,
-                                    p_id,
-                                    DefPathData::LifetimeNs(kw::UnderscoreLifetime),
-                                );
-
-                                v.insert((span, p_id, ParamName::Fresh, res));
-                                param = p_def_id;
-                            }
-                        }
-                    }
+                let param = self.local_def_id(param);
 
-                    self.captured_lifetimes = Some(captured_lifetimes);
-                }
                 hir::LifetimeName::Param(param, ParamName::Fresh)
             }
             LifetimeRes::Infer => hir::LifetimeName::Infer,
@@ -1888,11 +2038,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             LifetimeRes::Error => hir::LifetimeName::Error,
             res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
         };
-        debug!(?self.captured_lifetimes);
+
         debug!(?name);
         hir::Lifetime { hir_id: self.lower_node_id(id), span: self.lower_span(span), name }
     }
 
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn new_named_lifetime(
+        &mut self,
+        id: NodeId,
+        new_id: NodeId,
+        span: Span,
+        ident: Ident,
+    ) -> hir::Lifetime {
+        let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
+        self.new_named_lifetime_with_res(new_id, span, ident, res)
+    }
+
     fn lower_generic_params_mut<'s>(
         &'s mut self,
         params: &'s [GenericParam],
@@ -1975,14 +2137,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         p: &PolyTraitRef,
         itctx: ImplTraitContext,
     ) -> hir::PolyTraitRef<'hir> {
-        self.with_lifetime_binder(
-            p.trait_ref.ref_id,
-            &p.bound_generic_params,
-            |this, bound_generic_params| {
-                let trait_ref = this.lower_trait_ref(&p.trait_ref, itctx);
-                hir::PolyTraitRef { bound_generic_params, trait_ref, span: this.lower_span(p.span) }
-            },
-        )
+        let bound_generic_params =
+            self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
+        let trait_ref = self.lower_trait_ref(&p.trait_ref, itctx);
+        hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
     }
 
     fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
@@ -2015,7 +2173,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // Add a definition for the in-band `Param`.
         let def_id = self.local_def_id(node_id);
 
-        let hir_bounds = self.lower_param_bounds(bounds, ImplTraitContext::Universal);
         // Set the name to `impl Bound1 + Bound2`.
         let param = hir::GenericParam {
             hir_id: self.lower_node_id(node_id),
@@ -2030,7 +2187,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             ident,
             node_id,
             &GenericParamKind::Type { default: None },
-            hir_bounds,
+            bounds,
+            ImplTraitContext::Universal,
             hir::PredicateOrigin::ImplTrait,
         );
 
diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
new file mode 100644
index 00000000000..81006e00fd4
--- /dev/null
+++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
@@ -0,0 +1,115 @@
+use super::ResolverAstLoweringExt;
+use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
+use rustc_ast::{
+    FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, TraitBoundModifier, Ty,
+    TyKind,
+};
+use rustc_hir::def::LifetimeRes;
+use rustc_middle::span_bug;
+use rustc_middle::ty::ResolverAstLowering;
+use rustc_span::symbol::{kw, Ident};
+use rustc_span::Span;
+
+struct LifetimeCollectVisitor<'ast> {
+    resolver: &'ast ResolverAstLowering,
+    current_binders: Vec<NodeId>,
+    collected_lifetimes: Vec<Lifetime>,
+}
+
+impl<'ast> LifetimeCollectVisitor<'ast> {
+    fn new(resolver: &'ast ResolverAstLowering) -> Self {
+        Self { resolver, current_binders: Vec::new(), collected_lifetimes: Vec::new() }
+    }
+
+    fn record_lifetime_use(&mut self, lifetime: Lifetime) {
+        match self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error) {
+            LifetimeRes::Param { binder, .. } | LifetimeRes::Fresh { binder, .. } => {
+                if !self.current_binders.contains(&binder) {
+                    if !self.collected_lifetimes.contains(&lifetime) {
+                        self.collected_lifetimes.push(lifetime);
+                    }
+                }
+            }
+            LifetimeRes::Static | LifetimeRes::Error => {
+                if !self.collected_lifetimes.contains(&lifetime) {
+                    self.collected_lifetimes.push(lifetime);
+                }
+            }
+            LifetimeRes::Infer => {}
+            res => {
+                let bug_msg = format!(
+                    "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+                    res, lifetime.ident, lifetime.ident.span
+                );
+                span_bug!(lifetime.ident.span, "{}", bug_msg);
+            }
+        }
+    }
+
+    /// This collect lifetimes that are elided, for nodes like `Foo<T>` where there are no explicit
+    /// lifetime nodes. Is equivalent to having "pseudo" nodes introduced for each of the node ids
+    /// in the list start..end.
+    fn record_elided_anchor(&mut self, node_id: NodeId, span: Span) {
+        if let Some(LifetimeRes::ElidedAnchor { start, end }) =
+            self.resolver.get_lifetime_res(node_id)
+        {
+            for i in start..end {
+                let lifetime = Lifetime { id: i, ident: Ident::new(kw::UnderscoreLifetime, span) };
+                self.record_lifetime_use(lifetime);
+            }
+        }
+    }
+}
+
+impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
+    fn visit_lifetime(&mut self, lifetime: &'ast Lifetime, _: LifetimeCtxt) {
+        self.record_lifetime_use(*lifetime);
+    }
+
+    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'ast PathSegment) {
+        self.record_elided_anchor(path_segment.id, path_span);
+        visit::walk_path_segment(self, path_span, path_segment);
+    }
+
+    fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
+        self.current_binders.push(t.trait_ref.ref_id);
+
+        visit::walk_poly_trait_ref(self, t, m);
+
+        self.current_binders.pop();
+    }
+
+    fn visit_ty(&mut self, t: &'ast Ty) {
+        match t.kind {
+            TyKind::BareFn(_) => {
+                self.current_binders.push(t.id);
+                visit::walk_ty(self, t);
+                self.current_binders.pop();
+            }
+            TyKind::Rptr(None, _) => {
+                self.record_elided_anchor(t.id, t.span);
+                visit::walk_ty(self, t);
+            }
+            _ => {
+                visit::walk_ty(self, t);
+            }
+        }
+    }
+}
+
+pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec<Lifetime> {
+    let mut visitor = LifetimeCollectVisitor::new(resolver);
+    visitor.visit_fn_ret_ty(ret_ty);
+    visitor.collected_lifetimes
+}
+
+pub fn lifetimes_in_bounds(
+    resolver: &ResolverAstLowering,
+    bounds: &GenericBounds,
+) -> Vec<Lifetime> {
+    let mut visitor = LifetimeCollectVisitor::new(resolver);
+    for bound in bounds {
+        visitor.visit_param_bound(bound, BoundKind::Bound);
+    }
+    visitor.collected_lifetimes
+}
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index ad9ed798e55..6e33c261a03 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -2,7 +2,7 @@ use rustc_ast as ast;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
 use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
 use rustc_ast::{PatKind, RangeEnd, VariantData};
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, Applicability};
 use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_feature::{Features, GateIssue};
 use rustc_session::parse::{feature_err, feature_err_issue};
@@ -577,6 +577,32 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         }
     }
 
+    fn visit_stmt(&mut self, stmt: &'a ast::Stmt) {
+        if let ast::StmtKind::Semi(expr) = &stmt.kind
+            && let ast::ExprKind::Assign(lhs, _, _) = &expr.kind
+            && let ast::ExprKind::Type(..) = lhs.kind
+            && self.sess.parse_sess.span_diagnostic.err_count() == 0
+            && !self.features.type_ascription
+            && !lhs.span.allows_unstable(sym::type_ascription)
+        {
+            // When we encounter a statement of the form `foo: Ty = val;`, this will emit a type
+            // ascription error, but the likely intention was to write a `let` statement. (#78907).
+            feature_err_issue(
+                &self.sess.parse_sess,
+                sym::type_ascription,
+                lhs.span,
+                GateIssue::Language,
+                "type ascription is experimental",
+            ).span_suggestion_verbose(
+                lhs.span.shrink_to_lo(),
+                "you might have meant to introduce a new binding",
+                "let ".to_string(),
+                Applicability::MachineApplicable,
+            ).emit();
+        }
+        visit::walk_stmt(self, stmt);
+    }
+
     fn visit_expr(&mut self, e: &'a ast::Expr) {
         match e.kind {
             ast::ExprKind::Box(_) => {
@@ -795,8 +821,6 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
     // checks if `#![feature]` has been used to enable any lang feature
     // does not check the same for lib features unless there's at least one
     // declared lang feature
-    use rustc_errors::Applicability;
-
     if !sess.opts.unstable_features.is_nightly_build() {
         let lang_features = &sess.features_untracked().declared_lang_features;
         if lang_features.len() == 0 {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 55ddd24c48a..5eb7bf6347f 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -377,7 +377,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
 
     fn print_string(&mut self, st: &str, style: ast::StrStyle) {
         let st = match style {
-            ast::StrStyle::Cooked => (format!("\"{}\"", st.escape_debug())),
+            ast::StrStyle::Cooked => format!("\"{}\"", st.escape_debug()),
             ast::StrStyle::Raw(n) => {
                 format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
             }
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index eae162fe479..8bc8964bbd7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -16,9 +16,7 @@ use rustc_middle::mir::{
     FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
     ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
 };
-use rustc_middle::ty::{
-    self, subst::Subst, suggest_constraining_type_params, EarlyBinder, PredicateKind, Ty,
-};
+use rustc_middle::ty::{self, subst::Subst, suggest_constraining_type_params, PredicateKind, Ty};
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
@@ -39,7 +37,7 @@ use crate::{
 
 use super::{
     explain_borrow::{BorrowExplanation, LaterUseKind},
-    IncludingDowncast, RegionName, RegionNameSource, UseSpans,
+    DescribePlaceOpt, RegionName, RegionNameSource, UseSpans,
 };
 
 #[derive(Debug)]
@@ -137,7 +135,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 span,
                 desired_action.as_noun(),
                 partially_str,
-                self.describe_place_with_options(moved_place, IncludingDowncast(true)),
+                self.describe_place_with_options(
+                    moved_place,
+                    DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
+                ),
             );
 
             let reinit_spans = maybe_reinitialized_locations
@@ -274,8 +275,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 }
             }
 
-            let opt_name =
-                self.describe_place_with_options(place.as_ref(), IncludingDowncast(true));
+            let opt_name = self.describe_place_with_options(
+                place.as_ref(),
+                DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
+            );
             let note_msg = match opt_name {
                 Some(ref name) => format!("`{}`", name),
                 None => "value".to_owned(),
@@ -341,12 +344,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             }
         }
 
-        let (name, desc) =
-            match self.describe_place_with_options(moved_place, IncludingDowncast(true)) {
-                Some(name) => (format!("`{name}`"), format!("`{name}` ")),
-                None => ("the variable".to_string(), String::new()),
-            };
-        let path = match self.describe_place_with_options(used_place, IncludingDowncast(true)) {
+        let (name, desc) = match self.describe_place_with_options(
+            moved_place,
+            DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
+        ) {
+            Some(name) => (format!("`{name}`"), format!("`{name}` ")),
+            None => ("the variable".to_string(), String::new()),
+        };
+        let path = match self.describe_place_with_options(
+            used_place,
+            DescribePlaceOpt { including_downcast: true, including_tuple_field: true },
+        ) {
             Some(name) => format!("`{name}`"),
             None => "value".to_string(),
         };
@@ -451,23 +459,24 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         let tcx = self.infcx.tcx;
 
         // Find out if the predicates show that the type is a Fn or FnMut
-        let find_fn_kind_from_did = |predicates: &[(ty::Predicate<'tcx>, Span)], substs| {
-            predicates.iter().find_map(|(pred, _)| {
-                let pred = if let Some(substs) = substs {
-                    EarlyBinder(*pred).subst(tcx, substs).kind().skip_binder()
-                } else {
-                    pred.kind().skip_binder()
-                };
-                if let ty::PredicateKind::Trait(pred) = pred && pred.self_ty() == ty {
+        let find_fn_kind_from_did =
+            |predicates: ty::EarlyBinder<&[(ty::Predicate<'tcx>, Span)]>, substs| {
+                predicates.0.iter().find_map(|(pred, _)| {
+                    let pred = if let Some(substs) = substs {
+                        predicates.rebind(*pred).subst(tcx, substs).kind().skip_binder()
+                    } else {
+                        pred.kind().skip_binder()
+                    };
+                    if let ty::PredicateKind::Trait(pred) = pred && pred.self_ty() == ty {
                     if Some(pred.def_id()) == tcx.lang_items().fn_trait() {
                         return Some(hir::Mutability::Not);
                     } else if Some(pred.def_id()) == tcx.lang_items().fn_mut_trait() {
                         return Some(hir::Mutability::Mut);
                     }
                 }
-                None
-            })
-        };
+                    None
+                })
+            };
 
         // If the type is opaque/param/closure, and it is Fn or FnMut, let's suggest (mutably)
         // borrowing the type, since `&mut F: FnMut` iff `F: FnMut` and similarly for `Fn`.
@@ -475,11 +484,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         // borrowed variants in a function body when we see a move error.
         let borrow_level = match ty.kind() {
             ty::Param(_) => find_fn_kind_from_did(
-                tcx.explicit_predicates_of(self.mir_def_id().to_def_id()).predicates,
+                tcx.bound_explicit_predicates_of(self.mir_def_id().to_def_id())
+                    .map_bound(|p| p.predicates),
                 None,
             ),
             ty::Opaque(did, substs) => {
-                find_fn_kind_from_did(tcx.explicit_item_bounds(*did), Some(*substs))
+                find_fn_kind_from_did(tcx.bound_explicit_item_bounds(*did), Some(*substs))
             }
             ty::Closure(_, substs) => match substs.as_closure().kind() {
                 ty::ClosureKind::Fn => Some(hir::Mutability::Not),
@@ -2726,7 +2736,7 @@ impl<'b, 'v> Visitor<'v> for ConditionVisitor<'b> {
                                 self.errors.push((
                                     e.span,
                                     format!(
-                                        "if the `for` loop runs 0 times, {} is not initialized ",
+                                        "if the `for` loop runs 0 times, {} is not initialized",
                                         self.name
                                     ),
                                 ));
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 0300180f80a..098e8de9420 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -4,7 +4,7 @@ use itertools::Itertools;
 use rustc_const_eval::util::{call_kind, CallDesugaringKind};
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir as hir;
-use rustc_hir::def::Namespace;
+use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::GeneratorKind;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::tcx::PlaceTy;
@@ -16,7 +16,7 @@ use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{symbol::sym, Span, DUMMY_SP};
+use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
 
@@ -43,7 +43,15 @@ pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionError
 pub(crate) use region_name::{RegionName, RegionNameSource};
 pub(crate) use rustc_const_eval::util::CallKind;
 
-pub(super) struct IncludingDowncast(pub(super) bool);
+pub(super) struct DescribePlaceOpt {
+    pub including_downcast: bool,
+
+    /// Enable/Disable tuple fields.
+    /// For example `x` tuple. if it's `true` `x.0`. Otherwise `x`
+    pub including_tuple_field: bool,
+}
+
+pub(super) struct IncludingTupleField(pub(super) bool);
 
 impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// Adds a suggestion when a closure is invoked twice with a moved variable or when a closure
@@ -164,7 +172,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// End-user visible description of `place` if one can be found.
     /// If the place is a temporary for instance, `None` will be returned.
     pub(super) fn describe_place(&self, place_ref: PlaceRef<'tcx>) -> Option<String> {
-        self.describe_place_with_options(place_ref, IncludingDowncast(false))
+        self.describe_place_with_options(
+            place_ref,
+            DescribePlaceOpt { including_downcast: false, including_tuple_field: true },
+        )
     }
 
     /// End-user visible description of `place` if one can be found. If the place is a temporary
@@ -174,7 +185,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     pub(super) fn describe_place_with_options(
         &self,
         place: PlaceRef<'tcx>,
-        including_downcast: IncludingDowncast,
+        opt: DescribePlaceOpt,
     ) -> Option<String> {
         let local = place.local;
         let mut autoderef_index = None;
@@ -224,7 +235,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         }
                     }
                 }
-                ProjectionElem::Downcast(..) if including_downcast.0 => return None,
+                ProjectionElem::Downcast(..) if opt.including_downcast => return None,
                 ProjectionElem::Downcast(..) => (),
                 ProjectionElem::Field(field, _ty) => {
                     // FIXME(project-rfc_2229#36): print capture precisely here.
@@ -238,9 +249,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         let field_name = self.describe_field(
                             PlaceRef { local, projection: place.projection.split_at(index).0 },
                             *field,
+                            IncludingTupleField(opt.including_tuple_field),
                         );
-                        buf.push('.');
-                        buf.push_str(&field_name);
+                        if let Some(field_name_str) = field_name {
+                            buf.push('.');
+                            buf.push_str(&field_name_str);
+                        }
                     }
                 }
                 ProjectionElem::Index(index) => {
@@ -261,6 +275,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         ok.ok().map(|_| buf)
     }
 
+    fn describe_name(&self, place: PlaceRef<'tcx>) -> Option<Symbol> {
+        for elem in place.projection.into_iter() {
+            match elem {
+                ProjectionElem::Downcast(Some(name), _) => {
+                    return Some(*name);
+                }
+                _ => {}
+            }
+        }
+        None
+    }
+
     /// Appends end-user visible description of the `local` place to `buf`. If `local` doesn't have
     /// a name, or its name was generated by the compiler, then `Err` is returned
     fn append_local_to_string(&self, local: Local, buf: &mut String) -> Result<(), ()> {
@@ -275,7 +301,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     }
 
     /// End-user visible description of the `field`nth field of `base`
-    fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
+    fn describe_field(
+        &self,
+        place: PlaceRef<'tcx>,
+        field: Field,
+        including_tuple_field: IncludingTupleField,
+    ) -> Option<String> {
         let place_ty = match place {
             PlaceRef { local, projection: [] } => PlaceTy::from_ty(self.body.local_decls[local].ty),
             PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
@@ -289,7 +320,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
             },
         };
-        self.describe_field_from_ty(place_ty.ty, field, place_ty.variant_index)
+        self.describe_field_from_ty(
+            place_ty.ty,
+            field,
+            place_ty.variant_index,
+            including_tuple_field,
+        )
     }
 
     /// End-user visible description of the `field_index`nth field of `ty`
@@ -298,10 +334,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         ty: Ty<'_>,
         field: Field,
         variant_index: Option<VariantIdx>,
-    ) -> String {
+        including_tuple_field: IncludingTupleField,
+    ) -> Option<String> {
         if ty.is_box() {
             // If the type is a box, the field is described from the boxed type
-            self.describe_field_from_ty(ty.boxed_ty(), field, variant_index)
+            self.describe_field_from_ty(ty.boxed_ty(), field, variant_index, including_tuple_field)
         } else {
             match *ty.kind() {
                 ty::Adt(def, _) => {
@@ -311,14 +348,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     } else {
                         def.non_enum_variant()
                     };
-                    variant.fields[field.index()].name.to_string()
+                    if !including_tuple_field.0 && variant.ctor_kind == CtorKind::Fn {
+                        return None;
+                    }
+                    Some(variant.fields[field.index()].name.to_string())
                 }
-                ty::Tuple(_) => field.index().to_string(),
+                ty::Tuple(_) => Some(field.index().to_string()),
                 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
-                    self.describe_field_from_ty(ty, field, variant_index)
+                    self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
                 }
                 ty::Array(ty, _) | ty::Slice(ty) => {
-                    self.describe_field_from_ty(ty, field, variant_index)
+                    self.describe_field_from_ty(ty, field, variant_index, including_tuple_field)
                 }
                 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
                     // We won't be borrowck'ing here if the closure came from another crate,
@@ -335,7 +375,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         .unwrap()
                         .get_root_variable();
 
-                    self.infcx.tcx.hir().name(var_id).to_string()
+                    Some(self.infcx.tcx.hir().name(var_id).to_string())
                 }
                 _ => {
                     // Might need a revision when the fields in trait RFC is implemented
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index becb81b2e26..cb3cd479ae2 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -6,7 +6,7 @@ use rustc_mir_dataflow::move_paths::{
 };
 use rustc_span::Span;
 
-use crate::diagnostics::UseSpans;
+use crate::diagnostics::{DescribePlaceOpt, UseSpans};
 use crate::prefixes::PrefixSet;
 use crate::MirBorrowckCtxt;
 
@@ -368,13 +368,31 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             }
             _ => {
                 let source = self.borrowed_content_source(deref_base);
-                match (self.describe_place(move_place.as_ref()), source.describe_for_named_place())
-                {
-                    (Some(place_desc), Some(source_desc)) => self.cannot_move_out_of(
+                let move_place_ref = move_place.as_ref();
+                match (
+                    self.describe_place_with_options(
+                        move_place_ref,
+                        DescribePlaceOpt {
+                            including_downcast: false,
+                            including_tuple_field: false,
+                        },
+                    ),
+                    self.describe_name(move_place_ref),
+                    source.describe_for_named_place(),
+                ) {
+                    (Some(place_desc), Some(name), Some(source_desc)) => self.cannot_move_out_of(
+                        span,
+                        &format!("`{place_desc}` as enum variant `{name}` which is behind a {source_desc}"),
+                    ),
+                    (Some(place_desc), Some(name), None) => self.cannot_move_out_of(
+                        span,
+                        &format!("`{place_desc}` as enum variant `{name}`"),
+                    ),
+                    (Some(place_desc), _, Some(source_desc)) => self.cannot_move_out_of(
                         span,
                         &format!("`{place_desc}` which is behind a {source_desc}"),
                     ),
-                    (_, _) => self.cannot_move_out_of(
+                    (_, _, _) => self.cannot_move_out_of(
                         span,
                         &source.describe_for_unnamed_place(self.infcx.tcx),
                     ),
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index f68358ecfe6..a87e8bd5ba1 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -839,7 +839,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             hir::Node::Expr(hir::Expr {
                 kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
                 ..
-            }) => (tcx.sess.source_map().end_point(fn_decl_span)),
+            }) => tcx.sess.source_map().end_point(fn_decl_span),
             _ => self.body.span,
         };
 
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index f7d35da0259..d32b1edcd8f 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -2619,6 +2619,34 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             );
         }
 
+        // Now equate closure substs to regions inherited from `typeck_root_def_id`. Fixes #98589.
+        let typeck_root_def_id = tcx.typeck_root_def_id(self.body.source.def_id());
+        let typeck_root_substs = ty::InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
+
+        let parent_substs = match tcx.def_kind(def_id) {
+            DefKind::Closure => substs.as_closure().parent_substs(),
+            DefKind::Generator => substs.as_generator().parent_substs(),
+            DefKind::InlineConst => substs.as_inline_const().parent_substs(),
+            other => bug!("unexpected item {:?}", other),
+        };
+        let parent_substs = tcx.mk_substs(parent_substs.iter());
+
+        assert_eq!(typeck_root_substs.len(), parent_substs.len());
+        if let Err(_) = self.eq_substs(
+            typeck_root_substs,
+            parent_substs,
+            location.to_locations(),
+            ConstraintCategory::BoringNoLocation,
+        ) {
+            span_mirbug!(
+                self,
+                def_id,
+                "could not relate closure to parent {:?} != {:?}",
+                typeck_root_substs,
+                parent_substs
+            );
+        }
+
         tcx.predicates_of(def_id).instantiate(tcx, substs)
     }
 
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index c45850c6d84..c97a6a1a658 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -38,6 +38,23 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         .relate(a, b)?;
         Ok(())
     }
+
+    /// Add sufficient constraints to ensure `a == b`. See also [Self::relate_types].
+    pub(super) fn eq_substs(
+        &mut self,
+        a: ty::SubstsRef<'tcx>,
+        b: ty::SubstsRef<'tcx>,
+        locations: Locations,
+        category: ConstraintCategory<'tcx>,
+    ) -> Fallible<()> {
+        TypeRelating::new(
+            self.infcx,
+            NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::other()),
+            ty::Variance::Invariant,
+        )
+        .relate(a, b)?;
+        Ok(())
+    }
 }
 
 struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index a2205c3613d..1a0ea8f4160 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -410,12 +410,12 @@ fn parse_options<'a>(
             try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN);
         } else if !is_global_asm && p.eat_keyword(sym::nostack) {
             try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
+        } else if !is_global_asm && p.eat_keyword(sym::may_unwind) {
+            try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND);
         } else if p.eat_keyword(sym::att_syntax) {
             try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
         } else if p.eat_keyword(kw::Raw) {
             try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::RAW);
-        } else if p.eat_keyword(sym::may_unwind) {
-            try_set_option(p, args, kw::Raw, ast::InlineAsmOptions::MAY_UNWIND);
         } else {
             return p.unexpected();
         }
@@ -656,7 +656,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                     let span = arg_spans.next().unwrap_or(template_sp);
 
                     let operand_idx = match arg.position {
-                        parse::ArgumentIs(idx, _) | parse::ArgumentImplicitlyIs(idx) => {
+                        parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => {
                             if idx >= args.operands.len()
                                 || named_pos.contains_key(&idx)
                                 || args.reg_args.contains(&idx)
@@ -702,11 +702,12 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                                 Some(idx)
                             }
                         }
-                        parse::ArgumentNamed(name, span) => {
+                        parse::ArgumentNamed(name) => {
                             match args.named_args.get(&Symbol::intern(name)) {
                                 Some(&idx) => Some(idx),
                                 None => {
                                     let msg = format!("there is no argument named `{}`", name);
+                                    let span = arg.position_span;
                                     ecx.struct_span_err(
                                         template_span
                                             .from_inner(InnerSpan::new(span.start, span.end)),
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 082c7893426..9eb96ec7680 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -16,6 +16,7 @@ use smallvec::SmallVec;
 
 use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
+use rustc_parse_format::Count;
 use std::borrow::Cow;
 use std::collections::hash_map::Entry;
 
@@ -57,26 +58,45 @@ struct PositionalNamedArg {
     replacement: Symbol,
     /// The span for the positional named argument (so the lint can point a message to it)
     positional_named_arg_span: Span,
+    has_formatting: bool,
 }
 
 impl PositionalNamedArg {
-    /// Determines what span to replace with the name of the named argument
-    fn get_span_to_replace(&self, cx: &Context<'_, '_>) -> Option<Span> {
+    /// Determines:
+    /// 1) span to be replaced with the name of the named argument and
+    /// 2) span to be underlined for error messages
+    fn get_positional_arg_spans(&self, cx: &Context<'_, '_>) -> (Option<Span>, Option<Span>) {
         if let Some(inner_span) = &self.inner_span_to_replace {
-            return Some(
-                cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }),
-            );
+            let span =
+                cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end });
+            (Some(span), Some(span))
         } else if self.ty == PositionalNamedArgType::Arg {
-            // In the case of a named argument whose position is implicit, there will not be a span
-            // to replace. Instead, we insert the name after the `{`, which is the first character
-            // of arg_span.
-            return cx
-                .arg_spans
-                .get(self.cur_piece)
-                .map(|arg_span| arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo());
+            // In the case of a named argument whose position is implicit, if the argument *has*
+            // formatting, there will not be a span to replace. Instead, we insert the name after
+            // the `{`, which will be the first character of arg_span. If the argument does *not*
+            // have formatting, there may or may not be a span to replace. This is because
+            // whitespace is allowed in arguments without formatting (such as `format!("{  }", 1);`)
+            // but is not allowed in arguments with formatting (an error will be generated in cases
+            // like `format!("{ :1.1}", 1.0f32);`.
+            // For the message span, if there is formatting, we want to use the opening `{` and the
+            // next character, which will the `:` indicating the start of formatting. If there is
+            // not any formatting, we want to underline the entire span.
+            cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+                if self.has_formatting {
+                    (
+                        Some(arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()),
+                        Some(arg_span.with_hi(arg_span.lo() + BytePos(2))),
+                    )
+                } else {
+                    let replace_start = arg_span.lo() + BytePos(1);
+                    let replace_end = arg_span.hi() - BytePos(1);
+                    let to_replace = arg_span.with_lo(replace_start).with_hi(replace_end);
+                    (Some(to_replace), Some(*arg_span))
+                }
+            })
+        } else {
+            (None, None)
         }
-
-        None
     }
 }
 
@@ -117,10 +137,18 @@ impl PositionalNamedArgsLint {
         cur_piece: usize,
         inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
         names: &FxHashMap<Symbol, (usize, Span)>,
+        has_formatting: bool,
     ) {
         let start_of_named_args = total_args_length - names.len();
         if current_positional_arg >= start_of_named_args {
-            self.maybe_push(format_argument_index, ty, cur_piece, inner_span_to_replace, names)
+            self.maybe_push(
+                format_argument_index,
+                ty,
+                cur_piece,
+                inner_span_to_replace,
+                names,
+                has_formatting,
+            )
         }
     }
 
@@ -134,6 +162,7 @@ impl PositionalNamedArgsLint {
         cur_piece: usize,
         inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
         names: &FxHashMap<Symbol, (usize, Span)>,
+        has_formatting: bool,
     ) {
         let named_arg = names
             .iter()
@@ -156,6 +185,7 @@ impl PositionalNamedArgsLint {
                 inner_span_to_replace,
                 replacement,
                 positional_named_arg_span,
+                has_formatting,
             });
         }
     }
@@ -250,6 +280,11 @@ struct Context<'a, 'b> {
     unused_names_lint: PositionalNamedArgsLint,
 }
 
+pub struct FormatArg {
+    expr: P<ast::Expr>,
+    named: bool,
+}
+
 /// Parses the arguments from the given list of tokens, returning the diagnostic
 /// if there's a parse error so we can continue parsing other format!
 /// expressions.
@@ -263,8 +298,8 @@ fn parse_args<'a>(
     ecx: &mut ExtCtxt<'a>,
     sp: Span,
     tts: TokenStream,
-) -> PResult<'a, (P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, (usize, Span)>)> {
-    let mut args = Vec::<P<ast::Expr>>::new();
+) -> PResult<'a, (P<ast::Expr>, Vec<FormatArg>, FxHashMap<Symbol, (usize, Span)>)> {
+    let mut args = Vec::<FormatArg>::new();
     let mut names = FxHashMap::<Symbol, (usize, Span)>::default();
 
     let mut p = ecx.new_parser_from_tts(tts);
@@ -332,7 +367,7 @@ fn parse_args<'a>(
                 let e = p.parse_expr()?;
                 if let Some((prev, _)) = names.get(&ident.name) {
                     ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident))
-                        .span_label(args[*prev].span, "previously here")
+                        .span_label(args[*prev].expr.span, "previously here")
                         .span_label(e.span, "duplicate argument")
                         .emit();
                     continue;
@@ -344,7 +379,7 @@ fn parse_args<'a>(
                 // args. And remember the names.
                 let slot = args.len();
                 names.insert(ident.name, (slot, ident.span));
-                args.push(e);
+                args.push(FormatArg { expr: e, named: true });
             }
             _ => {
                 let e = p.parse_expr()?;
@@ -355,11 +390,11 @@ fn parse_args<'a>(
                     );
                     err.span_label(e.span, "positional arguments must be before named arguments");
                     for pos in names.values() {
-                        err.span_label(args[pos.0].span, "named argument");
+                        err.span_label(args[pos.0].expr.span, "named argument");
                     }
                     err.emit();
                 }
-                args.push(e);
+                args.push(FormatArg { expr: e, named: false });
             }
         }
     }
@@ -381,8 +416,8 @@ impl<'a, 'b> Context<'a, 'b> {
         match *p {
             parse::String(_) => {}
             parse::NextArgument(ref mut arg) => {
-                if let parse::ArgumentNamed(s, _) = arg.position {
-                    arg.position = parse::ArgumentIs(lookup(s), None);
+                if let parse::ArgumentNamed(s) = arg.position {
+                    arg.position = parse::ArgumentIs(lookup(s));
                 }
                 if let parse::CountIsName(s, _) = arg.format.width {
                     arg.format.width = parse::CountIsParam(lookup(s));
@@ -414,18 +449,22 @@ impl<'a, 'b> Context<'a, 'b> {
                     PositionalNamedArgType::Precision,
                 );
 
+                let has_precision = arg.format.precision != Count::CountImplied;
+                let has_width = arg.format.width != Count::CountImplied;
+
                 // argument second, if it's an implicit positional parameter
                 // it's written second, so it should come after width/precision.
                 let pos = match arg.position {
-                    parse::ArgumentIs(i, arg_end) => {
+                    parse::ArgumentIs(i) => {
                         self.unused_names_lint.maybe_add_positional_named_arg(
                             i,
                             self.args.len(),
                             i,
                             PositionalNamedArgType::Arg,
                             self.curpiece,
-                            arg_end,
+                            Some(arg.position_span),
                             &self.names,
+                            has_precision || has_width,
                         );
 
                         Exact(i)
@@ -439,11 +478,13 @@ impl<'a, 'b> Context<'a, 'b> {
                             self.curpiece,
                             None,
                             &self.names,
+                            has_precision || has_width,
                         );
                         Exact(i)
                     }
-                    parse::ArgumentNamed(s, span) => {
+                    parse::ArgumentNamed(s) => {
                         let symbol = Symbol::intern(s);
+                        let span = arg.position_span;
                         Named(symbol, InnerSpan::new(span.start, span.end))
                     }
                 };
@@ -529,6 +570,7 @@ impl<'a, 'b> Context<'a, 'b> {
                     self.curpiece,
                     *inner_span,
                     &self.names,
+                    true,
                 );
                 self.verify_arg_type(Exact(i), Count);
             }
@@ -878,8 +920,9 @@ impl<'a, 'b> Context<'a, 'b> {
                         // track the current argument ourselves.
                         let i = self.curarg;
                         self.curarg += 1;
-                        parse::ArgumentIs(i, None)
+                        parse::ArgumentIs(i)
                     },
+                    position_span: arg.position_span,
                     format: parse::FormatSpec {
                         fill: arg.format.fill,
                         align: parse::AlignUnknown,
@@ -1150,24 +1193,22 @@ pub fn expand_format_args_nl<'cx>(
 
 fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) {
     for named_arg in &cx.unused_names_lint.positional_named_args {
-        let arg_span = named_arg.get_span_to_replace(cx);
+        let (position_sp_to_replace, position_sp_for_msg) = named_arg.get_positional_arg_spans(cx);
 
         let msg = format!("named argument `{}` is not used by name", named_arg.replacement);
-        let replacement = match named_arg.ty {
-            PositionalNamedArgType::Arg => named_arg.replacement.to_string(),
-            _ => named_arg.replacement.to_string() + "$",
-        };
 
         cx.ecx.buffered_early_lint.push(BufferedEarlyLint {
             span: MultiSpan::from_span(named_arg.positional_named_arg_span),
             msg: msg.clone(),
             node_id: ast::CRATE_NODE_ID,
             lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY),
-            diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally(
-                arg_span,
-                named_arg.positional_named_arg_span,
-                replacement,
-            ),
+            diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
+                position_sp_to_replace,
+                position_sp_for_msg,
+                named_arg_sp: named_arg.positional_named_arg_span,
+                named_arg_name: named_arg.replacement.to_string(),
+                is_formatting_arg: named_arg.ty != PositionalNamedArgType::Arg,
+            },
         });
     }
 }
@@ -1178,7 +1219,7 @@ pub fn expand_preparsed_format_args(
     ecx: &mut ExtCtxt<'_>,
     sp: Span,
     efmt: P<ast::Expr>,
-    args: Vec<P<ast::Expr>>,
+    args: Vec<FormatArg>,
     names: FxHashMap<Symbol, (usize, Span)>,
     append_newline: bool,
 ) -> P<ast::Expr> {
@@ -1268,6 +1309,25 @@ pub fn expand_preparsed_format_args(
                 e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label);
             }
         }
+        if err.should_be_replaced_with_positional_argument {
+            let captured_arg_span =
+                fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
+            let positional_args = args.iter().filter(|arg| !arg.named).collect::<Vec<_>>();
+            if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) {
+                let span = match positional_args.last() {
+                    Some(arg) => arg.expr.span,
+                    None => fmt_sp,
+                };
+                e.multipart_suggestion_verbose(
+                    "consider using a positional formatting argument instead",
+                    vec![
+                        (captured_arg_span, positional_args.len().to_string()),
+                        (span.shrink_to_hi(), format!(", {}", arg)),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
         e.emit();
         return DummyResult::raw_expr(sp, true);
     }
@@ -1282,7 +1342,7 @@ pub fn expand_preparsed_format_args(
 
     let mut cx = Context {
         ecx,
-        args,
+        args: args.into_iter().map(|arg| arg.expr).collect(),
         num_captured_args: 0,
         arg_types,
         arg_unique_types,
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 13a7b6be947..63207803e32 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2267,7 +2267,7 @@ fn add_local_native_libraries(
                     // be added explicitly if necessary, see the error in `fn link_rlib`) compiled
                     // as an executable due to `--test`. Use whole-archive implicitly, like before
                     // the introduction of native lib modifiers.
-                    || (bundle != Some(false) && sess.opts.test)
+                    || (whole_archive == None && bundle != Some(false) && sess.opts.test)
                 {
                     cmd.link_whole_staticlib(
                         name,
@@ -2675,7 +2675,7 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
     let llvm_target = &sess.target.llvm_target;
     if sess.target.vendor != "apple"
         || !matches!(os.as_ref(), "ios" | "tvos" | "watchos")
-        || flavor != LinkerFlavor::Gcc
+        || (flavor != LinkerFlavor::Gcc && flavor != LinkerFlavor::Lld(LldFlavor::Ld64))
     {
         return;
     }
@@ -2706,13 +2706,16 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
             return;
         }
     };
-    if llvm_target.contains("macabi") {
-        cmd.args(&["-target", llvm_target])
-    } else {
-        let arch_name = llvm_target.split('-').next().expect("LLVM target must have a hyphen");
-        cmd.args(&["-arch", arch_name])
+
+    match flavor {
+        LinkerFlavor::Gcc => {
+            cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
+        }
+        LinkerFlavor::Lld(LldFlavor::Ld64) => {
+            cmd.args(&["-syslibroot", &sdk_root]);
+        }
+        _ => unreachable!(),
     }
-    cmd.args(&["-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]);
 }
 
 fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 1b5ad87107a..dbd55590e5c 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -256,8 +256,11 @@ impl ModuleConfig {
             {
                 MergeFunctions::Disabled => false,
                 MergeFunctions::Trampolines | MergeFunctions::Aliases => {
-                    sess.opts.optimize == config::OptLevel::Default
-                        || sess.opts.optimize == config::OptLevel::Aggressive
+                    use config::OptLevel::*;
+                    match sess.opts.optimize {
+                        Aggressive | Default | SizeMin | Size => true,
+                        Less | No => false,
+                    }
                 }
             },
 
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index ba8222dc152..936044fbe24 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -13,7 +13,7 @@ use rustc_middle::mir::pretty::display_allocation;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, subst::Subst, EarlyBinder, TyCtxt};
+use rustc_middle::ty::{self, subst::Subst, TyCtxt};
 use rustc_span::source_map::Span;
 use rustc_target::abi::{self, Abi};
 use std::borrow::Cow;
@@ -45,7 +45,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
         "Unexpected DefKind: {:?}",
         ecx.tcx.def_kind(cid.instance.def_id())
     );
-    let layout = ecx.layout_of(EarlyBinder(body.return_ty()).subst(tcx, cid.instance.substs))?;
+    let layout = ecx.layout_of(body.bound_return_ty().subst(tcx, cid.instance.substs))?;
     assert!(!layout.is_unsized());
     let ret = ecx.allocate(layout, MemoryKind::Stack)?;
 
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index de284bd3bae..94ba62c160c 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -37,9 +37,6 @@ pub enum Immediate<Prov: Provenance = AllocId> {
     Uninit,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Immediate, 56);
-
 impl<Prov: Provenance> From<ScalarMaybeUninit<Prov>> for Immediate<Prov> {
     #[inline(always)]
     fn from(val: ScalarMaybeUninit<Prov>) -> Self {
@@ -117,9 +114,6 @@ pub struct ImmTy<'tcx, Prov: Provenance = AllocId> {
     pub layout: TyAndLayout<'tcx>,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ImmTy<'_>, 72);
-
 impl<Prov: Provenance> std::fmt::Display for ImmTy<'_, Prov> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         /// Helper function for printing a scalar to a FmtPrinter
@@ -187,9 +181,6 @@ pub enum Operand<Prov: Provenance = AllocId> {
     Indirect(MemPlace<Prov>),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Operand, 64);
-
 #[derive(Clone, Debug)]
 pub struct OpTy<'tcx, Prov: Provenance = AllocId> {
     op: Operand<Prov>, // Keep this private; it helps enforce invariants.
@@ -204,9 +195,6 @@ pub struct OpTy<'tcx, Prov: Provenance = AllocId> {
     pub align: Option<Align>,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(OpTy<'_>, 88);
-
 impl<'tcx, Prov: Provenance> std::ops::Deref for OpTy<'tcx, Prov> {
     type Target = Operand<Prov>;
     #[inline(always)]
@@ -830,3 +818,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         })
     }
 }
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    // These are in alphabetical order, which is easy to maintain.
+    rustc_data_structures::static_assert_size!(Immediate, 56);
+    rustc_data_structures::static_assert_size!(ImmTy<'_>, 72);
+    rustc_data_structures::static_assert_size!(Operand, 64);
+    rustc_data_structures::static_assert_size!(OpTy<'_>, 88);
+}
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 473da71a0ab..f4571a1ca3d 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -25,9 +25,6 @@ pub enum MemPlaceMeta<Prov: Provenance = AllocId> {
     None,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MemPlaceMeta, 24);
-
 impl<Prov: Provenance> MemPlaceMeta<Prov> {
     pub fn unwrap_meta(self) -> Scalar<Prov> {
         match self {
@@ -56,9 +53,6 @@ pub struct MemPlace<Prov: Provenance = AllocId> {
     pub meta: MemPlaceMeta<Prov>,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MemPlace, 40);
-
 /// A MemPlace with its layout. Constructing it is only possible in this module.
 #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
 pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
@@ -71,9 +65,6 @@ pub struct MPlaceTy<'tcx, Prov: Provenance = AllocId> {
     pub align: Align,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64);
-
 #[derive(Copy, Clone, Debug)]
 pub enum Place<Prov: Provenance = AllocId> {
     /// A place referring to a value allocated in the `Memory` system.
@@ -84,9 +75,6 @@ pub enum Place<Prov: Provenance = AllocId> {
     Local { frame: usize, local: mir::Local },
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Place, 48);
-
 #[derive(Clone, Debug)]
 pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> {
     place: Place<Prov>, // Keep this private; it helps enforce invariants.
@@ -98,9 +86,6 @@ pub struct PlaceTy<'tcx, Prov: Provenance = AllocId> {
     pub align: Align,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(PlaceTy<'_>, 72);
-
 impl<'tcx, Prov: Provenance> std::ops::Deref for PlaceTy<'tcx, Prov> {
     type Target = Place<Prov>;
     #[inline(always)]
@@ -901,3 +886,15 @@ where
         Ok(mplace)
     }
 }
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    // These are in alphabetical order, which is easy to maintain.
+    rustc_data_structures::static_assert_size!(MemPlaceMeta, 24);
+    rustc_data_structures::static_assert_size!(MemPlace, 40);
+    rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64);
+    rustc_data_structures::static_assert_size!(Place, 48);
+    rustc_data_structures::static_assert_size!(PlaceTy<'_>, 72);
+}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 628298df473..0adb88a180f 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -772,7 +772,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                             let mut nonconst_call_permission = false;
                             if let Some(callee_trait) = tcx.trait_of_item(callee)
                                 && tcx.has_attr(callee_trait, sym::const_trait)
-                                && Some(callee_trait) == tcx.trait_of_item(caller)
+                                && Some(callee_trait) == tcx.trait_of_item(caller.to_def_id())
                                 // Can only call methods when it's `<Self as TheTrait>::f`.
                                 && tcx.types.self_param == substs.type_at(0)
                             {
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index e0994451172..45dadcfff2e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -5,12 +5,11 @@
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::TraitEngine;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::{
-    self, FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext,
+    self, ImplSource, Obligation, ObligationCause, SelectionContext,
 };
 
 use super::ConstCx;
@@ -189,15 +188,8 @@ impl Qualif for NeedsNonConstDrop {
                 return false;
             }
 
-            // If we successfully found one, then select all of the predicates
-            // implied by our const drop impl.
-            let mut fcx = FulfillmentContext::new();
-            for nested in impl_src.nested_obligations() {
-                fcx.register_predicate_obligation(&infcx, nested);
-            }
-
             // If we had any errors, then it's bad
-            !fcx.select_all_or_error(&infcx).is_empty()
+            !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
         })
     }
 
diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs
index fe4a726fe12..4f39dad205a 100644
--- a/compiler/rustc_const_eval/src/util/alignment.rs
+++ b/compiler/rustc_const_eval/src/util/alignment.rs
@@ -48,20 +48,16 @@ fn is_within_packed<'tcx, L>(
 where
     L: HasLocalDecls<'tcx>,
 {
-    for (place_base, elem) in place.iter_projections().rev() {
-        match elem {
-            // encountered a Deref, which is ABI-aligned
-            ProjectionElem::Deref => break,
-            ProjectionElem::Field(..) => {
-                let ty = place_base.ty(local_decls, tcx).ty;
-                match ty.kind() {
-                    ty::Adt(def, _) => return def.repr().pack,
-                    _ => {}
-                }
-            }
-            _ => {}
-        }
-    }
-
-    None
+    place
+        .iter_projections()
+        .rev()
+        // Stop at `Deref`; standard ABI alignment applies there.
+        .take_while(|(_base, elem)| !matches!(elem, ProjectionElem::Deref))
+        // Consider the packed alignments at play here...
+        .filter_map(|(base, _elem)| {
+            base.ty(local_decls, tcx).ty.ty_adt_def().and_then(|adt| adt.repr().pack)
+        })
+        // ... and compute their minimum.
+        // The overall smallest alignment is what matters.
+        .min()
 }
diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs
index a7a480dd1d7..af9d83f0609 100644
--- a/compiler/rustc_const_eval/src/util/call_kind.rs
+++ b/compiler/rustc_const_eval/src/util/call_kind.rs
@@ -66,9 +66,12 @@ pub fn call_kind<'tcx>(
     from_hir_call: bool,
     self_arg: Option<Ident>,
 ) -> CallKind<'tcx> {
-    let parent = tcx.opt_associated_item(method_did).and_then(|assoc| match assoc.container {
-        AssocItemContainer::ImplContainer(impl_did) => tcx.trait_id_of_impl(impl_did),
-        AssocItemContainer::TraitContainer(trait_did) => Some(trait_did),
+    let parent = tcx.opt_associated_item(method_did).and_then(|assoc| {
+        let container_id = assoc.container_id(tcx);
+        match assoc.container {
+            AssocItemContainer::ImplContainer => tcx.trait_id_of_impl(container_id),
+            AssocItemContainer::TraitContainer => Some(container_id),
+        }
     });
 
     let fn_call = parent
diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl
index b17eb9c2d26..d8056c77f0f 100644
--- a/compiler/rustc_error_messages/locales/en-US/passes.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl
@@ -262,3 +262,6 @@ passes-rustc-lint-opt-ty = `#[rustc_lint_opt_ty]` should be applied to a struct
 
 passes-rustc-lint-opt-deny-field-access = `#[rustc_lint_opt_deny_field_access]` should be applied to a field
     .label = not a field
+
+passes-link-ordinal = attribute should be applied to a foreign function or static
+    .label = not a foreign function or static
\ No newline at end of file
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index 7d7e92c5229..36805aa874f 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -18,7 +18,7 @@ rustc_lint_defs = { path = "../rustc_lint_defs" }
 unicode-width = "0.1.4"
 atty = "0.2"
 termcolor = "1.0"
-annotate-snippets = "0.8.0"
+annotate-snippets = "0.9"
 termize = "0.1.1"
 serde = { version = "1.0.125", features = ["derive"] }
 serde_json = "1.0.59"
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 0fcd61d1e58..3df562c7eda 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -183,7 +183,11 @@ impl AnnotateSnippetEmitterWriter {
                     annotation_type: annotation_type_for_level(*level),
                 }),
                 footer: vec![],
-                opt: FormatOptions { color: true, anonymized_line_numbers: self.ui_testing },
+                opt: FormatOptions {
+                    color: true,
+                    anonymized_line_numbers: self.ui_testing,
+                    margin: None,
+                },
                 slices: annotated_files
                     .iter()
                     .map(|(source, line_index, annotations)| {
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 2a4f609a2d8..17e6c9e9575 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -40,6 +40,26 @@ pub trait IntoDiagnosticArg {
     fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
 }
 
+pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display);
+
+impl IntoDiagnosticArg for DiagnosticArgFromDisplay<'_> {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        self.0.to_string().into_diagnostic_arg()
+    }
+}
+
+impl<'a> From<&'a dyn fmt::Display> for DiagnosticArgFromDisplay<'a> {
+    fn from(t: &'a dyn fmt::Display) -> Self {
+        DiagnosticArgFromDisplay(t)
+    }
+}
+
+impl<'a, T: fmt::Display> From<&'a T> for DiagnosticArgFromDisplay<'a> {
+    fn from(t: &'a T) -> Self {
+        DiagnosticArgFromDisplay(t)
+    }
+}
+
 macro_rules! into_diagnostic_arg_using_display {
     ($( $ty:ty ),+ $(,)?) => {
         $(
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index b173ac0e916..2d3155a70ed 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -371,8 +371,8 @@ impl fmt::Display for ExplicitBug {
 impl error::Error for ExplicitBug {}
 
 pub use diagnostic::{
-    AddSubdiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
-    DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
+    AddSubdiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay,
+    DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
 };
 pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, LintDiagnosticBuilder};
 use std::backtrace::Backtrace;
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 5f8801cc4e2..c2c551e78a4 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -338,7 +338,12 @@ impl Definitions {
 
     /// Adds a definition with a parent definition.
     pub fn create_def(&mut self, parent: LocalDefId, data: DefPathData) -> LocalDefId {
-        debug!("create_def(parent={:?}, data={:?})", parent, data);
+        // We can't use `Debug` implementation for `LocalDefId` here, since it tries to acquire a
+        // reference to `Definitions` and we're already holding a mutable reference.
+        debug!(
+            "create_def(parent={}, data={data:?})",
+            self.def_path(parent).to_string_no_crate_verbose(),
+        );
 
         // The root node must be created with `create_root_def()`.
         assert!(data != DefPathData::CrateRoot);
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index f71400898e6..617433a9803 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2222,6 +2222,7 @@ pub struct TraitItem<'hir> {
     pub generics: &'hir Generics<'hir>,
     pub kind: TraitItemKind<'hir>,
     pub span: Span,
+    pub defaultness: Defaultness,
 }
 
 impl TraitItem<'_> {
@@ -2281,6 +2282,7 @@ pub struct ImplItem<'hir> {
     pub def_id: LocalDefId,
     pub generics: &'hir Generics<'hir>,
     pub kind: ImplItemKind<'hir>,
+    pub defaultness: Defaultness,
     pub span: Span,
     pub vis_span: Span,
 }
@@ -3083,7 +3085,6 @@ pub struct TraitItemRef {
     pub ident: Ident,
     pub kind: AssocItemKind,
     pub span: Span,
-    pub defaultness: Defaultness,
 }
 
 /// A reference from an impl to one of its associated items. This
@@ -3098,7 +3099,6 @@ pub struct ImplItemRef {
     pub ident: Ident,
     pub kind: AssocItemKind,
     pub span: Span,
-    pub defaultness: Defaultness,
     /// When we are in a trait impl, link to the trait-item's id.
     pub trait_item_def_id: Option<DefId>,
 }
@@ -3489,17 +3489,18 @@ impl<'hir> Node<'hir> {
 // Some nodes are used a lot. Make sure they don't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
-    rustc_data_structures::static_assert_size!(super::Block<'static>, 48);
-    rustc_data_structures::static_assert_size!(super::Expr<'static>, 56);
-    rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
-    rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
-    rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
-    rustc_data_structures::static_assert_size!(super::GenericBound<'_>, 48);
-    rustc_data_structures::static_assert_size!(super::Generics<'static>, 56);
-    rustc_data_structures::static_assert_size!(super::Impl<'static>, 80);
-
-    rustc_data_structures::static_assert_size!(super::Item<'static>, 80);
-    rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 88);
-    rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 80);
-    rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 72);
+    use super::*;
+    // These are in alphabetical order, which is easy to maintain.
+    rustc_data_structures::static_assert_size!(Block<'static>, 48);
+    rustc_data_structures::static_assert_size!(Expr<'static>, 56);
+    rustc_data_structures::static_assert_size!(ForeignItem<'static>, 72);
+    rustc_data_structures::static_assert_size!(GenericBound<'_>, 48);
+    rustc_data_structures::static_assert_size!(Generics<'static>, 56);
+    rustc_data_structures::static_assert_size!(ImplItem<'static>, 88);
+    rustc_data_structures::static_assert_size!(Impl<'static>, 80);
+    rustc_data_structures::static_assert_size!(Item<'static>, 80);
+    rustc_data_structures::static_assert_size!(Pat<'static>, 88);
+    rustc_data_structures::static_assert_size!(QPath<'static>, 24);
+    rustc_data_structures::static_assert_size!(TraitItem<'static>, 96);
+    rustc_data_structures::static_assert_size!(Ty<'static>, 72);
 }
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 640974115b9..e676acebe35 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -946,32 +946,30 @@ pub fn walk_fn<'v, V: Visitor<'v>>(
 }
 
 pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) {
-    visitor.visit_ident(trait_item.ident);
-    visitor.visit_generics(&trait_item.generics);
-    match trait_item.kind {
+    // N.B., deliberately force a compilation error if/when new fields are added.
+    let TraitItem { ident, generics, ref defaultness, ref kind, span, def_id: _ } = *trait_item;
+    let hir_id = trait_item.hir_id();
+    visitor.visit_ident(ident);
+    visitor.visit_generics(&generics);
+    visitor.visit_defaultness(&defaultness);
+    match *kind {
         TraitItemKind::Const(ref ty, default) => {
-            visitor.visit_id(trait_item.hir_id());
+            visitor.visit_id(hir_id);
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_nested_body, default);
         }
         TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => {
-            visitor.visit_id(trait_item.hir_id());
+            visitor.visit_id(hir_id);
             visitor.visit_fn_decl(&sig.decl);
             for &param_name in param_names {
                 visitor.visit_ident(param_name);
             }
         }
         TraitItemKind::Fn(ref sig, TraitFn::Provided(body_id)) => {
-            visitor.visit_fn(
-                FnKind::Method(trait_item.ident, sig),
-                &sig.decl,
-                body_id,
-                trait_item.span,
-                trait_item.hir_id(),
-            );
+            visitor.visit_fn(FnKind::Method(ident, sig), &sig.decl, body_id, span, hir_id);
         }
         TraitItemKind::Type(bounds, ref default) => {
-            visitor.visit_id(trait_item.hir_id());
+            visitor.visit_id(hir_id);
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_ty, default);
         }
@@ -980,19 +978,27 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
 
 pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref: &'v TraitItemRef) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let TraitItemRef { id, ident, ref kind, span: _, ref defaultness } = *trait_item_ref;
+    let TraitItemRef { id, ident, ref kind, span: _ } = *trait_item_ref;
     visitor.visit_nested_trait_item(id);
     visitor.visit_ident(ident);
     visitor.visit_associated_item_kind(kind);
-    visitor.visit_defaultness(defaultness);
 }
 
 pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let ImplItem { def_id: _, ident, ref generics, ref kind, span: _, vis_span: _ } = *impl_item;
+    let ImplItem {
+        def_id: _,
+        ident,
+        ref generics,
+        ref kind,
+        ref defaultness,
+        span: _,
+        vis_span: _,
+    } = *impl_item;
 
     visitor.visit_ident(ident);
     visitor.visit_generics(generics);
+    visitor.visit_defaultness(defaultness);
     match *kind {
         ImplItemKind::Const(ref ty, body) => {
             visitor.visit_id(impl_item.hir_id());
@@ -1027,12 +1033,10 @@ pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>(
 
 pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let ImplItemRef { id, ident, ref kind, span: _, ref defaultness, trait_item_def_id: _ } =
-        *impl_item_ref;
+    let ImplItemRef { id, ident, ref kind, span: _, trait_item_def_id: _ } = *impl_item_ref;
     visitor.visit_nested_impl_item(id);
     visitor.visit_ident(ident);
     visitor.visit_associated_item_kind(kind);
-    visitor.visit_defaultness(defaultness);
 }
 
 pub fn walk_struct_def<'v, V: Visitor<'v>>(
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 13b3e954e1f..c337be12ae4 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -191,6 +191,9 @@ language_item_table! {
     CoerceUnsized,           sym::coerce_unsized,      coerce_unsized_trait,       Target::Trait,          GenericRequirement::Minimum(1);
     DispatchFromDyn,         sym::dispatch_from_dyn,   dispatch_from_dyn_trait,    Target::Trait,          GenericRequirement::Minimum(1);
 
+    // language items relating to transmutability
+    TransmuteTrait,          sym::transmute_trait,     transmute_trait,            Target::Trait,          GenericRequirement::Exact(6);
+
     Add(Op),                 sym::add,                 add_trait,                  Target::Trait,          GenericRequirement::Exact(1);
     Sub(Op),                 sym::sub,                 sub_trait,                  Target::Trait,          GenericRequirement::Exact(1);
     Mul(Op),                 sym::mul,                 mul_trait,                  Target::Trait,          GenericRequirement::Exact(1);
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index 96dd00ec5cf..6236dea10c8 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -60,51 +60,7 @@ pub enum Target {
 
 impl Display for Target {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(
-            f,
-            "{}",
-            match *self {
-                Target::ExternCrate => "extern crate",
-                Target::Use => "use",
-                Target::Static => "static item",
-                Target::Const => "constant item",
-                Target::Fn => "function",
-                Target::Closure => "closure",
-                Target::Mod => "module",
-                Target::ForeignMod => "foreign module",
-                Target::GlobalAsm => "global asm",
-                Target::TyAlias => "type alias",
-                Target::OpaqueTy => "opaque type",
-                Target::Enum => "enum",
-                Target::Variant => "enum variant",
-                Target::Struct => "struct",
-                Target::Field => "struct field",
-                Target::Union => "union",
-                Target::Trait => "trait",
-                Target::TraitAlias => "trait alias",
-                Target::Impl => "item",
-                Target::Expression => "expression",
-                Target::Statement => "statement",
-                Target::Arm => "match arm",
-                Target::AssocConst => "associated const",
-                Target::Method(kind) => match kind {
-                    MethodKind::Inherent => "inherent method",
-                    MethodKind::Trait { body: false } => "required trait method",
-                    MethodKind::Trait { body: true } => "provided trait method",
-                },
-                Target::AssocTy => "associated type",
-                Target::ForeignFn => "foreign function",
-                Target::ForeignStatic => "foreign static item",
-                Target::ForeignTy => "foreign type",
-                Target::GenericParam(kind) => match kind {
-                    GenericParamKind::Type => "type parameter",
-                    GenericParamKind::Lifetime => "lifetime parameter",
-                    GenericParamKind::Const => "const parameter",
-                },
-                Target::MacroDef => "macro def",
-                Target::Param => "function param",
-            }
-        )
+        write!(f, "{}", Self::name(*self))
     }
 }
 
@@ -185,4 +141,48 @@ impl Target {
             hir::GenericParamKind::Const { .. } => Target::GenericParam(GenericParamKind::Const),
         }
     }
+
+    pub fn name(self) -> &'static str {
+        match self {
+            Target::ExternCrate => "extern crate",
+            Target::Use => "use",
+            Target::Static => "static item",
+            Target::Const => "constant item",
+            Target::Fn => "function",
+            Target::Closure => "closure",
+            Target::Mod => "module",
+            Target::ForeignMod => "foreign module",
+            Target::GlobalAsm => "global asm",
+            Target::TyAlias => "type alias",
+            Target::OpaqueTy => "opaque type",
+            Target::Enum => "enum",
+            Target::Variant => "enum variant",
+            Target::Struct => "struct",
+            Target::Field => "struct field",
+            Target::Union => "union",
+            Target::Trait => "trait",
+            Target::TraitAlias => "trait alias",
+            Target::Impl => "implementation block",
+            Target::Expression => "expression",
+            Target::Statement => "statement",
+            Target::Arm => "match arm",
+            Target::AssocConst => "associated const",
+            Target::Method(kind) => match kind {
+                MethodKind::Inherent => "inherent method",
+                MethodKind::Trait { body: false } => "required trait method",
+                MethodKind::Trait { body: true } => "provided trait method",
+            },
+            Target::AssocTy => "associated type",
+            Target::ForeignFn => "foreign function",
+            Target::ForeignStatic => "foreign static item",
+            Target::ForeignTy => "foreign type",
+            Target::GenericParam(kind) => match kind {
+                GenericParamKind::Type => "type parameter",
+                GenericParamKind::Lifetime => "lifetime parameter",
+                GenericParamKind::Const => "const parameter",
+            },
+            Target::MacroDef => "macro def",
+            Target::Param => "function param",
+        }
+    }
 }
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 35a278e6c92..710c4a01b24 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -80,7 +80,7 @@ const BASE_STRUCT: &[&str] =
 /// Extra `DepNode`s for functions and methods.
 const EXTRA_ASSOCIATED: &[&str] = &[label_strs::associated_item];
 
-const EXTRA_TRAIT: &[&str] = &[label_strs::trait_of_item];
+const EXTRA_TRAIT: &[&str] = &[];
 
 // Fully Built Labels
 
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 9c30c81123b..ca7862c9dc4 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -511,7 +511,9 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
             }
             ty::ConstKind::Placeholder(placeholder) => {
                 return self.canonicalize_const_var(
-                    CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) },
+                    CanonicalVarInfo {
+                        kind: CanonicalVarKind::PlaceholderConst(placeholder, ct.ty()),
+                    },
                     ct,
                 );
             }
@@ -695,11 +697,14 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
                             ..placeholder
                         })
                     }
-                    CanonicalVarKind::PlaceholderConst(placeholder) => {
-                        CanonicalVarKind::PlaceholderConst(ty::Placeholder {
-                            universe: reverse_universe_map[&placeholder.universe],
-                            ..placeholder
-                        })
+                    CanonicalVarKind::PlaceholderConst(placeholder, t) => {
+                        CanonicalVarKind::PlaceholderConst(
+                            ty::Placeholder {
+                                universe: reverse_universe_map[&placeholder.universe],
+                                ..placeholder
+                            },
+                            t,
+                        )
                     }
                 },
             })
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index f251d561c60..a9294a85e51 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -144,13 +144,13 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
                 )
                 .into(),
 
-            CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, name }) => {
+            CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, name }, ty) => {
                 let universe_mapped = universe_map(universe);
                 let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name };
                 self.tcx
                     .mk_const(ty::ConstS {
                         kind: ty::ConstKind::Placeholder(placeholder_mapped),
-                        ty: name.ty,
+                        ty,
                     })
                     .into()
             }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 246d27be71c..9886c572a8a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -76,10 +76,11 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                             "...is used and required to live as long as `'static` here \
                              because of an implicit lifetime bound on the {}",
                             match ctxt.assoc_item.container {
-                                AssocItemContainer::TraitContainer(id) =>
-                                    format!("`impl` of `{}`", tcx.def_path_str(id)),
-                                AssocItemContainer::ImplContainer(_) =>
-                                    "inherent `impl`".to_string(),
+                                AssocItemContainer::TraitContainer => {
+                                    let id = ctxt.assoc_item.container_id(tcx);
+                                    format!("`impl` of `{}`", tcx.def_path_str(id))
+                                }
+                                AssocItemContainer::ImplContainer => "inherent `impl`".to_string(),
                             },
                         ),
                     );
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index ed257c144e0..d0d9efe152c 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -17,7 +17,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
     ///
     /// This is implemented by first entering a new universe.
     /// We then replace all bound variables in `sup` with placeholders,
-    /// and all bound variables in `sup` with inference vars.
+    /// and all bound variables in `sub` with inference vars.
     /// We can then just relate the two resulting types as normal.
     ///
     /// Note: this is a subtle algorithm. For a full explanation, please see
@@ -97,7 +97,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 self.tcx.mk_const(ty::ConstS {
                     kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
                         universe: next_universe,
-                        name: ty::BoundConst { var: bound_var, ty },
+                        name: bound_var,
                     }),
                     ty,
                 })
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 6d5f4993d8d..d7d1b5fa218 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -8,7 +8,7 @@ pub use self::ValuePairs::*;
 use self::opaque_types::OpaqueTypeStorage;
 pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
 
-use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
+use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine, TraitEngineExt};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
@@ -645,9 +645,7 @@ impl<'tcx, T> InferOk<'tcx, T> {
         fulfill_cx: &mut dyn TraitEngine<'tcx>,
     ) -> T {
         let InferOk { value, obligations } = self;
-        for obligation in obligations {
-            fulfill_cx.register_predicate_obligation(infcx, obligation);
-        }
+        fulfill_cx.register_predicate_obligations(infcx, obligations);
         value
     }
 }
@@ -842,18 +840,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         self.inner.borrow_mut().commit(undo_snapshot);
     }
 
-    /// Executes `f` and commit the bindings.
-    #[instrument(skip(self, f), level = "debug")]
-    pub fn commit_unconditionally<R, F>(&self, f: F) -> R
-    where
-        F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R,
-    {
-        let snapshot = self.start_snapshot();
-        let r = f(&snapshot);
-        self.commit_from(snapshot);
-        r
-    }
-
     /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`.
     #[instrument(skip(self, f), level = "debug")]
     pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E>
@@ -2069,7 +2055,7 @@ fn replace_param_and_infer_substs_with_placeholder<'tcx>(
                     ty,
                     kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
                         universe: ty::UniverseIndex::ROOT,
-                        name: ty::BoundConst { ty, var: ty::BoundVar::from_usize(idx) },
+                        name: ty::BoundVar::from_usize(idx),
                     }),
                 })
                 .into()
diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs
index 0ba6c56dbb5..21557a9c854 100644
--- a/compiler/rustc_lexer/src/cursor.rs
+++ b/compiler/rustc_lexer/src/cursor.rs
@@ -61,8 +61,8 @@ impl<'a> Cursor<'a> {
     }
 
     /// Returns amount of already consumed symbols.
-    pub(crate) fn len_consumed(&self) -> usize {
-        self.initial_len - self.chars.as_str().len()
+    pub(crate) fn len_consumed(&self) -> u32 {
+        (self.initial_len - self.chars.as_str().len()) as u32
     }
 
     /// Resets the number of bytes consumed to 0.
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index a41e0374f41..6d311af9007 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -38,18 +38,17 @@ use std::convert::TryFrom;
 #[derive(Debug)]
 pub struct Token {
     pub kind: TokenKind,
-    pub len: usize,
+    pub len: u32,
 }
 
 impl Token {
-    fn new(kind: TokenKind, len: usize) -> Token {
+    fn new(kind: TokenKind, len: u32) -> Token {
         Token { kind, len }
     }
 }
 
 /// Enum representing common lexeme types.
-// perf note: Changing all `usize` to `u32` doesn't change performance. See #77629
-#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum TokenKind {
     // Multi-char tokens:
     /// "// comment"
@@ -76,7 +75,7 @@ pub enum TokenKind {
     /// tokens.
     UnknownPrefix,
     /// "12_u8", "1.0e-40", "b"123"". See `LiteralKind` for more details.
-    Literal { kind: LiteralKind, suffix_start: usize },
+    Literal { kind: LiteralKind, suffix_start: u32 },
     /// "'a"
     Lifetime { starts_with_number: bool },
 
@@ -160,26 +159,24 @@ pub enum LiteralKind {
     Str { terminated: bool },
     /// "b"abc"", "b"abc"
     ByteStr { terminated: bool },
-    /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a"
-    RawStr { n_hashes: u8, err: Option<RawStrError> },
-    /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a"
-    RawByteStr { n_hashes: u8, err: Option<RawStrError> },
+    /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a". `None` indicates
+    /// an invalid literal.
+    RawStr { n_hashes: Option<u8> },
+    /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a". `None`
+    /// indicates an invalid literal.
+    RawByteStr { n_hashes: Option<u8> },
 }
 
-/// Error produced validating a raw string. Represents cases like:
-/// - `r##~"abcde"##`: `InvalidStarter`
-/// - `r###"abcde"##`: `NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)`
-/// - Too many `#`s (>255): `TooManyDelimiters`
-// perf note: It doesn't matter that this makes `Token` 36 bytes bigger. See #77629
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub enum RawStrError {
-    /// Non `#` characters exist between `r` and `"` eg. `r#~"..`
+    /// Non `#` characters exist between `r` and `"`, e.g. `r##~"abcde"##`
     InvalidStarter { bad_char: char },
-    /// The string was never terminated. `possible_terminator_offset` is the number of characters after `r` or `br` where they
-    /// may have intended to terminate it.
-    NoTerminator { expected: usize, found: usize, possible_terminator_offset: Option<usize> },
+    /// The string was not terminated, e.g. `r###"abcde"##`.
+    /// `possible_terminator_offset` is the number of characters after `r` or
+    /// `br` where they may have intended to terminate it.
+    NoTerminator { expected: u32, found: u32, possible_terminator_offset: Option<u32> },
     /// More than 255 `#`s exist.
-    TooManyDelimiters { found: usize },
+    TooManyDelimiters { found: u32 },
 }
 
 /// Base of numeric literal encoding according to its prefix.
@@ -221,11 +218,25 @@ pub fn strip_shebang(input: &str) -> Option<usize> {
 }
 
 /// Parses the first token from the provided input string.
+#[inline]
 pub fn first_token(input: &str) -> Token {
     debug_assert!(!input.is_empty());
     Cursor::new(input).advance_token()
 }
 
+/// Validates a raw string literal. Used for getting more information about a
+/// problem with a `RawStr`/`RawByteStr` with a `None` field.
+#[inline]
+pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError> {
+    debug_assert!(!input.is_empty());
+    let mut cursor = Cursor::new(input);
+    // Move past the leading `r` or `br`.
+    for _ in 0..prefix_len {
+        cursor.bump().unwrap();
+    }
+    cursor.raw_double_quoted_string(prefix_len).map(|_| ())
+}
+
 /// Creates an iterator that produces tokens from the input string.
 pub fn tokenize(input: &str) -> impl Iterator<Item = Token> + '_ {
     let mut cursor = Cursor::new(input);
@@ -315,12 +326,12 @@ impl Cursor<'_> {
             'r' => match (self.first(), self.second()) {
                 ('#', c1) if is_id_start(c1) => self.raw_ident(),
                 ('#', _) | ('"', _) => {
-                    let (n_hashes, err) = self.raw_double_quoted_string(1);
+                    let res = self.raw_double_quoted_string(1);
                     let suffix_start = self.len_consumed();
-                    if err.is_none() {
+                    if res.is_ok() {
                         self.eat_literal_suffix();
                     }
-                    let kind = RawStr { n_hashes, err };
+                    let kind = RawStr { n_hashes: res.ok() };
                     Literal { kind, suffix_start }
                 }
                 _ => self.ident_or_unknown_prefix(),
@@ -350,12 +361,12 @@ impl Cursor<'_> {
                 }
                 ('r', '"') | ('r', '#') => {
                     self.bump();
-                    let (n_hashes, err) = self.raw_double_quoted_string(2);
+                    let res = self.raw_double_quoted_string(2);
                     let suffix_start = self.len_consumed();
-                    if err.is_none() {
+                    if res.is_ok() {
                         self.eat_literal_suffix();
                     }
-                    let kind = RawByteStr { n_hashes, err };
+                    let kind = RawByteStr { n_hashes: res.ok() };
                     Literal { kind, suffix_start }
                 }
                 _ => self.ident_or_unknown_prefix(),
@@ -698,19 +709,18 @@ impl Cursor<'_> {
     }
 
     /// Eats the double-quoted string and returns `n_hashes` and an error if encountered.
-    fn raw_double_quoted_string(&mut self, prefix_len: usize) -> (u8, Option<RawStrError>) {
+    fn raw_double_quoted_string(&mut self, prefix_len: u32) -> Result<u8, RawStrError> {
         // Wrap the actual function to handle the error with too many hashes.
         // This way, it eats the whole raw string.
-        let (n_hashes, err) = self.raw_string_unvalidated(prefix_len);
+        let n_hashes = self.raw_string_unvalidated(prefix_len)?;
         // Only up to 255 `#`s are allowed in raw strings
         match u8::try_from(n_hashes) {
-            Ok(num) => (num, err),
-            // We lie about the number of hashes here :P
-            Err(_) => (0, Some(RawStrError::TooManyDelimiters { found: n_hashes })),
+            Ok(num) => Ok(num),
+            Err(_) => Err(RawStrError::TooManyDelimiters { found: n_hashes }),
         }
     }
 
-    fn raw_string_unvalidated(&mut self, prefix_len: usize) -> (usize, Option<RawStrError>) {
+    fn raw_string_unvalidated(&mut self, prefix_len: u32) -> Result<u32, RawStrError> {
         debug_assert!(self.prev() == 'r');
         let start_pos = self.len_consumed();
         let mut possible_terminator_offset = None;
@@ -729,7 +739,7 @@ impl Cursor<'_> {
             Some('"') => (),
             c => {
                 let c = c.unwrap_or(EOF_CHAR);
-                return (n_start_hashes, Some(RawStrError::InvalidStarter { bad_char: c }));
+                return Err(RawStrError::InvalidStarter { bad_char: c });
             }
         }
 
@@ -739,14 +749,11 @@ impl Cursor<'_> {
             self.eat_while(|c| c != '"');
 
             if self.is_eof() {
-                return (
-                    n_start_hashes,
-                    Some(RawStrError::NoTerminator {
-                        expected: n_start_hashes,
-                        found: max_hashes,
-                        possible_terminator_offset,
-                    }),
-                );
+                return Err(RawStrError::NoTerminator {
+                    expected: n_start_hashes,
+                    found: max_hashes,
+                    possible_terminator_offset,
+                });
             }
 
             // Eat closing double quote.
@@ -764,7 +771,7 @@ impl Cursor<'_> {
             }
 
             if n_end_hashes == n_start_hashes {
-                return (n_start_hashes, None);
+                return Ok(n_start_hashes);
             } else if n_end_hashes > max_hashes {
                 // Keep track of possible terminators to give a hint about
                 // where there might be a missing terminator
diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs
index 07daee06f0f..e4c1787f2cc 100644
--- a/compiler/rustc_lexer/src/tests.rs
+++ b/compiler/rustc_lexer/src/tests.rs
@@ -2,42 +2,39 @@ use super::*;
 
 use expect_test::{expect, Expect};
 
-fn check_raw_str(s: &str, expected_hashes: u8, expected_err: Option<RawStrError>) {
+fn check_raw_str(s: &str, expected: Result<u8, RawStrError>) {
     let s = &format!("r{}", s);
     let mut cursor = Cursor::new(s);
     cursor.bump();
-    let (n_hashes, err) = cursor.raw_double_quoted_string(0);
-    assert_eq!(n_hashes, expected_hashes);
-    assert_eq!(err, expected_err);
+    let res = cursor.raw_double_quoted_string(0);
+    assert_eq!(res, expected);
 }
 
 #[test]
 fn test_naked_raw_str() {
-    check_raw_str(r#""abc""#, 0, None);
+    check_raw_str(r#""abc""#, Ok(0));
 }
 
 #[test]
 fn test_raw_no_start() {
-    check_raw_str(r##""abc"#"##, 0, None);
+    check_raw_str(r##""abc"#"##, Ok(0));
 }
 
 #[test]
 fn test_too_many_terminators() {
     // this error is handled in the parser later
-    check_raw_str(r###"#"abc"##"###, 1, None);
+    check_raw_str(r###"#"abc"##"###, Ok(1));
 }
 
 #[test]
 fn test_unterminated() {
     check_raw_str(
         r#"#"abc"#,
-        1,
-        Some(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None }),
+        Err(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None }),
     );
     check_raw_str(
         r###"##"abc"#"###,
-        2,
-        Some(RawStrError::NoTerminator {
+        Err(RawStrError::NoTerminator {
             expected: 2,
             found: 1,
             possible_terminator_offset: Some(7),
@@ -46,14 +43,13 @@ fn test_unterminated() {
     // We're looking for "# not just any #
     check_raw_str(
         r###"##"abc#"###,
-        2,
-        Some(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None }),
+        Err(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None }),
     )
 }
 
 #[test]
 fn test_invalid_start() {
-    check_raw_str(r##"#~"abc"#"##, 1, Some(RawStrError::InvalidStarter { bad_char: '~' }));
+    check_raw_str(r##"#~"abc"#"##, Err(RawStrError::InvalidStarter { bad_char: '~' }));
 }
 
 #[test]
@@ -61,26 +57,24 @@ fn test_unterminated_no_pound() {
     // https://github.com/rust-lang/rust/issues/70677
     check_raw_str(
         r#"""#,
-        0,
-        Some(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None }),
+        Err(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None }),
     );
 }
 
 #[test]
 fn test_too_many_hashes() {
     let max_count = u8::MAX;
-    let mut hashes: String = "#".repeat(max_count.into());
+    let hashes1 = "#".repeat(max_count as usize);
+    let hashes2 = "#".repeat(max_count as usize + 1);
+    let middle = "\"abc\"";
+    let s1 = [&hashes1, middle, &hashes1].join("");
+    let s2 = [&hashes2, middle, &hashes2].join("");
 
-    // Valid number of hashes (255 = 2^8 - 1 = u8::MAX), but invalid string.
-    check_raw_str(&hashes, max_count, Some(RawStrError::InvalidStarter { bad_char: '\u{0}' }));
+    // Valid number of hashes (255 = 2^8 - 1 = u8::MAX).
+    check_raw_str(&s1, Ok(255));
 
     // One more hash sign (256 = 2^8) becomes too many.
-    hashes.push('#');
-    check_raw_str(
-        &hashes,
-        0,
-        Some(RawStrError::TooManyDelimiters { found: usize::from(max_count) + 1 }),
-    );
+    check_raw_str(&s2, Err(RawStrError::TooManyDelimiters { found: u32::from(max_count) + 1 }));
 }
 
 #[test]
@@ -251,7 +245,7 @@ fn raw_string() {
     check_lexing(
         "r###\"\"#a\\b\x00c\"\"###",
         expect![[r#"
-            Token { kind: Literal { kind: RawStr { n_hashes: 3, err: None }, suffix_start: 17 }, len: 17 }
+            Token { kind: Literal { kind: RawStr { n_hashes: Some(3) }, suffix_start: 17 }, len: 17 }
         "#]],
     )
 }
@@ -295,9 +289,9 @@ br###"raw"###suffix
             Token { kind: Whitespace, len: 1 }
             Token { kind: Literal { kind: Int { base: Decimal, empty_int: false }, suffix_start: 1 }, len: 3 }
             Token { kind: Whitespace, len: 1 }
-            Token { kind: Literal { kind: RawStr { n_hashes: 3, err: None }, suffix_start: 12 }, len: 18 }
+            Token { kind: Literal { kind: RawStr { n_hashes: Some(3) }, suffix_start: 12 }, len: 18 }
             Token { kind: Whitespace, len: 1 }
-            Token { kind: Literal { kind: RawByteStr { n_hashes: 3, err: None }, suffix_start: 13 }, len: 19 }
+            Token { kind: Literal { kind: RawByteStr { n_hashes: Some(3) }, suffix_start: 13 }, len: 19 }
             Token { kind: Whitespace, len: 1 }
         "#]],
     )
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index ca3e6ce4d60..bd58021f78f 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1364,7 +1364,6 @@ impl UnreachablePub {
         cx: &LateContext<'_>,
         what: &str,
         def_id: LocalDefId,
-        span: Span,
         vis_span: Span,
         exportable: bool,
     ) {
@@ -1373,7 +1372,7 @@ impl UnreachablePub {
             if vis_span.from_expansion() {
                 applicability = Applicability::MaybeIncorrect;
             }
-            let def_span = cx.tcx.sess.source_map().guess_head_span(span);
+            let def_span = cx.tcx.def_span(def_id);
             cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
                 let mut err = lint.build(fluent::lint::builtin_unreachable_pub);
                 err.set_arg("what", what);
@@ -1399,36 +1398,22 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
         if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
             return;
         }
-        self.perform_lint(cx, "item", item.def_id, item.span, item.vis_span, true);
+        self.perform_lint(cx, "item", item.def_id, item.vis_span, true);
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
-        self.perform_lint(
-            cx,
-            "item",
-            foreign_item.def_id,
-            foreign_item.span,
-            foreign_item.vis_span,
-            true,
-        );
+        self.perform_lint(cx, "item", foreign_item.def_id, foreign_item.vis_span, true);
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
         let def_id = cx.tcx.hir().local_def_id(field.hir_id);
-        self.perform_lint(cx, "field", def_id, field.span, field.vis_span, false);
+        self.perform_lint(cx, "field", def_id, field.vis_span, false);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
         // Only lint inherent impl items.
         if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() {
-            self.perform_lint(
-                cx,
-                "item",
-                impl_item.def_id,
-                impl_item.span,
-                impl_item.vis_span,
-                false,
-            );
+            self.perform_lint(cx, "item", impl_item.def_id, impl_item.vis_span, false);
         }
     }
 }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 04ac50f1d48..b95fc341db6 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -856,13 +856,18 @@ pub trait LintContext: Sized {
                         Applicability::MachineApplicable,
                     );
                 },
-                BuiltinLintDiagnostics::NamedArgumentUsedPositionally(positional_arg, named_arg, name) => {
-                    db.span_label(named_arg, "this named argument is only referred to by position in formatting string");
-                    if let Some(positional_arg) = positional_arg {
-                        let msg = format!("this formatting argument uses named argument `{}` by position", name);
-                        db.span_label(positional_arg, msg);
+                BuiltinLintDiagnostics::NamedArgumentUsedPositionally{ position_sp_to_replace, position_sp_for_msg, named_arg_sp, named_arg_name, is_formatting_arg} => {
+                    db.span_label(named_arg_sp, "this named argument is referred to by position in formatting string");
+                    if let Some(positional_arg_for_msg) = position_sp_for_msg {
+                        let msg = format!("this formatting argument uses named argument `{}` by position", named_arg_name);
+                        db.span_label(positional_arg_for_msg, msg);
+                    }
+
+                    if let Some(positional_arg_to_replace) = position_sp_to_replace {
+                        let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name };
+
                         db.span_suggestion_verbose(
-                            positional_arg,
+                            positional_arg_to_replace,
                             "use the named argument by name to avoid ambiguity",
                             name,
                             Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 33ac2ed02aa..8d04d68bf1c 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -22,8 +22,8 @@ pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext
     let def_id = cx.tcx.hir().local_def_id(id);
     let item = cx.tcx.associated_item(def_id);
     match item.container {
-        ty::TraitContainer(..) => MethodLateContext::TraitAutoImpl,
-        ty::ImplContainer(cid) => match cx.tcx.impl_trait_ref(cid) {
+        ty::TraitContainer => MethodLateContext::TraitAutoImpl,
+        ty::ImplContainer => match cx.tcx.impl_trait_ref(item.container_id(cx.tcx)) {
             Some(_) => MethodLateContext::TraitImpl,
             None => MethodLateContext::PlainImpl,
         },
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 53269d18527..b6cf182916c 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -396,6 +396,7 @@ enum UnusedDelimsCtx {
     LetScrutineeExpr,
     ArrayLenExpr,
     AnonConst,
+    MatchArmExpr,
 }
 
 impl From<UnusedDelimsCtx> for &'static str {
@@ -414,6 +415,7 @@ impl From<UnusedDelimsCtx> for &'static str {
             UnusedDelimsCtx::BlockRetValue => "block return value",
             UnusedDelimsCtx::LetScrutineeExpr => "`let` scrutinee expression",
             UnusedDelimsCtx::ArrayLenExpr | UnusedDelimsCtx::AnonConst => "const expression",
+            UnusedDelimsCtx::MatchArmExpr => "match arm expression",
         }
     }
 }
@@ -805,6 +807,18 @@ impl EarlyLintPass for UnusedParens {
                 }
                 return;
             }
+            ExprKind::Match(ref _expr, ref arm) => {
+                for a in arm {
+                    self.check_unused_delims_expr(
+                        cx,
+                        &a.body,
+                        UnusedDelimsCtx::MatchArmExpr,
+                        false,
+                        None,
+                        None,
+                    );
+                }
+            }
             _ => {}
         }
 
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 39690851d1e..f00165cd3b3 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -631,6 +631,32 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `unused_tuple_struct_fields` lint detects fields of tuple structs
+    /// that are never read.
+    ///
+    /// ### Example
+    ///
+    /// ```
+    /// #[warn(unused_tuple_struct_fields)]
+    /// struct S(i32, i32, i32);
+    /// let s = S(1, 2, 3);
+    /// let _ = (s.0, s.2);
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Tuple struct fields that are never read anywhere may indicate a
+    /// mistake or unfinished code. To silence this warning, consider
+    /// removing the unused field(s) or, to preserve the numbering of the
+    /// remaining fields, change the unused field(s) to have unit type.
+    pub UNUSED_TUPLE_STRUCT_FIELDS,
+    Allow,
+    "detects tuple struct fields that are never read"
+}
+
+declare_lint! {
     /// The `unreachable_code` lint detects unreachable code paths.
     ///
     /// ### Example
@@ -3281,6 +3307,7 @@ declare_lint_pass! {
         UNSUPPORTED_CALLING_CONVENTIONS,
         BREAK_WITH_LABEL_AND_LOOP,
         UNUSED_ATTRIBUTES,
+        UNUSED_TUPLE_STRUCT_FIELDS,
         NON_EXHAUSTIVE_OMITTED_PATTERNS,
         TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
         DEREF_INTO_DYN_SUPERTRAIT,
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 4fd57ed8533..6acbe97a7a1 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -467,7 +467,19 @@ pub enum BuiltinLintDiagnostics {
         /// If true, the lifetime will be fully elided.
         use_span: Option<(Span, bool)>,
     },
-    NamedArgumentUsedPositionally(Option<Span>, Span, String),
+    NamedArgumentUsedPositionally {
+        /// Span where the named argument is used by position and will be replaced with the named
+        /// argument name
+        position_sp_to_replace: Option<Span>,
+        /// Span where the named argument is used by position and is used for lint messages
+        position_sp_for_msg: Option<Span>,
+        /// Span where the named argument's name is (so we know where to put the warning message)
+        named_arg_sp: Span,
+        /// String containing the named arguments name
+        named_arg_name: String,
+        /// Indicates if the named argument is used as a width/precision for formatting
+        is_formatting_arg: bool,
+    },
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index c333738ded4..5f5b5de790e 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -1311,11 +1311,16 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) {
     return LLVMBFloatTypeKind;
   case Type::X86_AMXTyID:
     return LLVMX86_AMXTypeKind;
-#if LLVM_VERSION_GE(15, 0)
+#if LLVM_VERSION_GE(15, 0) && LLVM_VERSION_LT(16, 0)
   case Type::DXILPointerTyID:
     report_fatal_error("Rust does not support DirectX typed pointers.");
     break;
 #endif
+#if LLVM_VERSION_GE(16, 0)
+  case Type::TypedPointerTyID:
+    report_fatal_error("Rust does not support typed pointers.");
+    break;
+#endif
   }
   report_fatal_error("Unhandled TypeID.");
 }
diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml
index 25b3aadc1c5..547c8debb50 100644
--- a/compiler/rustc_macros/Cargo.toml
+++ b/compiler/rustc_macros/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
 proc-macro = true
 
 [dependencies]
-annotate-snippets = "0.8.0"
+annotate-snippets = "0.9"
 fluent-bundle = "0.15.2"
 fluent-syntax = "0.11"
 synstructure = "0.12.1"
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index c33219e4700..9f6079ecba4 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -472,7 +472,9 @@ impl<'tcx> Collector<'tcx> {
                 Abi::Fastcall { .. } => {
                     DllCallingConvention::Fastcall(self.i686_arg_list_size(item))
                 }
-                // Vectorcall is intentionally not supported at this time.
+                Abi::Vectorcall { .. } => {
+                    DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
+                }
                 _ => {
                     self.tcx.sess.span_fatal(
                         item.span,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 6b0b5ac7da9..40dc4fb052d 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1114,7 +1114,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
 
     fn get_fn_has_self_parameter(self, id: DefIndex) -> bool {
         match self.kind(id) {
-            EntryKind::AssocFn(data) => data.decode(self).has_self,
+            EntryKind::AssocFn { has_self, .. } => has_self,
             _ => false,
         }
     }
@@ -1134,28 +1134,21 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
     }
 
     fn get_associated_item(self, id: DefIndex) -> ty::AssocItem {
-        let def_key = self.def_key(id);
-        let parent = self.local_def_id(def_key.parent.unwrap());
         let name = self.item_name(id);
 
         let (kind, container, has_self) = match self.kind(id) {
             EntryKind::AssocConst(container) => (ty::AssocKind::Const, container, false),
-            EntryKind::AssocFn(data) => {
-                let data = data.decode(self);
-                (ty::AssocKind::Fn, data.container, data.has_self)
-            }
+            EntryKind::AssocFn { container, has_self } => (ty::AssocKind::Fn, container, has_self),
             EntryKind::AssocType(container) => (ty::AssocKind::Type, container, false),
-            _ => bug!("cannot get associated-item of `{:?}`", def_key),
+            _ => bug!("cannot get associated-item of `{:?}`", id),
         };
 
         ty::AssocItem {
             name,
             kind,
-            vis: self.get_visibility(id),
-            defaultness: container.defaultness(),
             def_id: self.local_def_id(id),
             trait_item_def_id: self.get_trait_item_def_id(id),
-            container: container.with_def_id(parent),
+            container,
             fn_has_self_parameter: has_self,
         }
     }
@@ -1310,19 +1303,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         }
     }
 
-    fn get_trait_of_item(self, id: DefIndex) -> Option<DefId> {
-        let def_key = self.def_key(id);
-        match def_key.disambiguated_data.data {
-            DefPathData::TypeNs(..) | DefPathData::ValueNs(..) => (),
-            // Not an associated item
-            _ => return None,
-        }
-        def_key.parent.and_then(|parent_index| match self.kind(parent_index) {
-            EntryKind::Trait | EntryKind::TraitAlias => Some(self.local_def_id(parent_index)),
-            _ => None,
-        })
-    }
-
     fn get_native_libraries(self, sess: &'a Session) -> impl Iterator<Item = NativeLib> + 'a {
         self.root.native_libraries.decode((self, sess))
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 6bf237b8ed5..38ce50e8323 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -235,7 +235,6 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
     is_foreign_item => { cdata.is_foreign_item(def_id.index) }
     item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) }
-    trait_of_item => { cdata.get_trait_of_item(def_id.index) }
     is_mir_available => { cdata.is_item_mir_available(def_id.index) }
     is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
 
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index f0886036899..33278367ce3 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1212,14 +1212,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let tcx = self.tcx;
 
         let ast_item = tcx.hir().expect_trait_item(def_id.expect_local());
+        self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
         let trait_item = tcx.associated_item(def_id);
 
-        let container = match trait_item.defaultness {
-            hir::Defaultness::Default { has_value: true } => AssocContainer::TraitWithDefault,
-            hir::Defaultness::Default { has_value: false } => AssocContainer::TraitRequired,
-            hir::Defaultness::Final => span_bug!(ast_item.span, "traits cannot have final items"),
-        };
-
         match trait_item.kind {
             ty::AssocKind::Const => {
                 let rendered = rustc_hir_pretty::to_string(
@@ -1227,7 +1222,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     |s| s.print_trait_item(ast_item),
                 );
 
-                record!(self.tables.kind[def_id] <- EntryKind::AssocConst(container));
+                record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::TraitContainer));
                 record!(self.tables.mir_const_qualif[def_id] <- mir::ConstQualifs::default());
                 record!(self.tables.rendered_const[def_id] <- rendered);
             }
@@ -1243,14 +1238,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 };
                 self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
                 self.tables.constness.set(def_id.index, hir::Constness::NotConst);
-                record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
-                    container,
+                record!(self.tables.kind[def_id] <- EntryKind::AssocFn {
+                    container: ty::AssocItemContainer::TraitContainer,
                     has_self: trait_item.fn_has_self_parameter,
-                })));
+                });
             }
             ty::AssocKind::Type => {
                 self.encode_explicit_item_bounds(def_id);
-                record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
+                record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::TraitContainer));
             }
         }
         match trait_item.kind {
@@ -1258,7 +1253,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 self.encode_item_type(def_id);
             }
             ty::AssocKind::Type => {
-                if trait_item.defaultness.has_value() {
+                if ast_item.defaultness.has_value() {
                     self.encode_item_type(def_id);
                 }
             }
@@ -1273,23 +1268,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         let tcx = self.tcx;
 
         let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
+        self.tables.impl_defaultness.set(def_id.index, ast_item.defaultness);
         let impl_item = self.tcx.associated_item(def_id);
 
-        let container = match impl_item.defaultness {
-            hir::Defaultness::Default { has_value: true } => AssocContainer::ImplDefault,
-            hir::Defaultness::Final => AssocContainer::ImplFinal,
-            hir::Defaultness::Default { has_value: false } => {
-                span_bug!(ast_item.span, "impl items always have values (currently)")
-            }
-        };
-
         match impl_item.kind {
             ty::AssocKind::Const => {
                 if let hir::ImplItemKind::Const(_, body_id) = ast_item.kind {
                     let qualifs = self.tcx.at(ast_item.span).mir_const_qualif(def_id);
                     let const_data = self.encode_rendered_const_for_body(body_id);
 
-                    record!(self.tables.kind[def_id] <- EntryKind::AssocConst(container));
+                    record!(self.tables.kind[def_id] <- EntryKind::AssocConst(ty::AssocItemContainer::ImplContainer));
                     record!(self.tables.mir_const_qualif[def_id] <- qualifs);
                     record!(self.tables.rendered_const[def_id] <- const_data);
                 } else {
@@ -1307,13 +1295,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     hir::Constness::NotConst
                 };
                 self.tables.constness.set(def_id.index, constness);
-                record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
-                    container,
+                record!(self.tables.kind[def_id] <- EntryKind::AssocFn {
+                    container: ty::AssocItemContainer::ImplContainer,
                     has_self: impl_item.fn_has_self_parameter,
-                })));
+                });
             }
             ty::AssocKind::Type => {
-                record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
+                record!(self.tables.kind[def_id] <- EntryKind::AssocType(ty::AssocItemContainer::ImplContainer));
             }
         }
         self.encode_item_type(def_id);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 23198a85369..66bdecc30db 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -419,9 +419,9 @@ enum EntryKind {
     Generator,
     Trait,
     Impl,
-    AssocFn(LazyValue<AssocFnData>),
-    AssocType(AssocContainer),
-    AssocConst(AssocContainer),
+    AssocFn { container: ty::AssocItemContainer, has_self: bool },
+    AssocType(ty::AssocItemContainer),
+    AssocConst(ty::AssocItemContainer),
     TraitAlias,
 }
 
@@ -434,47 +434,6 @@ struct VariantData {
     is_non_exhaustive: bool,
 }
 
-/// Describes whether the container of an associated item
-/// is a trait or an impl and whether, in a trait, it has
-/// a default, or an in impl, whether it's marked "default".
-#[derive(Copy, Clone, TyEncodable, TyDecodable)]
-enum AssocContainer {
-    TraitRequired,
-    TraitWithDefault,
-    ImplDefault,
-    ImplFinal,
-}
-
-impl AssocContainer {
-    fn with_def_id(&self, def_id: DefId) -> ty::AssocItemContainer {
-        match *self {
-            AssocContainer::TraitRequired | AssocContainer::TraitWithDefault => {
-                ty::TraitContainer(def_id)
-            }
-
-            AssocContainer::ImplDefault | AssocContainer::ImplFinal => ty::ImplContainer(def_id),
-        }
-    }
-
-    fn defaultness(&self) -> hir::Defaultness {
-        match *self {
-            AssocContainer::TraitRequired => hir::Defaultness::Default { has_value: false },
-
-            AssocContainer::TraitWithDefault | AssocContainer::ImplDefault => {
-                hir::Defaultness::Default { has_value: true }
-            }
-
-            AssocContainer::ImplFinal => hir::Defaultness::Final,
-        }
-    }
-}
-
-#[derive(MetadataEncodable, MetadataDecodable)]
-struct AssocFnData {
-    container: AssocContainer,
-    has_self: bool,
-}
-
 #[derive(TyEncodable, TyDecodable)]
 struct GeneratorData<'tcx> {
     layout: mir::GeneratorLayout<'tcx>,
@@ -492,7 +451,6 @@ pub fn provide(providers: &mut Providers) {
 
 trivially_parameterized_over_tcx! {
     VariantData,
-    AssocFnData,
     EntryKind,
     RawDefId,
     TraitImpls,
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index c6fe3e72103..200de9079c2 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -105,7 +105,7 @@ impl<'tcx> CanonicalVarInfo<'tcx> {
             CanonicalVarKind::Region(_) => true,
             CanonicalVarKind::PlaceholderRegion(..) => false,
             CanonicalVarKind::Const(..) => true,
-            CanonicalVarKind::PlaceholderConst(_) => false,
+            CanonicalVarKind::PlaceholderConst(_, _) => false,
         }
     }
 }
@@ -133,7 +133,7 @@ pub enum CanonicalVarKind<'tcx> {
     Const(ty::UniverseIndex, Ty<'tcx>),
 
     /// A "placeholder" that represents "any const".
-    PlaceholderConst(ty::PlaceholderConst<'tcx>),
+    PlaceholderConst(ty::PlaceholderConst<'tcx>, Ty<'tcx>),
 }
 
 impl<'tcx> CanonicalVarKind<'tcx> {
@@ -148,7 +148,7 @@ impl<'tcx> CanonicalVarKind<'tcx> {
             CanonicalVarKind::Region(ui) => ui,
             CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
             CanonicalVarKind::Const(ui, _) => ui,
-            CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
+            CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.universe,
         }
     }
 }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 64e158ba348..7ab71f9009d 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -431,6 +431,12 @@ impl<'tcx> Body<'tcx> {
         self.local_decls[RETURN_PLACE].ty
     }
 
+    /// Returns the return type; it always return first element from `local_decls` array.
+    #[inline]
+    pub fn bound_return_ty(&self) -> ty::EarlyBinder<Ty<'tcx>> {
+        ty::EarlyBinder(self.local_decls[RETURN_PLACE].ty)
+    }
+
     /// Gets the location of the terminator for the given block.
     #[inline]
     pub fn terminator_loc(&self, bb: BasicBlock) -> Location {
diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs
index c1e1cfef9f8..15496842d90 100644
--- a/compiler/rustc_middle/src/mir/patch.rs
+++ b/compiler/rustc_middle/src/mir/patch.rs
@@ -11,7 +11,8 @@ pub struct MirPatch<'tcx> {
     new_blocks: Vec<BasicBlockData<'tcx>>,
     new_statements: Vec<(Location, StatementKind<'tcx>)>,
     new_locals: Vec<LocalDecl<'tcx>>,
-    resume_block: BasicBlock,
+    resume_block: Option<BasicBlock>,
+    body_span: Span,
     next_local: usize,
 }
 
@@ -23,47 +24,36 @@ impl<'tcx> MirPatch<'tcx> {
             new_statements: vec![],
             new_locals: vec![],
             next_local: body.local_decls.len(),
-            resume_block: START_BLOCK,
+            resume_block: None,
+            body_span: body.span,
         };
 
-        // make sure the MIR we create has a resume block. It is
-        // completely legal to convert jumps to the resume block
-        // to jumps to None, but we occasionally have to add
-        // instructions just before that.
-
-        let mut resume_block = None;
-        let mut resume_stmt_block = None;
+        // Check if we already have a resume block
         for (bb, block) in body.basic_blocks().iter_enumerated() {
-            if let TerminatorKind::Resume = block.terminator().kind {
-                if !block.statements.is_empty() {
-                    assert!(resume_stmt_block.is_none());
-                    resume_stmt_block = Some(bb);
-                } else {
-                    resume_block = Some(bb);
-                }
+            if let TerminatorKind::Resume = block.terminator().kind && block.statements.is_empty() {
+                result.resume_block = Some(bb);
                 break;
             }
         }
-        let resume_block = resume_block.unwrap_or_else(|| {
-            result.new_block(BasicBlockData {
-                statements: vec![],
-                terminator: Some(Terminator {
-                    source_info: SourceInfo::outermost(body.span),
-                    kind: TerminatorKind::Resume,
-                }),
-                is_cleanup: true,
-            })
-        });
-        result.resume_block = resume_block;
-        if let Some(resume_stmt_block) = resume_stmt_block {
-            result
-                .patch_terminator(resume_stmt_block, TerminatorKind::Goto { target: resume_block });
-        }
+
         result
     }
 
-    pub fn resume_block(&self) -> BasicBlock {
-        self.resume_block
+    pub fn resume_block(&mut self) -> BasicBlock {
+        if let Some(bb) = self.resume_block {
+            return bb;
+        }
+
+        let bb = self.new_block(BasicBlockData {
+            statements: vec![],
+            terminator: Some(Terminator {
+                source_info: SourceInfo::outermost(self.body_span),
+                kind: TerminatorKind::Resume,
+            }),
+            is_cleanup: true,
+        });
+        self.resume_block = Some(bb);
+        bb
     }
 
     pub fn is_patched(&self, bb: BasicBlock) -> bool {
@@ -138,12 +128,17 @@ impl<'tcx> MirPatch<'tcx> {
             self.new_blocks.len(),
             body.basic_blocks().len()
         );
-        body.basic_blocks_mut().extend(self.new_blocks);
+        let bbs = if self.patch_map.is_empty() && self.new_blocks.is_empty() {
+            body.basic_blocks.as_mut_preserves_cfg()
+        } else {
+            body.basic_blocks.as_mut()
+        };
+        bbs.extend(self.new_blocks);
         body.local_decls.extend(self.new_locals);
         for (src, patch) in self.patch_map.into_iter_enumerated() {
             if let Some(patch) = patch {
                 debug!("MirPatch: patching block {:?}", src);
-                body[src].terminator_mut().kind = patch;
+                bbs[src].terminator_mut().kind = patch;
             }
         }
 
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 8e3c2283efc..eb90169d0e3 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -800,9 +800,6 @@ pub struct Place<'tcx> {
     pub projection: &'tcx List<PlaceElem<'tcx>>,
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(Place<'_>, 16);
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[derive(TyEncodable, TyDecodable, HashStable)]
 pub enum ProjectionElem<V, T> {
@@ -866,11 +863,6 @@ pub enum ProjectionElem<V, T> {
 /// and the index is a local.
 pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
 
-// This type is fairly frequently used, so we shouldn't unintentionally increase
-// its size.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(PlaceElem<'_>, 24);
-
 ///////////////////////////////////////////////////////////////////////////
 // Operands
 
@@ -913,9 +905,6 @@ pub enum Operand<'tcx> {
     Constant(Box<Constant<'tcx>>),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(Operand<'_>, 24);
-
 ///////////////////////////////////////////////////////////////////////////
 // Rvalues
 
@@ -1067,9 +1056,6 @@ pub enum Rvalue<'tcx> {
     CopyForDeref(Place<'tcx>),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(Rvalue<'_>, 40);
-
 #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum CastKind {
     /// An exposing pointer to address cast. A cast between a pointer and an integer type, or
@@ -1105,9 +1091,6 @@ pub enum AggregateKind<'tcx> {
     Generator(LocalDefId, SubstsRef<'tcx>, hir::Movability),
 }
 
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(AggregateKind<'_>, 48);
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum NullOp {
     /// Returns the size of a value of that type
@@ -1171,3 +1154,15 @@ pub enum BinOp {
     /// The `ptr.offset` operator
     Offset,
 }
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    // These are in alphabetical order, which is easy to maintain.
+    static_assert_size!(AggregateKind<'_>, 48);
+    static_assert_size!(Operand<'_>, 24);
+    static_assert_size!(Place<'_>, 16);
+    static_assert_size!(PlaceElem<'_>, 24);
+    static_assert_size!(Rvalue<'_>, 40);
+}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index ffa66b79dbf..d8483e7e409 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1147,14 +1147,6 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    /// Given an `associated_item`, find the trait it belongs to.
-    /// Return `None` if the `DefId` is not an associated item.
-    query trait_of_item(associated_item: DefId) -> Option<DefId> {
-        desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) }
-        cache_on_disk_if { associated_item.is_local() }
-        separate_provide_extern
-    }
-
     query is_ctfe_mir_available(key: DefId) -> bool {
         desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 8b27ca57046..b856af1d8f8 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -190,10 +190,6 @@ pub enum StmtKind<'tcx> {
     },
 }
 
-// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Expr<'_>, 104);
-
 #[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
 #[derive(TypeFoldable, TypeVisitable)]
 pub struct LocalVarId(pub hir::HirId);
@@ -812,3 +808,14 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
         }
     }
 }
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    // These are in alphabetical order, which is easy to maintain.
+    rustc_data_structures::static_assert_size!(Block, 56);
+    rustc_data_structures::static_assert_size!(Expr<'_>, 104);
+    rustc_data_structures::static_assert_size!(Pat<'_>, 24);
+    rustc_data_structures::static_assert_size!(Stmt<'_>, 120);
+}
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 0ca5a532b75..e836ba47eed 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -109,6 +109,10 @@ pub enum SelectionCandidate<'tcx> {
         /// `false` if there are no *further* obligations.
         has_nested: bool,
     },
+
+    /// Implementation of transmutability trait.
+    TransmutabilityCandidate,
+
     ParamCandidate(ty::PolyTraitPredicate<'tcx>),
     ImplCandidate(DefId),
     AutoImplCandidate(DefId),
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index 3c1d0061ae1..2465f8e2533 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -217,7 +217,7 @@ impl<'tcx> Ancestors<'tcx> {
         self.find_map(|node| {
             if let Some(item) = node.item(tcx, trait_item_def_id) {
                 if finalizing_node.is_none() {
-                    let is_specializable = item.defaultness.is_default()
+                    let is_specializable = item.defaultness(tcx).is_default()
                         || tcx.impl_defaultness(node.def_id()).is_default();
 
                     if !is_specializable {
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 809406aff18..2e596b27527 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -563,7 +563,7 @@ impl<'tcx> AdtDef<'tcx> {
     ///
     /// Due to normalization being eager, this applies even if
     /// the associated type is behind a pointer (e.g., issue #31299).
-    pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> &'tcx [Ty<'tcx>] {
-        tcx.adt_sized_constraint(self.did()).0
+    pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> ty::EarlyBinder<&'tcx [Ty<'tcx>]> {
+        ty::EarlyBinder(tcx.adt_sized_constraint(self.did()).0)
     }
 }
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index eb732148e3e..c97156ac17f 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -1,6 +1,6 @@
 pub use self::AssocItemContainer::*;
 
-use crate::ty;
+use crate::ty::{self, DefIdTree};
 use rustc_data_structures::sorted_map::SortedIndexMultiMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
@@ -11,33 +11,8 @@ use super::{TyCtxt, Visibility};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash, Encodable, Decodable)]
 pub enum AssocItemContainer {
-    TraitContainer(DefId),
-    ImplContainer(DefId),
-}
-
-impl AssocItemContainer {
-    pub fn impl_def_id(&self) -> Option<DefId> {
-        match *self {
-            ImplContainer(id) => Some(id),
-            _ => None,
-        }
-    }
-
-    /// Asserts that this is the `DefId` of an associated item declared
-    /// in a trait, and returns the trait `DefId`.
-    pub fn assert_trait(&self) -> DefId {
-        match *self {
-            TraitContainer(id) => id,
-            _ => bug!("associated item has wrong container type: {:?}", self),
-        }
-    }
-
-    pub fn id(&self) -> DefId {
-        match *self {
-            TraitContainer(id) => id,
-            ImplContainer(id) => id,
-        }
-    }
+    TraitContainer,
+    ImplContainer,
 }
 
 /// Information about an associated item
@@ -46,8 +21,6 @@ pub struct AssocItem {
     pub def_id: DefId,
     pub name: Symbol,
     pub kind: AssocKind,
-    pub vis: Visibility,
-    pub defaultness: hir::Defaultness,
     pub container: AssocItemContainer,
 
     /// If this is an item in an impl of a trait then this is the `DefId` of
@@ -64,6 +37,36 @@ impl AssocItem {
         Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
     }
 
+    pub fn defaultness(&self, tcx: TyCtxt<'_>) -> hir::Defaultness {
+        tcx.impl_defaultness(self.def_id)
+    }
+
+    #[inline]
+    pub fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility {
+        tcx.visibility(self.def_id)
+    }
+
+    #[inline]
+    pub fn container_id(&self, tcx: TyCtxt<'_>) -> DefId {
+        tcx.parent(self.def_id)
+    }
+
+    #[inline]
+    pub fn trait_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+        match self.container {
+            AssocItemContainer::ImplContainer => None,
+            AssocItemContainer::TraitContainer => Some(tcx.parent(self.def_id)),
+        }
+    }
+
+    #[inline]
+    pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
+        match self.container {
+            AssocItemContainer::ImplContainer => Some(tcx.parent(self.def_id)),
+            AssocItemContainer::TraitContainer => None,
+        }
+    }
+
     pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
         match self.kind {
             ty::AssocKind::Fn => {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 2714493b9fc..0a0f45ce1a0 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1459,11 +1459,11 @@ impl<'tcx> TyCtxt<'tcx> {
         };
 
         format!(
-            "{}[{}]{}",
+            "{}[{:04x}]{}",
             crate_name,
             // Don't print the whole stable crate id. That's just
             // annoying in debug output.
-            &(format!("{:08x}", stable_crate_id.to_u64()))[..4],
+            stable_crate_id.to_u64() >> 8 * 6,
             self.def_path(def_id).to_string_no_crate_verbose()
         )
     }
@@ -1668,8 +1668,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     // Checks if the bound region is in Impl Item.
     pub fn is_bound_region_in_impl_item(self, suitable_region_binding_scope: LocalDefId) -> bool {
-        let container_id =
-            self.associated_item(suitable_region_binding_scope.to_def_id()).container.id();
+        let container_id = self.parent(suitable_region_binding_scope.to_def_id());
         if self.impl_trait_ref(container_id).is_some() {
             // For now, we do not try to target impls of traits. This is
             // because this message is going to suggest that the user
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 91246051316..4b0bc3c1114 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -673,7 +673,7 @@ impl<T> Trait<T> for X {
             // the associated type or calling a method that returns the associated type".
             let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
                 diag,
-                assoc.container.id(),
+                assoc.container_id(self),
                 current_method_ident,
                 proj_ty.item_def_id,
                 values.expected,
@@ -844,7 +844,8 @@ fn foo(&self) -> Self::T { String::new() }
                         hir::AssocItemKind::Type => {
                             // FIXME: account for returning some type in a trait fn impl that has
                             // an assoc type as a return type (#72076).
-                            if let hir::Defaultness::Default { has_value: true } = item.defaultness
+                            if let hir::Defaultness::Default { has_value: true } =
+                                self.impl_defaultness(item.id.def_id)
                             {
                                 if self.type_of(item.id.def_id) == found {
                                     diag.span_label(
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 33a46f809b0..53218225d53 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -460,7 +460,7 @@ impl<'tcx> Instance<'tcx> {
                             && !matches!(
                                 tcx.opt_associated_item(def.did),
                                 Some(ty::AssocItem {
-                                    container: ty::AssocItemContainer::TraitContainer(_),
+                                    container: ty::AssocItemContainer::TraitContainer,
                                     ..
                                 })
                             )
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index fc4cc20119c..79309097e78 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -48,7 +48,7 @@ pub use subst::*;
 pub use vtable::*;
 
 use std::fmt::Debug;
-use std::hash::Hash;
+use std::hash::{Hash, Hasher};
 use std::ops::ControlFlow;
 use std::{fmt, str};
 
@@ -178,6 +178,11 @@ pub struct ResolverAstLowering {
     pub label_res_map: NodeMap<ast::NodeId>,
     /// Resolutions for lifetimes.
     pub lifetimes_res_map: NodeMap<LifetimeRes>,
+    /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
+    /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
+    /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
+    /// field from the original parameter 'a to the new parameter 'a1.
+    pub generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
     /// Lifetime parameters that lowering will have to introduce.
     pub extra_lifetime_params_map: NodeMap<Vec<(Ident, ast::NodeId, LifetimeRes)>>,
 
@@ -1201,7 +1206,7 @@ pub struct BoundConst<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
-pub type PlaceholderConst<'tcx> = Placeholder<BoundConst<'tcx>>;
+pub type PlaceholderConst<'tcx> = Placeholder<BoundVar>;
 
 /// A `DefId` which, in case it is a const argument, is potentially bundled with
 /// the `DefId` of the generic parameter it instantiates.
@@ -1705,6 +1710,59 @@ impl VariantDef {
     }
 }
 
+impl PartialEq for VariantDef {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        // There should be only one `VariantDef` for each `def_id`, therefore
+        // it is fine to implement `PartialEq` only based on `def_id`.
+        //
+        // Below, we exhaustively destructure `self` and `other` so that if the
+        // definition of `VariantDef` changes, a compile-error will be produced,
+        // reminding us to revisit this assumption.
+
+        let Self {
+            def_id: lhs_def_id,
+            ctor_def_id: _,
+            name: _,
+            discr: _,
+            fields: _,
+            ctor_kind: _,
+            flags: _,
+        } = &self;
+
+        let Self {
+            def_id: rhs_def_id,
+            ctor_def_id: _,
+            name: _,
+            discr: _,
+            fields: _,
+            ctor_kind: _,
+            flags: _,
+        } = other;
+
+        lhs_def_id == rhs_def_id
+    }
+}
+
+impl Eq for VariantDef {}
+
+impl Hash for VariantDef {
+    #[inline]
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        // There should be only one `VariantDef` for each `def_id`, therefore
+        // it is fine to implement `Hash` only based on `def_id`.
+        //
+        // Below, we exhaustively destructure `self` so that if the definition
+        // of `VariantDef` changes, a compile-error will be produced, reminding
+        // us to revisit this assumption.
+
+        let Self { def_id, ctor_def_id: _, name: _, discr: _, fields: _, ctor_kind: _, flags: _ } =
+            &self;
+
+        def_id.hash(s)
+    }
+}
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub enum VariantDiscr {
     /// Explicit value for this variant, i.e., `X = 123`.
@@ -1725,6 +1783,42 @@ pub struct FieldDef {
     pub vis: Visibility,
 }
 
+impl PartialEq for FieldDef {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        // There should be only one `FieldDef` for each `did`, therefore it is
+        // fine to implement `PartialEq` only based on `did`.
+        //
+        // Below, we exhaustively destructure `self` so that if the definition
+        // of `FieldDef` changes, a compile-error will be produced, reminding
+        // us to revisit this assumption.
+
+        let Self { did: lhs_did, name: _, vis: _ } = &self;
+
+        let Self { did: rhs_did, name: _, vis: _ } = other;
+
+        lhs_did == rhs_did
+    }
+}
+
+impl Eq for FieldDef {}
+
+impl Hash for FieldDef {
+    #[inline]
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        // There should be only one `FieldDef` for each `did`, therefore it is
+        // fine to implement `Hash` only based on `did`.
+        //
+        // Below, we exhaustively destructure `self` so that if the definition
+        // of `FieldDef` changes, a compile-error will be produced, reminding
+        // us to revisit this assumption.
+
+        let Self { did, name: _, vis: _ } = &self;
+
+        did.hash(s)
+    }
+}
+
 bitflags! {
     #[derive(TyEncodable, TyDecodable, Default, HashStable)]
     pub struct ReprFlags: u8 {
@@ -1946,7 +2040,7 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
         self.associated_items(id)
             .in_definition_order()
-            .filter(|item| item.kind == AssocKind::Fn && item.defaultness.has_value())
+            .filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value())
     }
 
     /// Look up the name of a definition across crates. This does not look at HIR.
@@ -2192,13 +2286,29 @@ impl<'tcx> TyCtxt<'tcx> {
         self.impl_trait_ref(def_id).map(|tr| tr.def_id)
     }
 
+    /// If the given `DefId` describes an item belonging to a trait,
+    /// returns the `DefId` of the trait that the trait item belongs to;
+    /// otherwise, returns `None`.
+    pub fn trait_of_item(self, def_id: DefId) -> Option<DefId> {
+        if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
+            let parent = self.parent(def_id);
+            if let DefKind::Trait | DefKind::TraitAlias = self.def_kind(parent) {
+                return Some(parent);
+            }
+        }
+        None
+    }
+
     /// If the given `DefId` describes a method belonging to an impl, returns the
     /// `DefId` of the impl that the method belongs to; otherwise, returns `None`.
     pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
-        self.opt_associated_item(def_id).and_then(|trait_item| match trait_item.container {
-            TraitContainer(_) => None,
-            ImplContainer(def_id) => Some(def_id),
-        })
+        if let DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy = self.def_kind(def_id) {
+            let parent = self.parent(def_id);
+            if let DefKind::Impl = self.def_kind(parent) {
+                return Some(parent);
+            }
+        }
+        None
     }
 
     /// If the given `DefId` belongs to a trait that was automatically derived, returns `true`.
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 411d5c55829..52c3a38861e 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1179,13 +1179,14 @@ pub struct ProjectionTy<'tcx> {
     /// The `DefId` of the `TraitItem` for the associated type `N`.
     ///
     /// Note that this is not the `DefId` of the `TraitRef` containing this
-    /// associated type, which is in `tcx.associated_item(item_def_id).container`.
+    /// associated type, which is in `tcx.associated_item(item_def_id).container`,
+    /// aka. `tcx.parent(item_def_id).unwrap()`.
     pub item_def_id: DefId,
 }
 
 impl<'tcx> ProjectionTy<'tcx> {
     pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
-        tcx.associated_item(self.item_def_id).container.id()
+        tcx.parent(self.item_def_id)
     }
 
     /// Extracts the underlying trait reference and own substs from this projection.
@@ -1195,7 +1196,7 @@ impl<'tcx> ProjectionTy<'tcx> {
         &self,
         tcx: TyCtxt<'tcx>,
     ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
-        let def_id = tcx.associated_item(self.item_def_id).container.id();
+        let def_id = tcx.parent(self.item_def_id);
         let trait_generics = tcx.generics_of(def_id);
         (
             ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
@@ -1433,7 +1434,7 @@ impl<'tcx> ExistentialProjection<'tcx> {
     /// then this function would return an `exists T. T: Iterator` existential trait
     /// reference.
     pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
-        let def_id = tcx.associated_item(self.item_def_id).container.id();
+        let def_id = tcx.parent(self.item_def_id);
         let subst_count = tcx.generics_of(def_id).count() - 1;
         let substs = tcx.intern_substs(&self.substs[..subst_count]);
         ty::ExistentialTraitRef { def_id, substs }
@@ -2190,7 +2191,7 @@ impl<'tcx> Ty<'tcx> {
 
             ty::Tuple(tys) => tys.iter().all(|ty| ty.is_trivially_sized(tcx)),
 
-            ty::Adt(def, _substs) => def.sized_constraint(tcx).is_empty(),
+            ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(),
 
             ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => false,
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 4d2f69b23fa..591bb7831b5 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -402,7 +402,7 @@ impl<'tcx> TyCtxt<'tcx> {
             Some(dtor) => dtor.did,
         };
 
-        let impl_def_id = self.associated_item(dtor).container.id();
+        let impl_def_id = self.parent(dtor);
         let impl_generics = self.generics_of(impl_def_id);
 
         // We have a destructor - all the parameters that are not
@@ -680,6 +680,24 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn bound_const_param_default(self, def_id: DefId) -> ty::EarlyBinder<ty::Const<'tcx>> {
         ty::EarlyBinder(self.const_param_default(def_id))
     }
+
+    pub fn bound_predicates_of(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
+        ty::EarlyBinder(self.predicates_of(def_id))
+    }
+
+    pub fn bound_explicit_predicates_of(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<ty::generics::GenericPredicates<'tcx>> {
+        ty::EarlyBinder(self.explicit_predicates_of(def_id))
+    }
+
+    pub fn bound_impl_subject(self, def_id: DefId) -> ty::EarlyBinder<ty::ImplSubject<'tcx>> {
+        ty::EarlyBinder(self.impl_subject(def_id))
+    }
 }
 
 struct OpaqueTypeExpander<'tcx> {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 58b1564cc5d..cefb5f36b6a 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -2334,7 +2334,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // This place is not really used because this destination place
         // should never be used to take values at the end of the failure
         // block.
-        let dummy_place = Place { local: RETURN_PLACE, projection: ty::List::empty() };
+        let dummy_place = self.temp(self.tcx.types.never, else_block.span);
         let failure_block;
         unpack!(
             failure_block = self.ast_block(
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index d21a8c4f9b9..54d549fd66c 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -1,10 +1,10 @@
 use rustc_data_structures::graph::iterate::{
     NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
 };
-use rustc_hir::intravisit::FnKind;
+use rustc_hir::def::DefKind;
 use rustc_middle::mir::{BasicBlock, BasicBlocks, Body, Operand, TerminatorKind};
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
-use rustc_middle::ty::{self, AssocItem, AssocItemContainer, Instance, TyCtxt};
+use rustc_middle::ty::{self, Instance, TyCtxt};
 use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
 use rustc_span::Span;
 use std::ops::ControlFlow;
@@ -12,18 +12,11 @@ use std::ops::ControlFlow;
 pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     let def_id = body.source.def_id().expect_local();
 
-    if let Some(fn_kind) = tcx.hir().get_by_def_id(def_id).fn_kind() {
-        if let FnKind::Closure = fn_kind {
-            // closures can't recur, so they don't matter.
-            return;
-        }
-
+    if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) {
         // If this is trait/impl method, extract the trait's substs.
-        let trait_substs = match tcx.opt_associated_item(def_id.to_def_id()) {
-            Some(AssocItem {
-                container: AssocItemContainer::TraitContainer(trait_def_id), ..
-            }) => {
-                let trait_substs_count = tcx.generics_of(*trait_def_id).count();
+        let trait_substs = match tcx.trait_of_item(def_id.to_def_id()) {
+            Some(trait_def_id) => {
+                let trait_substs_count = tcx.generics_of(trait_def_id).count();
                 &InternalSubsts::identity_for_item(tcx, def_id.to_def_id())[..trait_substs_count]
             }
             _ => &[],
@@ -41,8 +34,8 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
 
         vis.reachable_recursive_calls.sort();
 
+        let sp = tcx.def_span(def_id);
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-        let sp = tcx.sess.source_map().guess_head_span(tcx.hir().span_with_body(hir_id));
         tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| {
             let mut db = lint.build("function cannot return without recursing");
             db.span_label(sp, "cannot return without recursing");
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 60db98073a3..8d6f8efb600 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -261,7 +261,7 @@ impl IntRange {
     /// Lint on likely incorrect range patterns (#63987)
     pub(super) fn lint_overlapping_range_endpoints<'a, 'p: 'a, 'tcx: 'a>(
         &self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
         pats: impl Iterator<Item = &'a DeconstructedPat<'p, 'tcx>>,
         column_count: usize,
         hir_id: HirId,
@@ -617,7 +617,7 @@ impl SplitVarLenSlice {
             // The only admissible fixed-length slice is one of the array size. Whether `max_slice`
             // is fixed-length or variable-length, it will be the only relevant slice to output
             // here.
-            Some(_) => (0..0), // empty range
+            Some(_) => 0..0, // empty range
             // We cover all arities in the range `(self.arity..infinity)`. We split that range into
             // two: lengths smaller than `max_slice.arity()` are treated independently as
             // fixed-lengths slices, and lengths above are captured by `max_slice`.
@@ -696,7 +696,7 @@ impl<'tcx> Constructor<'tcx> {
     /// `EvalResult::Deny { .. }`.
     ///
     /// This means that the variant has a stdlib unstable feature marking it.
-    pub(super) fn is_unstable_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+    pub(super) fn is_unstable_variant(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool {
         if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() {
             let variant_def_id = adt.variant(*idx).def_id;
             // Filter variants that depend on a disabled unstable feature.
@@ -710,7 +710,7 @@ impl<'tcx> Constructor<'tcx> {
 
     /// Checks if the `Constructor` is a `Constructor::Variant` with a `#[doc(hidden)]`
     /// attribute from a type not local to the current crate.
-    pub(super) fn is_doc_hidden_variant(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+    pub(super) fn is_doc_hidden_variant(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool {
         if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() {
             let variant_def_id = adt.variants()[*idx].def_id;
             return pcx.cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local();
@@ -731,7 +731,7 @@ impl<'tcx> Constructor<'tcx> {
 
     /// The number of fields for this constructor. This must be kept in sync with
     /// `Fields::wildcards`.
-    pub(super) fn arity(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> usize {
+    pub(super) fn arity(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> usize {
         match self {
             Single | Variant(_) => match pcx.ty.kind() {
                 ty::Tuple(fs) => fs.len(),
@@ -775,7 +775,7 @@ impl<'tcx> Constructor<'tcx> {
     /// matrix, unless all of them are.
     pub(super) fn split<'a>(
         &self,
-        pcx: PatCtxt<'_, '_, 'tcx>,
+        pcx: &PatCtxt<'_, '_, 'tcx>,
         ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
     ) -> SmallVec<[Self; 1]>
     where
@@ -811,7 +811,7 @@ impl<'tcx> Constructor<'tcx> {
     /// this checks for inclusion.
     // We inline because this has a single call site in `Matrix::specialize_constructor`.
     #[inline]
-    pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
+    pub(super) fn is_covered_by<'p>(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool {
         // This must be kept in sync with `is_covered_by_any`.
         match (self, other) {
             // Wildcards cover anything
@@ -865,7 +865,7 @@ impl<'tcx> Constructor<'tcx> {
     /// assumed to have been split from a wildcard.
     fn is_covered_by_any<'p>(
         &self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
         used_ctors: &[Constructor<'tcx>],
     ) -> bool {
         if used_ctors.is_empty() {
@@ -918,7 +918,7 @@ pub(super) struct SplitWildcard<'tcx> {
 }
 
 impl<'tcx> SplitWildcard<'tcx> {
-    pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self {
+    pub(super) fn new<'p>(pcx: &PatCtxt<'_, 'p, 'tcx>) -> Self {
         debug!("SplitWildcard::new({:?})", pcx.ty);
         let cx = pcx.cx;
         let make_range = |start, end| {
@@ -1044,7 +1044,7 @@ impl<'tcx> SplitWildcard<'tcx> {
     /// do what you want.
     pub(super) fn split<'a>(
         &mut self,
-        pcx: PatCtxt<'_, '_, 'tcx>,
+        pcx: &PatCtxt<'_, '_, 'tcx>,
         ctors: impl Iterator<Item = &'a Constructor<'tcx>> + Clone,
     ) where
         'tcx: 'a,
@@ -1056,21 +1056,21 @@ impl<'tcx> SplitWildcard<'tcx> {
     }
 
     /// Whether there are any value constructors for this type that are not present in the matrix.
-    fn any_missing(&self, pcx: PatCtxt<'_, '_, 'tcx>) -> bool {
+    fn any_missing(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool {
         self.iter_missing(pcx).next().is_some()
     }
 
     /// Iterate over the constructors for this type that are not present in the matrix.
     pub(super) fn iter_missing<'a, 'p>(
         &'a self,
-        pcx: PatCtxt<'a, 'p, 'tcx>,
+        pcx: &'a PatCtxt<'a, 'p, 'tcx>,
     ) -> impl Iterator<Item = &'a Constructor<'tcx>> + Captures<'p> {
         self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors))
     }
 
     /// Return the set of constructors resulting from splitting the wildcard. As explained at the
     /// top of the file, if any constructors are missing we can ignore the present ones.
-    fn into_ctors(self, pcx: PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
+    fn into_ctors(self, pcx: &PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
         if self.any_missing(pcx) {
             // Some constructors are missing, thus we can specialize with the special `Missing`
             // constructor, which stands for those constructors that are not seen in the matrix,
@@ -1202,35 +1202,32 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
 
     /// Creates a new list of wildcard fields for a given constructor. The result must have a
     /// length of `constructor.arity()`.
-    pub(super) fn wildcards(
-        cx: &MatchCheckCtxt<'p, 'tcx>,
-        ty: Ty<'tcx>,
-        constructor: &Constructor<'tcx>,
-    ) -> Self {
+    #[instrument(level = "trace")]
+    pub(super) fn wildcards(pcx: &PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self {
         let ret = match constructor {
-            Single | Variant(_) => match ty.kind() {
-                ty::Tuple(fs) => Fields::wildcards_from_tys(cx, fs.iter()),
-                ty::Ref(_, rty, _) => Fields::wildcards_from_tys(cx, once(*rty)),
+            Single | Variant(_) => match pcx.ty.kind() {
+                ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()),
+                ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)),
                 ty::Adt(adt, substs) => {
                     if adt.is_box() {
                         // The only legal patterns of type `Box` (outside `std`) are `_` and box
                         // patterns. If we're here we can assume this is a box pattern.
-                        Fields::wildcards_from_tys(cx, once(substs.type_at(0)))
+                        Fields::wildcards_from_tys(pcx.cx, once(substs.type_at(0)))
                     } else {
                         let variant = &adt.variant(constructor.variant_index_for_adt(*adt));
-                        let tys = Fields::list_variant_nonhidden_fields(cx, ty, variant)
+                        let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant)
                             .map(|(_, ty)| ty);
-                        Fields::wildcards_from_tys(cx, tys)
+                        Fields::wildcards_from_tys(pcx.cx, tys)
                     }
                 }
-                _ => bug!("Unexpected type for `Single` constructor: {:?}", ty),
+                _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx),
             },
-            Slice(slice) => match *ty.kind() {
+            Slice(slice) => match *pcx.ty.kind() {
                 ty::Slice(ty) | ty::Array(ty, _) => {
                     let arity = slice.arity();
-                    Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty))
+                    Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty))
                 }
-                _ => bug!("bad slice pattern {:?} {:?}", constructor, ty),
+                _ => bug!("bad slice pattern {:?} {:?}", constructor, pcx),
             },
             Str(..)
             | FloatRange(..)
@@ -1243,7 +1240,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
                 bug!("called `Fields::wildcards` on an `Or` ctor")
             }
         };
-        debug!("Fields::wildcards({:?}, {:?}) = {:#?}", constructor, ty, ret);
+        debug!(?ret);
         ret
     }
 
@@ -1285,8 +1282,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
     /// Construct a pattern that matches everything that starts with this constructor.
     /// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
     /// `Some(_)`.
-    pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
-        let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
+    pub(super) fn wild_from_ctor(pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
+        let fields = Fields::wildcards(pcx, &ctor);
         DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP)
     }
 
@@ -1553,13 +1550,13 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
     /// `other_ctor` can be different from `self.ctor`, but must be covered by it.
     pub(super) fn specialize<'a>(
         &'a self,
-        cx: &MatchCheckCtxt<'p, 'tcx>,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
         other_ctor: &Constructor<'tcx>,
     ) -> SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]> {
         match (&self.ctor, other_ctor) {
             (Wildcard, _) => {
                 // We return a wildcard for each field of `other_ctor`.
-                Fields::wildcards(cx, self.ty, other_ctor).iter_patterns().collect()
+                Fields::wildcards(pcx, other_ctor).iter_patterns().collect()
             }
             (Slice(self_slice), Slice(other_slice))
                 if self_slice.arity() != other_slice.arity() =>
@@ -1578,7 +1575,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
                         let prefix = &self.fields.fields[..prefix];
                         let suffix = &self.fields.fields[self_slice.arity() - suffix..];
                         let wildcard: &_ =
-                            cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
+                            pcx.cx.pattern_arena.alloc(DeconstructedPat::wildcard(inner_ty));
                         let extra_wildcards = other_slice.arity() - self_slice.arity();
                         let extra_wildcards = (0..extra_wildcards).map(|_| wildcard);
                         prefix.iter().chain(extra_wildcards).chain(suffix).collect()
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 9e7a267ecbd..0a660ef30c8 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -411,12 +411,12 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
     /// This is roughly the inverse of `Constructor::apply`.
     fn pop_head_constructor(
         &self,
-        cx: &MatchCheckCtxt<'p, 'tcx>,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
         ctor: &Constructor<'tcx>,
     ) -> PatStack<'p, 'tcx> {
         // We pop the head pattern and push the new fields extracted from the arguments of
         // `self.head()`.
-        let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(cx, ctor);
+        let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor);
         new_fields.extend_from_slice(&self.pats[1..]);
         PatStack::from_vec(new_fields)
     }
@@ -469,13 +469,13 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
     /// This computes `S(constructor, self)`. See top of the file for explanations.
     fn specialize_constructor(
         &self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
         ctor: &Constructor<'tcx>,
     ) -> Matrix<'p, 'tcx> {
         let mut matrix = Matrix::empty();
         for row in &self.patterns {
             if ctor.is_covered_by(pcx, row.head().ctor()) {
-                let new_row = row.pop_head_constructor(pcx.cx, ctor);
+                let new_row = row.pop_head_constructor(pcx, ctor);
                 matrix.push(new_row);
             }
         }
@@ -575,7 +575,7 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
     /// with the results of specializing with the other constructors.
     fn apply_constructor(
         self,
-        pcx: PatCtxt<'_, 'p, 'tcx>,
+        pcx: &PatCtxt<'_, 'p, 'tcx>,
         matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors
         ctor: &Constructor<'tcx>,
     ) -> Self {
@@ -713,7 +713,7 @@ impl<'p, 'tcx> Witness<'p, 'tcx> {
     ///
     /// left_ty: struct X { a: (bool, &'static str), b: usize}
     /// pats: [(false, "foo"), 42]  => X { a: (false, "foo"), b: 42 }
-    fn apply_constructor(mut self, pcx: PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Self {
+    fn apply_constructor(mut self, pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Self {
         let pat = {
             let len = self.0.len();
             let arity = ctor.arity(pcx);
@@ -786,7 +786,7 @@ fn is_useful<'p, 'tcx>(
     is_under_guard: bool,
     is_top_level: bool,
 ) -> Usefulness<'p, 'tcx> {
-    debug!("matrix,v={:?}{:?}", matrix, v);
+    debug!(?matrix, ?v);
     let Matrix { patterns: rows, .. } = matrix;
 
     // The base case. We are pattern-matching on () and the return value is
@@ -806,11 +806,6 @@ fn is_useful<'p, 'tcx>(
 
     debug_assert!(rows.iter().all(|r| r.len() == v.len()));
 
-    let ty = v.head().ty();
-    let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
-    debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
-    let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
-
     // If the first pattern is an or-pattern, expand it.
     let mut ret = Usefulness::new_not_useful(witness_preference);
     if v.head().is_or_pat() {
@@ -832,6 +827,11 @@ fn is_useful<'p, 'tcx>(
             }
         }
     } else {
+        let ty = v.head().ty();
+        let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
+        debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
+        let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
+
         let v_ctor = v.head().ctor();
         debug!(?v_ctor);
         if let Constructor::IntRange(ctor_range) = &v_ctor {
@@ -853,7 +853,7 @@ fn is_useful<'p, 'tcx>(
             debug!("specialize({:?})", ctor);
             // We cache the result of `Fields::wildcards` because it is used a lot.
             let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor);
-            let v = v.pop_head_constructor(cx, &ctor);
+            let v = v.pop_head_constructor(pcx, &ctor);
             let usefulness = ensure_sufficient_stack(|| {
                 is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false)
             });
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index e64136928cc..21132eb991f 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -222,18 +222,6 @@ impl<'a, 'tcx> AnalysisDomain<'tcx> for MaybeTransitiveLiveLocals<'a> {
     }
 }
 
-struct TransferWrapper<'a>(&'a mut ChunkedBitSet<Local>);
-
-impl<'a> GenKill<Local> for TransferWrapper<'a> {
-    fn gen(&mut self, l: Local) {
-        self.0.insert(l);
-    }
-
-    fn kill(&mut self, l: Local) {
-        self.0.remove(l);
-    }
-}
-
 impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
     fn apply_statement_effect(
         &self,
@@ -271,7 +259,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
                 return;
             }
         }
-        TransferFunction(&mut TransferWrapper(trans)).visit_statement(statement, location);
+        TransferFunction(trans).visit_statement(statement, location);
     }
 
     fn apply_terminator_effect(
@@ -280,7 +268,7 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
         terminator: &mir::Terminator<'tcx>,
         location: Location,
     ) {
-        TransferFunction(&mut TransferWrapper(trans)).visit_terminator(terminator, location);
+        TransferFunction(trans).visit_terminator(terminator, location);
     }
 
     fn apply_call_return_effect(
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 85ad6b8f2fe..fbc0a767f07 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -18,9 +18,7 @@ use rustc_middle::mir::{
 };
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{
-    self, ConstKind, EarlyBinder, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable,
-};
+use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisitable};
 use rustc_span::{def_id::DefId, Span};
 use rustc_target::abi::{self, HasDataLayout, Size, TargetDataLayout};
 use rustc_target::spec::abi::Abi as CallAbi;
@@ -387,7 +385,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         );
 
         let ret_layout = ecx
-            .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
+            .layout_of(body.bound_return_ty().subst(tcx, substs))
             .ok()
             // Don't bother allocating memory for large values.
             // I don't know how return types can seem to be unsized but this happens in the
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 3ae6a88a140..c2ea55af48a 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -23,8 +23,7 @@ use rustc_middle::mir::{
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{
-    self, ConstInt, ConstKind, EarlyBinder, Instance, ParamEnv, ScalarInt, Ty, TyCtxt,
-    TypeVisitable,
+    self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitable,
 };
 use rustc_session::lint;
 use rustc_span::Span;
@@ -196,7 +195,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         );
 
         let ret_layout = ecx
-            .layout_of(EarlyBinder(body.return_ty()).subst(tcx, substs))
+            .layout_of(body.bound_return_ty().subst(tcx, substs))
             .ok()
             // Don't bother allocating memory for large values.
             // I don't know how return types can seem to be unsized but this happens in the
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 89808d3d4cd..5c441c5b194 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -83,9 +83,9 @@ impl RemoveNoopLandingPads {
     fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
         debug!("body: {:#?}", body);
 
-        // make sure there's a single resume block
+        // make sure there's a resume block
         let resume_block = {
-            let patch = MirPatch::new(body);
+            let mut patch = MirPatch::new(body);
             let resume_block = patch.resume_block();
             patch.apply(body);
             resume_block
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index e9701ec2d7f..848e142e59c 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -22,6 +22,13 @@ mod unicode_chars;
 
 use unescape_error_reporting::{emit_unescape_error, escaped_char};
 
+// This type is used a lot. Make sure it doesn't unintentionally get bigger.
+//
+// This assertion is in this crate, rather than in `rustc_lexer`, because that
+// crate cannot depend on `rustc_data_structures`.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12);
+
 #[derive(Clone, Debug)]
 pub struct UnmatchedBrace {
     pub expected_delim: Delimiter,
@@ -37,8 +44,7 @@ pub(crate) fn parse_token_trees<'a>(
     start_pos: BytePos,
     override_span: Option<Span>,
 ) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
-    StringReader { sess, start_pos, pos: start_pos, end_src_index: src.len(), src, override_span }
-        .into_token_trees()
+    StringReader { sess, start_pos, pos: start_pos, src, override_span }.into_token_trees()
 }
 
 struct StringReader<'a> {
@@ -47,8 +53,6 @@ struct StringReader<'a> {
     start_pos: BytePos,
     /// The absolute offset within the source_map of the current character.
     pos: BytePos,
-    /// Stop reading src at this index.
-    end_src_index: usize,
     /// Source text to tokenize.
     src: &'a str,
     override_span: Option<Span>,
@@ -64,20 +68,17 @@ impl<'a> StringReader<'a> {
         let mut spacing = Spacing::Joint;
 
         // Skip `#!` at the start of the file
-        let start_src_index = self.src_index(self.pos);
-        let text: &str = &self.src[start_src_index..self.end_src_index];
-        let is_beginning_of_file = self.pos == self.start_pos;
-        if is_beginning_of_file {
-            if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
-                self.pos = self.pos + BytePos::from_usize(shebang_len);
-                spacing = Spacing::Alone;
-            }
+        if self.pos == self.start_pos
+            && let Some(shebang_len) = rustc_lexer::strip_shebang(self.src)
+        {
+            self.pos = self.pos + BytePos::from_usize(shebang_len);
+            spacing = Spacing::Alone;
         }
 
         // Skip trivial (whitespace & comments) tokens
         loop {
             let start_src_index = self.src_index(self.pos);
-            let text: &str = &self.src[start_src_index..self.end_src_index];
+            let text: &str = &self.src[start_src_index..];
 
             if text.is_empty() {
                 let span = self.mk_sp(self.pos, self.pos);
@@ -87,7 +88,7 @@ impl<'a> StringReader<'a> {
             let token = rustc_lexer::first_token(text);
 
             let start = self.pos;
-            self.pos = self.pos + BytePos::from_usize(token.len);
+            self.pos = self.pos + BytePos(token.len);
 
             debug!("next_token: {:?}({:?})", token.kind, self.str_from(start));
 
@@ -239,7 +240,7 @@ impl<'a> StringReader<'a> {
                 token::Ident(sym, false)
             }
             rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
-                let suffix_start = start + BytePos(suffix_start as u32);
+                let suffix_start = start + BytePos(suffix_start);
                 let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
                 let suffix = if suffix_start < self.pos {
                     let string = self.str_from(suffix_start);
@@ -404,15 +405,21 @@ impl<'a> StringReader<'a> {
                 }
                 (token::ByteStr, Mode::ByteStr, 2, 1) // b" "
             }
-            rustc_lexer::LiteralKind::RawStr { n_hashes, err } => {
-                self.report_raw_str_error(start, err);
-                let n = u32::from(n_hashes);
-                (token::StrRaw(n_hashes), Mode::RawStr, 2 + n, 1 + n) // r##" "##
+            rustc_lexer::LiteralKind::RawStr { n_hashes } => {
+                if let Some(n_hashes) = n_hashes {
+                    let n = u32::from(n_hashes);
+                    (token::StrRaw(n_hashes), Mode::RawStr, 2 + n, 1 + n) // r##" "##
+                } else {
+                    self.report_raw_str_error(start, 1);
+                }
             }
-            rustc_lexer::LiteralKind::RawByteStr { n_hashes, err } => {
-                self.report_raw_str_error(start, err);
-                let n = u32::from(n_hashes);
-                (token::ByteStrRaw(n_hashes), Mode::RawByteStr, 3 + n, 1 + n) // br##" "##
+            rustc_lexer::LiteralKind::RawByteStr { n_hashes } => {
+                if let Some(n_hashes) = n_hashes {
+                    let n = u32::from(n_hashes);
+                    (token::ByteStrRaw(n_hashes), Mode::RawByteStr, 3 + n, 1 + n) // br##" "##
+                } else {
+                    self.report_raw_str_error(start, 2);
+                }
             }
             rustc_lexer::LiteralKind::Int { base, empty_int } => {
                 return if empty_int {
@@ -483,17 +490,17 @@ impl<'a> StringReader<'a> {
         &self.src[self.src_index(start)..self.src_index(end)]
     }
 
-    fn report_raw_str_error(&self, start: BytePos, opt_err: Option<RawStrError>) {
-        match opt_err {
-            Some(RawStrError::InvalidStarter { bad_char }) => {
+    fn report_raw_str_error(&self, start: BytePos, prefix_len: u32) -> ! {
+        match rustc_lexer::validate_raw_str(self.str_from(start), prefix_len) {
+            Err(RawStrError::InvalidStarter { bad_char }) => {
                 self.report_non_started_raw_string(start, bad_char)
             }
-            Some(RawStrError::NoTerminator { expected, found, possible_terminator_offset }) => self
+            Err(RawStrError::NoTerminator { expected, found, possible_terminator_offset }) => self
                 .report_unterminated_raw_string(start, expected, possible_terminator_offset, found),
-            Some(RawStrError::TooManyDelimiters { found }) => {
+            Err(RawStrError::TooManyDelimiters { found }) => {
                 self.report_too_many_hashes(start, found)
             }
-            None => (),
+            Ok(()) => panic!("no error found for supposedly invalid raw string literal"),
         }
     }
 
@@ -510,9 +517,9 @@ impl<'a> StringReader<'a> {
     fn report_unterminated_raw_string(
         &self,
         start: BytePos,
-        n_hashes: usize,
-        possible_offset: Option<usize>,
-        found_terminators: usize,
+        n_hashes: u32,
+        possible_offset: Option<u32>,
+        found_terminators: u32,
     ) -> ! {
         let mut err = self.sess.span_diagnostic.struct_span_fatal_with_code(
             self.mk_sp(start, start),
@@ -525,7 +532,7 @@ impl<'a> StringReader<'a> {
         if n_hashes > 0 {
             err.note(&format!(
                 "this raw string should be terminated with `\"{}`",
-                "#".repeat(n_hashes)
+                "#".repeat(n_hashes as usize)
             ));
         }
 
@@ -536,7 +543,7 @@ impl<'a> StringReader<'a> {
             err.span_suggestion(
                 span,
                 "consider terminating the string here",
-                "#".repeat(n_hashes),
+                "#".repeat(n_hashes as usize),
                 Applicability::MaybeIncorrect,
             );
         }
@@ -637,7 +644,7 @@ impl<'a> StringReader<'a> {
         }
     }
 
-    fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! {
+    fn report_too_many_hashes(&self, start: BytePos, found: u32) -> ! {
         self.fatal_span_(
             start,
             self.pos,
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index 0816bc8deb6..aa70912dcde 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -277,6 +277,7 @@ struct TokenStreamBuilder {
 }
 
 impl TokenStreamBuilder {
+    #[inline(always)]
     fn push(&mut self, tree: TokenTree) {
         if let Some(TokenTree::Token(prev_token, Spacing::Joint)) = self.buf.last()
             && let TokenTree::Token(token, joint) = &tree
@@ -284,9 +285,9 @@ impl TokenStreamBuilder {
         {
             self.buf.pop();
             self.buf.push(TokenTree::Token(glued, *joint));
-            return;
+        } else {
+            self.buf.push(tree)
         }
-        self.buf.push(tree);
     }
 
     fn into_token_stream(self) -> TokenStream {
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 09329f18c67..a2155ac1d1a 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -560,7 +560,8 @@ impl<'a> Parser<'a> {
                     || (sm.is_multiline(
                         self.prev_token.span.shrink_to_hi().until(self.token.span.shrink_to_lo())
                     ) && t == &token::Pound)
-            }) {
+            }) && !expected.contains(&TokenType::Token(token::Comma))
+            {
                 // Missing semicolon typo. This is triggered if the next token could either start a
                 // new statement or is a block close. For example:
                 //
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index c0f661f7dbb..e473f4d30cf 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1391,8 +1391,6 @@ impl<'a> Parser<'a> {
         } else if self.is_do_yeet() {
             self.parse_yeet_expr(attrs)
         } else if self.check_keyword(kw::Let) {
-            self.manage_let_chains_context();
-            self.bump();
             self.parse_let_expr(attrs)
         } else if self.eat_keyword(kw::Underscore) {
             Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore, attrs))
@@ -2342,32 +2340,24 @@ impl<'a> Parser<'a> {
 
     /// Parses the condition of a `if` or `while` expression.
     fn parse_cond_expr(&mut self) -> PResult<'a, P<Expr>> {
-        self.with_let_management(true, |local_self| {
-            local_self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)
-        })
+        self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, None)
     }
 
-    // Checks if `let` is in an invalid position like `let x = let y = 1;` or
-    // if the current `let` is in a let_chains context but nested in another
-    // expression like `if let Some(_) = _opt && [1, 2, 3][let _ = ()] = 1`.
-    //
-    // This method expects that the current token is `let`.
-    fn manage_let_chains_context(&mut self) {
-        debug_assert!(matches!(self.token.kind, TokenKind::Ident(kw::Let, _)));
-        let is_in_a_let_chains_context_but_nested_in_other_expr = self.let_expr_allowed
-            && !matches!(
-                self.prev_token.kind,
-                TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _)
-            );
-        if !self.let_expr_allowed || is_in_a_let_chains_context_but_nested_in_other_expr {
+    /// Parses a `let $pat = $expr` pseudo-expression.
+    fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+        // This is a *approximate* heuristic that detects if `let` chains are
+        // being parsed in the right position. It's approximate because it
+        // doesn't deny all invalid `let` expressions, just completely wrong usages.
+        let not_in_chain = !matches!(
+            self.prev_token.kind,
+            TokenKind::AndAnd | TokenKind::Ident(kw::If, _) | TokenKind::Ident(kw::While, _)
+        );
+        if !self.restrictions.contains(Restrictions::ALLOW_LET) || not_in_chain {
             self.struct_span_err(self.token.span, "expected expression, found `let` statement")
                 .emit();
         }
-    }
 
-    /// Parses a `let $pat = $expr` pseudo-expression.
-    /// The `let` token has already been eaten.
-    fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
+        self.bump(); // Eat `let` token
         let lo = self.prev_token.span;
         let pat = self.parse_pat_allow_top_alt(
             None,
@@ -2687,7 +2677,9 @@ impl<'a> Parser<'a> {
         // `&&` tokens.
         fn check_let_expr(expr: &Expr) -> bool {
             match expr.kind {
-                ExprKind::Binary(_, ref lhs, ref rhs) => check_let_expr(lhs) || check_let_expr(rhs),
+                ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, ref lhs, ref rhs) => {
+                    check_let_expr(lhs) || check_let_expr(rhs)
+                }
                 ExprKind::Let(..) => true,
                 _ => false,
             }
@@ -2703,9 +2695,8 @@ impl<'a> Parser<'a> {
             )?;
             let guard = if this.eat_keyword(kw::If) {
                 let if_span = this.prev_token.span;
-                let cond = this.with_let_management(true, |local_this| local_this.parse_expr())?;
-                let has_let_expr = check_let_expr(&cond);
-                if has_let_expr {
+                let cond = this.parse_expr_res(Restrictions::ALLOW_LET, None)?;
+                if check_let_expr(&cond) {
                     let span = if_span.to(cond.span);
                     this.sess.gated_spans.gate(sym::if_let_guard, span);
                 }
@@ -3279,17 +3270,4 @@ impl<'a> Parser<'a> {
             Ok((res, trailing))
         })
     }
-
-    // Calls `f` with the internal `let_expr_allowed` set to `let_expr_allowed` and then
-    // sets the internal `let_expr_allowed` back to its original value.
-    fn with_let_management<T>(
-        &mut self,
-        let_expr_allowed: bool,
-        f: impl FnOnce(&mut Self) -> T,
-    ) -> T {
-        let last_let_expr_allowed = mem::replace(&mut self.let_expr_allowed, let_expr_allowed);
-        let rslt = f(self);
-        self.let_expr_allowed = last_let_expr_allowed;
-        rslt
-    }
 }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 2c1e5807aa7..72c23776d33 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -271,7 +271,10 @@ impl<'a> Parser<'a> {
             // MACRO_RULES ITEM
             self.parse_item_macro_rules(vis, has_bang)?
         } else if self.isnt_macro_invocation()
-            && (self.token.is_ident_named(sym::import) || self.token.is_ident_named(sym::using))
+            && (self.token.is_ident_named(sym::import)
+                || self.token.is_ident_named(sym::using)
+                || self.token.is_ident_named(sym::include)
+                || self.token.is_ident_named(sym::require))
         {
             return self.recover_import_as_use();
         } else if self.isnt_macro_invocation() && vis.kind.is_pub() {
@@ -1179,10 +1182,11 @@ impl<'a> Parser<'a> {
 
         // Parse the type of a `const` or `static mut?` item.
         // That is, the `":" $ty` fragment.
-        let ty = if self.eat(&token::Colon) {
-            self.parse_ty()?
-        } else {
-            self.recover_missing_const_type(id, m)
+        let ty = match (self.eat(&token::Colon), self.check(&token::Eq) | self.check(&token::Semi))
+        {
+            // If there wasn't a `:` or the colon was followed by a `=` or `;` recover a missing type.
+            (true, false) => self.parse_ty()?,
+            (colon, _) => self.recover_missing_const_type(colon, m),
         };
 
         let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
@@ -1190,9 +1194,9 @@ impl<'a> Parser<'a> {
         Ok((id, ty, expr))
     }
 
-    /// We were supposed to parse `:` but the `:` was missing.
+    /// We were supposed to parse `":" $ty` but the `:` or the type was missing.
     /// This means that the type is missing.
-    fn recover_missing_const_type(&mut self, id: Ident, m: Option<Mutability>) -> P<Ty> {
+    fn recover_missing_const_type(&mut self, colon_present: bool, m: Option<Mutability>) -> P<Ty> {
         // Construct the error and stash it away with the hope
         // that typeck will later enrich the error with a type.
         let kind = match m {
@@ -1200,22 +1204,48 @@ impl<'a> Parser<'a> {
             Some(Mutability::Not) => "static",
             None => "const",
         };
-        let mut err = self.struct_span_err(id.span, &format!("missing type for `{kind}` item"));
+
+        let colon = match colon_present {
+            true => "",
+            false => ":",
+        };
+
+        let span = self.prev_token.span.shrink_to_hi();
+        let mut err = self.struct_span_err(span, &format!("missing type for `{kind}` item"));
         err.span_suggestion(
-            id.span,
+            span,
             "provide a type for the item",
-            format!("{id}: <type>"),
+            format!("{colon} <type>"),
             Applicability::HasPlaceholders,
         );
-        err.stash(id.span, StashKey::ItemNoType);
+        err.stash(span, StashKey::ItemNoType);
 
         // The user intended that the type be inferred,
         // so treat this as if the user wrote e.g. `const A: _ = expr;`.
-        P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID, tokens: None })
+        P(Ty { kind: TyKind::Infer, span, id: ast::DUMMY_NODE_ID, tokens: None })
     }
 
     /// Parses an enum declaration.
     fn parse_item_enum(&mut self) -> PResult<'a, ItemInfo> {
+        if self.token.is_keyword(kw::Struct) {
+            let mut err = self.struct_span_err(
+                self.prev_token.span.to(self.token.span),
+                "`enum` and `struct` are mutually exclusive",
+            );
+            err.span_suggestion(
+                self.prev_token.span.to(self.token.span),
+                "replace `enum struct` with",
+                "enum",
+                Applicability::MachineApplicable,
+            );
+            if self.look_ahead(1, |t| t.is_ident()) {
+                self.bump();
+                err.emit();
+            } else {
+                return Err(err);
+            }
+        }
+
         let id = self.parse_ident()?;
         let mut generics = self.parse_generics()?;
         generics.where_clause = self.parse_where_clause()?;
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 1ac8b224248..0c523ad22c2 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -47,6 +47,7 @@ bitflags::bitflags! {
         const STMT_EXPR         = 1 << 0;
         const NO_STRUCT_LITERAL = 1 << 1;
         const CONST_EXPR        = 1 << 2;
+        const ALLOW_LET         = 1 << 3;
     }
 }
 
@@ -147,15 +148,12 @@ pub struct Parser<'a> {
     /// This allows us to recover when the user forget to add braces around
     /// multiple statements in the closure body.
     pub current_closure: Option<ClosureSpans>,
-    /// Used to track where `let`s are allowed. For example, `if true && let 1 = 1` is valid
-    /// but `[1, 2, 3][let _ = ()]` is not.
-    let_expr_allowed: bool,
 }
 
 // This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure
 // it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Parser<'_>, 336);
+rustc_data_structures::static_assert_size!(Parser<'_>, 328);
 
 /// Stores span information about a closure.
 #[derive(Clone)]
@@ -462,7 +460,6 @@ impl<'a> Parser<'a> {
                 inner_attr_ranges: Default::default(),
             },
             current_closure: None,
-            let_expr_allowed: false,
         };
 
         // Make parser point to the first token.
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 5deb17b8651..4890fade50f 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -70,6 +70,9 @@ pub enum Piece<'a> {
 pub struct Argument<'a> {
     /// Where to find this argument
     pub position: Position<'a>,
+    /// The span of the position indicator. Includes any whitespace in implicit
+    /// positions (`{  }`).
+    pub position_span: InnerSpan,
     /// How to format the argument
     pub format: FormatSpec<'a>,
 }
@@ -105,9 +108,9 @@ pub enum Position<'a> {
     /// The argument is implied to be located at an index
     ArgumentImplicitlyIs(usize),
     /// The argument is located at a specific index given in the format,
-    ArgumentIs(usize, Option<InnerSpan>),
+    ArgumentIs(usize),
     /// The argument has a name.
-    ArgumentNamed(&'a str, InnerSpan),
+    ArgumentNamed(&'a str),
 }
 
 impl Position<'_> {
@@ -172,6 +175,7 @@ pub struct ParseError {
     pub label: string::String,
     pub span: InnerSpan,
     pub secondary_label: Option<(string::String, InnerSpan)>,
+    pub should_be_replaced_with_positional_argument: bool,
 }
 
 /// The parser structure for interpreting the input format string. This is
@@ -216,14 +220,15 @@ impl<'a> Iterator for Parser<'a> {
                 '{' => {
                     let curr_last_brace = self.last_opening_brace;
                     let byte_pos = self.to_span_index(pos);
-                    self.last_opening_brace = Some(byte_pos.to(InnerOffset(byte_pos.0 + 1)));
+                    let lbrace_end = InnerOffset(byte_pos.0 + 1);
+                    self.last_opening_brace = Some(byte_pos.to(lbrace_end));
                     self.cur.next();
                     if self.consume('{') {
                         self.last_opening_brace = curr_last_brace;
 
                         Some(String(self.string(pos + 1)))
                     } else {
-                        let arg = self.argument();
+                        let arg = self.argument(lbrace_end);
                         if let Some(rbrace_byte_idx) = self.must_consume('}') {
                             let lbrace_inner_offset = self.to_span_index(pos);
                             let rbrace_inner_offset = self.to_span_index(rbrace_byte_idx);
@@ -232,6 +237,8 @@ impl<'a> Iterator for Parser<'a> {
                                     lbrace_inner_offset.to(InnerOffset(rbrace_inner_offset.0 + 1)),
                                 );
                             }
+                        } else {
+                            self.suggest_positional_arg_instead_of_captured_arg(arg);
                         }
                         Some(NextArgument(arg))
                     }
@@ -309,6 +316,7 @@ impl<'a> Parser<'a> {
             label: label.into(),
             span,
             secondary_label: None,
+            should_be_replaced_with_positional_argument: false,
         });
     }
 
@@ -332,6 +340,7 @@ impl<'a> Parser<'a> {
             label: label.into(),
             span,
             secondary_label: None,
+            should_be_replaced_with_positional_argument: false,
         });
     }
 
@@ -403,6 +412,7 @@ impl<'a> Parser<'a> {
                     label,
                     span: pos.to(pos),
                     secondary_label,
+                    should_be_replaced_with_positional_argument: false,
                 });
                 None
             }
@@ -430,6 +440,7 @@ impl<'a> Parser<'a> {
                     label,
                     span: pos.to(pos),
                     secondary_label,
+                    should_be_replaced_with_positional_argument: false,
                 });
             } else {
                 self.err(description, format!("expected `{:?}`", c), pos.to(pos));
@@ -477,8 +488,16 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses an `Argument` structure, or what's contained within braces inside the format string.
-    fn argument(&mut self) -> Argument<'a> {
+    fn argument(&mut self, start: InnerOffset) -> Argument<'a> {
         let pos = self.position();
+
+        let end = self
+            .cur
+            .clone()
+            .find(|(_, ch)| !ch.is_whitespace())
+            .map_or(start, |(end, _)| self.to_span_index(end));
+        let position_span = start.to(end);
+
         let format = match self.mode {
             ParseMode::Format => self.format(),
             ParseMode::InlineAsm => self.inline_asm(),
@@ -494,7 +513,7 @@ impl<'a> Parser<'a> {
             }
         };
 
-        Argument { position: pos, format }
+        Argument { position: pos, position_span, format }
     }
 
     /// Parses a positional argument for a format. This could either be an
@@ -502,23 +521,11 @@ impl<'a> Parser<'a> {
     /// Returns `Some(parsed_position)` if the position is not implicitly
     /// consuming a macro argument, `None` if it's the case.
     fn position(&mut self) -> Option<Position<'a>> {
-        let start_position = self.cur.peek().map(|item| item.0);
         if let Some(i) = self.integer() {
-            let inner_span = start_position.and_then(|start| {
-                self.cur
-                    .peek()
-                    .cloned()
-                    .and_then(|item| Some(self.to_span_index(start).to(self.to_span_index(item.0))))
-            });
-            Some(ArgumentIs(i, inner_span))
+            Some(ArgumentIs(i))
         } else {
             match self.cur.peek() {
-                Some(&(start, c)) if rustc_lexer::is_id_start(c) => {
-                    let word = self.word();
-                    let end = start + word.len();
-                    let span = self.to_span_index(start).to(self.to_span_index(end));
-                    Some(ArgumentNamed(word, span))
-                }
+                Some(&(_, c)) if rustc_lexer::is_id_start(c) => Some(ArgumentNamed(self.word())),
 
                 // This is an `ArgumentNext`.
                 // Record the fact and do the resolution after parsing the
@@ -750,6 +757,34 @@ impl<'a> Parser<'a> {
         }
         if found { Some(cur) } else { None }
     }
+
+    fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) {
+        if let Some(end) = self.consume_pos('.') {
+            let byte_pos = self.to_span_index(end);
+            let start = InnerOffset(byte_pos.0 + 1);
+            let field = self.argument(start);
+            // We can only parse `foo.bar` field access, any deeper nesting,
+            // or another type of expression, like method calls, are not supported
+            if !self.consume('}') {
+                return;
+            }
+            if let ArgumentNamed(_) = arg.position {
+                if let ArgumentNamed(_) = field.position {
+                    self.errors.insert(
+                        0,
+                        ParseError {
+                            description: "field access isn't supported".to_string(),
+                            note: None,
+                            label: "not supported".to_string(),
+                            span: InnerSpan::new(arg.position_span.start, field.position_span.end),
+                            secondary_label: None,
+                            should_be_replaced_with_positional_argument: true,
+                        },
+                    );
+                }
+            }
+        }
+    }
 }
 
 /// Finds the indices of all characters that have been processed and differ between the actual
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index a98f816644b..57853069610 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -58,14 +58,22 @@ fn invalid06() {
 
 #[test]
 fn format_nothing() {
-    same("{}", &[NextArgument(Argument { position: ArgumentImplicitlyIs(0), format: fmtdflt() })]);
+    same(
+        "{}",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
+            format: fmtdflt(),
+        })],
+    );
 }
 #[test]
 fn format_position() {
     same(
         "{3}",
         &[NextArgument(Argument {
-            position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(3),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: fmtdflt(),
         })],
     );
@@ -75,17 +83,30 @@ fn format_position_nothing_else() {
     same(
         "{3:}",
         &[NextArgument(Argument {
-            position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(3),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: fmtdflt(),
         })],
     );
 }
 #[test]
+fn format_named() {
+    same(
+        "{name}",
+        &[NextArgument(Argument {
+            position: ArgumentNamed("name"),
+            position_span: InnerSpan { start: 2, end: 6 },
+            format: fmtdflt(),
+        })],
+    )
+}
+#[test]
 fn format_type() {
     same(
         "{3:x}",
         &[NextArgument(Argument {
-            position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(3),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -105,7 +126,8 @@ fn format_align_fill() {
     same(
         "{3:>}",
         &[NextArgument(Argument {
-            position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(3),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: None,
                 align: AlignRight,
@@ -122,7 +144,8 @@ fn format_align_fill() {
     same(
         "{3:0<}",
         &[NextArgument(Argument {
-            position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(3),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: Some('0'),
                 align: AlignLeft,
@@ -139,7 +162,8 @@ fn format_align_fill() {
     same(
         "{3:*<abcd}",
         &[NextArgument(Argument {
-            position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(3),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: Some('*'),
                 align: AlignLeft,
@@ -160,6 +184,7 @@ fn format_counts() {
         "{:10x}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -177,6 +202,7 @@ fn format_counts() {
         "{:10$.10x}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -193,7 +219,8 @@ fn format_counts() {
     same(
         "{1:0$.10x}",
         &[NextArgument(Argument {
-            position: ArgumentIs(1, Some(InnerSpan { start: 2, end: 3 })),
+            position: ArgumentIs(1),
+            position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -211,6 +238,7 @@ fn format_counts() {
         "{:.*x}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(1),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -228,6 +256,7 @@ fn format_counts() {
         "{:.10$x}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -245,6 +274,7 @@ fn format_counts() {
         "{:a$.b$?}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -265,6 +295,7 @@ fn format_flags() {
         "{:-}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -282,6 +313,7 @@ fn format_flags() {
         "{:+#}",
         &[NextArgument(Argument {
             position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
@@ -303,7 +335,8 @@ fn format_mixture() {
         &[
             String("abcd "),
             NextArgument(Argument {
-                position: ArgumentIs(3, Some(InnerSpan { start: 7, end: 8 })),
+                position: ArgumentIs(3),
+                position_span: InnerSpan { start: 7, end: 8 },
                 format: FormatSpec {
                     fill: None,
                     align: AlignUnknown,
@@ -320,3 +353,22 @@ fn format_mixture() {
         ],
     );
 }
+#[test]
+fn format_whitespace() {
+    same(
+        "{ }",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 3 },
+            format: fmtdflt(),
+        })],
+    );
+    same(
+        "{  }",
+        &[NextArgument(Argument {
+            position: ArgumentImplicitlyIs(0),
+            position_span: InnerSpan { start: 2, end: 4 },
+            format: fmtdflt(),
+        })],
+    );
+}
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index fde12b9eee6..6fea68ce8b3 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -53,7 +53,7 @@ pub(crate) fn target_from_impl_item<'tcx>(
 #[derive(Clone, Copy)]
 enum ItemLike<'tcx> {
     Item(&'tcx Item<'tcx>),
-    ForeignItem(&'tcx ForeignItem<'tcx>),
+    ForeignItem,
 }
 
 struct CheckAttrVisitor<'tcx> {
@@ -146,6 +146,7 @@ impl CheckAttrVisitor<'_> {
                 | sym::stable
                 | sym::rustc_allowed_through_unstable_modules
                 | sym::rustc_promotable => self.check_stability_promotable(&attr, span, target),
+                sym::link_ordinal => self.check_link_ordinal(&attr, span, target),
                 _ => true,
             };
             is_valid &= attr_is_valid;
@@ -209,7 +210,14 @@ impl CheckAttrVisitor<'_> {
         }
 
         // FIXME(@lcnr): this doesn't belong here.
-        if matches!(target, Target::Closure | Target::Fn | Target::Method(_) | Target::ForeignFn) {
+        if matches!(
+            target,
+            Target::Closure
+                | Target::Fn
+                | Target::Method(_)
+                | Target::ForeignFn
+                | Target::ForeignStatic
+        ) {
             self.tcx.ensure().codegen_fn_attrs(self.tcx.hir().local_def_id(hir_id));
         }
 
@@ -596,8 +604,6 @@ impl CheckAttrVisitor<'_> {
 
         let span = meta.span();
         if let Some(location) = match target {
-            Target::Impl => Some("implementation block"),
-            Target::ForeignMod => Some("extern block"),
             Target::AssocTy => {
                 let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
                 let containing_item = self.tcx.hir().expect_item(parent_hir_id);
@@ -619,7 +625,34 @@ impl CheckAttrVisitor<'_> {
             }
             // we check the validity of params elsewhere
             Target::Param => return false,
-            _ => None,
+            Target::Expression
+            | Target::Statement
+            | Target::Arm
+            | Target::ForeignMod
+            | Target::Closure
+            | Target::Impl => Some(target.name()),
+            Target::ExternCrate
+            | Target::Use
+            | Target::Static
+            | Target::Const
+            | Target::Fn
+            | Target::Mod
+            | Target::GlobalAsm
+            | Target::TyAlias
+            | Target::OpaqueTy
+            | Target::Enum
+            | Target::Variant
+            | Target::Struct
+            | Target::Field
+            | Target::Union
+            | Target::Trait
+            | Target::TraitAlias
+            | Target::Method(..)
+            | Target::ForeignFn
+            | Target::ForeignStatic
+            | Target::ForeignTy
+            | Target::GenericParam(..)
+            | Target::MacroDef => None,
         } {
             tcx.sess.emit_err(errors::DocAliasBadLocation { span, attr_str, location });
             return false;
@@ -1861,6 +1894,16 @@ impl CheckAttrVisitor<'_> {
         }
     }
 
+    fn check_link_ordinal(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
+        match target {
+            Target::ForeignFn | Target::ForeignStatic => true,
+            _ => {
+                self.tcx.sess.emit_err(errors::LinkOrdinal { attr_span: attr.span });
+                false
+            }
+        }
+    }
+
     fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) {
         match target {
             Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
@@ -1995,12 +2038,7 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
 
     fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
         let target = Target::from_foreign_item(f_item);
-        self.check_attributes(
-            f_item.hir_id(),
-            f_item.span,
-            target,
-            Some(ItemLike::ForeignItem(f_item)),
-        );
+        self.check_attributes(f_item.hir_id(), f_item.span, target, Some(ItemLike::ForeignItem));
         intravisit::walk_foreign_item(self, f_item)
     }
 
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index f1a81b65329..70518284cf9 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -97,7 +97,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
 
             // If the function belongs to a trait, then it must enable the const_trait_impl
             // feature to use that trait function (with a const default body).
-            if tcx.trait_of_item(def_id).is_some() {
+            if tcx.trait_of_item(def_id.to_def_id()).is_some() {
                 return true;
             }
 
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 58c5e5b4dfe..1e2fbeb384c 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -4,7 +4,7 @@
 
 use itertools::Itertools;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, MultiSpan};
+use rustc_errors::{pluralize, Applicability, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -42,6 +42,7 @@ struct MarkSymbolVisitor<'tcx> {
     maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
     live_symbols: FxHashSet<LocalDefId>,
     repr_has_repr_c: bool,
+    repr_has_repr_simd: bool,
     in_pat: bool,
     ignore_variant_stack: Vec<DefId>,
     // maps from tuple struct constructors to tuple struct items
@@ -220,6 +221,32 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         }
     }
 
+    fn handle_tuple_field_pattern_match(
+        &mut self,
+        lhs: &hir::Pat<'_>,
+        res: Res,
+        pats: &[hir::Pat<'_>],
+        dotdot: Option<usize>,
+    ) {
+        let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
+            ty::Adt(adt, _) => adt.variant_of_res(res),
+            _ => span_bug!(lhs.span, "non-ADT in tuple struct pattern"),
+        };
+        let first_n = pats.iter().enumerate().take(dotdot.unwrap_or(pats.len()));
+        let missing = variant.fields.len() - pats.len();
+        let last_n = pats
+            .iter()
+            .enumerate()
+            .skip(dotdot.unwrap_or(pats.len()))
+            .map(|(idx, pat)| (idx + missing, pat));
+        for (idx, pat) in first_n.chain(last_n) {
+            if let PatKind::Wild = pat.kind {
+                continue;
+            }
+            self.insert_def_id(variant.fields[idx].did);
+        }
+    }
+
     fn mark_live_symbols(&mut self) {
         let mut scanned = FxHashSet::default();
         while let Some(id) = self.worklist.pop() {
@@ -274,12 +301,15 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         }
 
         let had_repr_c = self.repr_has_repr_c;
+        let had_repr_simd = self.repr_has_repr_simd;
         self.repr_has_repr_c = false;
+        self.repr_has_repr_simd = false;
         match node {
             Node::Item(item) => match item.kind {
                 hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
                     let def = self.tcx.adt_def(item.def_id);
                     self.repr_has_repr_c = def.repr().c();
+                    self.repr_has_repr_simd = def.repr().simd();
 
                     intravisit::walk_item(self, &item)
                 }
@@ -315,6 +345,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
             }
             _ => {}
         }
+        self.repr_has_repr_simd = had_repr_simd;
         self.repr_has_repr_c = had_repr_c;
     }
 
@@ -347,9 +378,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
     ) {
         let tcx = self.tcx;
         let has_repr_c = self.repr_has_repr_c;
+        let has_repr_simd = self.repr_has_repr_simd;
         let live_fields = def.fields().iter().filter_map(|f| {
             let def_id = tcx.hir().local_def_id(f.hir_id);
-            if has_repr_c {
+            if has_repr_c || (f.is_positional() && has_repr_simd) {
                 return Some(def_id);
             }
             if !tcx.visibility(f.hir_id.owner).is_public() {
@@ -408,6 +440,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
                 let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
                 self.handle_res(res);
             }
+            PatKind::TupleStruct(ref qpath, ref fields, dotdot) => {
+                let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
+                self.handle_tuple_field_pattern_match(pat, res, fields, dotdot);
+            }
             _ => (),
         }
 
@@ -440,7 +476,11 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
     }
 }
 
-fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+fn has_allow_dead_code_or_lang_attr_helper(
+    tcx: TyCtxt<'_>,
+    id: hir::HirId,
+    lint: &'static lint::Lint,
+) -> bool {
     let attrs = tcx.hir().attrs(id);
     if tcx.sess.contains_name(attrs, sym::lang) {
         return true;
@@ -470,7 +510,11 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
         }
     }
 
-    tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow
+    tcx.lint_level_at_node(lint, id).0 == lint::Allow
+}
+
+fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+    has_allow_dead_code_or_lang_attr_helper(tcx, id, lint::builtin::DEAD_CODE)
 }
 
 // These check_* functions seeds items that
@@ -623,6 +667,7 @@ fn live_symbols_and_ignored_derived_traits<'tcx>(
         maybe_typeck_results: None,
         live_symbols: Default::default(),
         repr_has_repr_c: false,
+        repr_has_repr_simd: false,
         in_pat: false,
         ignore_variant_stack: vec![],
         struct_constructors,
@@ -644,17 +689,30 @@ struct DeadVisitor<'tcx> {
     ignored_derived_traits: &'tcx FxHashMap<LocalDefId, Vec<(DefId, DefId)>>,
 }
 
+enum ShouldWarnAboutField {
+    Yes(bool), // positional?
+    No,
+}
+
 impl<'tcx> DeadVisitor<'tcx> {
-    fn should_warn_about_field(&mut self, field: &ty::FieldDef) -> bool {
+    fn should_warn_about_field(&mut self, field: &ty::FieldDef) -> ShouldWarnAboutField {
         if self.live_symbols.contains(&field.did.expect_local()) {
-            return false;
+            return ShouldWarnAboutField::No;
+        }
+        let field_type = self.tcx.type_of(field.did);
+        if field_type.is_phantom_data() {
+            return ShouldWarnAboutField::No;
         }
         let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit());
-        if is_positional {
-            return false;
+        if is_positional
+            && self
+                .tcx
+                .layout_of(self.tcx.param_env(field.did).and(field_type))
+                .map_or(true, |layout| layout.is_zst())
+        {
+            return ShouldWarnAboutField::No;
         }
-        let field_type = self.tcx.type_of(field.did);
-        !field_type.is_phantom_data()
+        ShouldWarnAboutField::Yes(is_positional)
     }
 
     fn warn_multiple_dead_codes(
@@ -662,6 +720,7 @@ impl<'tcx> DeadVisitor<'tcx> {
         dead_codes: &[LocalDefId],
         participle: &str,
         parent_item: Option<LocalDefId>,
+        is_positional: bool,
     ) {
         if let Some(&first_id) = dead_codes.first() {
             let tcx = self.tcx;
@@ -669,7 +728,7 @@ impl<'tcx> DeadVisitor<'tcx> {
                 .iter()
                 .map(|&def_id| tcx.item_name(def_id.to_def_id()).to_string())
                 .collect();
-            let spans = dead_codes
+            let spans: Vec<_> = dead_codes
                 .iter()
                 .map(|&def_id| match tcx.def_ident_span(def_id) {
                     Some(s) => s.with_ctxt(tcx.def_span(def_id).ctxt()),
@@ -678,9 +737,13 @@ impl<'tcx> DeadVisitor<'tcx> {
                 .collect();
 
             tcx.struct_span_lint_hir(
-                lint::builtin::DEAD_CODE,
+                if is_positional {
+                    lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
+                } else {
+                    lint::builtin::DEAD_CODE
+                },
                 tcx.hir().local_def_id_to_hir_id(first_id),
-                MultiSpan::from_spans(spans),
+                MultiSpan::from_spans(spans.clone()),
                 |lint| {
                     let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
                     let span_len = dead_codes.len();
@@ -702,6 +765,21 @@ impl<'tcx> DeadVisitor<'tcx> {
                         are = pluralize!("is", span_len),
                     ));
 
+                    if is_positional {
+                        err.multipart_suggestion(
+                            &format!(
+                                "consider changing the field{s} to be of unit type to \
+                                      suppress this warning while preserving the field \
+                                      numbering, or remove the field{s}",
+                                s = pluralize!(span_len)
+                            ),
+                            spans.iter().map(|sp| (*sp, "()".to_string())).collect(),
+                            // "HasPlaceholders" because applying this fix by itself isn't
+                            // enough: All constructor calls have to be adjusted as well
+                            Applicability::HasPlaceholders,
+                        );
+                    }
+
                     if let Some(parent_item) = parent_item {
                         let parent_descr = tcx.def_kind(parent_item).descr(parent_item.to_def_id());
                         err.span_label(
@@ -743,6 +821,7 @@ impl<'tcx> DeadVisitor<'tcx> {
         def_id: LocalDefId,
         participle: &str,
         dead_codes: Vec<DeadVariant>,
+        is_positional: bool,
     ) {
         let mut dead_codes = dead_codes
             .iter()
@@ -758,12 +837,13 @@ impl<'tcx> DeadVisitor<'tcx> {
                 &group.map(|v| v.def_id).collect::<Vec<_>>(),
                 participle,
                 Some(def_id),
+                is_positional,
             );
         }
     }
 
     fn warn_dead_code(&mut self, id: LocalDefId, participle: &str) {
-        self.warn_multiple_dead_codes(&[id], participle, None);
+        self.warn_multiple_dead_codes(&[id], participle, None, false);
     }
 
     fn check_definition(&mut self, def_id: LocalDefId) {
@@ -829,24 +909,37 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
                     continue;
                 }
 
+                let mut is_positional = false;
                 let dead_fields = variant
                     .fields
                     .iter()
                     .filter_map(|field| {
                         let def_id = field.did.expect_local();
                         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-                        if visitor.should_warn_about_field(&field) {
-                            let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0;
+                        if let ShouldWarnAboutField::Yes(is_pos) =
+                            visitor.should_warn_about_field(&field)
+                        {
+                            let level = tcx
+                                .lint_level_at_node(
+                                    if is_pos {
+                                        is_positional = true;
+                                        lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
+                                    } else {
+                                        lint::builtin::DEAD_CODE
+                                    },
+                                    hir_id,
+                                )
+                                .0;
                             Some(DeadVariant { def_id, name: field.name, level })
                         } else {
                             None
                         }
                     })
                     .collect();
-                visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields)
+                visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields, is_positional)
             }
 
-            visitor.warn_dead_fields_and_variants(item.def_id, "constructed", dead_variants);
+            visitor.warn_dead_fields_and_variants(item.def_id, "constructed", dead_variants, false);
         }
     }
 
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 5feb0e2956b..cd465380867 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -552,6 +552,13 @@ pub struct ConstTrait {
 }
 
 #[derive(SessionDiagnostic)]
+#[error(passes::link_ordinal)]
+pub struct LinkOrdinal {
+    #[primary_span]
+    pub attr_span: Span,
+}
+
+#[derive(SessionDiagnostic)]
 #[error(passes::stability_promotable)]
 pub struct StabilityPromotable {
     #[primary_span]
diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs
index b0fac91f6eb..aca7d770f34 100644
--- a/compiler/rustc_privacy/src/errors.rs
+++ b/compiler/rustc_privacy/src/errors.rs
@@ -1,3 +1,4 @@
+use rustc_errors::DiagnosticArgFromDisplay;
 use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic};
 use rustc_span::{Span, Symbol};
 
@@ -35,7 +36,7 @@ pub struct ItemIsPrivate<'a> {
     #[label]
     pub span: Span,
     pub kind: &'a str,
-    pub descr: String,
+    pub descr: DiagnosticArgFromDisplay<'a>,
 }
 
 #[derive(SessionDiagnostic)]
@@ -55,7 +56,7 @@ pub struct InPublicInterfaceTraits<'a> {
     pub span: Span,
     pub vis_descr: &'static str,
     pub kind: &'a str,
-    pub descr: String,
+    pub descr: DiagnosticArgFromDisplay<'a>,
     #[label(privacy::visibility_label)]
     pub vis_span: Span,
 }
@@ -69,7 +70,7 @@ pub struct InPublicInterface<'a> {
     pub span: Span,
     pub vis_descr: &'static str,
     pub kind: &'a str,
-    pub descr: String,
+    pub descr: DiagnosticArgFromDisplay<'a>,
     #[label(privacy::visibility_label)]
     pub vis_span: Span,
 }
@@ -78,7 +79,7 @@ pub struct InPublicInterface<'a> {
 #[lint(privacy::from_private_dep_in_public_interface)]
 pub struct FromPrivateDependencyInPublicInterface<'a> {
     pub kind: &'a str,
-    pub descr: String,
+    pub descr: DiagnosticArgFromDisplay<'a>,
     pub krate: Symbol,
 }
 
@@ -87,5 +88,5 @@ pub struct FromPrivateDependencyInPublicInterface<'a> {
 pub struct PrivateInPublicLint<'a> {
     pub vis_descr: &'static str,
     pub kind: &'a str,
-    pub descr: String,
+    pub descr: DiagnosticArgFromDisplay<'a>,
 }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 390d6f5a856..c28d0569d4c 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -212,7 +212,7 @@ where
                 // `impl Pub<Priv> { pub fn my_method() {} }` is considered a private type,
                 // so we need to visit the self type additionally.
                 if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
-                    if let ty::ImplContainer(impl_def_id) = assoc_item.container {
+                    if let Some(impl_def_id) = assoc_item.impl_container(tcx) {
                         tcx.type_of(impl_def_id).visit_with(self)?;
                     }
                 }
@@ -734,11 +734,12 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     self.reach(item.def_id, item_level).generics().predicates();
 
                     for trait_item_ref in trait_item_refs {
+                        let tcx = self.tcx;
                         let mut reach = self.reach(trait_item_ref.id.def_id, item_level);
                         reach.generics().predicates();
 
                         if trait_item_ref.kind == AssocItemKind::Type
-                            && !trait_item_ref.defaultness.has_value()
+                            && !tcx.impl_defaultness(trait_item_ref.id.def_id).has_value()
                         {
                             // No type to visit.
                         } else {
@@ -1078,11 +1079,7 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
     fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
         let is_error = !self.item_is_accessible(def_id);
         if is_error {
-            self.tcx.sess.emit_err(ItemIsPrivate {
-                span: self.span,
-                kind,
-                descr: descr.to_string(),
-            });
+            self.tcx.sess.emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() });
         }
         is_error
     }
@@ -1254,7 +1251,9 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
                 };
                 let kind = kind.descr(def_id);
                 let _ = match name {
-                    Some(name) => sess.emit_err(ItemIsPrivate { span, kind, descr: name }),
+                    Some(name) => {
+                        sess.emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })
+                    }
                     None => sess.emit_err(UnnamedItemIsPrivate { span, kind }),
                 };
                 return;
@@ -1722,7 +1721,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
                 self.tcx.def_span(self.item_def_id.to_def_id()),
                 FromPrivateDependencyInPublicInterface {
                     kind,
-                    descr: descr.to_string(),
+                    descr: descr.into(),
                     krate: self.tcx.crate_name(def_id.krate),
                 },
             );
@@ -1749,19 +1748,17 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
                 }
             };
             let span = self.tcx.def_span(self.item_def_id.to_def_id());
-            let descr = descr.to_string();
             if self.has_old_errors
                 || self.in_assoc_ty
                 || self.tcx.resolutions(()).has_pub_restricted
             {
-                let vis_span =
-                    self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id));
+                let vis_span = self.tcx.def_span(def_id);
                 if kind == "trait" {
                     self.tcx.sess.emit_err(InPublicInterfaceTraits {
                         span,
                         vis_descr,
                         kind,
-                        descr,
+                        descr: descr.into(),
                         vis_span,
                     });
                 } else {
@@ -1769,7 +1766,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
                         span,
                         vis_descr,
                         kind,
-                        descr,
+                        descr: descr.into(),
                         vis_span,
                     });
                 }
@@ -1778,7 +1775,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
                     lint::builtin::PRIVATE_IN_PUBLIC,
                     hir_id,
                     span,
-                    PrivateInPublicLint { vis_descr, kind, descr },
+                    PrivateInPublicLint { vis_descr, kind, descr: descr.into() },
                 );
             }
         }
@@ -1840,14 +1837,13 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
         &self,
         def_id: LocalDefId,
         assoc_item_kind: AssocItemKind,
-        defaultness: hir::Defaultness,
         vis: ty::Visibility,
     ) {
         let mut check = self.check(def_id, vis);
 
         let (check_ty, is_assoc_ty) = match assoc_item_kind {
             AssocItemKind::Const | AssocItemKind::Fn { .. } => (true, false),
-            AssocItemKind::Type => (defaultness.has_value(), true),
+            AssocItemKind::Type => (self.tcx.impl_defaultness(def_id).has_value(), true),
         };
         check.in_assoc_ty = is_assoc_ty;
         check.generics().predicates();
@@ -1879,7 +1875,6 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                         self.check_assoc_item(
                             trait_item_ref.id.def_id,
                             trait_item_ref.kind,
-                            trait_item_ref.defaultness,
                             item_visibility,
                         );
 
@@ -1952,7 +1947,6 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> {
                         self.check_assoc_item(
                             impl_item_ref.id.def_id,
                             impl_item_ref.kind,
-                            impl_item_ref.defaultness,
                             impl_item_vis,
                         );
                     }
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 9f5779194af..6d2aff38172 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -1,4 +1,3 @@
-use crate::dep_graph::DepContext;
 use crate::query::plumbing::CycleError;
 use crate::query::{QueryContext, QueryStackFrame};
 use rustc_hir::def::DefKind;
@@ -536,17 +535,13 @@ pub(crate) fn report_cycle<'a>(
 ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
     assert!(!stack.is_empty());
 
-    let fix_span = |span: Span, query: &QueryStackFrame| {
-        sess.source_map().guess_head_span(query.default_span(span))
-    };
-
-    let span = fix_span(stack[1 % stack.len()].span, &stack[0].query);
+    let span = stack[0].query.default_span(stack[1 % stack.len()].span);
     let mut err =
         struct_span_err!(sess, span, E0391, "cycle detected when {}", stack[0].query.description);
 
     for i in 1..stack.len() {
         let query = &stack[i].query;
-        let span = fix_span(stack[(i + 1) % stack.len()].span, query);
+        let span = query.default_span(stack[(i + 1) % stack.len()].span);
         err.span_note(span, &format!("...which requires {}...", query.description));
     }
 
@@ -577,7 +572,7 @@ pub(crate) fn report_cycle<'a>(
     }
 
     if let Some((span, query)) = usage {
-        err.span_note(fix_span(span, &query), &format!("cycle used when {}", query.description));
+        err.span_note(query.default_span(span), &format!("cycle used when {}", query.description));
     }
 
     err
@@ -606,8 +601,7 @@ pub fn print_query_stack<CTX: QueryContext>(
             Level::FailureNote,
             &format!("#{} [{}] {}", i, query_info.query.name, query_info.query.description),
         );
-        diag.span =
-            tcx.dep_context().sess().source_map().guess_head_span(query_info.job.span).into();
+        diag.span = query_info.job.span.into();
         handler.force_print_diagnostic(diag);
 
         current_query = query_info.job.parent;
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 22a307a15ed..8839fb1a151 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1587,11 +1587,7 @@ impl<'a> Resolver<'a> {
         };
         let def_span = suggestion.res.opt_def_id().and_then(|def_id| match def_id.krate {
             LOCAL_CRATE => self.opt_span(def_id),
-            _ => Some(
-                self.session
-                    .source_map()
-                    .guess_head_span(self.cstore().get_span_untracked(def_id, self.session)),
-            ),
+            _ => Some(self.cstore().get_span_untracked(def_id, self.session)),
         });
         if let Some(def_span) = def_span {
             if span.overlaps(def_span) {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index ed65100ae77..dea3eaecda6 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1644,14 +1644,30 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 continue;
             }
 
-            let missing = match source {
-                PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => true,
+            let node_ids = self.r.next_node_ids(expected_lifetimes);
+            self.record_lifetime_res(
+                segment_id,
+                LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
+                LifetimeElisionCandidate::Ignore,
+            );
+
+            let inferred = match source {
+                PathSource::Trait(..) | PathSource::TraitItem(..) | PathSource::Type => false,
                 PathSource::Expr(..)
                 | PathSource::Pat
                 | PathSource::Struct
-                | PathSource::TupleStruct(..) => false,
+                | PathSource::TupleStruct(..) => true,
             };
-            if !missing && !segment.has_generic_args {
+            if inferred {
+                // Do not create a parameter for patterns and expressions: type checking can infer
+                // the appropriate lifetime for us.
+                for id in node_ids {
+                    self.record_lifetime_res(
+                        id,
+                        LifetimeRes::Infer,
+                        LifetimeElisionCandidate::Named,
+                    );
+                }
                 continue;
             }
 
@@ -1666,25 +1682,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             };
             let ident = Ident::new(kw::UnderscoreLifetime, elided_lifetime_span);
 
-            let node_ids = self.r.next_node_ids(expected_lifetimes);
-            self.record_lifetime_res(
-                segment_id,
-                LifetimeRes::ElidedAnchor { start: node_ids.start, end: node_ids.end },
-                LifetimeElisionCandidate::Ignore,
-            );
-
-            if !missing {
-                // Do not create a parameter for patterns and expressions.
-                for id in node_ids {
-                    self.record_lifetime_res(
-                        id,
-                        LifetimeRes::Infer,
-                        LifetimeElisionCandidate::Named,
-                    );
-                }
-                continue;
-            }
-
             let missing_lifetime = MissingLifetime {
                 id: node_ids.start,
                 span: elided_lifetime_span,
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 6b49c6b1ac6..2b1f2b88ec4 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -136,12 +136,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
     fn def_span(&self, def_id: DefId) -> Option<Span> {
         match def_id.krate {
             LOCAL_CRATE => self.r.opt_span(def_id),
-            _ => Some(
-                self.r
-                    .session
-                    .source_map()
-                    .guess_head_span(self.r.cstore().get_span_untracked(def_id, self.r.session)),
-            ),
+            _ => Some(self.r.cstore().get_span_untracked(def_id, self.r.session)),
         }
     }
 
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 31d10008efb..ef3c3da89c5 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -913,6 +913,11 @@ pub struct Resolver<'a> {
     label_res_map: NodeMap<NodeId>,
     /// Resolutions for lifetimes.
     lifetimes_res_map: NodeMap<LifetimeRes>,
+    /// Mapping from generics `def_id`s to TAIT generics `def_id`s.
+    /// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
+    /// defined on the TAIT, so we have type Foo<'a1> = ... and we establish a mapping in this
+    /// field from the original parameter 'a to the new parameter 'a1.
+    generics_def_id_map: Vec<FxHashMap<LocalDefId, LocalDefId>>,
     /// Lifetime parameters that lowering will have to introduce.
     extra_lifetime_params_map: NodeMap<Vec<(Ident, NodeId, LifetimeRes)>>,
 
@@ -1277,6 +1282,7 @@ impl<'a> Resolver<'a> {
             import_res_map: Default::default(),
             label_res_map: Default::default(),
             lifetimes_res_map: Default::default(),
+            generics_def_id_map: Vec::new(),
             extra_lifetime_params_map: Default::default(),
             extern_crate_map: Default::default(),
             reexport_map: FxHashMap::default(),
@@ -1444,6 +1450,7 @@ impl<'a> Resolver<'a> {
             import_res_map: self.import_res_map,
             label_res_map: self.label_res_map,
             lifetimes_res_map: self.lifetimes_res_map,
+            generics_def_id_map: self.generics_def_id_map,
             extra_lifetime_params_map: self.extra_lifetime_params_map,
             next_node_id: self.next_node_id,
             node_id_to_def_id: self.node_id_to_def_id,
@@ -1488,6 +1495,7 @@ impl<'a> Resolver<'a> {
             import_res_map: self.import_res_map.clone(),
             label_res_map: self.label_res_map.clone(),
             lifetimes_res_map: self.lifetimes_res_map.clone(),
+            generics_def_id_map: self.generics_def_id_map.clone(),
             extra_lifetime_params_map: self.extra_lifetime_params_map.clone(),
             next_node_id: self.next_node_id.clone(),
             node_id_to_def_id: self.node_id_to_def_id.clone(),
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 0a0c674d179..a1a2040bbca 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -564,8 +564,8 @@ impl<'tcx> SaveContext<'tcx> {
                     return None;
                 };
                 let (def_id, decl_id) = match self.tcx.associated_item(method_id).container {
-                    ty::ImplContainer(_) => (Some(method_id), None),
-                    ty::TraitContainer(_) => (None, Some(method_id)),
+                    ty::ImplContainer => (Some(method_id), None),
+                    ty::TraitContainer => (None, Some(method_id)),
                 };
                 let sub_span = seg.ident.span;
                 filter!(self.span_utils, sub_span);
@@ -697,7 +697,7 @@ impl<'tcx> SaveContext<'tcx> {
             }
             Res::Def(HirDefKind::AssocFn, decl_id) => {
                 let def_id = if decl_id.is_local() {
-                    if self.tcx.associated_item(decl_id).defaultness.has_value() {
+                    if self.tcx.impl_defaultness(decl_id).has_value() {
                         Some(decl_id)
                     } else {
                         None
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 060e7a7b90a..f81a69c1cce 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1170,6 +1170,7 @@ symbols! {
         repr_packed,
         repr_simd,
         repr_transparent,
+        require,
         residual,
         result,
         rhs,
@@ -1464,6 +1465,7 @@ symbols! {
         trait_alias,
         trait_upcasting,
         transmute,
+        transmute_trait,
         transparent,
         transparent_enums,
         transparent_unions,
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index ca1d1302ec6..577126a95cc 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -669,8 +669,10 @@ impl<'a, Ty> FnAbi<'a, Ty> {
 
         match &cx.target_spec().arch[..] {
             "x86" => {
-                let flavor = if let spec::abi::Abi::Fastcall { .. } = abi {
-                    x86::Flavor::Fastcall
+                let flavor = if let spec::abi::Abi::Fastcall { .. }
+                | spec::abi::Abi::Vectorcall { .. } = abi
+                {
+                    x86::Flavor::FastcallOrVectorcall
                 } else {
                     x86::Flavor::General
                 };
diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs
index d169087dfbd..c7d59baf919 100644
--- a/compiler/rustc_target/src/abi/call/x86.rs
+++ b/compiler/rustc_target/src/abi/call/x86.rs
@@ -5,7 +5,7 @@ use crate::spec::HasTargetSpec;
 #[derive(PartialEq)]
 pub enum Flavor {
     General,
-    Fastcall,
+    FastcallOrVectorcall,
 }
 
 pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor)
@@ -60,9 +60,9 @@ where
         }
     }
 
-    if flavor == Flavor::Fastcall {
+    if flavor == Flavor::FastcallOrVectorcall {
         // Mark arguments as InReg like clang does it,
-        // so our fastcall is compatible with C/C++ fastcall.
+        // so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall.
 
         // Clang reference: lib/CodeGen/TargetInfo.cpp
         // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index d4d5674e246..92ce4d91d84 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -508,6 +508,7 @@ impl fmt::Debug for Align {
 
 impl Align {
     pub const ONE: Align = Align { pow2: 0 };
+    pub const MAX: Align = Align { pow2: 29 };
 
     #[inline]
     pub fn from_bits(bits: u64) -> Result<Align, String> {
@@ -540,7 +541,7 @@ impl Align {
         if bytes != 1 {
             return Err(not_power_of_2(align));
         }
-        if pow2 > 29 {
+        if pow2 > Self::MAX.pow2 {
             return Err(too_large(align));
         }
 
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
index 57634cbbfb1..1dad07a9a42 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
@@ -1,9 +1,14 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{FramePointer, Target, TargetOptions};
+use crate::spec::{FramePointer, LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
+    let llvm_target = "arm64-apple-ios14.0-macabi";
+
+    let mut base = opts("ios", Arch::Arm64_macabi);
+    base.add_pre_link_args(LinkerFlavor::Gcc, &["-target", llvm_target]);
+
     Target {
-        llvm_target: "arm64-apple-ios14.0-macabi".into(),
+        llvm_target: llvm_target.into(),
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(),
         arch: "aarch64".into(),
@@ -21,7 +26,7 @@ pub fn target() -> Target {
                 -disable-llvm-passes\0\
                 -Os\0"
                 .into(),
-            ..opts("ios", Arch::Arm64_macabi)
+            ..base
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 9bfae46ef32..15e4fb9be63 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -109,15 +109,34 @@ pub fn ios_llvm_target(arch: &str) -> String {
     format!("{}-apple-ios{}.{}.0", arch, major, minor)
 }
 
+pub fn ios_lld_platform_version() -> String {
+    let (major, minor) = ios_deployment_target();
+    format!("{}.{}", major, minor)
+}
+
 pub fn ios_sim_llvm_target(arch: &str) -> String {
     let (major, minor) = ios_deployment_target();
     format!("{}-apple-ios{}.{}.0-simulator", arch, major, minor)
 }
 
+fn tvos_deployment_target() -> (u32, u32) {
+    deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
+}
+
+pub fn tvos_lld_platform_version() -> String {
+    let (major, minor) = tvos_deployment_target();
+    format!("{}.{}", major, minor)
+}
+
 fn watchos_deployment_target() -> (u32, u32) {
     deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
 }
 
+pub fn watchos_lld_platform_version() -> String {
+    let (major, minor) = watchos_deployment_target();
+    format!("{}.{}", major, minor)
+}
+
 pub fn watchos_sim_llvm_target(arch: &str) -> String {
     let (major, minor) = watchos_deployment_target();
     format!("{}-apple-watchos{}.{}.0-simulator", arch, major, minor)
diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs
index 0328ea98c48..d77558f0f84 100644
--- a/compiler/rustc_target/src/spec/apple_sdk_base.rs
+++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs
@@ -1,4 +1,4 @@
-use crate::{spec::cvs, spec::TargetOptions};
+use crate::spec::{cvs, LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
 use std::borrow::Cow;
 
 use Arch::*;
@@ -17,6 +17,18 @@ pub enum Arch {
     Arm64_sim,
 }
 
+fn target_arch_name(arch: Arch) -> &'static str {
+    match arch {
+        Armv7 => "armv7",
+        Armv7k => "armv7k",
+        Armv7s => "armv7s",
+        Arm64 | Arm64_macabi | Arm64_sim => "arm64",
+        Arm64_32 => "arm64_32",
+        I386 => "i386",
+        X86_64 | X86_64_macabi => "x86_64",
+    }
+}
+
 fn target_abi(arch: Arch) -> &'static str {
     match arch {
         Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 => "",
@@ -49,11 +61,51 @@ fn link_env_remove(arch: Arch) -> Cow<'static, [Cow<'static, str>]> {
     }
 }
 
+fn pre_link_args(os: &'static str, arch: Arch) -> LinkArgs {
+    let mut args = LinkArgs::new();
+
+    let target_abi = target_abi(arch);
+
+    let platform_name = match target_abi {
+        "sim" => format!("{}-simulator", os),
+        "macabi" => "mac-catalyst".to_string(),
+        _ => os.to_string(),
+    };
+
+    let platform_version = match os.as_ref() {
+        "ios" => super::apple_base::ios_lld_platform_version(),
+        "tvos" => super::apple_base::tvos_lld_platform_version(),
+        "watchos" => super::apple_base::watchos_lld_platform_version(),
+        _ => unreachable!(),
+    };
+
+    let arch_str = target_arch_name(arch);
+
+    if target_abi != "macabi" {
+        args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), arch_str.into()]);
+    }
+
+    args.insert(
+        LinkerFlavor::Lld(LldFlavor::Ld64),
+        vec![
+            "-arch".into(),
+            arch_str.into(),
+            "-platform_version".into(),
+            platform_name.into(),
+            platform_version.clone().into(),
+            platform_version.into(),
+        ],
+    );
+
+    args
+}
+
 pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
     TargetOptions {
         abi: target_abi(arch).into(),
         cpu: target_cpu(arch).into(),
         dynamic_linking: false,
+        pre_link_args: pre_link_args(os, arch),
         link_env_remove: link_env_remove(arch),
         has_thread_local: false,
         ..super::apple_base::opts(os)
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index c7c5a231901..1db6db78b17 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -46,7 +46,10 @@ impl Target {
                         )
                     }
                     (LinkerFlavor::Gcc, LldFlavor::Ld64) => {
-                        assert_matches!(flavor, LinkerFlavor::Gcc)
+                        assert_matches!(
+                            flavor,
+                            LinkerFlavor::Lld(LldFlavor::Ld64) | LinkerFlavor::Gcc
+                        )
                     }
                     (LinkerFlavor::Msvc | LinkerFlavor::Lld(LldFlavor::Link), LldFlavor::Link) => {
                         assert_matches!(
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
index c75632571ad..2122bcd37fc 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
@@ -1,10 +1,14 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{StackProbeType, Target, TargetOptions};
+use crate::spec::{LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("ios", Arch::X86_64_macabi);
+    let llvm_target = "x86_64-apple-ios13.0-macabi";
+
+    let mut base = opts("ios", Arch::X86_64_macabi);
+    base.add_pre_link_args(LinkerFlavor::Gcc, &["-target", llvm_target]);
+
     Target {
-        llvm_target: "x86_64-apple-ios13.0-macabi".into(),
+        llvm_target: llvm_target.into(),
         pointer_width: 64,
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .into(),
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
index aebeb49e623..566f236f26a 100644
--- a/compiler/rustc_trait_selection/Cargo.toml
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -23,4 +23,5 @@ rustc_query_system = { path = "../rustc_query_system" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
+rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 5763e6d1b55..6b230210888 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -205,10 +205,8 @@ impl<'tcx> AutoTraitFinder<'tcx> {
             // At this point, we already have all of the bounds we need. FulfillmentContext is used
             // to store all of the necessary region/lifetime bounds in the InferContext, as well as
             // an additional sanity check.
-            let mut fulfill = FulfillmentContext::new();
-            fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy());
-            let errors = fulfill.select_all_or_error(&infcx);
-
+            let errors =
+                super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
             if !errors.is_empty() {
                 panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
             }
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 5fcaa52d417..c0700748c79 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -5,7 +5,7 @@
 
 use crate::infer::{DefiningAnchor, TyCtxtInferExt};
 use crate::traits::{
-    FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
+    ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, TraitEngineExt,
     Unimplemented,
 };
 use rustc_middle::traits::CodegenObligationError;
@@ -23,8 +23,6 @@ pub fn codegen_fulfill_obligation<'tcx>(
     tcx: TyCtxt<'tcx>,
     (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
 ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
-    // Remove any references to regions; this helps improve caching.
-    let trait_ref = tcx.erase_regions(trait_ref);
     // We expect the input to be fully normalized.
     debug_assert_eq!(trait_ref, tcx.normalize_erasing_regions(param_env, trait_ref));
 
@@ -55,7 +53,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
         // Currently, we use a fulfillment context to completely resolve
         // all nested obligations. This is because they can inform the
         // inference of the impl's type parameters.
-        let mut fulfill_cx = FulfillmentContext::new();
+        let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
         let impl_source = selection.map(|predicate| {
             fulfill_cx.register_predicate_obligation(&infcx, predicate);
         });
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index f62ccb99df5..8ab1aa65d3a 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -10,14 +10,14 @@ use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::util::impl_subject_and_oblig;
 use crate::traits::SkipLeakCheck;
 use crate::traits::{
-    self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
-    PredicateObligations, SelectionContext,
+    self, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations,
+    SelectionContext,
 };
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::Diagnostic;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
-use rustc_infer::traits::{util, TraitEngine};
+use rustc_infer::traits::util;
 use rustc_middle::traits::specialization_graph::OverlapMode;
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::subst::Subst;
@@ -302,7 +302,6 @@ fn negative_impl<'cx, 'tcx>(
         let impl_env = tcx.param_env(impl1_def_id);
         let subject1 = match traits::fully_normalize(
             &infcx,
-            FulfillmentContext::new(),
             ObligationCause::dummy(),
             impl_env,
             tcx.impl_subject(impl1_def_id),
@@ -385,16 +384,11 @@ fn resolve_negative_obligation<'cx, 'tcx>(
         return false;
     };
 
-    let mut fulfillment_cx = FulfillmentContext::new();
-    fulfillment_cx.register_predicate_obligation(infcx, o);
-
-    let errors = fulfillment_cx.select_all_or_error(infcx);
-
+    let errors = super::fully_solve_obligation(infcx, o);
     if !errors.is_empty() {
         return false;
     }
 
-    // FIXME -- also add "assumed to be well formed" types into the `outlives_env`
     let outlives_env = OutlivesEnvironment::new(param_env);
     infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
 
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 7ee3fe844b5..e442c5c9189 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2129,7 +2129,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                             }
                         ] = path.segments
                         && data.trait_ref.def_id == *trait_id
-                        && self.tcx.trait_of_item(item_id) == Some(*trait_id)
+                        && self.tcx.trait_of_item(*item_id) == Some(*trait_id)
                         && !self.is_tainted_by_errors()
                     {
                         let (verb, noun) = match self.tcx.associated_item(item_id).kind {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 7e8872d9018..e6907637c57 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -223,8 +223,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 if let Some(def) = aty.ty_adt_def() {
                     // We also want to be able to select the slice's type's original
                     // signature with no type arguments resolved
-                    let type_string = self.tcx.type_of(def.did()).to_string();
-                    flags.push((sym::_Self, Some(format!("[{type_string}]"))));
+                    flags.push((sym::_Self, Some(format!("[{}]", self.tcx.type_of(def.did())))));
                 }
                 if aty.is_integral() {
                     flags.push((sym::_Self, Some("[{integral}]".to_string())));
@@ -242,10 +241,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 if let Some(def) = aty.ty_adt_def() {
                     // We also want to be able to select the array's type's original
                     // signature with no type arguments resolved
-                    let type_string = self.tcx.type_of(def.did()).to_string();
-                    flags.push((sym::_Self, Some(format!("[{type_string}; _]"))));
+                    let def_ty = self.tcx.type_of(def.did());
+                    flags.push((sym::_Self, Some(format!("[{def_ty}; _]"))));
                     if let Some(n) = len {
-                        flags.push((sym::_Self, Some(format!("[{type_string}; {n}]"))));
+                        flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]"))));
                     }
                 }
                 if aty.is_integral() {
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 b2eb8fdf8a5..219413121d8 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1946,7 +1946,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             ));
 
             let original_span = err.span.primary_span().unwrap();
-            let original_span = self.tcx.sess.source_map().guess_head_span(original_span);
             let mut span = MultiSpan::from_span(original_span);
 
             let message = outer_generator
@@ -2715,7 +2714,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 if let Some(ident) = self
                     .tcx
                     .opt_associated_item(trait_item_def_id)
-                    .and_then(|i| self.tcx.opt_item_ident(i.container.id()))
+                    .and_then(|i| self.tcx.opt_item_ident(i.container_id(self.tcx)))
                 {
                     assoc_span.push_span_label(ident.span, "in this trait");
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index dd2769c7186..e1bd48ba8ac 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -63,8 +63,7 @@ pub fn can_type_implement_copy<'tcx>(
                 } else {
                     ObligationCause::dummy_with_span(span)
                 };
-                let ctx = traits::FulfillmentContext::new();
-                match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) {
+                match traits::fully_normalize(&infcx, cause, param_env, ty) {
                     Ok(ty) => {
                         if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
                             infringing.push((field, ty));
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index d0a17f712d3..2e5400c42d0 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -30,6 +30,7 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
+use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::visit::TypeVisitable;
@@ -161,22 +162,20 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
         // this function's result remains infallible, we must confirm
         // that guess. While imperfect, I believe this is sound.
 
-        // The handling of regions in this area of the code is terrible,
-        // see issue #29149. We should be able to improve on this with
-        // NLL.
-        let mut fulfill_cx = FulfillmentContext::new();
-
         // We can use a dummy node-id here because we won't pay any mind
         // to region obligations that arise (there shouldn't really be any
         // anyhow).
         let cause = ObligationCause::misc(span, hir::CRATE_HIR_ID);
 
-        fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause);
+        // The handling of regions in this area of the code is terrible,
+        // see issue #29149. We should be able to improve on this with
+        // NLL.
+        let errors = fully_solve_bound(infcx, cause, param_env, ty, def_id);
 
         // Note: we only assume something is `Copy` if we can
         // *definitively* show that it implements `Copy`. Otherwise,
         // assume it is move; linear is always ok.
-        match fulfill_cx.select_all_or_error(infcx).as_slice() {
+        match &errors[..] {
             [] => {
                 debug!(
                     "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
@@ -222,15 +221,13 @@ fn do_normalize_predicates<'tcx>(
     // them here too, and we will remove this function when
     // we move over to lazy normalization *anyway*.
     tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
-        let fulfill_cx = FulfillmentContext::new();
-        let predicates =
-            match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) {
-                Ok(predicates) => predicates,
-                Err(errors) => {
-                    let reported = infcx.report_fulfillment_errors(&errors, None, false);
-                    return Err(reported);
-                }
-            };
+        let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
+            Ok(predicates) => predicates,
+            Err(errors) => {
+                let reported = infcx.report_fulfillment_errors(&errors, None, false);
+                return Err(reported);
+            }
+        };
 
         debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
 
@@ -381,9 +378,9 @@ pub fn normalize_param_env_or_error<'tcx>(
     )
 }
 
+/// Normalize a type and process all resulting obligations, returning any errors
 pub fn fully_normalize<'a, 'tcx, T>(
     infcx: &InferCtxt<'a, 'tcx>,
-    mut fulfill_cx: FulfillmentContext<'tcx>,
     cause: ObligationCause<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     value: T,
@@ -399,8 +396,10 @@ where
         "fully_normalize: normalized_value={:?} obligations={:?}",
         normalized_value, obligations
     );
+
+    let mut fulfill_cx = FulfillmentContext::new();
     for obligation in obligations {
-        fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
+        fulfill_cx.register_predicate_obligation(infcx, obligation);
     }
 
     debug!("fully_normalize: select_all_or_error start");
@@ -414,6 +413,43 @@ where
     Ok(resolved_value)
 }
 
+/// Process an obligation (and any nested obligations that come from it) to
+/// completion, returning any errors
+pub fn fully_solve_obligation<'a, 'tcx>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    obligation: PredicateObligation<'tcx>,
+) -> Vec<FulfillmentError<'tcx>> {
+    let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+    engine.register_predicate_obligation(infcx, obligation);
+    engine.select_all_or_error(infcx)
+}
+
+/// Process a set of obligations (and any nested obligations that come from them)
+/// to completion
+pub fn fully_solve_obligations<'a, 'tcx>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
+) -> Vec<FulfillmentError<'tcx>> {
+    let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+    engine.register_predicate_obligations(infcx, obligations);
+    engine.select_all_or_error(infcx)
+}
+
+/// Process a bound (and any nested obligations that come from it) to completion.
+/// This is a convenience function for traits that have no generic arguments, such
+/// as auto traits, and builtin traits like Copy or Sized.
+pub fn fully_solve_bound<'a, 'tcx>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    cause: ObligationCause<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    ty: Ty<'tcx>,
+    bound: DefId,
+) -> Vec<FulfillmentError<'tcx>> {
+    let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
+    engine.register_bound(infcx, param_env, ty, bound, cause);
+    engine.select_all_or_error(infcx)
+}
+
 /// Normalizes the predicates and checks whether they hold in an empty environment. If this
 /// returns true, then either normalize encountered an error or one of the predicates did not
 /// hold. Used when creating vtables to check for unsatisfiable methods.
@@ -428,20 +464,13 @@ pub fn impossible_predicates<'tcx>(
         infcx.set_tainted_by_errors();
 
         let param_env = ty::ParamEnv::reveal_all();
-        let mut selcx = SelectionContext::new(&infcx);
-        let mut fulfill_cx = FulfillmentContext::new();
-        let cause = ObligationCause::dummy();
-        let Normalized { value: predicates, obligations } =
-            normalize(&mut selcx, param_env, cause.clone(), predicates);
-        for obligation in obligations {
-            fulfill_cx.register_predicate_obligation(&infcx, obligation);
-        }
+        let ocx = ObligationCtxt::new(&infcx);
+        let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
         for predicate in predicates {
-            let obligation = Obligation::new(cause.clone(), param_env, predicate);
-            fulfill_cx.register_predicate_obligation(&infcx, obligation);
+            let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
+            ocx.register_obligation(obligation);
         }
-
-        let errors = fulfill_cx.select_all_or_error(&infcx);
+        let errors = ocx.select_all_or_error();
 
         // Clean up after ourselves
         let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 2921ce0ffef..612f5130908 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -690,7 +690,7 @@ fn receiver_is_dispatchable<'tcx>(
         // U: Trait<Arg1, ..., ArgN>
         let trait_predicate = {
             let substs =
-                InternalSubsts::for_item(tcx, method.container.assert_trait(), |param, _| {
+                InternalSubsts::for_item(tcx, method.trait_container(tcx).unwrap(), |param, _| {
                     if param.index == 0 {
                         unsized_self_ty.into()
                     } else {
diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
index 4d3b0b4cf07..9227bbf011d 100644
--- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
@@ -300,7 +300,7 @@ impl<'tcx> OnUnimplementedFormatString {
             match token {
                 Piece::String(_) => (), // Normal string, no need to check it
                 Piece::NextArgument(a) => match a.position {
-                    Position::ArgumentNamed(s, _) => {
+                    Position::ArgumentNamed(s) => {
                         match Symbol::intern(s) {
                             // `{Self}` is allowed
                             kw::SelfUpper => (),
@@ -386,7 +386,7 @@ impl<'tcx> OnUnimplementedFormatString {
             .map(|p| match p {
                 Piece::String(s) => s,
                 Piece::NextArgument(a) => match a.position {
-                    Position::ArgumentNamed(s, _) => {
+                    Position::ArgumentNamed(s) => {
                         let s = Symbol::intern(s);
                         match generic_map.get(&s) {
                             Some(val) => val,
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 9de4d3a646c..adf47ece69d 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -32,7 +32,7 @@ use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable};
-use rustc_middle::ty::{self, EarlyBinder, Term, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 
 use std::collections::BTreeMap;
@@ -744,10 +744,7 @@ impl<'tcx> TypeFolder<'tcx> for BoundVarReplacer<'_, 'tcx> {
             }
             ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
                 let universe = self.universe_for(debruijn);
-                let p = ty::PlaceholderConst {
-                    universe,
-                    name: ty::BoundConst { var: bound_const, ty: ct.ty() },
-                };
+                let p = ty::PlaceholderConst { universe, name: bound_const };
                 self.mapped_consts.insert(p, bound_const);
                 self.infcx
                     .tcx
@@ -1988,7 +1985,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
         return Progress { term: tcx.ty_error().into(), obligations: nested };
     };
 
-    if !assoc_ty.item.defaultness.has_value() {
+    if !assoc_ty.item.defaultness(tcx).has_value() {
         // This means that the impl is missing a definition for the
         // associated type. This error will be reported by the type
         // checker method `check_impl_items_against_trait`, so here we
@@ -2008,16 +2005,16 @@ fn confirm_impl_candidate<'cx, 'tcx>(
     let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs);
     let substs =
         translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.defining_node);
-    let ty = tcx.type_of(assoc_ty.item.def_id);
+    let ty = tcx.bound_type_of(assoc_ty.item.def_id);
     let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
-    let term: ty::Term<'tcx> = if is_const {
+    let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
         let identity_substs =
             crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
         let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id);
         let kind = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs));
-        tcx.mk_const(ty::ConstS { ty, kind }).into()
+        ty.map_bound(|ty| tcx.mk_const(ty::ConstS { ty, kind }).into())
     } else {
-        ty.into()
+        ty.map_bound(|ty| ty.into())
     };
     if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() {
         let err = tcx.ty_error_with_message(
@@ -2027,7 +2024,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
         Progress { term: err.into(), obligations: nested }
     } else {
         assoc_ty_own_obligations(selcx, obligation, &mut nested);
-        Progress { term: EarlyBinder(term).subst(tcx, substs), obligations: nested }
+        Progress { term: term.subst(tcx, substs), obligations: nested }
     }
 }
 
@@ -2089,7 +2086,11 @@ fn assoc_def(
         return Ok(specialization_graph::LeafDef {
             item: *item,
             defining_node: impl_node,
-            finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
+            finalizing_node: if item.defaultness(tcx).is_default() {
+                None
+            } else {
+                Some(impl_node)
+            },
         });
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index c99564936aa..f6e196e3141 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -1,11 +1,9 @@
 use crate::infer::canonical::query_response;
 use crate::infer::{InferCtxt, InferOk};
-use crate::traits::engine::TraitEngineExt as _;
+use crate::traits;
 use crate::traits::query::type_op::TypeOpOutput;
 use crate::traits::query::Fallible;
-use crate::traits::TraitEngine;
 use rustc_infer::infer::region_constraints::RegionConstraintData;
-use rustc_infer::traits::TraitEngineExt as _;
 use rustc_span::source_map::DUMMY_SP;
 
 use std::fmt;
@@ -62,8 +60,6 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
     infcx: &InferCtxt<'_, 'tcx>,
     op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
 ) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
-    let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
     // During NLL, we expect that nobody will register region
     // obligations **except** as part of a custom type op (and, at the
     // end of each custom type op, we scrape out the region
@@ -77,8 +73,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
     );
 
     let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
-    fulfill_cx.register_predicate_obligations(infcx, obligations);
-    let errors = fulfill_cx.select_all_or_error(infcx);
+    let errors = traits::fully_solve_obligations(infcx, obligations);
     if !errors.is_empty() {
         infcx.tcx.sess.diagnostic().delay_span_bug(
             DUMMY_SP,
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 6e8581128dd..50e9b95a445 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -8,7 +8,7 @@
 use hir::LangItem;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_infer::traits::TraitEngine;
+use rustc_infer::traits::ObligationCause;
 use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
 use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -305,6 +305,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 self.assemble_candidates_for_unsizing(obligation, &mut candidates);
             } else if lang_items.destruct_trait() == Some(def_id) {
                 self.assemble_const_destruct_candidates(obligation, &mut candidates);
+            } else if lang_items.transmute_trait() == Some(def_id) {
+                // User-defined transmutability impls are permitted.
+                self.assemble_candidates_from_impls(obligation, &mut candidates);
+                self.assemble_candidates_for_transmutability(obligation, &mut candidates);
             } else {
                 if lang_items.clone_trait() == Some(def_id) {
                     // Same builtin conditions as `Copy`, i.e., every type which has builtin support
@@ -702,8 +706,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn need_migrate_deref_output_trait_object(
         &mut self,
         ty: Ty<'tcx>,
-        cause: &traits::ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
+        cause: &ObligationCause<'tcx>,
     ) -> Option<(Ty<'tcx>, DefId)> {
         let tcx = self.tcx();
         if tcx.features().trait_upcasting {
@@ -725,24 +729,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return None;
         }
 
-        let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
-        let normalized_ty = fulfillcx.normalize_projection_type(
-            &self.infcx,
+        let ty = traits::normalize_projection_type(
+            self,
             param_env,
             ty::ProjectionTy {
                 item_def_id: tcx.lang_items().deref_target()?,
                 substs: trait_ref.substs,
             },
             cause.clone(),
-        );
-
-        let ty::Dynamic(data, ..) = normalized_ty.kind() else {
-            return None;
-        };
-
-        let def_id = data.principal_def_id()?;
-
-        return Some((normalized_ty, def_id));
+            0,
+            // We're *intentionally* throwing these away,
+            // since we don't actually use them.
+            &mut vec![],
+        )
+        .ty()
+        .unwrap();
+
+        if let ty::Dynamic(data, ..) = ty.kind() {
+            Some((ty, data.principal_def_id()?))
+        } else {
+            None
+        }
     }
 
     /// Searches for unsizing that might apply to `obligation`.
@@ -805,8 +812,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         if let Some((deref_output_ty, deref_output_trait_did)) = self
                             .need_migrate_deref_output_trait_object(
                                 source,
-                                &obligation.cause,
                                 obligation.param_env,
+                                &obligation.cause,
                             )
                         {
                             if deref_output_trait_did == target_trait_did {
@@ -874,6 +881,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
+    fn assemble_candidates_for_transmutability(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) {
+        if obligation.has_param_types_or_consts() {
+            return;
+        }
+
+        if obligation.has_infer_types_or_consts() {
+            candidates.ambiguous = true;
+            return;
+        }
+
+        candidates.vec.push(TransmutabilityCandidate);
+    }
+
+    #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
     fn assemble_candidates_for_trait_alias(
         &mut self,
         obligation: &TraitObligation<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index d4c9fd1c5f9..2a1099fc82a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -48,6 +48,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplSource::Builtin(data)
             }
 
+            TransmutabilityCandidate => {
+                let data = self.confirm_transmutability_candidate(obligation)?;
+                ImplSource::Builtin(data)
+            }
+
             ParamCandidate(param) => {
                 let obligations =
                     self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
@@ -139,67 +144,65 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         idx: usize,
     ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        self.infcx.commit_unconditionally(|_| {
-            let tcx = self.tcx();
-
-            let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
-            let placeholder_trait_predicate =
-                self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
-            let placeholder_self_ty = placeholder_trait_predicate.self_ty();
-            let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
-            let (def_id, substs) = match *placeholder_self_ty.kind() {
-                ty::Projection(proj) => (proj.item_def_id, proj.substs),
-                ty::Opaque(def_id, substs) => (def_id, substs),
-                _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
-            };
+        let tcx = self.tcx();
 
-            let candidate_predicate =
-                tcx.bound_item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs);
-            let candidate = candidate_predicate
-                .to_opt_poly_trait_pred()
-                .expect("projection candidate is not a trait predicate")
-                .map_bound(|t| t.trait_ref);
-            let mut obligations = Vec::new();
-            let candidate = normalize_with_depth_to(
-                self,
-                obligation.param_env,
-                obligation.cause.clone(),
-                obligation.recursion_depth + 1,
-                candidate,
-                &mut obligations,
-            );
+        let trait_predicate = self.infcx.shallow_resolve(obligation.predicate);
+        let placeholder_trait_predicate =
+            self.infcx().replace_bound_vars_with_placeholders(trait_predicate).trait_ref;
+        let placeholder_self_ty = placeholder_trait_predicate.self_ty();
+        let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
+        let (def_id, substs) = match *placeholder_self_ty.kind() {
+            ty::Projection(proj) => (proj.item_def_id, proj.substs),
+            ty::Opaque(def_id, substs) => (def_id, substs),
+            _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
+        };
 
-            obligations.extend(self.infcx.commit_if_ok(|_| {
-                self.infcx
-                    .at(&obligation.cause, obligation.param_env)
-                    .sup(placeholder_trait_predicate, candidate)
-                    .map(|InferOk { obligations, .. }| obligations)
-                    .map_err(|_| Unimplemented)
-            })?);
-
-            if let ty::Projection(..) = placeholder_self_ty.kind() {
-                let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
-                debug!(?predicates, "projection predicates");
-                for predicate in predicates {
-                    let normalized = normalize_with_depth_to(
-                        self,
-                        obligation.param_env,
-                        obligation.cause.clone(),
-                        obligation.recursion_depth + 1,
-                        predicate,
-                        &mut obligations,
-                    );
-                    obligations.push(Obligation::with_depth(
-                        obligation.cause.clone(),
-                        obligation.recursion_depth + 1,
-                        obligation.param_env,
-                        normalized,
-                    ));
-                }
+        let candidate_predicate =
+            tcx.bound_item_bounds(def_id).map_bound(|i| i[idx]).subst(tcx, substs);
+        let candidate = candidate_predicate
+            .to_opt_poly_trait_pred()
+            .expect("projection candidate is not a trait predicate")
+            .map_bound(|t| t.trait_ref);
+        let mut obligations = Vec::new();
+        let candidate = normalize_with_depth_to(
+            self,
+            obligation.param_env,
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            candidate,
+            &mut obligations,
+        );
+
+        obligations.extend(self.infcx.commit_if_ok(|_| {
+            self.infcx
+                .at(&obligation.cause, obligation.param_env)
+                .sup(placeholder_trait_predicate, candidate)
+                .map(|InferOk { obligations, .. }| obligations)
+                .map_err(|_| Unimplemented)
+        })?);
+
+        if let ty::Projection(..) = placeholder_self_ty.kind() {
+            let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
+            debug!(?predicates, "projection predicates");
+            for predicate in predicates {
+                let normalized = normalize_with_depth_to(
+                    self,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    predicate,
+                    &mut obligations,
+                );
+                obligations.push(Obligation::with_depth(
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    obligation.param_env,
+                    normalized,
+                ));
             }
+        }
 
-            Ok(obligations)
-        })
+        Ok(obligations)
     }
 
     fn confirm_param_candidate(
@@ -267,6 +270,53 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         ImplSourceBuiltinData { nested: obligations }
     }
 
+    fn confirm_transmutability_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+    ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        debug!(?obligation, "confirm_transmutability_candidate");
+
+        let predicate = obligation.predicate;
+
+        let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i));
+        let bool_at = |i| {
+            predicate
+                .skip_binder()
+                .trait_ref
+                .substs
+                .const_at(i)
+                .try_eval_bool(self.tcx(), obligation.param_env)
+                .unwrap_or(true)
+        };
+
+        let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types {
+            src: p.trait_ref.substs.type_at(1),
+            dst: p.trait_ref.substs.type_at(0),
+        });
+
+        let scope = type_at(2).skip_binder();
+
+        let assume = rustc_transmute::Assume {
+            alignment: bool_at(3),
+            lifetimes: bool_at(4),
+            validity: bool_at(5),
+            visibility: bool_at(6),
+        };
+
+        let cause = obligation.cause.clone();
+
+        let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
+
+        let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume);
+
+        use rustc_transmute::Answer;
+
+        match maybe_transmutable {
+            Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
+            _ => Err(Unimplemented),
+        }
+    }
+
     /// This handles the case where an `auto trait Foo` impl is being used.
     /// The idea is that the impl applies to `X : Foo` if the following conditions are met:
     ///
@@ -295,19 +345,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         ensure_sufficient_stack(|| {
             let cause = obligation.derived_cause(BuiltinDerivedObligation);
 
-            let trait_obligations: Vec<PredicateObligation<'_>> =
-                self.infcx.commit_unconditionally(|_| {
-                    let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
-                    let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
-                    self.impl_or_trait_obligations(
-                        &cause,
-                        obligation.recursion_depth + 1,
-                        obligation.param_env,
-                        trait_def_id,
-                        &trait_ref.substs,
-                        obligation.predicate,
-                    )
-                });
+            let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
+            let trait_ref = self.infcx.replace_bound_vars_with_placeholders(poly_trait_ref);
+            let trait_obligations: Vec<PredicateObligation<'_>> = self.impl_or_trait_obligations(
+                &cause,
+                obligation.recursion_depth + 1,
+                obligation.param_env,
+                trait_def_id,
+                &trait_ref.substs,
+                obligation.predicate,
+            );
 
             let mut obligations = self.collect_predicates_for_types(
                 obligation.param_env,
@@ -336,19 +383,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
-        self.infcx.commit_unconditionally(|_| {
-            let substs = self.rematch_impl(impl_def_id, obligation);
-            debug!(?substs, "impl substs");
-            ensure_sufficient_stack(|| {
-                self.vtable_impl(
-                    impl_def_id,
-                    substs,
-                    &obligation.cause,
-                    obligation.recursion_depth + 1,
-                    obligation.param_env,
-                    obligation.predicate,
-                )
-            })
+        let substs = self.rematch_impl(impl_def_id, obligation);
+        debug!(?substs, "impl substs");
+        ensure_sufficient_stack(|| {
+            self.vtable_impl(
+                impl_def_id,
+                substs,
+                &obligation.cause,
+                obligation.recursion_depth + 1,
+                obligation.param_env,
+                obligation.predicate,
+            )
         })
     }
 
@@ -595,25 +640,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> {
         debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate");
 
-        self.infcx.commit_unconditionally(|_| {
-            let predicate = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate);
-            let trait_ref = predicate.trait_ref;
-            let trait_def_id = trait_ref.def_id;
-            let substs = trait_ref.substs;
+        let predicate = self.infcx().replace_bound_vars_with_placeholders(obligation.predicate);
+        let trait_ref = predicate.trait_ref;
+        let trait_def_id = trait_ref.def_id;
+        let substs = trait_ref.substs;
 
-            let trait_obligations = self.impl_or_trait_obligations(
-                &obligation.cause,
-                obligation.recursion_depth,
-                obligation.param_env,
-                trait_def_id,
-                &substs,
-                obligation.predicate,
-            );
+        let trait_obligations = self.impl_or_trait_obligations(
+            &obligation.cause,
+            obligation.recursion_depth,
+            obligation.param_env,
+            trait_def_id,
+            &substs,
+            obligation.predicate,
+        );
 
-            debug!(?trait_def_id, ?trait_obligations, "trait alias obligations");
+        debug!(?trait_def_id, ?trait_obligations, "trait alias obligations");
 
-            ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations }
-        })
+        ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations }
     }
 
     fn confirm_generator_candidate(
@@ -711,15 +754,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // Normalize the obligation and expected trait refs together, because why not
         let Normalized { obligations: nested, value: (obligation_trait_ref, expected_trait_ref) } =
             ensure_sufficient_stack(|| {
-                self.infcx.commit_unconditionally(|_| {
-                    normalize_with_depth(
-                        self,
-                        obligation.param_env,
-                        obligation.cause.clone(),
-                        obligation.recursion_depth + 1,
-                        (obligation_trait_ref, expected_trait_ref),
-                    )
-                })
+                normalize_with_depth(
+                    self,
+                    obligation.param_env,
+                    obligation.cause.clone(),
+                    obligation.recursion_depth + 1,
+                    (obligation_trait_ref, expected_trait_ref),
+                )
             });
 
         self.infcx
@@ -1095,32 +1136,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // first check it like a regular impl candidate.
         // This is copied from confirm_impl_candidate but remaps the predicate to `~const Drop` beforehand.
         if let Some(impl_def_id) = impl_def_id {
-            let obligations = self.infcx.commit_unconditionally(|_| {
-                let mut new_obligation = obligation.clone();
-                new_obligation.predicate = new_obligation.predicate.map_bound(|mut trait_pred| {
-                    trait_pred.trait_ref.def_id = drop_trait;
-                    trait_pred
-                });
-                let substs = self.rematch_impl(impl_def_id, &new_obligation);
-                debug!(?substs, "impl substs");
-
-                let cause = obligation.derived_cause(|derived| {
-                    ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
-                        derived,
-                        impl_def_id,
-                        span: obligation.cause.span,
-                    }))
-                });
-                ensure_sufficient_stack(|| {
-                    self.vtable_impl(
-                        impl_def_id,
-                        substs,
-                        &cause,
-                        new_obligation.recursion_depth + 1,
-                        new_obligation.param_env,
-                        obligation.predicate,
-                    )
-                })
+            let mut new_obligation = obligation.clone();
+            new_obligation.predicate = new_obligation.predicate.map_bound(|mut trait_pred| {
+                trait_pred.trait_ref.def_id = drop_trait;
+                trait_pred
+            });
+            let substs = self.rematch_impl(impl_def_id, &new_obligation);
+            debug!(?substs, "impl substs");
+
+            let cause = obligation.derived_cause(|derived| {
+                ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+                    derived,
+                    impl_def_id,
+                    span: obligation.cause.span,
+                }))
+            });
+            let obligations = ensure_sufficient_stack(|| {
+                self.vtable_impl(
+                    impl_def_id,
+                    substs,
+                    &cause,
+                    new_obligation.recursion_depth + 1,
+                    new_obligation.param_env,
+                    obligation.predicate,
+                )
             });
             nested.extend(obligations.nested);
         }
@@ -1171,34 +1210,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // If we have a projection type, make sure to normalize it so we replace it
                 // with a fresh infer variable
                 ty::Projection(..) => {
-                    self.infcx.commit_unconditionally(|_| {
-                        let predicate = normalize_with_depth_to(
-                            self,
-                            obligation.param_env,
-                            cause.clone(),
-                            obligation.recursion_depth + 1,
-                            self_ty
-                                .rebind(ty::TraitPredicate {
-                                    trait_ref: ty::TraitRef {
-                                        def_id: self
-                                            .tcx()
-                                            .require_lang_item(LangItem::Destruct, None),
-                                        substs: self.tcx().mk_substs_trait(nested_ty, &[]),
-                                    },
-                                    constness: ty::BoundConstness::ConstIfConst,
-                                    polarity: ty::ImplPolarity::Positive,
-                                })
-                                .to_predicate(tcx),
-                            &mut nested,
-                        );
-
-                        nested.push(Obligation::with_depth(
-                            cause.clone(),
-                            obligation.recursion_depth + 1,
-                            obligation.param_env,
-                            predicate,
-                        ));
-                    });
+                    let predicate = normalize_with_depth_to(
+                        self,
+                        obligation.param_env,
+                        cause.clone(),
+                        obligation.recursion_depth + 1,
+                        self_ty
+                            .rebind(ty::TraitPredicate {
+                                trait_ref: ty::TraitRef {
+                                    def_id: self.tcx().require_lang_item(LangItem::Destruct, None),
+                                    substs: self.tcx().mk_substs_trait(nested_ty, &[]),
+                                },
+                                constness: ty::BoundConstness::ConstIfConst,
+                                polarity: ty::ImplPolarity::Positive,
+                            })
+                            .to_predicate(tcx),
+                        &mut nested,
+                    );
+
+                    nested.push(Obligation::with_depth(
+                        cause.clone(),
+                        obligation.recursion_depth + 1,
+                        obligation.param_env,
+                        predicate,
+                    ));
                 }
 
                 // If we have any other type (e.g. an ADT), just register a nested obligation
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 17f34012d1d..c01ac197991 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1630,6 +1630,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 );
             }
 
+            // FIXME(@jswrenn): this should probably be more sophisticated
+            (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false,
+
             // (*)
             (
                 BuiltinCandidate { has_nested: false }
@@ -1883,7 +1886,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 let sized_crit = def.sized_constraint(self.tcx());
                 // (*) binder moved here
                 Where(obligation.predicate.rebind({
-                    sized_crit.iter().map(|ty| EarlyBinder(*ty).subst(self.tcx(), substs)).collect()
+                    sized_crit
+                        .0
+                        .iter()
+                        .map(|ty| sized_crit.rebind(*ty).subst(self.tcx(), substs))
+                        .collect()
                 }))
             }
 
@@ -2081,30 +2088,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .flat_map(|ty| {
                 let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/
 
-                self.infcx.commit_unconditionally(|_| {
-                    let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty);
-                    let Normalized { value: normalized_ty, mut obligations } =
-                        ensure_sufficient_stack(|| {
-                            project::normalize_with_depth(
-                                self,
-                                param_env,
-                                cause.clone(),
-                                recursion_depth,
-                                placeholder_ty,
-                            )
-                        });
-                    let placeholder_obligation = predicate_for_trait_def(
-                        self.tcx(),
-                        param_env,
-                        cause.clone(),
-                        trait_def_id,
-                        recursion_depth,
-                        normalized_ty,
-                        &[],
-                    );
-                    obligations.push(placeholder_obligation);
-                    obligations
-                })
+                let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty);
+                let Normalized { value: normalized_ty, mut obligations } =
+                    ensure_sufficient_stack(|| {
+                        project::normalize_with_depth(
+                            self,
+                            param_env,
+                            cause.clone(),
+                            recursion_depth,
+                            placeholder_ty,
+                        )
+                    });
+                let placeholder_obligation = predicate_for_trait_def(
+                    self.tcx(),
+                    param_env,
+                    cause.clone(),
+                    trait_def_id,
+                    recursion_depth,
+                    normalized_ty,
+                    &[],
+                );
+                obligations.push(placeholder_obligation);
+                obligations
             })
             .collect()
     }
@@ -2356,11 +2361,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // obligation will normalize to `<$0 as Iterator>::Item = $1` and
         // `$1: Copy`, so we must ensure the obligations are emitted in
         // that order.
-        let predicates = tcx.predicates_of(def_id);
+        let predicates = tcx.bound_predicates_of(def_id);
         debug!(?predicates);
-        assert_eq!(predicates.parent, None);
-        let mut obligations = Vec::with_capacity(predicates.predicates.len());
-        for (predicate, span) in predicates.predicates {
+        assert_eq!(predicates.0.parent, None);
+        let mut obligations = Vec::with_capacity(predicates.0.predicates.len());
+        for (predicate, span) in predicates.0.predicates {
             let span = *span;
             let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
                 ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
@@ -2374,7 +2379,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 param_env,
                 cause.clone(),
                 recursion_depth,
-                EarlyBinder(*predicate).subst(tcx, substs),
+                predicates.rebind(*predicate).subst(tcx, substs),
                 &mut obligations,
             );
             obligations.push(Obligation { cause, recursion_depth, param_env, predicate });
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 5f77aae6f22..0f76fef0eee 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -14,7 +14,7 @@ use specialization_graph::GraphExt;
 
 use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
 use crate::traits::select::IntercrateAmbiguityCause;
-use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine};
+use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder};
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -25,7 +25,7 @@ use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
 use rustc_span::{Span, DUMMY_SP};
 
 use super::util;
-use super::{FulfillmentContext, SelectionContext};
+use super::SelectionContext;
 
 /// Information pertinent to an overlapping impl error.
 #[derive(Debug)]
@@ -149,18 +149,19 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
 
     // Create an infcx, taking the predicates of impl1 as assumptions:
     tcx.infer_ctxt().enter(|infcx| {
-        // Normalize the trait reference. The WF rules ought to ensure
-        // that this always succeeds.
         let impl1_trait_ref = match traits::fully_normalize(
             &infcx,
-            FulfillmentContext::new(),
             ObligationCause::dummy(),
             penv,
             impl1_trait_ref,
         ) {
             Ok(impl1_trait_ref) => impl1_trait_ref,
-            Err(err) => {
-                bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
+            Err(_errors) => {
+                tcx.sess.delay_span_bug(
+                    tcx.def_span(impl1_def_id),
+                    format!("failed to fully normalize {impl1_trait_ref}"),
+                );
+                impl1_trait_ref
             }
         };
 
@@ -207,11 +208,8 @@ fn fulfill_implication<'a, 'tcx>(
     // (which are packed up in penv)
 
     infcx.save_and_restore_in_snapshot_flag(|infcx| {
-        let mut fulfill_cx = FulfillmentContext::new();
-        for oblig in obligations.chain(more_obligations) {
-            fulfill_cx.register_predicate_obligation(&infcx, oblig);
-        }
-        match fulfill_cx.select_all_or_error(infcx).as_slice() {
+        let errors = traits::fully_solve_obligations(&infcx, obligations.chain(more_obligations));
+        match &errors[..] {
             [] => {
                 debug!(
                     "fulfill_implication: an impl for {:?} specializes {:?}",
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index c278752e3d9..5829a0f92ee 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -1,6 +1,6 @@
 use crate::infer::{InferCtxt, TyCtxtInferExt};
 use crate::traits::ObligationCause;
-use crate::traits::{self, TraitEngine};
+use crate::traits::{TraitEngine, TraitEngineExt};
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
@@ -72,7 +72,7 @@ fn type_marked_structural<'tcx>(
     adt_ty: Ty<'tcx>,
     cause: ObligationCause<'tcx>,
 ) -> bool {
-    let mut fulfillment_cx = traits::FulfillmentContext::new();
+    let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
     // require `#[derive(PartialEq)]`
     let structural_peq_def_id =
         infcx.tcx.require_lang_item(LangItem::StructuralPeq, Some(cause.span));
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 3170b29ee69..d2500601662 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -6,7 +6,7 @@ use smallvec::SmallVec;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, Subst, SubstsRef};
-use rustc_middle::ty::{self, EarlyBinder, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable};
 
 use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext};
 pub use rustc_infer::traits::{self, util::*};
@@ -200,8 +200,8 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
     impl_def_id: DefId,
     impl_substs: SubstsRef<'tcx>,
 ) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
-    let subject = selcx.tcx().impl_subject(impl_def_id);
-    let subject = EarlyBinder(subject).subst(selcx.tcx(), impl_substs);
+    let subject = selcx.tcx().bound_impl_subject(impl_def_id);
+    let subject = subject.subst(selcx.tcx(), impl_substs);
     let Normalized { value: subject, obligations: normalization_obligations1 } =
         super::normalize(selcx, param_env, ObligationCause::dummy(), subject);
 
@@ -358,7 +358,8 @@ pub fn generator_trait_ref_and_outputs<'tcx>(
 }
 
 pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool {
-    assoc_item.defaultness.is_final() && tcx.impl_defaultness(assoc_item.container.id()).is_final()
+    assoc_item.defaultness(tcx).is_final()
+        && tcx.impl_defaultness(assoc_item.container_id(tcx)).is_final()
 }
 
 pub enum TupleArgumentsFlag {
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 497819ce5c5..ff5ca0cbcb7 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -8,9 +8,7 @@
 
 use rustc_middle::traits::ChalkRustInterner as RustInterner;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{
-    self, AssocItemContainer, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
-};
+use rustc_middle::ty::{self, AssocKind, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable};
 
 use rustc_ast::ast;
 use rustc_attr as attr;
@@ -53,11 +51,11 @@ impl<'tcx> RustIrDatabase<'tcx> {
     where
         ty::Predicate<'tcx>: LowerInto<'tcx, std::option::Option<T>>,
     {
-        self.interner
-            .tcx
-            .explicit_item_bounds(def_id)
+        let bounds = self.interner.tcx.bound_explicit_item_bounds(def_id);
+        bounds
+            .0
             .iter()
-            .map(|(bound, _)| EarlyBinder(*bound).subst(self.interner.tcx, &bound_vars))
+            .map(|(bound, _)| bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars))
             .filter_map(|bound| LowerInto::<Option<_>>::lower_into(bound, self.interner))
             .collect()
     }
@@ -74,7 +72,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
     ) -> Arc<chalk_solve::rust_ir::AssociatedTyDatum<RustInterner<'tcx>>> {
         let def_id = assoc_type_id.0;
         let assoc_item = self.interner.tcx.associated_item(def_id);
-        let AssocItemContainer::TraitContainer(trait_def_id) = assoc_item.container else {
+        let Some(trait_def_id) = assoc_item.trait_container(self.interner.tcx) else {
             unimplemented!("Not possible??");
         };
         match assoc_item.kind {
@@ -270,21 +268,20 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
 
         let where_clauses = self.where_clauses_for(def_id, bound_vars);
 
-        let sig = self.interner.tcx.fn_sig(def_id);
+        let sig = self.interner.tcx.bound_fn_sig(def_id);
         let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars(
             self.interner,
             self.interner.tcx,
-            EarlyBinder(sig.inputs_and_output()).subst(self.interner.tcx, bound_vars),
+            sig.map_bound(|s| s.inputs_and_output()).subst(self.interner.tcx, bound_vars),
         );
 
         let argument_types = inputs_and_output[..inputs_and_output.len() - 1]
             .iter()
-            .map(|t| {
-                EarlyBinder(*t).subst(self.interner.tcx, &bound_vars).lower_into(self.interner)
-            })
+            .map(|t| sig.rebind(*t).subst(self.interner.tcx, &bound_vars).lower_into(self.interner))
             .collect();
 
-        let return_type = EarlyBinder(inputs_and_output[inputs_and_output.len() - 1])
+        let return_type = sig
+            .rebind(inputs_and_output[inputs_and_output.len() - 1])
             .subst(self.interner.tcx, &bound_vars)
             .lower_into(self.interner);
 
@@ -297,7 +294,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
         };
         Arc::new(chalk_solve::rust_ir::FnDefDatum {
             id: fn_def_id,
-            sig: sig.lower_into(self.interner),
+            sig: sig.0.lower_into(self.interner),
             binders: chalk_ir::Binders::new(binders, bound),
         })
     }
@@ -455,7 +452,7 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
     ) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
         let def_id = associated_ty_id.0;
         let assoc_item = self.interner.tcx.associated_item(def_id);
-        let impl_id = assoc_item.container.id();
+        let impl_id = assoc_item.container_id(self.interner.tcx);
         match assoc_item.kind {
             AssocKind::Type => {}
             _ => unimplemented!("Not possible??"),
@@ -505,12 +502,14 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
 
         let identity_substs = InternalSubsts::identity_for_item(self.interner.tcx, opaque_ty_id.0);
 
+        let explicit_item_bounds = self.interner.tcx.bound_explicit_item_bounds(opaque_ty_id.0);
         let bounds =
-            self.interner
-                .tcx
-                .explicit_item_bounds(opaque_ty_id.0)
+            explicit_item_bounds
+                .0
                 .iter()
-                .map(|(bound, _)| EarlyBinder(*bound).subst(self.interner.tcx, &bound_vars))
+                .map(|(bound, _)| {
+                    explicit_item_bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars)
+                })
                 .map(|bound| {
                     bound.fold_with(&mut ReplaceOpaqueTyFolder {
                         tcx: self.interner.tcx,
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index db7ea4253e3..f76386fa720 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -76,7 +76,7 @@ pub(crate) fn evaluate_goal<'tcx>(
                         chalk_ir::UniverseIndex { counter: ui.index() },
                     ),
                     CanonicalVarKind::Const(_ui, _ty) => unimplemented!(),
-                    CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
+                    CanonicalVarKind::PlaceholderConst(_pc, _ty) => unimplemented!(),
                 }),
             ),
             value: obligation.value.lower_into(interner),
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index 4d4d55de5f4..e3e78f70b15 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -14,8 +14,7 @@ use rustc_span::source_map::DUMMY_SP;
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
 use rustc_trait_selection::traits::wf;
-use rustc_trait_selection::traits::FulfillmentContext;
-use rustc_trait_selection::traits::TraitEngine;
+use rustc_trait_selection::traits::{TraitEngine, TraitEngineExt};
 use smallvec::{smallvec, SmallVec};
 
 pub(crate) fn provide(p: &mut Providers) {
@@ -52,7 +51,7 @@ fn compute_implied_outlives_bounds<'tcx>(
 
     let mut implied_bounds = vec![];
 
-    let mut fulfill_cx = FulfillmentContext::new();
+    let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(tcx);
 
     while let Some(arg) = wf_args.pop() {
         if !checked_wf_args.insert(arg) {
diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml
new file mode 100644
index 00000000000..9dc96e08a8e
--- /dev/null
+++ b/compiler/rustc_transmute/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "rustc_transmute"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+tracing = "0.1"
+rustc_data_structures = { path = "../rustc_data_structures", optional = true}
+rustc_infer = { path = "../rustc_infer", optional = true}
+rustc_macros = { path = "../rustc_macros", optional = true}
+rustc_middle = { path = "../rustc_middle", optional = true}
+rustc_span = { path = "../rustc_span", optional = true}
+rustc_target = { path = "../rustc_target", optional = true}
+
+[features]
+rustc = [
+    "rustc_middle",
+    "rustc_data_structures",
+    "rustc_infer",
+    "rustc_macros",
+    "rustc_span",
+    "rustc_target",
+]
+
+[dev-dependencies]
+itertools = "0.10.1"
\ No newline at end of file
diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs
new file mode 100644
index 00000000000..b60ea6e7a24
--- /dev/null
+++ b/compiler/rustc_transmute/src/layout/dfa.rs
@@ -0,0 +1,184 @@
+use super::{nfa, Byte, Nfa, Ref};
+use crate::Map;
+use std::fmt;
+use std::sync::atomic::{AtomicU32, Ordering};
+
+#[derive(PartialEq, Clone, Debug)]
+pub(crate) struct Dfa<R>
+where
+    R: Ref,
+{
+    pub(crate) transitions: Map<State, Transitions<R>>,
+    pub(crate) start: State,
+    pub(crate) accepting: State,
+}
+
+#[derive(PartialEq, Clone, Debug)]
+pub(crate) struct Transitions<R>
+where
+    R: Ref,
+{
+    byte_transitions: Map<Byte, State>,
+    ref_transitions: Map<R, State>,
+}
+
+impl<R> Default for Transitions<R>
+where
+    R: Ref,
+{
+    fn default() -> Self {
+        Self { byte_transitions: Map::default(), ref_transitions: Map::default() }
+    }
+}
+
+impl<R> Transitions<R>
+where
+    R: Ref,
+{
+    fn insert(&mut self, transition: Transition<R>, state: State) {
+        match transition {
+            Transition::Byte(b) => {
+                self.byte_transitions.insert(b, state);
+            }
+            Transition::Ref(r) => {
+                self.ref_transitions.insert(r, state);
+            }
+        }
+    }
+}
+
+/// The states in a `Nfa` represent byte offsets.
+#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
+pub(crate) struct State(u32);
+
+#[derive(Hash, Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Transition<R>
+where
+    R: Ref,
+{
+    Byte(Byte),
+    Ref(R),
+}
+
+impl fmt::Debug for State {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "S_{}", self.0)
+    }
+}
+
+impl<R> fmt::Debug for Transition<R>
+where
+    R: Ref,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match &self {
+            Self::Byte(b) => b.fmt(f),
+            Self::Ref(r) => r.fmt(f),
+        }
+    }
+}
+
+impl<R> Dfa<R>
+where
+    R: Ref,
+{
+    pub(crate) fn unit() -> Self {
+        let transitions: Map<State, Transitions<R>> = Map::default();
+        let start = State::new();
+        let accepting = start;
+
+        Self { transitions, start, accepting }
+    }
+
+    #[cfg(test)]
+    pub(crate) fn bool() -> Self {
+        let mut transitions: Map<State, Transitions<R>> = Map::default();
+        let start = State::new();
+        let accepting = State::new();
+
+        transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x00)), accepting);
+
+        transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x01)), accepting);
+
+        Self { transitions, start, accepting }
+    }
+
+    #[instrument(level = "debug")]
+    #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
+    pub(crate) fn from_nfa(nfa: Nfa<R>) -> Self {
+        let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa;
+
+        let mut dfa_transitions: Map<State, Transitions<R>> = Map::default();
+        let mut nfa_to_dfa: Map<nfa::State, State> = Map::default();
+        let dfa_start = State::new();
+        nfa_to_dfa.insert(nfa_start, dfa_start);
+
+        let mut queue = vec![(nfa_start, dfa_start)];
+
+        while let Some((nfa_state, dfa_state)) = queue.pop() {
+            if nfa_state == nfa_accepting {
+                continue;
+            }
+
+            for (nfa_transition, next_nfa_states) in nfa_transitions[&nfa_state].iter() {
+                let dfa_transitions =
+                    dfa_transitions.entry(dfa_state).or_insert_with(Default::default);
+
+                let mapped_state = next_nfa_states.iter().find_map(|x| nfa_to_dfa.get(x).copied());
+
+                let next_dfa_state = match nfa_transition {
+                    &nfa::Transition::Byte(b) => *dfa_transitions
+                        .byte_transitions
+                        .entry(b)
+                        .or_insert_with(|| mapped_state.unwrap_or_else(State::new)),
+                    &nfa::Transition::Ref(r) => *dfa_transitions
+                        .ref_transitions
+                        .entry(r)
+                        .or_insert_with(|| mapped_state.unwrap_or_else(State::new)),
+                };
+
+                for &next_nfa_state in next_nfa_states {
+                    nfa_to_dfa.entry(next_nfa_state).or_insert_with(|| {
+                        queue.push((next_nfa_state, next_dfa_state));
+                        next_dfa_state
+                    });
+                }
+            }
+        }
+
+        let dfa_accepting = nfa_to_dfa[&nfa_accepting];
+
+        Self { transitions: dfa_transitions, start: dfa_start, accepting: dfa_accepting }
+    }
+
+    pub(crate) fn bytes_from(&self, start: State) -> Option<&Map<Byte, State>> {
+        Some(&self.transitions.get(&start)?.byte_transitions)
+    }
+
+    pub(crate) fn byte_from(&self, start: State, byte: Byte) -> Option<State> {
+        self.transitions.get(&start)?.byte_transitions.get(&byte).copied()
+    }
+
+    pub(crate) fn refs_from(&self, start: State) -> Option<&Map<R, State>> {
+        Some(&self.transitions.get(&start)?.ref_transitions)
+    }
+}
+
+impl State {
+    pub(crate) fn new() -> Self {
+        static COUNTER: AtomicU32 = AtomicU32::new(0);
+        Self(COUNTER.fetch_add(1, Ordering::SeqCst))
+    }
+}
+
+impl<R> From<nfa::Transition<R>> for Transition<R>
+where
+    R: Ref,
+{
+    fn from(nfa_transition: nfa::Transition<R>) -> Self {
+        match nfa_transition {
+            nfa::Transition::Byte(byte) => Transition::Byte(byte),
+            nfa::Transition::Ref(r) => Transition::Ref(r),
+        }
+    }
+}
diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs
new file mode 100644
index 00000000000..07035ebdfb1
--- /dev/null
+++ b/compiler/rustc_transmute/src/layout/mod.rs
@@ -0,0 +1,71 @@
+use std::fmt::{self, Debug};
+use std::hash::Hash;
+
+pub(crate) mod tree;
+pub(crate) use tree::Tree;
+
+pub(crate) mod nfa;
+pub(crate) use nfa::Nfa;
+
+pub(crate) mod dfa;
+pub(crate) use dfa::Dfa;
+
+#[derive(Debug)]
+pub(crate) struct Uninhabited;
+
+/// An instance of a byte is either initialized to a particular value, or uninitialized.
+#[derive(Hash, Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Byte {
+    Uninit,
+    Init(u8),
+}
+
+impl fmt::Debug for Byte {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match &self {
+            Self::Uninit => f.write_str("??u8"),
+            Self::Init(b) => write!(f, "{:#04x}u8", b),
+        }
+    }
+}
+
+pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {}
+pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {}
+
+impl Def for ! {}
+impl Ref for ! {}
+
+#[cfg(feature = "rustc")]
+pub(crate) mod rustc {
+    use rustc_middle::mir::Mutability;
+    use rustc_middle::ty;
+    use rustc_middle::ty::Region;
+    use rustc_middle::ty::Ty;
+
+    /// A reference in the layout.
+    #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)]
+    pub struct Ref<'tcx> {
+        lifetime: Region<'tcx>,
+        ty: Ty<'tcx>,
+        mutability: Mutability,
+    }
+
+    impl<'tcx> super::Ref for Ref<'tcx> {}
+
+    impl<'tcx> Ref<'tcx> {
+        pub fn min_align(&self) -> usize {
+            todo!()
+        }
+    }
+
+    /// A visibility node in the layout.
+    #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
+    pub enum Def<'tcx> {
+        Adt(ty::AdtDef<'tcx>),
+        Variant(&'tcx ty::VariantDef),
+        Field(&'tcx ty::FieldDef),
+        Primitive,
+    }
+
+    impl<'tcx> super::Def for Def<'tcx> {}
+}
diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs
new file mode 100644
index 00000000000..f25e3c1fd8a
--- /dev/null
+++ b/compiler/rustc_transmute/src/layout/nfa.rs
@@ -0,0 +1,179 @@
+use super::{Byte, Ref, Tree, Uninhabited};
+use crate::{Map, Set};
+use std::fmt;
+use std::sync::atomic::{AtomicU32, Ordering};
+
+/// A non-deterministic finite automaton (NFA) that represents the layout of a type.
+/// The transmutability of two given types is computed by comparing their `Nfa`s.
+#[derive(PartialEq, Debug)]
+pub(crate) struct Nfa<R>
+where
+    R: Ref,
+{
+    pub(crate) transitions: Map<State, Map<Transition<R>, Set<State>>>,
+    pub(crate) start: State,
+    pub(crate) accepting: State,
+}
+
+/// The states in a `Nfa` represent byte offsets.
+#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
+pub(crate) struct State(u32);
+
+/// The transitions between states in a `Nfa` reflect bit validity.
+#[derive(Hash, Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Transition<R>
+where
+    R: Ref,
+{
+    Byte(Byte),
+    Ref(R),
+}
+
+impl fmt::Debug for State {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "S_{}", self.0)
+    }
+}
+
+impl<R> fmt::Debug for Transition<R>
+where
+    R: Ref,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match &self {
+            Self::Byte(b) => b.fmt(f),
+            Self::Ref(r) => r.fmt(f),
+        }
+    }
+}
+
+impl<R> Nfa<R>
+where
+    R: Ref,
+{
+    pub(crate) fn unit() -> Self {
+        let transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
+        let start = State::new();
+        let accepting = start;
+
+        Nfa { transitions, start, accepting }
+    }
+
+    pub(crate) fn from_byte(byte: Byte) -> Self {
+        let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
+        let start = State::new();
+        let accepting = State::new();
+
+        let source = transitions.entry(start).or_default();
+        let edge = source.entry(Transition::Byte(byte)).or_default();
+        edge.insert(accepting);
+
+        Nfa { transitions, start, accepting }
+    }
+
+    pub(crate) fn from_ref(r: R) -> Self {
+        let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
+        let start = State::new();
+        let accepting = State::new();
+
+        let source = transitions.entry(start).or_default();
+        let edge = source.entry(Transition::Ref(r)).or_default();
+        edge.insert(accepting);
+
+        Nfa { transitions, start, accepting }
+    }
+
+    pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
+        Ok(match tree {
+            Tree::Byte(b) => Self::from_byte(b),
+            Tree::Def(..) => unreachable!(),
+            Tree::Ref(r) => Self::from_ref(r),
+            Tree::Alt(alts) => {
+                let mut alts = alts.into_iter().map(Self::from_tree);
+                let mut nfa = alts.next().ok_or(Uninhabited)??;
+                for alt in alts {
+                    nfa = nfa.union(alt?);
+                }
+                nfa
+            }
+            Tree::Seq(elts) => {
+                let mut nfa = Self::unit();
+                for elt in elts.into_iter().map(Self::from_tree) {
+                    nfa = nfa.concat(elt?);
+                }
+                nfa
+            }
+        })
+    }
+
+    /// Concatenate two `Nfa`s.
+    pub(crate) fn concat(self, other: Self) -> Self {
+        if self.start == self.accepting {
+            return other;
+        } else if other.start == other.accepting {
+            return self;
+        }
+
+        let start = self.start;
+        let accepting = other.accepting;
+
+        let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions;
+
+        // the iteration order doesn't matter
+        #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
+        for (source, transition) in other.transitions {
+            let fix_state = |state| if state == other.start { self.accepting } else { state };
+            let entry = transitions.entry(fix_state(source)).or_default();
+            for (edge, destinations) in transition {
+                let entry = entry.entry(edge.clone()).or_default();
+                for destination in destinations {
+                    entry.insert(fix_state(destination));
+                }
+            }
+        }
+
+        Self { transitions, start, accepting }
+    }
+
+    /// Compute the union of two `Nfa`s.
+    pub(crate) fn union(self, other: Self) -> Self {
+        let start = self.start;
+        let accepting = self.accepting;
+
+        let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions.clone();
+
+        // the iteration order doesn't matter
+        #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
+        for (&(mut source), transition) in other.transitions.iter() {
+            // if source is starting state of `other`, replace with starting state of `self`
+            if source == other.start {
+                source = self.start;
+            }
+            let entry = transitions.entry(source).or_default();
+            for (edge, destinations) in transition {
+                let entry = entry.entry(edge.clone()).or_default();
+                // the iteration order doesn't matter
+                #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
+                for &(mut destination) in destinations {
+                    // if dest is accepting state of `other`, replace with accepting state of `self`
+                    if destination == other.accepting {
+                        destination = self.accepting;
+                    }
+                    entry.insert(destination);
+                }
+            }
+        }
+        Self { transitions, start, accepting }
+    }
+
+    pub(crate) fn edges_from(&self, start: State) -> Option<&Map<Transition<R>, Set<State>>> {
+        self.transitions.get(&start)
+    }
+}
+
+impl State {
+    pub(crate) fn new() -> Self {
+        static COUNTER: AtomicU32 = AtomicU32::new(0);
+        Self(COUNTER.fetch_add(1, Ordering::SeqCst))
+    }
+}
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
new file mode 100644
index 00000000000..70b3ba02b05
--- /dev/null
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -0,0 +1,471 @@
+use super::{Byte, Def, Ref};
+
+#[cfg(test)]
+mod tests;
+
+/// A tree-based representation of a type layout.
+///
+/// Invariants:
+/// 1. All paths through the layout have the same length (in bytes).
+///
+/// Nice-to-haves:
+/// 1. An `Alt` is never directly nested beneath another `Alt`.
+/// 2. A `Seq` is never directly nested beneath another `Seq`.
+/// 3. `Seq`s and `Alt`s with a single member do not exist.
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub(crate) enum Tree<D, R>
+where
+    D: Def,
+    R: Ref,
+{
+    /// A sequence of successive layouts.
+    Seq(Vec<Self>),
+    /// A choice between alternative layouts.
+    Alt(Vec<Self>),
+    /// A definition node.
+    Def(D),
+    /// A reference node.
+    Ref(R),
+    /// A byte node.
+    Byte(Byte),
+}
+
+impl<D, R> Tree<D, R>
+where
+    D: Def,
+    R: Ref,
+{
+    /// A `Tree` consisting only of a definition node.
+    pub(crate) fn def(def: D) -> Self {
+        Self::Def(def)
+    }
+
+    /// A `Tree` representing an uninhabited type.
+    pub(crate) fn uninhabited() -> Self {
+        Self::Alt(vec![])
+    }
+
+    /// A `Tree` representing a zero-sized type.
+    pub(crate) fn unit() -> Self {
+        Self::Seq(Vec::new())
+    }
+
+    /// A `Tree` containing a single, uninitialized byte.
+    pub(crate) fn uninit() -> Self {
+        Self::Byte(Byte::Uninit)
+    }
+
+    /// A `Tree` representing the layout of `bool`.
+    pub(crate) fn bool() -> Self {
+        Self::from_bits(0x00).or(Self::from_bits(0x01))
+    }
+
+    /// A `Tree` whose layout matches that of a `u8`.
+    pub(crate) fn u8() -> Self {
+        Self::Alt((0u8..=255).map(Self::from_bits).collect())
+    }
+
+    /// A `Tree` whose layout accepts exactly the given bit pattern.
+    pub(crate) fn from_bits(bits: u8) -> Self {
+        Self::Byte(Byte::Init(bits))
+    }
+
+    /// A `Tree` whose layout is a number of the given width.
+    pub(crate) fn number(width_in_bytes: usize) -> Self {
+        Self::Seq(vec![Self::u8(); width_in_bytes])
+    }
+
+    /// A `Tree` whose layout is entirely padding of the given width.
+    pub(crate) fn padding(width_in_bytes: usize) -> Self {
+        Self::Seq(vec![Self::uninit(); width_in_bytes])
+    }
+
+    /// Remove all `Def` nodes, and all branches of the layout for which `f` produces false.
+    pub(crate) fn prune<F>(self, f: &F) -> Tree<!, R>
+    where
+        F: Fn(D) -> bool,
+    {
+        match self {
+            Self::Seq(elts) => elts
+                .into_iter()
+                .map(|elt| elt.prune(f))
+                .try_fold(Tree::unit(), |elts, elt| {
+                    if elt == Tree::uninhabited() {
+                        Err(Tree::uninhabited())
+                    } else {
+                        Ok(elts.then(elt))
+                    }
+                })
+                .into_ok_or_err(),
+            Self::Alt(alts) => alts
+                .into_iter()
+                .map(|alt| alt.prune(f))
+                .fold(Tree::uninhabited(), |alts, alt| alts.or(alt)),
+            Self::Byte(b) => Tree::Byte(b),
+            Self::Ref(r) => Tree::Ref(r),
+            Self::Def(d) => {
+                if !f(d) {
+                    Tree::uninhabited()
+                } else {
+                    Tree::unit()
+                }
+            }
+        }
+    }
+
+    /// Produces `true` if `Tree` is an inhabited type; otherwise false.
+    pub(crate) fn is_inhabited(&self) -> bool {
+        match self {
+            Self::Seq(elts) => elts.into_iter().all(|elt| elt.is_inhabited()),
+            Self::Alt(alts) => alts.into_iter().any(|alt| alt.is_inhabited()),
+            Self::Byte(..) | Self::Ref(..) | Self::Def(..) => true,
+        }
+    }
+}
+
+impl<D, R> Tree<D, R>
+where
+    D: Def,
+    R: Ref,
+{
+    /// Produces a new `Tree` where `other` is sequenced after `self`.
+    pub(crate) fn then(self, other: Self) -> Self {
+        match (self, other) {
+            (Self::Seq(elts), other) | (other, Self::Seq(elts)) if elts.len() == 0 => other,
+            (Self::Seq(mut lhs), Self::Seq(mut rhs)) => {
+                lhs.append(&mut rhs);
+                Self::Seq(lhs)
+            }
+            (Self::Seq(mut lhs), rhs) => {
+                lhs.push(rhs);
+                Self::Seq(lhs)
+            }
+            (lhs, Self::Seq(mut rhs)) => {
+                rhs.insert(0, lhs);
+                Self::Seq(rhs)
+            }
+            (lhs, rhs) => Self::Seq(vec![lhs, rhs]),
+        }
+    }
+
+    /// Produces a new `Tree` accepting either `self` or `other` as alternative layouts.
+    pub(crate) fn or(self, other: Self) -> Self {
+        match (self, other) {
+            (Self::Alt(alts), other) | (other, Self::Alt(alts)) if alts.len() == 0 => other,
+            (Self::Alt(mut lhs), Self::Alt(rhs)) => {
+                lhs.extend(rhs);
+                Self::Alt(lhs)
+            }
+            (Self::Alt(mut alts), alt) | (alt, Self::Alt(mut alts)) => {
+                alts.push(alt);
+                Self::Alt(alts)
+            }
+            (lhs, rhs) => Self::Alt(vec![lhs, rhs]),
+        }
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum Err {
+    /// The layout of the type is unspecified.
+    Unspecified,
+    /// This error will be surfaced elsewhere by rustc, so don't surface it.
+    Unknown,
+}
+
+#[cfg(feature = "rustc")]
+pub(crate) mod rustc {
+    use super::{Err, Tree};
+    use crate::layout::rustc::{Def, Ref};
+
+    use rustc_middle::ty;
+    use rustc_middle::ty::layout::LayoutError;
+    use rustc_middle::ty::util::Discr;
+    use rustc_middle::ty::AdtDef;
+    use rustc_middle::ty::ParamEnv;
+    use rustc_middle::ty::SubstsRef;
+    use rustc_middle::ty::Ty;
+    use rustc_middle::ty::TyCtxt;
+    use rustc_middle::ty::VariantDef;
+    use rustc_target::abi::Align;
+    use std::alloc;
+
+    impl<'tcx> From<LayoutError<'tcx>> for Err {
+        fn from(err: LayoutError<'tcx>) -> Self {
+            match err {
+                LayoutError::Unknown(..) => Self::Unknown,
+                err @ _ => unimplemented!("{:?}", err),
+            }
+        }
+    }
+
+    trait LayoutExt {
+        fn clamp_align(&self, min_align: Align, max_align: Align) -> Self;
+    }
+
+    impl LayoutExt for alloc::Layout {
+        fn clamp_align(&self, min_align: Align, max_align: Align) -> Self {
+            let min_align = min_align.bytes().try_into().unwrap();
+            let max_align = max_align.bytes().try_into().unwrap();
+            Self::from_size_align(self.size(), self.align().clamp(min_align, max_align)).unwrap()
+        }
+    }
+
+    struct LayoutSummary {
+        total_align: Align,
+        total_size: usize,
+        discriminant_size: usize,
+        discriminant_align: Align,
+    }
+
+    impl LayoutSummary {
+        fn from_ty<'tcx>(ty: Ty<'tcx>, ctx: TyCtxt<'tcx>) -> Result<Self, LayoutError<'tcx>> {
+            use rustc_middle::ty::ParamEnvAnd;
+            use rustc_target::abi::{TyAndLayout, Variants};
+
+            let param_env = ParamEnv::reveal_all();
+            let param_env_and_type = ParamEnvAnd { param_env, value: ty };
+            let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?;
+
+            let total_size: usize = layout.size().bytes_usize();
+            let total_align: Align = layout.align().abi;
+            let discriminant_align: Align;
+            let discriminant_size: usize;
+
+            if let Variants::Multiple { tag, .. } = layout.variants() {
+                discriminant_align = tag.align(&ctx).abi;
+                discriminant_size = tag.size(&ctx).bytes_usize();
+            } else {
+                discriminant_align = Align::ONE;
+                discriminant_size = 0;
+            };
+
+            Ok(Self { total_align, total_size, discriminant_align, discriminant_size })
+        }
+
+        fn into(&self) -> alloc::Layout {
+            alloc::Layout::from_size_align(
+                self.total_size,
+                self.total_align.bytes().try_into().unwrap(),
+            )
+            .unwrap()
+        }
+    }
+
+    impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
+        pub fn from_ty(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Result<Self, Err> {
+            use rustc_middle::ty::FloatTy::*;
+            use rustc_middle::ty::IntTy::*;
+            use rustc_middle::ty::UintTy::*;
+            use rustc_target::abi::HasDataLayout;
+
+            let target = tcx.data_layout();
+
+            match ty.kind() {
+                ty::Bool => Ok(Self::bool()),
+
+                ty::Int(I8) | ty::Uint(U8) => Ok(Self::u8()),
+                ty::Int(I16) | ty::Uint(U16) => Ok(Self::number(2)),
+                ty::Int(I32) | ty::Uint(U32) | ty::Float(F32) => Ok(Self::number(4)),
+                ty::Int(I64) | ty::Uint(U64) | ty::Float(F64) => Ok(Self::number(8)),
+                ty::Int(I128) | ty::Uint(U128) => Ok(Self::number(16)),
+                ty::Int(Isize) | ty::Uint(Usize) => {
+                    Ok(Self::number(target.pointer_size.bytes_usize()))
+                }
+
+                ty::Tuple(members) => {
+                    if members.len() == 0 {
+                        Ok(Tree::unit())
+                    } else {
+                        Err(Err::Unspecified)
+                    }
+                }
+
+                ty::Array(ty, len) => {
+                    let len = len.try_eval_usize(tcx, ParamEnv::reveal_all()).unwrap();
+                    let elt = Tree::from_ty(*ty, tcx)?;
+                    Ok(std::iter::repeat(elt)
+                        .take(len as usize)
+                        .fold(Tree::unit(), |tree, elt| tree.then(elt)))
+                }
+
+                ty::Adt(adt_def, substs_ref) => {
+                    use rustc_middle::ty::AdtKind;
+
+                    // If the layout is ill-specified, halt.
+                    if !(adt_def.repr().c() || adt_def.repr().int.is_some()) {
+                        return Err(Err::Unspecified);
+                    }
+
+                    // Compute a summary of the type's layout.
+                    let layout_summary = LayoutSummary::from_ty(ty, tcx)?;
+
+                    // The layout begins with this adt's visibility.
+                    let vis = Self::def(Def::Adt(*adt_def));
+
+                    // And is followed the layout(s) of its variants
+                    Ok(vis.then(match adt_def.adt_kind() {
+                        AdtKind::Struct => Self::from_repr_c_variant(
+                            ty,
+                            *adt_def,
+                            substs_ref,
+                            &layout_summary,
+                            None,
+                            adt_def.non_enum_variant(),
+                            tcx,
+                        )?,
+                        AdtKind::Enum => {
+                            tracing::trace!(?adt_def, "treeifying enum");
+                            let mut tree = Tree::uninhabited();
+
+                            for (idx, discr) in adt_def.discriminants(tcx) {
+                                tree = tree.or(Self::from_repr_c_variant(
+                                    ty,
+                                    *adt_def,
+                                    substs_ref,
+                                    &layout_summary,
+                                    Some(discr),
+                                    adt_def.variant(idx),
+                                    tcx,
+                                )?);
+                            }
+
+                            tree
+                        }
+                        AdtKind::Union => {
+                            // is the layout well-defined?
+                            if !adt_def.repr().c() {
+                                return Err(Err::Unspecified);
+                            }
+
+                            let ty_layout = layout_of(tcx, ty)?;
+
+                            let mut tree = Tree::uninhabited();
+
+                            for field in adt_def.all_fields() {
+                                let variant_ty = field.ty(tcx, substs_ref);
+                                let variant_layout = layout_of(tcx, variant_ty)?;
+                                let padding_needed = ty_layout.size() - variant_layout.size();
+                                let variant = Self::def(Def::Field(field))
+                                    .then(Self::from_ty(variant_ty, tcx)?)
+                                    .then(Self::padding(padding_needed));
+
+                                tree = tree.or(variant);
+                            }
+
+                            tree
+                        }
+                    }))
+                }
+                _ => Err(Err::Unspecified),
+            }
+        }
+
+        fn from_repr_c_variant(
+            ty: Ty<'tcx>,
+            adt_def: AdtDef<'tcx>,
+            substs_ref: SubstsRef<'tcx>,
+            layout_summary: &LayoutSummary,
+            discr: Option<Discr<'tcx>>,
+            variant_def: &'tcx VariantDef,
+            tcx: TyCtxt<'tcx>,
+        ) -> Result<Self, Err> {
+            let mut tree = Tree::unit();
+
+            let repr = adt_def.repr();
+            let min_align = repr.align.unwrap_or(Align::ONE);
+            let max_align = repr.pack.unwrap_or(Align::MAX);
+
+            let clamp =
+                |align: Align| align.clamp(min_align, max_align).bytes().try_into().unwrap();
+
+            let variant_span = tracing::trace_span!(
+                "treeifying variant",
+                min_align = ?min_align,
+                max_align = ?max_align,
+            )
+            .entered();
+
+            let mut variant_layout = alloc::Layout::from_size_align(
+                0,
+                layout_summary.total_align.bytes().try_into().unwrap(),
+            )
+            .unwrap();
+
+            // The layout of the variant is prefixed by the discriminant, if any.
+            if let Some(discr) = discr {
+                tracing::trace!(?discr, "treeifying discriminant");
+                let discr_layout = alloc::Layout::from_size_align(
+                    layout_summary.discriminant_size,
+                    clamp(layout_summary.discriminant_align),
+                )
+                .unwrap();
+                tracing::trace!(?discr_layout, "computed discriminant layout");
+                variant_layout = variant_layout.extend(discr_layout).unwrap().0;
+                tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size));
+            }
+
+            // Next come fields.
+            let fields_span = tracing::trace_span!("treeifying fields").entered();
+            for field_def in variant_def.fields.iter() {
+                let field_ty = field_def.ty(tcx, substs_ref);
+                let _span = tracing::trace_span!("treeifying field", field = ?field_ty).entered();
+
+                // begin with the field's visibility
+                tree = tree.then(Self::def(Def::Field(field_def)));
+
+                // compute the field's layout charactaristics
+                let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align);
+
+                // next comes the field's padding
+                let padding_needed = variant_layout.padding_needed_for(field_layout.align());
+                if padding_needed > 0 {
+                    tree = tree.then(Self::padding(padding_needed));
+                }
+
+                // finally, the field's layout
+                tree = tree.then(Self::from_ty(field_ty, tcx)?);
+
+                // extend the variant layout with the field layout
+                variant_layout = variant_layout.extend(field_layout).unwrap().0;
+            }
+            drop(fields_span);
+
+            // finally: padding
+            let padding_span = tracing::trace_span!("adding trailing padding").entered();
+            let padding_needed = layout_summary.total_size - variant_layout.size();
+            if padding_needed > 0 {
+                tree = tree.then(Self::padding(padding_needed));
+            };
+            drop(padding_span);
+            drop(variant_span);
+            Ok(tree)
+        }
+
+        pub fn from_disr(discr: Discr<'tcx>, tcx: TyCtxt<'tcx>, size: usize) -> Self {
+            // FIXME(@jswrenn): I'm certain this is missing needed endian nuance.
+            let bytes = discr.val.to_ne_bytes();
+            let bytes = &bytes[..size];
+            Self::Seq(bytes.into_iter().copied().map(|b| Self::from_bits(b)).collect())
+        }
+    }
+
+    fn layout_of<'tcx>(
+        ctx: TyCtxt<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Result<alloc::Layout, LayoutError<'tcx>> {
+        use rustc_middle::ty::ParamEnvAnd;
+        use rustc_target::abi::TyAndLayout;
+
+        let param_env = ParamEnv::reveal_all();
+        let param_env_and_type = ParamEnvAnd { param_env, value: ty };
+        let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?;
+        let layout = alloc::Layout::from_size_align(
+            layout.size().bytes_usize(),
+            layout.align().abi.bytes().try_into().unwrap(),
+        )
+        .unwrap();
+        tracing::trace!(?ty, ?layout, "computed layout for type");
+        Ok(layout)
+    }
+}
diff --git a/compiler/rustc_transmute/src/layout/tree/tests.rs b/compiler/rustc_transmute/src/layout/tree/tests.rs
new file mode 100644
index 00000000000..90515e92f7a
--- /dev/null
+++ b/compiler/rustc_transmute/src/layout/tree/tests.rs
@@ -0,0 +1,80 @@
+use super::Tree;
+
+#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
+pub enum Def {
+    Visible,
+    Invisible,
+}
+
+impl super::Def for Def {}
+
+mod prune {
+    use super::*;
+
+    mod should_simplify {
+        use super::*;
+
+        #[test]
+        fn seq_1() {
+            let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::from_bits(0x00));
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00));
+        }
+
+        #[test]
+        fn seq_2() {
+            let layout: Tree<Def, !> =
+                Tree::from_bits(0x00).then(Tree::def(Def::Visible)).then(Tree::from_bits(0x01));
+
+            assert_eq!(
+                layout.prune(&|d| matches!(d, Def::Visible)),
+                Tree::from_bits(0x00).then(Tree::from_bits(0x01))
+            );
+        }
+    }
+
+    mod should_reject {
+        use super::*;
+
+        #[test]
+        fn invisible_def() {
+            let layout: Tree<Def, !> = Tree::def(Def::Invisible);
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
+        }
+
+        #[test]
+        fn invisible_def_in_seq_len_2() {
+            let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::def(Def::Invisible));
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
+        }
+
+        #[test]
+        fn invisible_def_in_seq_len_3() {
+            let layout: Tree<Def, !> =
+                Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Invisible));
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
+        }
+    }
+
+    mod should_accept {
+        use super::*;
+
+        #[test]
+        fn visible_def() {
+            let layout: Tree<Def, !> = Tree::def(Def::Visible);
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit());
+        }
+
+        #[test]
+        fn visible_def_in_seq_len_2() {
+            let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::def(Def::Visible));
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit());
+        }
+
+        #[test]
+        fn visible_def_in_seq_len_3() {
+            let layout: Tree<Def, !> =
+                Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Visible));
+            assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00));
+        }
+    }
+}
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
new file mode 100644
index 00000000000..cfc7c752a6b
--- /dev/null
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -0,0 +1,117 @@
+#![feature(
+    alloc_layout_extra,
+    control_flow_enum,
+    decl_macro,
+    iterator_try_reduce,
+    never_type,
+    result_into_ok_or_err
+)]
+#![allow(dead_code, unused_variables)]
+
+#[macro_use]
+extern crate tracing;
+
+#[cfg(feature = "rustc")]
+pub(crate) use rustc_data_structures::fx::{FxHashMap as Map, FxHashSet as Set};
+
+#[cfg(not(feature = "rustc"))]
+pub(crate) use std::collections::{HashMap as Map, HashSet as Set};
+
+pub(crate) mod layout;
+pub(crate) mod maybe_transmutable;
+
+#[derive(Default)]
+pub struct Assume {
+    pub alignment: bool,
+    pub lifetimes: bool,
+    pub validity: bool,
+    pub visibility: bool,
+}
+
+/// The type encodes answers to the question: "Are these types transmutable?"
+#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
+pub enum Answer<R>
+where
+    R: layout::Ref,
+{
+    /// `Src` is transmutable into `Dst`.
+    Yes,
+
+    /// `Src` is NOT transmutable into `Dst`.
+    No(Reason),
+
+    /// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`.
+    IfTransmutable { src: R, dst: R },
+
+    /// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
+    IfAll(Vec<Answer<R>>),
+
+    /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
+    IfAny(Vec<Answer<R>>),
+}
+
+/// Answers: Why wasn't the source type transmutable into the destination type?
+#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
+pub enum Reason {
+    /// The layout of the source type is unspecified.
+    SrcIsUnspecified,
+    /// The layout of the destination type is unspecified.
+    DstIsUnspecified,
+    /// The layout of the destination type is bit-incompatible with the source type.
+    DstIsBitIncompatible,
+    /// There aren't any public constructors for `Dst`.
+    DstIsPrivate,
+    /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
+    DstIsTooBig,
+}
+
+#[cfg(feature = "rustc")]
+mod rustc {
+    use rustc_infer::infer::InferCtxt;
+    use rustc_macros::{TypeFoldable, TypeVisitable};
+    use rustc_middle::traits::ObligationCause;
+    use rustc_middle::ty::Binder;
+    use rustc_middle::ty::Ty;
+
+    /// The source and destination types of a transmutation.
+    #[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)]
+    pub struct Types<'tcx> {
+        /// The source type.
+        pub src: Ty<'tcx>,
+        /// The destination type.
+        pub dst: Ty<'tcx>,
+    }
+
+    pub struct TransmuteTypeEnv<'cx, 'tcx> {
+        infcx: &'cx InferCtxt<'cx, 'tcx>,
+    }
+
+    impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> {
+        pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> Self {
+            Self { infcx }
+        }
+
+        #[allow(unused)]
+        pub fn is_transmutable(
+            &mut self,
+            cause: ObligationCause<'tcx>,
+            src_and_dst: Binder<'tcx, Types<'tcx>>,
+            scope: Ty<'tcx>,
+            assume: crate::Assume,
+        ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
+            let src = src_and_dst.map_bound(|types| types.src).skip_binder();
+            let dst = src_and_dst.map_bound(|types| types.dst).skip_binder();
+            crate::maybe_transmutable::MaybeTransmutableQuery::new(
+                src,
+                dst,
+                scope,
+                assume,
+                self.infcx.tcx,
+            )
+            .answer()
+        }
+    }
+}
+
+#[cfg(feature = "rustc")]
+pub use rustc::*;
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
new file mode 100644
index 00000000000..076d922d1b7
--- /dev/null
+++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
@@ -0,0 +1,320 @@
+use crate::Map;
+use crate::{Answer, Reason};
+
+#[cfg(test)]
+mod tests;
+
+mod query_context;
+use query_context::QueryContext;
+
+use crate::layout::{self, dfa, Byte, Dfa, Nfa, Tree, Uninhabited};
+pub(crate) struct MaybeTransmutableQuery<L, C>
+where
+    C: QueryContext,
+{
+    src: L,
+    dst: L,
+    scope: <C as QueryContext>::Scope,
+    assume: crate::Assume,
+    context: C,
+}
+
+impl<L, C> MaybeTransmutableQuery<L, C>
+where
+    C: QueryContext,
+{
+    pub(crate) fn new(
+        src: L,
+        dst: L,
+        scope: <C as QueryContext>::Scope,
+        assume: crate::Assume,
+        context: C,
+    ) -> Self {
+        Self { src, dst, scope, assume, context }
+    }
+
+    pub(crate) fn map_layouts<F, M>(
+        self,
+        f: F,
+    ) -> Result<MaybeTransmutableQuery<M, C>, Answer<<C as QueryContext>::Ref>>
+    where
+        F: FnOnce(
+            L,
+            L,
+            <C as QueryContext>::Scope,
+            &C,
+        ) -> Result<(M, M), Answer<<C as QueryContext>::Ref>>,
+    {
+        let Self { src, dst, scope, assume, context } = self;
+
+        let (src, dst) = f(src, dst, scope, &context)?;
+
+        Ok(MaybeTransmutableQuery { src, dst, scope, assume, context })
+    }
+}
+
+#[cfg(feature = "rustc")]
+mod rustc {
+    use super::*;
+    use crate::layout::tree::Err;
+
+    use rustc_middle::ty::Ty;
+    use rustc_middle::ty::TyCtxt;
+
+    impl<'tcx> MaybeTransmutableQuery<Ty<'tcx>, TyCtxt<'tcx>> {
+        /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s,
+        /// then computes an answer using those trees.
+        #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
+        pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
+            let query_or_answer = self.map_layouts(|src, dst, scope, &context| {
+                // Convert `src` and `dst` from their rustc representations, to `Tree`-based
+                // representations. If these conversions fail, conclude that the transmutation is
+                // unacceptable; the layouts of both the source and destination types must be
+                // well-defined.
+                let src = Tree::from_ty(src, context).map_err(|err| match err {
+                    // Answer `Yes` here, because "Unknown Type" will already be reported by
+                    // rustc. No need to spam the user with more errors.
+                    Err::Unknown => Answer::Yes,
+                    Err::Unspecified => Answer::No(Reason::SrcIsUnspecified),
+                })?;
+
+                let dst = Tree::from_ty(dst, context).map_err(|err| match err {
+                    Err::Unknown => Answer::Yes,
+                    Err::Unspecified => Answer::No(Reason::DstIsUnspecified),
+                })?;
+
+                Ok((src, dst))
+            });
+
+            match query_or_answer {
+                Ok(query) => query.answer(),
+                Err(answer) => answer,
+            }
+        }
+    }
+}
+
+impl<C> MaybeTransmutableQuery<Tree<<C as QueryContext>::Def, <C as QueryContext>::Ref>, C>
+where
+    C: QueryContext,
+{
+    /// Answers whether a `Tree` is transmutable into another `Tree`.
+    ///
+    /// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`,
+    /// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs.
+    #[inline(always)]
+    #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
+    pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
+        let assume_visibility = self.assume.visibility;
+        let query_or_answer = self.map_layouts(|src, dst, scope, context| {
+            // Remove all `Def` nodes from `src`, without checking their visibility.
+            let src = src.prune(&|def| true);
+
+            tracing::trace!(?src, "pruned src");
+
+            // Remove all `Def` nodes from `dst`, additionally...
+            let dst = if assume_visibility {
+                // ...if visibility is assumed, don't check their visibility.
+                dst.prune(&|def| true)
+            } else {
+                // ...otherwise, prune away all unreachable paths through the `Dst` layout.
+                dst.prune(&|def| context.is_accessible_from(def, scope))
+            };
+
+            tracing::trace!(?dst, "pruned dst");
+
+            // Convert `src` from a tree-based representation to an NFA-based representation.
+            // If the conversion fails because `src` is uninhabited, conclude that the transmutation
+            // is acceptable, because instances of the `src` type do not exist.
+            let src = Nfa::from_tree(src).map_err(|Uninhabited| Answer::Yes)?;
+
+            // Convert `dst` from a tree-based representation to an NFA-based representation.
+            // If the conversion fails because `src` is uninhabited, conclude that the transmutation
+            // is unacceptable, because instances of the `dst` type do not exist.
+            let dst =
+                Nfa::from_tree(dst).map_err(|Uninhabited| Answer::No(Reason::DstIsPrivate))?;
+
+            Ok((src, dst))
+        });
+
+        match query_or_answer {
+            Ok(query) => query.answer(),
+            Err(answer) => answer,
+        }
+    }
+}
+
+impl<C> MaybeTransmutableQuery<Nfa<<C as QueryContext>::Ref>, C>
+where
+    C: QueryContext,
+{
+    /// Answers whether a `Nfa` is transmutable into another `Nfa`.
+    ///
+    /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs.
+    #[inline(always)]
+    #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
+    pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
+        let query_or_answer = self
+            .map_layouts(|src, dst, scope, context| Ok((Dfa::from_nfa(src), Dfa::from_nfa(dst))));
+
+        match query_or_answer {
+            Ok(query) => query.answer(),
+            Err(answer) => answer,
+        }
+    }
+}
+
+impl<C> MaybeTransmutableQuery<Dfa<<C as QueryContext>::Ref>, C>
+where
+    C: QueryContext,
+{
+    /// Answers whether a `Nfa` is transmutable into another `Nfa`.
+    ///
+    /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs.
+    pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
+        MaybeTransmutableQuery {
+            src: &self.src,
+            dst: &self.dst,
+            scope: self.scope,
+            assume: self.assume,
+            context: self.context,
+        }
+        .answer()
+    }
+}
+
+impl<'l, C> MaybeTransmutableQuery<&'l Dfa<<C as QueryContext>::Ref>, C>
+where
+    C: QueryContext,
+{
+    pub(crate) fn answer(&mut self) -> Answer<<C as QueryContext>::Ref> {
+        self.answer_memo(&mut Map::default(), self.src.start, self.dst.start)
+    }
+
+    #[inline(always)]
+    #[instrument(level = "debug", skip(self))]
+    fn answer_memo(
+        &self,
+        cache: &mut Map<(dfa::State, dfa::State), Answer<<C as QueryContext>::Ref>>,
+        src_state: dfa::State,
+        dst_state: dfa::State,
+    ) -> Answer<<C as QueryContext>::Ref> {
+        if let Some(answer) = cache.get(&(src_state, dst_state)) {
+            answer.clone()
+        } else {
+            let answer = if dst_state == self.dst.accepting {
+                // truncation: `size_of(Src) >= size_of(Dst)`
+                Answer::Yes
+            } else if src_state == self.src.accepting {
+                // extension: `size_of(Src) >= size_of(Dst)`
+                if let Some(dst_state_prime) = self.dst.byte_from(dst_state, Byte::Uninit) {
+                    self.answer_memo(cache, src_state, dst_state_prime)
+                } else {
+                    Answer::No(Reason::DstIsTooBig)
+                }
+            } else {
+                let src_quantification = if self.assume.validity {
+                    // if the compiler may assume that the programmer is doing additional validity checks,
+                    // (e.g.: that `src != 3u8` when the destination type is `bool`)
+                    // then there must exist at least one transition out of `src_state` such that the transmute is viable...
+                    there_exists
+                } else {
+                    // if the compiler cannot assume that the programmer is doing additional validity checks,
+                    // then for all transitions out of `src_state`, such that the transmute is viable...
+                    // then there must exist at least one transition out of `src_state` such that the transmute is viable...
+                    for_all
+                };
+
+                src_quantification(
+                    self.src.bytes_from(src_state).unwrap_or(&Map::default()),
+                    |(&src_validity, &src_state_prime)| {
+                        if let Some(dst_state_prime) = self.dst.byte_from(dst_state, src_validity) {
+                            self.answer_memo(cache, src_state_prime, dst_state_prime)
+                        } else if let Some(dst_state_prime) =
+                            self.dst.byte_from(dst_state, Byte::Uninit)
+                        {
+                            self.answer_memo(cache, src_state_prime, dst_state_prime)
+                        } else {
+                            Answer::No(Reason::DstIsBitIncompatible)
+                        }
+                    },
+                )
+            };
+            cache.insert((src_state, dst_state), answer.clone());
+            answer
+        }
+    }
+}
+
+impl<R> Answer<R>
+where
+    R: layout::Ref,
+{
+    pub(crate) fn and(self, rhs: Self) -> Self {
+        match (self, rhs) {
+            (Self::No(reason), _) | (_, Self::No(reason)) => Self::No(reason),
+            (Self::Yes, Self::Yes) => Self::Yes,
+            (Self::IfAll(mut lhs), Self::IfAll(ref mut rhs)) => {
+                lhs.append(rhs);
+                Self::IfAll(lhs)
+            }
+            (constraint, Self::IfAll(mut constraints))
+            | (Self::IfAll(mut constraints), constraint) => {
+                constraints.push(constraint);
+                Self::IfAll(constraints)
+            }
+            (lhs, rhs) => Self::IfAll(vec![lhs, rhs]),
+        }
+    }
+
+    pub(crate) fn or(self, rhs: Self) -> Self {
+        match (self, rhs) {
+            (Self::Yes, _) | (_, Self::Yes) => Self::Yes,
+            (Self::No(lhr), Self::No(rhr)) => Self::No(lhr),
+            (Self::IfAny(mut lhs), Self::IfAny(ref mut rhs)) => {
+                lhs.append(rhs);
+                Self::IfAny(lhs)
+            }
+            (constraint, Self::IfAny(mut constraints))
+            | (Self::IfAny(mut constraints), constraint) => {
+                constraints.push(constraint);
+                Self::IfAny(constraints)
+            }
+            (lhs, rhs) => Self::IfAny(vec![lhs, rhs]),
+        }
+    }
+}
+
+pub fn for_all<R, I, F>(iter: I, f: F) -> Answer<R>
+where
+    R: layout::Ref,
+    I: IntoIterator,
+    F: FnMut(<I as IntoIterator>::Item) -> Answer<R>,
+{
+    use std::ops::ControlFlow::{Break, Continue};
+    let (Continue(result) | Break(result)) =
+        iter.into_iter().map(f).try_fold(Answer::Yes, |constraints, constraint| {
+            match constraint.and(constraints) {
+                Answer::No(reason) => Break(Answer::No(reason)),
+                maybe => Continue(maybe),
+            }
+        });
+    result
+}
+
+pub fn there_exists<R, I, F>(iter: I, f: F) -> Answer<R>
+where
+    R: layout::Ref,
+    I: IntoIterator,
+    F: FnMut(<I as IntoIterator>::Item) -> Answer<R>,
+{
+    use std::ops::ControlFlow::{Break, Continue};
+    let (Continue(result) | Break(result)) = iter.into_iter().map(f).try_fold(
+        Answer::No(Reason::DstIsBitIncompatible),
+        |constraints, constraint| match constraint.or(constraints) {
+            Answer::Yes => Break(Answer::Yes),
+            maybe => Continue(maybe),
+        },
+    );
+    result
+}
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
new file mode 100644
index 00000000000..9c2cf4c9a92
--- /dev/null
+++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
@@ -0,0 +1,93 @@
+use crate::layout;
+
+/// Context necessary to answer the question "Are these types transmutable?".
+pub(crate) trait QueryContext {
+    type Def: layout::Def;
+    type Ref: layout::Ref;
+    type Scope: Copy;
+
+    /// Is `def` accessible from the defining module of `scope`?
+    fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool;
+
+    fn min_align(&self, reference: Self::Ref) -> usize;
+}
+
+#[cfg(test)]
+pub(crate) mod test {
+    use super::QueryContext;
+
+    pub(crate) struct UltraMinimal;
+
+    #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
+    pub(crate) enum Def {
+        Visible,
+        Invisible,
+    }
+
+    impl crate::layout::Def for Def {}
+
+    impl QueryContext for UltraMinimal {
+        type Def = Def;
+        type Ref = !;
+        type Scope = ();
+
+        fn is_accessible_from(&self, def: Def, scope: ()) -> bool {
+            matches!(Def::Visible, def)
+        }
+
+        fn min_align(&self, reference: !) -> usize {
+            unimplemented!()
+        }
+    }
+}
+
+#[cfg(feature = "rustc")]
+mod rustc {
+    use super::*;
+    use rustc_middle::ty::{Ty, TyCtxt};
+
+    impl<'tcx> super::QueryContext for TyCtxt<'tcx> {
+        type Def = layout::rustc::Def<'tcx>;
+        type Ref = layout::rustc::Ref<'tcx>;
+
+        type Scope = Ty<'tcx>;
+
+        #[instrument(level = "debug", skip(self))]
+        fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool {
+            use layout::rustc::Def;
+            use rustc_middle::ty;
+
+            let parent = if let ty::Adt(adt_def, ..) = scope.kind() {
+                use rustc_middle::ty::DefIdTree;
+                let parent = self.parent(adt_def.did());
+                parent
+            } else {
+                // Is this always how we want to handle a non-ADT scope?
+                return false;
+            };
+
+            let def_id = match def {
+                Def::Adt(adt_def) => adt_def.did(),
+                Def::Variant(variant_def) => variant_def.def_id,
+                Def::Field(field_def) => field_def.did,
+                Def::Primitive => {
+                    // primitives do not have a def_id, but they're always accessible
+                    return true;
+                }
+            };
+
+            let ret = if self.visibility(def_id).is_accessible_from(parent, *self) {
+                true
+            } else {
+                false
+            };
+
+            tracing::trace!(?ret, "ret");
+            ret
+        }
+
+        fn min_align(&self, reference: Self::Ref) -> usize {
+            unimplemented!()
+        }
+    }
+}
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
new file mode 100644
index 00000000000..d9d125687f6
--- /dev/null
+++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
@@ -0,0 +1,115 @@
+use super::query_context::test::{Def, UltraMinimal};
+use crate::maybe_transmutable::MaybeTransmutableQuery;
+use crate::{layout, Answer, Reason, Set};
+use itertools::Itertools;
+
+mod bool {
+    use super::*;
+
+    #[test]
+    fn should_permit_identity_transmutation_tree() {
+        println!("{:?}", layout::Tree::<!, !>::bool());
+        let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
+            layout::Tree::<Def, !>::bool(),
+            layout::Tree::<Def, !>::bool(),
+            (),
+            crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false },
+            UltraMinimal,
+        )
+        .answer();
+        assert_eq!(answer, Answer::Yes);
+    }
+
+    #[test]
+    fn should_permit_identity_transmutation_dfa() {
+        let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
+            layout::Dfa::<!>::bool(),
+            layout::Dfa::<!>::bool(),
+            (),
+            crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false },
+            UltraMinimal,
+        )
+        .answer();
+        assert_eq!(answer, Answer::Yes);
+    }
+
+    #[test]
+    fn should_permit_validity_expansion_and_reject_contraction() {
+        let un = layout::Tree::<Def, !>::uninhabited();
+        let b0 = layout::Tree::<Def, !>::from_bits(0);
+        let b1 = layout::Tree::<Def, !>::from_bits(1);
+        let b2 = layout::Tree::<Def, !>::from_bits(2);
+
+        let alts = [b0, b1, b2];
+
+        let into_layout = |alts: Vec<_>| {
+            alts.into_iter().fold(layout::Tree::<Def, !>::uninhabited(), layout::Tree::<Def, !>::or)
+        };
+
+        let into_set = |alts: Vec<_>| {
+            #[cfg(feature = "rustc")]
+            let mut set = Set::default();
+            #[cfg(not(feature = "rustc"))]
+            let mut set = Set::new();
+            set.extend(alts);
+            set
+        };
+
+        for src_alts in alts.clone().into_iter().powerset() {
+            let src_layout = into_layout(src_alts.clone());
+            let src_set = into_set(src_alts.clone());
+
+            for dst_alts in alts.clone().into_iter().powerset().filter(|alts| !alts.is_empty()) {
+                let dst_layout = into_layout(dst_alts.clone());
+                let dst_set = into_set(dst_alts.clone());
+
+                if src_set.is_subset(&dst_set) {
+                    assert_eq!(
+                        Answer::Yes,
+                        MaybeTransmutableQuery::new(
+                            src_layout.clone(),
+                            dst_layout.clone(),
+                            (),
+                            crate::Assume { validity: false, ..crate::Assume::default() },
+                            UltraMinimal,
+                        )
+                        .answer(),
+                        "{:?} SHOULD be transmutable into {:?}",
+                        src_layout,
+                        dst_layout
+                    );
+                } else if !src_set.is_disjoint(&dst_set) {
+                    assert_eq!(
+                        Answer::Yes,
+                        MaybeTransmutableQuery::new(
+                            src_layout.clone(),
+                            dst_layout.clone(),
+                            (),
+                            crate::Assume { validity: true, ..crate::Assume::default() },
+                            UltraMinimal,
+                        )
+                        .answer(),
+                        "{:?} SHOULD be transmutable (assuming validity) into {:?}",
+                        src_layout,
+                        dst_layout
+                    );
+                } else {
+                    assert_eq!(
+                        Answer::No(Reason::DstIsBitIncompatible),
+                        MaybeTransmutableQuery::new(
+                            src_layout.clone(),
+                            dst_layout.clone(),
+                            (),
+                            crate::Assume { validity: false, ..crate::Assume::default() },
+                            UltraMinimal,
+                        )
+                        .answer(),
+                        "{:?} should NOT be transmutable into {:?}",
+                        src_layout,
+                        dst_layout
+                    );
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 4142c999ca7..515a73ead77 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -1,6 +1,6 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty::{self, TyCtxt};
 
 pub fn provide(providers: &mut ty::query::Providers) {
@@ -9,7 +9,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
         associated_item_def_ids,
         associated_items,
         impl_item_implementor_ids,
-        trait_of_item,
         ..*providers
     };
 }
@@ -40,16 +39,6 @@ fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId
         .collect()
 }
 
-/// If the given `DefId` describes an item belonging to a trait,
-/// returns the `DefId` of the trait that the trait item belongs to;
-/// otherwise, returns `None`.
-fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
-    tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
-        ty::TraitContainer(def_id) => Some(def_id),
-        ty::ImplContainer(_) => None,
-    })
-}
-
 fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
     let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
     let parent_def_id = tcx.hir().get_parent_item(id);
@@ -59,8 +48,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
             if let Some(impl_item_ref) =
                 impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
             {
-                let assoc_item =
-                    associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
+                let assoc_item = associated_item_from_impl_item_ref(impl_item_ref);
                 debug_assert_eq!(assoc_item.def_id, def_id);
                 return assoc_item;
             }
@@ -70,8 +58,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
             if let Some(trait_item_ref) =
                 trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
             {
-                let assoc_item =
-                    associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
+                let assoc_item = associated_item_from_trait_item_ref(trait_item_ref);
                 debug_assert_eq!(assoc_item.def_id, def_id);
                 return assoc_item;
             }
@@ -87,11 +74,7 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
     )
 }
 
-fn associated_item_from_trait_item_ref(
-    tcx: TyCtxt<'_>,
-    parent_def_id: LocalDefId,
-    trait_item_ref: &hir::TraitItemRef,
-) -> ty::AssocItem {
+fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
     let def_id = trait_item_ref.id.def_id;
     let (kind, has_self) = match trait_item_ref.kind {
         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
@@ -102,20 +85,14 @@ fn associated_item_from_trait_item_ref(
     ty::AssocItem {
         name: trait_item_ref.ident.name,
         kind,
-        vis: tcx.visibility(def_id),
-        defaultness: trait_item_ref.defaultness,
         def_id: def_id.to_def_id(),
         trait_item_def_id: Some(def_id.to_def_id()),
-        container: ty::TraitContainer(parent_def_id.to_def_id()),
+        container: ty::TraitContainer,
         fn_has_self_parameter: has_self,
     }
 }
 
-fn associated_item_from_impl_item_ref(
-    tcx: TyCtxt<'_>,
-    parent_def_id: LocalDefId,
-    impl_item_ref: &hir::ImplItemRef,
-) -> ty::AssocItem {
+fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
     let def_id = impl_item_ref.id.def_id;
     let (kind, has_self) = match impl_item_ref.kind {
         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
@@ -126,11 +103,9 @@ fn associated_item_from_impl_item_ref(
     ty::AssocItem {
         name: impl_item_ref.ident.name,
         kind,
-        vis: tcx.visibility(def_id),
-        defaultness: impl_item_ref.defaultness,
         def_id: def_id.to_def_id(),
         trait_item_def_id: impl_item_ref.trait_item_def_id,
-        container: ty::ImplContainer(parent_def_id.to_def_id()),
+        container: ty::ImplContainer,
         fn_has_self_parameter: has_self,
     }
 }
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 979e997f244..bd1d568cd9a 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -281,7 +281,7 @@ fn resolve_associated_item<'tcx>(
             }
 
             // If the item does not have a value, then we cannot return an instance.
-            if !leaf_def.item.defaultness.has_value() {
+            if !leaf_def.item.defaultness(tcx).has_value() {
                 return Ok(None);
             }
 
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index b1af3051719..db0d45b86fc 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -2,9 +2,7 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{
-    self, Binder, EarlyBinder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt,
-};
+use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
 use rustc_trait_selection::traits;
 
 fn sized_constraint_for_ty<'tcx>(
@@ -33,8 +31,9 @@ fn sized_constraint_for_ty<'tcx>(
             let adt_tys = adt.sized_constraint(tcx);
             debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys);
             adt_tys
+                .0
                 .iter()
-                .map(|ty| EarlyBinder(*ty).subst(tcx, substs))
+                .map(|ty| adt_tys.rebind(*ty).subst(tcx, substs))
                 .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty))
                 .collect()
         }
@@ -70,11 +69,13 @@ fn sized_constraint_for_ty<'tcx>(
 }
 
 fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
-    let item = tcx.hir().expect_item(def_id.expect_local());
-    if let hir::ItemKind::Impl(impl_) = &item.kind {
-        impl_.defaultness
-    } else {
-        bug!("`impl_defaultness` called on {:?}", item);
+    match tcx.hir().get_by_def_id(def_id.expect_local()) {
+        hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.defaultness,
+        hir::Node::ImplItem(hir::ImplItem { defaultness, .. })
+        | hir::Node::TraitItem(hir::TraitItem { defaultness, .. }) => *defaultness,
+        node => {
+            bug!("`impl_defaultness` called on {:?}", node);
+        }
     }
 }
 
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index 99a8101dc96..ff39bf36129 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -255,7 +255,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 trait_bound_spans.push(*span);
             }
             for assoc_item in items {
-                let trait_def_id = assoc_item.container.id();
+                let trait_def_id = assoc_item.container_id(tcx);
                 names.push(format!(
                     "`{}` (from trait `{}`)",
                     assoc_item.name,
@@ -321,7 +321,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             let mut dupes = false;
             for item in assoc_items {
                 let prefix = if names[&item.name] > 1 {
-                    let trait_def_id = item.container.id();
+                    let trait_def_id = item.container_id(tcx);
                     dupes = true;
                     format!("{}::", tcx.def_path_str(trait_def_id))
                 } else {
@@ -376,7 +376,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let mut label = vec![];
                 for item in assoc_items {
                     let postfix = if names[&item.name] > 1 {
-                        let trait_def_id = item.container.id();
+                        let trait_def_id = item.container_id(tcx);
                         format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
                     } else {
                         String::new()
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 444f0fdd45a..8a5c7fee697 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1141,7 +1141,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .or_else(|| find_item_of_kind(ty::AssocKind::Const))
             .expect("missing associated type");
 
-        if !assoc_item.vis.is_accessible_from(def_scope, tcx) {
+        if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
             tcx.sess
                 .struct_span_err(
                     binding.span,
@@ -1160,7 +1160,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         span: binding.span,
                         prev_span: *prev_span,
                         item_name: binding.item_name,
-                        def_path: tcx.def_path_str(assoc_item.container.id()),
+                        def_path: tcx.def_path_str(assoc_item.container_id(tcx)),
                     });
                 })
                 .or_insert(binding.span);
@@ -1997,7 +1997,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let ty = self.normalize_ty(span, ty);
 
         let kind = DefKind::AssocTy;
-        if !item.vis.is_accessible_from(def_scope, tcx) {
+        if !item.visibility(tcx).is_accessible_from(def_scope, tcx) {
             let kind = kind.descr(item.def_id);
             let msg = format!("{} `{}` is private", kind, assoc_ident);
             tcx.sess
diff --git a/compiler/rustc_typeck/src/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs
index df315b8a3bc..1b13c98e4c3 100644
--- a/compiler/rustc_typeck/src/check/_match.rs
+++ b/compiler/rustc_typeck/src/check/_match.rs
@@ -293,6 +293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(crate) fn if_cause(
         &self,
         span: Span,
+        cond_span: Span,
         then_expr: &'tcx hir::Expr<'tcx>,
         else_expr: &'tcx hir::Expr<'tcx>,
         then_ty: Ty<'tcx>,
@@ -357,8 +358,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // ```
             if block.expr.is_none() && block.stmts.is_empty()
                 && let Some(outer_span) = &mut outer_span
+                && let Some(cond_span) = cond_span.find_ancestor_inside(*outer_span)
             {
-                *outer_span = self.tcx.sess.source_map().guess_head_span(*outer_span);
+                *outer_span = outer_span.with_hi(cond_span.hi())
             }
 
             (self.find_block_span(block), block.hir_id)
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 9497d5c4528..9c1fd9b30b4 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -1098,7 +1098,7 @@ fn check_impl_items_against_trait<'tcx>(
         for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
             let is_implemented = ancestors
                 .leaf_def(tcx, trait_item_id)
-                .map_or(false, |node_item| node_item.item.defaultness.has_value());
+                .map_or(false, |node_item| node_item.item.defaultness(tcx).has_value());
 
             if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
                 missing_items.push(tcx.associated_item(trait_item_id));
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 639cab98f17..21d0a7869d6 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -38,10 +38,12 @@
 use crate::astconv::AstConv;
 use crate::check::FnCtxt;
 use rustc_errors::{
-    struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+    struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::Expr;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{Coercion, InferOk, InferResult};
 use rustc_infer::traits::{Obligation, TraitEngine, TraitEngineExt};
@@ -87,6 +89,19 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> {
 
 type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>;
 
+struct CollectRetsVisitor<'tcx> {
+    ret_exprs: Vec<&'tcx hir::Expr<'tcx>>,
+}
+
+impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> {
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        if let hir::ExprKind::Ret(_) = expr.kind {
+            self.ret_exprs.push(expr);
+        }
+        intravisit::walk_expr(self, expr);
+    }
+}
+
 /// Coercing a mutable reference to an immutable works, while
 /// coercing `&T` to `&mut T` should be forbidden.
 fn coerce_mutbls<'tcx>(
@@ -737,7 +752,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
         G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
     {
-        self.commit_unconditionally(|snapshot| {
+        self.commit_if_ok(|snapshot| {
             let result = if let ty::FnPtr(fn_ty_b) = b.kind()
                 && let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) =
                     (fn_ty_a.unsafety(), fn_ty_b.unsafety())
@@ -1478,9 +1493,11 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     // type)
                     (self.final_ty.unwrap_or(self.expected_ty), expression_ty)
                 };
+                let (expected, found) = fcx.resolve_vars_if_possible((expected, found));
 
                 let mut err;
                 let mut unsized_return = false;
+                let mut visitor = CollectRetsVisitor { ret_exprs: vec![] };
                 match *cause.code() {
                     ObligationCauseCode::ReturnNoExpression => {
                         err = struct_span_err!(
@@ -1506,6 +1523,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                         if !fcx.tcx.features().unsized_locals {
                             unsized_return = self.is_return_ty_unsized(fcx, blk_id);
                         }
+                        if let Some(expression) = expression
+                            && let hir::ExprKind::Loop(loop_blk, ..) = expression.kind {
+                              intravisit::walk_block(& mut visitor, loop_blk);
+                        }
                     }
                     ObligationCauseCode::ReturnValue(id) => {
                         err = self.report_return_mismatched_types(
@@ -1551,12 +1572,39 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                     );
                 }
 
+                if visitor.ret_exprs.len() > 0 && let Some(expr) = expression {
+                    self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs);
+                }
                 err.emit_unless(unsized_return);
 
                 self.final_ty = Some(fcx.tcx.ty_error());
             }
         }
     }
+    fn note_unreachable_loop_return<'a>(
+        &self,
+        err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>,
+        expr: &hir::Expr<'tcx>,
+        ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>,
+    ) {
+        let hir::ExprKind::Loop(_, _, _, loop_span) = expr.kind else { return;};
+        let mut span: MultiSpan = vec![loop_span].into();
+        span.push_span_label(loop_span, "this might have zero elements to iterate on".to_string());
+        for ret_expr in ret_exprs {
+            span.push_span_label(
+                ret_expr.span,
+                "if the loop doesn't execute, this value would never get returned".to_string(),
+            );
+        }
+        err.span_note(
+            span,
+            "the function expects a value to always be returned, but loops might run zero times",
+        );
+        err.help(
+            "return a value for the case when the loop has zero elements to iterate on, or \
+           consider changing the return type to account for that possibility",
+        );
+    }
 
     fn report_return_mismatched_types<'a>(
         &self,
@@ -1648,9 +1696,30 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             );
         }
 
-        if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.get(), fn_output) {
+        let ret_coercion_span = fcx.ret_coercion_span.get();
+
+        if let Some(sp) = ret_coercion_span
+            // If the closure has an explicit return type annotation, or if
+            // the closure's return type has been inferred from outside
+            // requirements (such as an Fn* trait bound), then a type error
+            // may occur at the first return expression we see in the closure
+            // (if it conflicts with the declared return type). Skip adding a
+            // note in this case, since it would be incorrect.
+            && !fcx.return_type_pre_known
+        {
+            err.span_note(
+                sp,
+                &format!(
+                    "return type inferred to be `{}` here",
+                    expected
+                ),
+            );
+        }
+
+        if let (Some(sp), Some(fn_output)) = (ret_coercion_span, fn_output) {
             self.add_impl_trait_explanation(&mut err, cause, fcx, expected, sp, fn_output);
         }
+
         err
     }
 
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index e3ac23686b6..666498403c4 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -165,7 +165,7 @@ fn compare_predicate_entailment<'tcx>(
 
     // Create mapping from trait to placeholder.
     let trait_to_placeholder_substs =
-        impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container.id(), trait_to_impl_substs);
+        impl_to_placeholder_substs.rebase_onto(tcx, impl_m.container_id(tcx), trait_to_impl_substs);
     debug!("compare_impl_method: trait_to_placeholder_substs={:?}", trait_to_placeholder_substs);
 
     let impl_m_generics = tcx.generics_of(impl_m.def_id);
@@ -511,8 +511,8 @@ fn compare_self_type<'tcx>(
 
     let self_string = |method: &ty::AssocItem| {
         let untransformed_self_ty = match method.container {
-            ty::ImplContainer(_) => impl_trait_ref.self_ty(),
-            ty::TraitContainer(_) => tcx.types.self_param,
+            ty::ImplContainer => impl_trait_ref.self_ty(),
+            ty::TraitContainer => tcx.types.self_param,
         };
         let self_arg_ty = tcx.fn_sig(method.def_id).input(0);
         let param_env = ty::ParamEnv::reveal_all();
@@ -1194,7 +1194,7 @@ fn compare_type_predicate_entailment<'tcx>(
 ) -> Result<(), ErrorGuaranteed> {
     let impl_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
     let trait_to_impl_substs =
-        impl_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
+        impl_substs.rebase_onto(tcx, impl_ty.container_id(tcx), impl_trait_ref.substs);
 
     let impl_ty_generics = tcx.generics_of(impl_ty.def_id);
     let trait_ty_generics = tcx.generics_of(trait_ty.def_id);
@@ -1390,9 +1390,9 @@ pub fn check_type_bounds<'tcx>(
     });
     let bound_vars = tcx.mk_bound_variable_kinds(bound_vars.into_iter());
     let impl_ty_substs = tcx.intern_substs(&substs);
+    let container_id = impl_ty.container_id(tcx);
 
-    let rebased_substs =
-        impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
+    let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
     let impl_ty_value = tcx.type_of(impl_ty.def_id);
 
     let param_env = tcx.param_env(impl_ty.def_id);
@@ -1441,8 +1441,7 @@ pub fn check_type_bounds<'tcx>(
     debug!(?normalize_param_env);
 
     let impl_ty_substs = InternalSubsts::identity_for_item(tcx, impl_ty.def_id);
-    let rebased_substs =
-        impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
+    let rebased_substs = impl_ty_substs.rebase_onto(tcx, container_id, impl_trait_ref.substs);
 
     tcx.infer_ctxt().enter(move |infcx| {
         let ocx = ObligationCtxt::new(&infcx);
@@ -1505,10 +1504,13 @@ pub fn check_type_bounds<'tcx>(
         // Finally, resolve all regions. This catches wily misuses of
         // lifetime parameters.
         let implied_bounds = match impl_ty.container {
-            ty::TraitContainer(_) => FxHashSet::default(),
-            ty::ImplContainer(def_id) => {
-                wfcheck::impl_implied_bounds(tcx, param_env, def_id.expect_local(), impl_ty_span)
-            }
+            ty::TraitContainer => FxHashSet::default(),
+            ty::ImplContainer => wfcheck::impl_implied_bounds(
+                tcx,
+                param_env,
+                container_id.expect_local(),
+                impl_ty_span,
+            ),
         };
         let mut outlives_environment = OutlivesEnvironment::new(param_env);
         outlives_environment.add_implied_bounds(&infcx, implied_bounds, impl_ty_hir_id);
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index f0110645551..0595b9a73be 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -45,7 +45,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.note_type_is_not_clone(err, expected, expr_ty, expr);
         self.note_need_for_fn_pointer(err, expected, expr_ty);
         self.note_internal_mutation_in_method(err, expr, expected, expr_ty);
-        self.report_closure_inferred_return_type(err, expected);
     }
 
     // Requires that the two types unify, and prints an error message if
@@ -775,7 +774,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             self.typeck_results.borrow().type_dependent_def_id(expr.hir_id).map(
                                 |did| {
                                     let ai = self.tcx.associated_item(did);
-                                    ai.container == ty::TraitContainer(clone_trait)
+                                    ai.trait_container(self.tcx) == Some(clone_trait)
                                 },
                             ),
                             segment.ident.name,
@@ -1418,25 +1417,4 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => false,
         }
     }
-
-    // Report the type inferred by the return statement.
-    fn report_closure_inferred_return_type(&self, err: &mut Diagnostic, expected: Ty<'tcx>) {
-        if let Some(sp) = self.ret_coercion_span.get()
-            // If the closure has an explicit return type annotation, or if
-            // the closure's return type has been inferred from outside
-            // requirements (such as an Fn* trait bound), then a type error
-            // may occur at the first return expression we see in the closure
-            // (if it conflicts with the declared return type). Skip adding a
-            // note in this case, since it would be incorrect.
-            && !self.return_type_pre_known
-        {
-            err.span_note(
-                sp,
-                &format!(
-                    "return type inferred to be `{}` here",
-                    self.resolve_vars_if_possible(expected)
-                ),
-            );
-        }
-    }
 }
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index e20c6a2d99a..6e97b0bf2ab 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1003,8 +1003,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let else_diverges = self.diverges.get();
 
             let opt_suggest_box_span = self.opt_suggest_box_span(else_ty, orig_expected);
-            let if_cause =
-                self.if_cause(sp, then_expr, else_expr, then_ty, else_ty, opt_suggest_box_span);
+            let if_cause = self.if_cause(
+                sp,
+                cond_expr.span,
+                then_expr,
+                else_expr,
+                then_ty,
+                else_ty,
+                opt_suggest_box_span,
+            );
 
             coerce.coerce(self, &if_cause, else_expr, else_ty);
 
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 22087219667..3a809334511 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -1090,13 +1090,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 is_alias_variant_ctor = true;
             }
             Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
-                let container = tcx.associated_item(def_id).container;
-                debug!(?def_id, ?container);
+                let assoc_item = tcx.associated_item(def_id);
+                let container = assoc_item.container;
+                let container_id = assoc_item.container_id(tcx);
+                debug!(?def_id, ?container, ?container_id);
                 match container {
-                    ty::TraitContainer(trait_did) => {
-                        callee::check_legal_trait_for_method_call(tcx, span, None, span, trait_did)
+                    ty::TraitContainer => {
+                        callee::check_legal_trait_for_method_call(tcx, span, None, span, container_id)
                     }
-                    ty::ImplContainer(impl_def_id) => {
+                    ty::ImplContainer => {
                         if segments.len() == 1 {
                             // `<T>::assoc` will end up here, and so
                             // can `T::assoc`. It this came from an
@@ -1104,7 +1106,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // `T` for posterity (see `UserSelfTy` for
                             // details).
                             let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
-                            user_self_ty = Some(UserSelfTy { impl_def_id, self_ty });
+                            user_self_ty = Some(UserSelfTy { impl_def_id: container_id, self_ty });
                         }
                     }
                 }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 33a3f825ac2..660e7e4e399 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -1761,13 +1761,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             .filter_map(|seg| seg.args.as_ref())
                             .flat_map(|a| a.args.iter())
                         {
-                            if let hir::GenericArg::Type(hir_ty) = &arg {
-                                let ty = self.resolve_vars_if_possible(
-                                    self.typeck_results.borrow().node_type(hir_ty.hir_id),
-                                );
-                                if ty == predicate.self_ty() {
-                                    error.obligation.cause.span = hir_ty.span;
-                                }
+                            if let hir::GenericArg::Type(hir_ty) = &arg
+                                && let Some(ty) =
+                                    self.typeck_results.borrow().node_type_opt(hir_ty.hir_id)
+                                && self.resolve_vars_if_possible(ty) == predicate.self_ty()
+                            {
+                                error.obligation.cause.span = hir_ty.span;
+                                break;
                             }
                         }
                     }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index 097fff6418e..57771e0969b 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -839,8 +839,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && results.type_dependent_def_id(expr.hir_id).map_or(
                 false,
                 |did| {
-                    self.tcx.associated_item(did).container
-                        == ty::AssocItemContainer::TraitContainer(clone_trait_did)
+                    let assoc_item = self.tcx.associated_item(did);
+                    assoc_item.container == ty::AssocItemContainer::TraitContainer
+                        && assoc_item.container_id(self.tcx) == clone_trait_did
                 },
             )
             // If that clone call hasn't already dereferenced the self type (i.e. don't give this
diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs
index b14f3d6de4e..2c89b63ae84 100644
--- a/compiler/rustc_typeck/src/check/method/confirm.rs
+++ b/compiler/rustc_typeck/src/check/method/confirm.rs
@@ -238,7 +238,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
     ) -> SubstsRef<'tcx> {
         match pick.kind {
             probe::InherentImplPick => {
-                let impl_def_id = pick.item.container.id();
+                let impl_def_id = pick.item.container_id(self.tcx);
                 assert!(
                     self.tcx.impl_trait_ref(impl_def_id).is_none(),
                     "impl {:?} is not an inherent impl",
@@ -248,7 +248,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             }
 
             probe::ObjectPick => {
-                let trait_def_id = pick.item.container.id();
+                let trait_def_id = pick.item.container_id(self.tcx);
                 self.extract_existential_trait_ref(self_ty, |this, object_ty, principal| {
                     // The object data has no entry for the Self
                     // Type. For the purposes of this method call, we
@@ -273,7 +273,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             }
 
             probe::TraitPick => {
-                let trait_def_id = pick.item.container.id();
+                let trait_def_id = pick.item.container_id(self.tcx);
 
                 // Make a trait reference `$0 : Trait<$1...$n>`
                 // consisting entirely of type variables. Later on in
@@ -540,15 +540,14 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
 
     fn enforce_illegal_method_limitations(&self, pick: &probe::Pick<'_>) {
         // Disallow calls to the method `drop` defined in the `Drop` trait.
-        match pick.item.container {
-            ty::TraitContainer(trait_def_id) => callee::check_legal_trait_for_method_call(
+        if let Some(trait_def_id) = pick.item.trait_container(self.tcx) {
+            callee::check_legal_trait_for_method_call(
                 self.tcx,
                 self.span,
                 Some(self.self_expr.span),
                 self.call_expr.span,
                 trait_def_id,
-            ),
-            ty::ImplContainer(..) => {}
+            )
         }
     }
 
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index c09f63f1e8f..0e678c41f8b 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -231,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ProbeScope::AllTraits,
             ) {
                 // If we find a different result the caller probably forgot to import a trait.
-                Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container.id()],
+                Ok(ref new_pick) if *new_pick != pick => vec![new_pick.item.container_id(self.tcx)],
                 Err(Ambiguity(ref sources)) => sources
                     .iter()
                     .filter_map(|source| {
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs
index a2f1f5692c7..7c68d930405 100644
--- a/compiler/rustc_typeck/src/check/method/prelude2021.rs
+++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs
@@ -148,7 +148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let trait_name = self.trait_path_or_bare_name(
                         span,
                         call_expr.hir_id,
-                        pick.item.container.id(),
+                        pick.item.container_id(self.tcx),
                     );
 
                     let mut lint = lint.build(&format!(
@@ -261,8 +261,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
             // "type" refers to either a type or, more likely, a trait from which
             // the associated function or method is from.
-            let trait_path = self.trait_path_or_bare_name(span, expr_id, pick.item.container.id());
-            let trait_generics = self.tcx.generics_of(pick.item.container.id());
+            let container_id = pick.item.container_id(self.tcx);
+            let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
+            let trait_generics = self.tcx.generics_of(container_id);
 
             let trait_name =
                 if trait_generics.params.len() <= trait_generics.has_self as usize {
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 8f5f3657fc9..efe15fec7cb 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -592,9 +592,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
     fn push_candidate(&mut self, candidate: Candidate<'tcx>, is_inherent: bool) {
         let is_accessible = if let Some(name) = self.method_name {
             let item = candidate.item;
-            let def_scope =
-                self.tcx.adjust_ident_and_get_scope(name, item.container.id(), self.body_id).1;
-            item.vis.is_accessible_from(def_scope, self.tcx)
+            let def_scope = self
+                .tcx
+                .adjust_ident_and_get_scope(name, item.container_id(self.tcx), self.body_id)
+                .1;
+            item.visibility(self.tcx).is_accessible_from(def_scope, self.tcx)
         } else {
             true
         };
@@ -1025,7 +1027,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         self.assemble_extension_candidates_for_all_traits();
 
         let out_of_scope_traits = match self.pick_core() {
-            Some(Ok(p)) => vec![p.item.container.id()],
+            Some(Ok(p)) => vec![p.item.container_id(self.tcx)],
             //Some(Ok(p)) => p.iter().map(|p| p.item.container().id()).collect(),
             Some(Err(MethodError::Ambiguity(v))) => v
                 .into_iter()
@@ -1387,7 +1389,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                             self.tcx.def_path_str(stable_pick.item.def_id),
                         ));
                     }
-                    (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer(def_id)) => {
+                    (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
+                        let def_id = stable_pick.item.container_id(self.tcx);
                         diag.span_suggestion(
                             self.span,
                             "use the fully qualified path to the associated const",
@@ -1429,9 +1432,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
     fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) -> CandidateSource {
         match candidate.kind {
-            InherentImplCandidate(..) => CandidateSource::Impl(candidate.item.container.id()),
+            InherentImplCandidate(..) => {
+                CandidateSource::Impl(candidate.item.container_id(self.tcx))
+            }
             ObjectCandidate | WhereClauseCandidate(_) => {
-                CandidateSource::Trait(candidate.item.container.id())
+                CandidateSource::Trait(candidate.item.container_id(self.tcx))
             }
             TraitCandidate(trait_ref) => self.probe(|_| {
                 let _ = self
@@ -1444,7 +1449,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                         // to that impl.
                         CandidateSource::Impl(impl_data.impl_def_id)
                     }
-                    _ => CandidateSource::Trait(candidate.item.container.id()),
+                    _ => CandidateSource::Trait(candidate.item.container_id(self.tcx)),
                 }
             }),
         }
@@ -1502,7 +1507,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty);
 
                     // Check whether the impl imposes obligations we have to worry about.
-                    let impl_def_id = probe.item.container.id();
+                    let impl_def_id = probe.item.container_id(self.tcx);
                     let impl_bounds = self.tcx.predicates_of(impl_def_id);
                     let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
                     let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
@@ -1653,12 +1658,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         probes: &[(&Candidate<'tcx>, ProbeResult)],
     ) -> Option<Pick<'tcx>> {
         // Do all probes correspond to the same trait?
-        let container = probes[0].0.item.container;
-        if let ty::ImplContainer(_) = container {
-            return None;
-        }
-        if probes[1..].iter().any(|&(p, _)| p.item.container != container) {
-            return None;
+        let container = probes[0].0.item.trait_container(self.tcx)?;
+        for (p, _) in &probes[1..] {
+            let p_container = p.item.trait_container(self.tcx)?;
+            if p_container != container {
+                return None;
+            }
         }
 
         // FIXME: check the return type here somehow.
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 56fcd9e0a89..c92b93cbc22 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -1789,7 +1789,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // We point at the method, but we just skip the rest of the check for arbitrary
                         // self types and rely on the suggestion to `use` the trait from
                         // `suggest_valid_traits`.
-                        let did = Some(pick.item.container.id());
+                        let did = Some(pick.item.container_id(self.tcx));
                         let skip = skippable.contains(&did);
                         if pick.autoderefs == 0 && !skip {
                             err.span_label(
@@ -1825,7 +1825,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         )
                     {
                         debug!("try_alt_rcvr: pick candidate {:?}", pick);
-                        let did = Some(pick.item.container.id());
+                        let did = Some(pick.item.container_id(self.tcx));
                         // We don't want to suggest a container type when the missing
                         // method is `.clone()` or `.deref()` otherwise we'd suggest
                         // `Arc::new(foo).clone()`, which is far from what the user wants.
@@ -1937,7 +1937,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 }
                             }
                             // We only want to suggest public or local traits (#45781).
-                            item.vis.is_public() || info.def_id.is_local()
+                            item.visibility(self.tcx).is_public() || info.def_id.is_local()
                         })
                         .is_some()
             })
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 837c323553c..a13c7152582 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -600,7 +600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // If there are multiple arms, make sure they all agree on
         // what the type of the binding `x` ought to be.
         if var_id != pat.hir_id {
-            self.check_binding_alt_eq_ty(pat.span, var_id, local_ty, ti);
+            self.check_binding_alt_eq_ty(ba, pat.span, var_id, local_ty, ti);
         }
 
         if let Some(p) = sub {
@@ -610,7 +610,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         local_ty
     }
 
-    fn check_binding_alt_eq_ty(&self, span: Span, var_id: HirId, ty: Ty<'tcx>, ti: TopInfo<'tcx>) {
+    fn check_binding_alt_eq_ty(
+        &self,
+        ba: hir::BindingAnnotation,
+        span: Span,
+        var_id: HirId,
+        ty: Ty<'tcx>,
+        ti: TopInfo<'tcx>,
+    ) {
         let var_ty = self.local_ty(span, var_id).decl_ty;
         if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
             let hir = self.tcx.hir();
@@ -628,12 +635,50 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             });
             let pre = if in_match { "in the same arm, " } else { "" };
             err.note(&format!("{}a binding must have the same type in all alternatives", pre));
-            // FIXME: check if `var_ty` and `ty` can be made the same type by adding or removing
-            // `ref` or `&` to the pattern.
+            self.suggest_adding_missing_ref_or_removing_ref(
+                &mut err,
+                span,
+                var_ty,
+                self.resolve_vars_with_obligations(ty),
+                ba,
+            );
             err.emit();
         }
     }
 
+    fn suggest_adding_missing_ref_or_removing_ref(
+        &self,
+        err: &mut Diagnostic,
+        span: Span,
+        expected: Ty<'tcx>,
+        actual: Ty<'tcx>,
+        ba: hir::BindingAnnotation,
+    ) {
+        match (expected.kind(), actual.kind(), ba) {
+            (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::Unannotated)
+                if self.can_eq(self.param_env, *inner_ty, actual).is_ok() =>
+            {
+                err.span_suggestion_verbose(
+                    span.shrink_to_lo(),
+                    "consider adding `ref`",
+                    "ref ",
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::Ref)
+                if self.can_eq(self.param_env, expected, *inner_ty).is_ok() =>
+            {
+                err.span_suggestion_verbose(
+                    span.with_hi(span.lo() + BytePos(4)),
+                    "consider removing `ref`",
+                    "",
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            _ => (),
+        }
+    }
+
     // Precondition: pat is a Ref(_) pattern
     fn borrow_pat_suggestion(&self, err: &mut Diagnostic, pat: &Pat<'_>) {
         let tcx = self.tcx;
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index faab862cc3c..d0334cd0df7 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -15,8 +15,8 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
-    self, AdtKind, DefIdTree, EarlyBinder, GenericParamDefKind, ToPredicate, Ty, TyCtxt,
-    TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    self, AdtKind, DefIdTree, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable,
+    TypeSuperVisitable, TypeVisitable, TypeVisitor,
 };
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -977,11 +977,14 @@ fn check_associated_item(
         let item = tcx.associated_item(item_id);
 
         let (mut implied_bounds, self_ty) = match item.container {
-            ty::TraitContainer(_) => (FxHashSet::default(), tcx.types.self_param),
-            ty::ImplContainer(def_id) => (
-                impl_implied_bounds(tcx, wfcx.param_env, def_id.expect_local(), span),
-                tcx.type_of(def_id),
-            ),
+            ty::TraitContainer => (FxHashSet::default(), tcx.types.self_param),
+            ty::ImplContainer => {
+                let def_id = item.container_id(tcx);
+                (
+                    impl_implied_bounds(tcx, wfcx.param_env, def_id.expect_local(), span),
+                    tcx.type_of(def_id),
+                )
+            }
         };
 
         match item.kind {
@@ -1004,10 +1007,10 @@ fn check_associated_item(
                 check_method_receiver(wfcx, hir_sig, item, self_ty);
             }
             ty::AssocKind::Type => {
-                if let ty::AssocItemContainer::TraitContainer(_) = item.container {
+                if let ty::AssocItemContainer::TraitContainer = item.container {
                     check_associated_type_bounds(wfcx, item, span)
                 }
-                if item.defaultness.has_value() {
+                if item.defaultness(tcx).has_value() {
                     let ty = tcx.type_of(item.def_id);
                     let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
                     wfcx.register_wf_obligation(span, loc, ty.into());
@@ -1292,7 +1295,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
     let infcx = wfcx.infcx;
     let tcx = wfcx.tcx();
 
-    let predicates = tcx.predicates_of(def_id);
+    let predicates = tcx.bound_predicates_of(def_id.to_def_id());
     let generics = tcx.generics_of(def_id);
 
     let is_our_default = |def: &ty::GenericParamDef| match def.kind {
@@ -1389,6 +1392,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
 
     // Now we build the substituted predicates.
     let default_obligations = predicates
+        .0
         .predicates
         .iter()
         .flat_map(|&(pred, sp)| {
@@ -1419,7 +1423,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
             }
             let mut param_count = CountParams::default();
             let has_region = pred.visit_with(&mut param_count).is_break();
-            let substituted_pred = EarlyBinder(pred).subst(tcx, substs);
+            let substituted_pred = predicates.rebind(pred).subst(tcx, substs);
             // Don't check non-defaulted params, dependent defaults (including lifetimes)
             // or preds with multiple params.
             if substituted_pred.has_param_types_or_consts()
@@ -1427,7 +1431,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
                 || has_region
             {
                 None
-            } else if predicates.predicates.iter().any(|&(p, _)| p == substituted_pred) {
+            } else if predicates.0.predicates.iter().any(|&(p, _)| p == substituted_pred) {
                 // Avoid duplication of predicates that contain no parameters, for example.
                 None
             } else {
@@ -1453,7 +1457,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
             traits::Obligation::new(cause, wfcx.param_env, pred)
         });
 
-    let predicates = predicates.instantiate_identity(tcx);
+    let predicates = predicates.0.instantiate_identity(tcx);
 
     let predicates = wfcx.normalize(span, None, predicates);
 
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index c23cbd71723..043e21fc1e3 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeV
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
 use rustc_trait_selection::traits::predicate_for_trait_def;
-use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
+use rustc_trait_selection::traits::{self, ObligationCause};
 use std::collections::BTreeMap;
 
 pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
@@ -109,15 +109,13 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
                 // it is not immediately clear why Copy is not implemented for a field, since
                 // all we point at is the field itself.
                 tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
-                    let mut fulfill_cx = traits::FulfillmentContext::new();
-                    fulfill_cx.register_bound(
+                    for error in traits::fully_solve_bound(
                         &infcx,
+                        traits::ObligationCause::dummy_with_span(field_ty_span),
                         param_env,
                         ty,
                         tcx.lang_items().copy_trait().unwrap(),
-                        traits::ObligationCause::dummy_with_span(field_ty_span),
-                    );
-                    for error in fulfill_cx.select_all_or_error(&infcx) {
+                    ) {
                         let error_predicate = error.obligation.predicate;
                         // Only note if it's not the root obligation, otherwise it's trivial and
                         // should be self-explanatory (i.e. a field literally doesn't implement Copy).
@@ -315,24 +313,20 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
                     ))
                     .emit();
                 } else {
-                    let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
-                    for field in coerced_fields {
-                        let predicate = predicate_for_trait_def(
-                            tcx,
-                            param_env,
-                            cause.clone(),
-                            dispatch_from_dyn_trait,
-                            0,
-                            field.ty(tcx, substs_a),
-                            &[field.ty(tcx, substs_b).into()],
-                        );
-
-                        fulfill_cx.register_predicate_obligation(&infcx, predicate);
-                    }
-
-                    // Check that all transitive obligations are satisfied.
-                    let errors = fulfill_cx.select_all_or_error(&infcx);
+                    let errors = traits::fully_solve_obligations(
+                        &infcx,
+                        coerced_fields.into_iter().map(|field| {
+                            predicate_for_trait_def(
+                                tcx,
+                                param_env,
+                                cause.clone(),
+                                dispatch_from_dyn_trait,
+                                0,
+                                field.ty(tcx, substs_a),
+                                &[field.ty(tcx, substs_b).into()],
+                            )
+                        }),
+                    );
                     if !errors.is_empty() {
                         infcx.report_fulfillment_errors(&errors, None, false);
                     }
@@ -573,8 +567,6 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
             }
         };
 
-        let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
         // Register an obligation for `A: Trait<B>`.
         let cause = traits::ObligationCause::misc(span, impl_hir_id);
         let predicate = predicate_for_trait_def(
@@ -586,10 +578,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
             source,
             &[target.into()],
         );
-        fulfill_cx.register_predicate_obligation(&infcx, predicate);
-
-        // Check that all transitive obligations are satisfied.
-        let errors = fulfill_cx.select_all_or_error(&infcx);
+        let errors = traits::fully_solve_obligation(&infcx, predicate);
         if !errors.is_empty() {
             infcx.report_fulfillment_errors(&errors, None, false);
         }
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 36111637a56..99996e80c9c 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1234,7 +1234,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
 
                 match item {
                     Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
-                        if !item.defaultness.has_value() {
+                        if !tcx.impl_defaultness(item.id.def_id).has_value() {
                             tcx.sess
                                 .struct_span_err(
                                     item.span,
@@ -2433,7 +2433,7 @@ fn explicit_predicates_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::Generic
             //   supertrait).
             if let ty::Projection(projection) = ty.kind() {
                 projection.substs == trait_identity_substs
-                    && tcx.associated_item(projection.item_def_id).container.id() == def_id
+                    && tcx.associated_item(projection.item_def_id).container_id(tcx) == def_id
             } else {
                 false
             }
@@ -3264,7 +3264,7 @@ fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx FxHashSet<S
 /// applied to the method prototype.
 fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     if let Some(impl_item) = tcx.opt_associated_item(def_id)
-        && let ty::AssocItemContainer::ImplContainer(_) = impl_item.container
+        && let ty::AssocItemContainer::ImplContainer = impl_item.container
         && let Some(trait_item) = impl_item.trait_item_def_id
     {
         return tcx
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index 8801d0260bf..0d2b75d3328 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -3,7 +3,7 @@ use crate::astconv::AstConv;
 use rustc_hir as hir;
 use rustc_infer::traits::util;
 use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 
@@ -30,7 +30,7 @@ fn associated_type_bounds<'tcx>(
     // Associated types are implicitly sized unless a `?Sized` bound is found
     <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
 
-    let trait_def_id = tcx.associated_item(assoc_item_def_id).container.id();
+    let trait_def_id = tcx.parent(assoc_item_def_id);
     let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
 
     let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index 534ddfa9531..f1dbe64f13a 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -801,6 +801,9 @@ fn infer_placeholder_type<'a>(
     match tcx.sess.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
         Some(mut err) => {
             if !ty.references_error() {
+                // Only suggest adding `:` if it was missing (and suggested by parsing diagnostic)
+                let colon = if span == item_ident.span.shrink_to_hi() { ":" } else { "" };
+
                 // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type.
                 // We are typeck and have the real type, so remove that and suggest the actual type.
                 // FIXME(eddyb) this looks like it should be functionality on `Diagnostic`.
@@ -816,7 +819,7 @@ fn infer_placeholder_type<'a>(
                     err.span_suggestion(
                         span,
                         &format!("provide a type for the {item}", item = kind),
-                        format!("{}: {}", item_ident, sugg_ty),
+                        format!("{colon} {sugg_ty}"),
                         Applicability::MachineApplicable,
                     );
                 } else {
diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs
index 3dc728271b0..fd9715e6ca3 100644
--- a/compiler/rustc_typeck/src/hir_wf_check.rs
+++ b/compiler/rustc_typeck/src/hir_wf_check.rs
@@ -3,7 +3,6 @@ use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{ForeignItem, ForeignItemKind, HirId};
 use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::TraitEngine;
 use rustc_infer::traits::{ObligationCause, WellFormedLoc};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder};
@@ -66,7 +65,6 @@ fn diagnostic_hir_wf_check<'tcx>(
     impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
         fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
             self.tcx.infer_ctxt().enter(|infcx| {
-                let mut fulfill = traits::FulfillmentContext::new();
                 let tcx_ty =
                     self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
                 let cause = traits::ObligationCause::new(
@@ -74,7 +72,7 @@ fn diagnostic_hir_wf_check<'tcx>(
                     self.hir_id,
                     traits::ObligationCauseCode::WellFormed(None),
                 );
-                fulfill.register_predicate_obligation(
+                let errors = traits::fully_solve_obligation(
                     &infcx,
                     traits::Obligation::new(
                         cause,
@@ -83,8 +81,6 @@ fn diagnostic_hir_wf_check<'tcx>(
                             .to_predicate(self.tcx),
                     ),
                 );
-
-                let errors = fulfill.select_all_or_error(&infcx);
                 if !errors.is_empty() {
                     debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
                     for error in errors {
diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs
index 8c26c96816d..9fee1eaaec9 100644
--- a/compiler/rustc_typeck/src/impl_wf_check.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check.rs
@@ -106,7 +106,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
             let item = tcx.associated_item(def_id);
             match item.kind {
                 ty::AssocKind::Type => {
-                    if item.defaultness.has_value() {
+                    if item.defaultness(tcx).has_value() {
                         cgp::parameters_for(&tcx.type_of(def_id), true)
                     } else {
                         Vec::new()
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 706b9ee40aa..1563f3552c5 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -104,7 +104,6 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Node, CRATE_HIR_ID};
 use rustc_infer::infer::{InferOk, TyCtxtInferExt};
-use rustc_infer::traits::TraitEngineExt as _;
 use rustc_middle::middle;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -112,11 +111,8 @@ use rustc_middle::util;
 use rustc_session::config::EntryFnType;
 use rustc_span::{symbol::sym, Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
-use rustc_trait_selection::traits::{
-    self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
-};
+use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
 
 use std::iter;
 
@@ -148,18 +144,15 @@ fn require_same_types<'tcx>(
 ) -> bool {
     tcx.infer_ctxt().enter(|ref infcx| {
         let param_env = ty::ParamEnv::empty();
-        let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-        match infcx.at(cause, param_env).eq(expected, actual) {
-            Ok(InferOk { obligations, .. }) => {
-                fulfill_cx.register_predicate_obligations(infcx, obligations);
-            }
+        let errors = match infcx.at(cause, param_env).eq(expected, actual) {
+            Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
             Err(err) => {
                 infcx.report_mismatched_types(cause, expected, actual, err).emit();
                 return false;
             }
-        }
+        };
 
-        match fulfill_cx.select_all_or_error(infcx).as_slice() {
+        match &errors[..] {
             [] => true,
             errors => {
                 infcx.report_fulfillment_errors(errors, None, false);
@@ -303,7 +296,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
     }
 
     let expected_return_type;
-    if let Some(term_id) = tcx.lang_items().termination() {
+    if let Some(term_did) = tcx.lang_items().termination() {
         let return_ty = main_fnsig.output();
         let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
         if !return_ty.bound_vars().is_empty() {
@@ -314,33 +307,17 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         }
         let return_ty = return_ty.skip_binder();
         tcx.infer_ctxt().enter(|infcx| {
+            // Main should have no WC, so empty param env is OK here.
+            let param_env = ty::ParamEnv::empty();
             let cause = traits::ObligationCause::new(
                 return_ty_span,
                 main_diagnostics_hir_id,
                 ObligationCauseCode::MainFunctionType,
             );
-            let mut fulfillment_cx = traits::FulfillmentContext::new();
-            // normalize any potential projections in the return type, then add
-            // any possible obligations to the fulfillment context.
-            // HACK(ThePuzzlemaker) this feels symptomatic of a problem within
-            // checking trait fulfillment, not this here. I'm not sure why it
-            // works in the example in `fn test()` given in #88609? This also
-            // probably isn't the best way to do this.
-            let InferOk { value: norm_return_ty, obligations } = infcx
-                .partially_normalize_associated_types_in(
-                    cause.clone(),
-                    ty::ParamEnv::empty(),
-                    return_ty,
-                );
-            fulfillment_cx.register_predicate_obligations(&infcx, obligations);
-            fulfillment_cx.register_bound(
-                &infcx,
-                ty::ParamEnv::empty(),
-                norm_return_ty,
-                term_id,
-                cause,
-            );
-            let errors = fulfillment_cx.select_all_or_error(&infcx);
+            let ocx = traits::ObligationCtxt::new(&infcx);
+            let norm_return_ty = ocx.normalize(cause.clone(), param_env, return_ty);
+            ocx.register_bound(cause, param_env, norm_return_ty, term_did);
+            let errors = ocx.select_all_or_error();
             if !errors.is_empty() {
                 infcx.report_fulfillment_errors(&errors, None, false);
                 error = true;
diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
index 257a9520eeb..3b779280eda 100644
--- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
@@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
 use rustc_span::Span;
 
 use super::explicit::ExplicitPredicatesMap;
@@ -202,7 +202,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
                 debug!("Projection");
                 check_explicit_predicates(
                     tcx,
-                    tcx.associated_item(obj.item_def_id).container.id(),
+                    tcx.parent(obj.item_def_id),
                     obj.substs,
                     required_predicates,
                     explicit_map,
diff --git a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
index 70b8bcd0220..229a6465084 100644
--- a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
+++ b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs
@@ -3,7 +3,7 @@ use rustc_middle::ty::{self, Ty};
 use rustc_trait_selection::infer::InferCtxt;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput};
 use rustc_trait_selection::traits::query::NoSolution;
-use rustc_trait_selection::traits::{FulfillmentContext, ObligationCause, TraitEngine};
+use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt};
 
 pub use rustc_middle::traits::query::OutlivesBound;
 
@@ -63,7 +63,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
         if let Some(constraints) = constraints {
             // Instantiation may have produced new inference variables and constraints on those
             // variables. Process these constraints.
-            let mut fulfill_cx = FulfillmentContext::new();
+            let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.tcx);
             let cause = ObligationCause::misc(span, body_id);
             for &constraint in &constraints.outlives {
                 let obligation = self.query_outlives_constraint_to_obligation(
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 59066a33c96..82e63a7fe1d 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -2,6 +2,7 @@ use crate::ascii;
 use crate::cmp::Ordering;
 use crate::ffi::c_char;
 use crate::fmt::{self, Write};
+use crate::intrinsics;
 use crate::ops;
 use crate::slice;
 use crate::slice::memchr;
@@ -384,21 +385,41 @@ impl CStr {
     #[must_use]
     #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
     #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
+    #[rustc_allow_const_fn_unstable(const_eval_select)]
     pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
-        // We're in a const fn, so this is the best we can do
-        debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
-        // SAFETY: Calling an inner function with the same prerequisites.
-        unsafe { Self::_from_bytes_with_nul_unchecked(bytes) }
-    }
+        fn rt_impl(bytes: &[u8]) -> &CStr {
+            // Chance at catching some UB at runtime with debug builds.
+            debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
 
-    #[inline]
-    const unsafe fn _from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
-        // SAFETY: Casting to CStr is safe because its internal representation
-        // is a [u8] too (safe only inside std).
-        // Dereferencing the obtained pointer is safe because it comes from a
-        // reference. Making a reference is then safe because its lifetime
-        // is bound by the lifetime of the given `bytes`.
-        unsafe { &*(bytes as *const [u8] as *const CStr) }
+            // SAFETY: Casting to CStr is safe because its internal representation
+            // is a [u8] too (safe only inside std).
+            // Dereferencing the obtained pointer is safe because it comes from a
+            // reference. Making a reference is then safe because its lifetime
+            // is bound by the lifetime of the given `bytes`.
+            unsafe { &*(bytes as *const [u8] as *const CStr) }
+        }
+
+        const fn const_impl(bytes: &[u8]) -> &CStr {
+            // Saturating so that an empty slice panics in the assert with a good
+            // message, not here due to underflow.
+            let mut i = bytes.len().saturating_sub(1);
+            assert!(!bytes.is_empty() && bytes[i] == 0, "input was not nul-terminated");
+
+            // Ending null byte exists, skip to the rest.
+            while i != 0 {
+                i -= 1;
+                let byte = bytes[i];
+                assert!(byte != 0, "input contained interior nul");
+            }
+
+            // SAFETY: See `rt_impl` cast.
+            unsafe { &*(bytes as *const [u8] as *const CStr) }
+        }
+
+        // SAFETY: The const and runtime versions have identical behavior
+        // unless the safety contract of `from_bytes_with_nul_unchecked` is
+        // violated, which is UB.
+        unsafe { intrinsics::const_eval_select((bytes,), const_impl, rt_impl) }
     }
 
     /// Returns the inner pointer to this C string.
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 7e65f4ebdad..cabc5017f1d 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1207,13 +1207,26 @@ extern "rust-intrinsic" {
 
     /// Reinterprets the bits of a value of one type as another type.
     ///
-    /// Both types must have the same size. Neither the original, nor the result,
-    /// may be an [invalid value](../../nomicon/what-unsafe-does.html).
+    /// Both types must have the same size. Compilation will fail if this is not guaranteed.
     ///
     /// `transmute` is semantically equivalent to a bitwise move of one type
     /// into another. It copies the bits from the source value into the
-    /// destination value, then forgets the original. It's equivalent to C's
-    /// `memcpy` under the hood, just like `transmute_copy`.
+    /// destination value, then forgets the original. Note that source and destination
+    /// are passed by-value, which means if `T` or `U` contain padding, that padding
+    /// is *not* guaranteed to be preserved by `transmute`.
+    ///
+    /// Both the argument and the result must be [valid](../../nomicon/what-unsafe-does.html) at
+    /// their given type. Violating this condition leads to [undefined behavior][ub]. The compiler
+    /// will generate code *assuming that you, the programmer, ensure that there will never be
+    /// undefined behavior*. It is therefore your responsibility to guarantee that every value
+    /// passed to `transmute` is valid at both types `T` and `U`. Failing to uphold this condition
+    /// may lead to unexpected and unstable compilation results. This makes `transmute` **incredibly
+    /// unsafe**. `transmute` should be the absolute last resort.
+    ///
+    /// Transmuting pointers to integers in a `const` context is [undefined behavior][ub].
+    /// Any attempt to use the resulting value for integer operations will abort const-evaluation.
+    /// (And even outside `const`, such transmutation is touching on many unspecified aspects of the
+    /// Rust memory model and should be avoided. See below for alternatives.)
     ///
     /// Because `transmute` is a by-value operation, alignment of the *transmuted values
     /// themselves* is not a concern. As with any other function, the compiler already ensures
@@ -1221,15 +1234,7 @@ extern "rust-intrinsic" {
     /// elsewhere* (such as pointers, references, boxes…), the caller has to ensure proper
     /// alignment of the pointed-to values.
     ///
-    /// `transmute` is **incredibly** unsafe. There are a vast number of ways to
-    /// cause [undefined behavior][ub] with this function. `transmute` should be
-    /// the absolute last resort.
-    ///
-    /// Transmuting pointers to integers in a `const` context is [undefined behavior][ub].
-    /// Any attempt to use the resulting value for integer operations will abort const-evaluation.
-    ///
-    /// The [nomicon](../../nomicon/transmutes.html) has additional
-    /// documentation.
+    /// The [nomicon](../../nomicon/transmutes.html) has additional documentation.
     ///
     /// [ub]: ../../reference/behavior-considered-undefined.html
     ///
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 6351e6fbd13..20b2d5e2681 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -27,6 +27,10 @@ mod valid_align;
 // alignment as a parameter, such as `Layout::padding_needed_for`.
 pub(crate) use valid_align::ValidAlign;
 
+mod transmutability;
+#[unstable(feature = "transmutability", issue = "99571")]
+pub use transmutability::{Assume, BikeshedIntrinsicFrom};
+
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(inline)]
 pub use crate::intrinsics::transmute;
diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs
new file mode 100644
index 00000000000..b59a5b89d83
--- /dev/null
+++ b/library/core/src/mem/transmutability.rs
@@ -0,0 +1,43 @@
+/// Are values of a type transmutable into values of another type?
+///
+/// This trait is implemented on-the-fly by the compiler for types `Src` and `Self` when the bits of
+/// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`,
+/// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied.
+#[unstable(feature = "transmutability", issue = "99571")]
+#[cfg_attr(not(bootstrap), lang = "transmute_trait")]
+#[rustc_on_unimplemented(
+    message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.",
+    label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`."
+)]
+pub unsafe trait BikeshedIntrinsicFrom<
+    Src,
+    Context,
+    const ASSUME_ALIGNMENT: bool,
+    const ASSUME_LIFETIMES: bool,
+    const ASSUME_VALIDITY: bool,
+    const ASSUME_VISIBILITY: bool,
+> where
+    Src: ?Sized,
+{
+}
+
+/// What transmutation safety conditions shall the compiler assume that *you* are checking?
+#[unstable(feature = "transmutability", issue = "99571")]
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct Assume {
+    /// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that
+    /// destination referents do not have stricter alignment requirements than source referents.
+    pub alignment: bool,
+
+    /// When `true`, the compiler assume that *you* are ensuring that lifetimes are not extended in a manner
+    /// that violates Rust's memory model.
+    pub lifetimes: bool,
+
+    /// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid
+    /// instance of the destination type.
+    pub validity: bool,
+
+    /// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the
+    /// type and field privacy of the destination type (and sometimes of the source type, too).
+    pub visibility: bool,
+}
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index e0655d68d2c..2cd6e23c71a 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1336,11 +1336,8 @@ impl<T: ?Sized> *const T {
             panic!("is_aligned_to: align is not a power-of-two");
         }
 
-        // SAFETY: `is_power_of_two()` will return `false` for zero.
-        unsafe { core::intrinsics::assume(align != 0) };
-
         // Cast is needed for `T: !Sized`
-        self.cast::<u8>().addr() % align == 0
+        self.cast::<u8>().addr() & align - 1 == 0
     }
 }
 
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index fc3dd2a9b25..56ad5f7658e 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1614,11 +1614,8 @@ impl<T: ?Sized> *mut T {
             panic!("is_aligned_to: align is not a power-of-two");
         }
 
-        // SAFETY: `is_power_of_two()` will return `false` for zero.
-        unsafe { core::intrinsics::assume(align != 0) };
-
         // Cast is needed for `T: !Sized`
-        self.cast::<u8>().addr() % align == 0
+        self.cast::<u8>().addr() & align - 1 == 0
     }
 }
 
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 76b4a534e5d..f1e65930967 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -1788,6 +1788,12 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksMut<'a, T> {
     const MAY_HAVE_SIDE_EFFECT: bool = false;
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T> Send for ChunksMut<'_, T> where T: Send {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T> Sync for ChunksMut<'_, T> where T: Sync {}
+
 /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
 /// time), starting at the beginning of the slice.
 ///
@@ -2114,6 +2120,12 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for ChunksExactMut<'a, T> {
     const MAY_HAVE_SIDE_EFFECT: bool = false;
 }
 
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+unsafe impl<T> Send for ChunksExactMut<'_, T> where T: Send {}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+unsafe impl<T> Sync for ChunksExactMut<'_, T> where T: Sync {}
+
 /// A windowed iterator over a slice in overlapping chunks (`N` elements at a
 /// time), starting at the beginning of the slice
 ///
@@ -2835,6 +2847,12 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksMut<'a, T> {
     const MAY_HAVE_SIDE_EFFECT: bool = false;
 }
 
+#[stable(feature = "rchunks", since = "1.31.0")]
+unsafe impl<T> Send for RChunksMut<'_, T> where T: Send {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+unsafe impl<T> Sync for RChunksMut<'_, T> where T: Sync {}
+
 /// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
 /// time), starting at the end of the slice.
 ///
@@ -3168,6 +3186,12 @@ unsafe impl<'a, T> TrustedRandomAccessNoCoerce for RChunksExactMut<'a, T> {
     const MAY_HAVE_SIDE_EFFECT: bool = false;
 }
 
+#[stable(feature = "rchunks", since = "1.31.0")]
+unsafe impl<T> Send for RChunksExactMut<'_, T> where T: Send {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+unsafe impl<T> Sync for RChunksExactMut<'_, T> where T: Sync {}
+
 #[doc(hidden)]
 #[unstable(feature = "trusted_random_access", issue = "none")]
 unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {}
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index c4f2e283eb3..ee66895a7ed 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -2353,7 +2353,7 @@ impl str {
     #[inline]
     pub fn is_ascii(&self) -> bool {
         // We can treat each byte as character here: all multibyte characters
-        // start with a byte that is not in the ascii range, so we will stop
+        // start with a byte that is not in the ASCII range, so we will stop
         // there already.
         self.as_bytes().is_ascii()
     }
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 6d1516958f3..0656109e9db 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -1192,6 +1192,27 @@ fn test_rchunks_exact_mut_zip() {
 }
 
 #[test]
+fn chunks_mut_are_send_and_sync() {
+    use std::cell::Cell;
+    use std::slice::{ChunksExactMut, ChunksMut, RChunksExactMut, RChunksMut};
+    use std::sync::MutexGuard;
+
+    #[allow(unused)]
+    fn assert_send_and_sync()
+    where
+        ChunksMut<'static, Cell<i32>>: Send,
+        ChunksMut<'static, MutexGuard<'static, u32>>: Sync,
+        ChunksExactMut<'static, Cell<i32>>: Send,
+        ChunksExactMut<'static, MutexGuard<'static, u32>>: Sync,
+        RChunksMut<'static, Cell<i32>>: Send,
+        RChunksMut<'static, MutexGuard<'static, u32>>: Sync,
+        RChunksExactMut<'static, Cell<i32>>: Send,
+        RChunksExactMut<'static, MutexGuard<'static, u32>>: Sync,
+    {
+    }
+}
+
+#[test]
 fn test_windows_count() {
     let v: &[i32] = &[0, 1, 2, 3, 4, 5];
     let c = v.windows(3);
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index ff7b70c328d..722df119d22 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -260,20 +260,6 @@ pub trait Error: Debug + Display {
         TypeId::of::<Self>()
     }
 
-    /// Returns a stack backtrace, if available, of where this error occurred.
-    ///
-    /// This function allows inspecting the location, in code, of where an error
-    /// happened. The returned `Backtrace` contains information about the stack
-    /// trace of the OS thread of execution of where the error originated from.
-    ///
-    /// Note that not all errors contain a `Backtrace`. Also note that a
-    /// `Backtrace` may actually be empty. For more information consult the
-    /// `Backtrace` type itself.
-    #[unstable(feature = "backtrace", issue = "53487")]
-    fn backtrace(&self) -> Option<&Backtrace> {
-        None
-    }
-
     /// ```
     /// if let Err(e) = "xc".parse::<u32>() {
     ///     // Print `e` itself, no need for description().
@@ -370,7 +356,7 @@ pub trait Error: Debug + Display {
 }
 
 #[unstable(feature = "error_generic_member_access", issue = "99301")]
-impl Provider for dyn Error + 'static {
+impl<'b> Provider for dyn Error + 'b {
     fn provide<'a>(&'a self, req: &mut Demand<'a>) {
         self.provide(req)
     }
@@ -757,8 +743,8 @@ impl<'a, T: Error + ?Sized> Error for &'a T {
         Error::source(&**self)
     }
 
-    fn backtrace(&self) -> Option<&Backtrace> {
-        Error::backtrace(&**self)
+    fn provide<'b>(&'b self, req: &mut Demand<'b>) {
+        Error::provide(&**self, req);
     }
 }
 
@@ -778,8 +764,8 @@ impl<T: Error + ?Sized> Error for Arc<T> {
         Error::source(&**self)
     }
 
-    fn backtrace(&self) -> Option<&Backtrace> {
-        Error::backtrace(&**self)
+    fn provide<'a>(&'a self, req: &mut Demand<'a>) {
+        Error::provide(&**self, req);
     }
 }
 
@@ -871,6 +857,20 @@ impl Error for alloc::ffi::IntoStringError {
     }
 }
 
+impl<'a> dyn Error + 'a {
+    /// Request a reference of type `T` as context about this error.
+    #[unstable(feature = "error_generic_member_access", issue = "99301")]
+    pub fn request_ref<T: ?Sized + 'static>(&'a self) -> Option<&'a T> {
+        core::any::request_ref(self)
+    }
+
+    /// Request a value of type `T` as context about this error.
+    #[unstable(feature = "error_generic_member_access", issue = "99301")]
+    pub fn request_value<T: 'static>(&'a self) -> Option<T> {
+        core::any::request_value(self)
+    }
+}
+
 // Copied from `any.rs`.
 impl dyn Error + 'static {
     /// Returns `true` if the inner type is the same as `T`.
@@ -910,18 +910,6 @@ impl dyn Error + 'static {
             None
         }
     }
-
-    /// Request a reference of type `T` as context about this error.
-    #[unstable(feature = "error_generic_member_access", issue = "99301")]
-    pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
-        core::any::request_ref(self)
-    }
-
-    /// Request a value of type `T` as context about this error.
-    #[unstable(feature = "error_generic_member_access", issue = "99301")]
-    pub fn request_value<T: 'static>(&self) -> Option<T> {
-        core::any::request_value(self)
-    }
 }
 
 impl dyn Error + 'static + Send {
@@ -949,13 +937,13 @@ impl dyn Error + 'static + Send {
     /// Request a reference of type `T` as context about this error.
     #[unstable(feature = "error_generic_member_access", issue = "99301")]
     pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
-        <dyn Error + 'static>::request_ref(self)
+        <dyn Error>::request_ref(self)
     }
 
     /// Request a value of type `T` as context about this error.
     #[unstable(feature = "error_generic_member_access", issue = "99301")]
     pub fn request_value<T: 'static>(&self) -> Option<T> {
-        <dyn Error + 'static>::request_value(self)
+        <dyn Error>::request_value(self)
     }
 }
 
@@ -984,13 +972,13 @@ impl dyn Error + 'static + Send + Sync {
     /// Request a reference of type `T` as context about this error.
     #[unstable(feature = "error_generic_member_access", issue = "99301")]
     pub fn request_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
-        <dyn Error + 'static>::request_ref(self)
+        <dyn Error>::request_ref(self)
     }
 
     /// Request a value of type `T` as context about this error.
     #[unstable(feature = "error_generic_member_access", issue = "99301")]
     pub fn request_value<T: 'static>(&self) -> Option<T> {
-        <dyn Error + 'static>::request_value(self)
+        <dyn Error>::request_value(self)
     }
 }
 
@@ -1467,8 +1455,11 @@ impl<E> Report<E> {
     /// ```rust
     /// #![feature(error_reporter)]
     /// #![feature(backtrace)]
+    /// #![feature(provide_any)]
+    /// #![feature(error_generic_member_access)]
     /// # use std::error::Error;
     /// # use std::fmt;
+    /// use std::any::Demand;
     /// use std::error::Report;
     /// use std::backtrace::Backtrace;
     ///
@@ -1498,8 +1489,9 @@ impl<E> Report<E> {
     /// }
     ///
     /// impl Error for SuperErrorSideKick {
-    ///     fn backtrace(&self) -> Option<&Backtrace> {
-    ///         Some(&self.backtrace)
+    ///     fn provide<'a>(&'a self, req: &mut Demand<'a>) {
+    ///         req
+    ///             .provide_ref::<Backtrace>(&self.backtrace);
     ///     }
     /// }
     ///
@@ -1552,11 +1544,11 @@ where
     fn backtrace(&self) -> Option<&Backtrace> {
         // have to grab the backtrace on the first error directly since that error may not be
         // 'static
-        let backtrace = self.error.backtrace();
+        let backtrace = (&self.error as &dyn Error).request_ref();
         let backtrace = backtrace.or_else(|| {
             self.error
                 .source()
-                .map(|source| source.chain().find_map(|source| source.backtrace()))
+                .map(|source| source.chain().find_map(|source| source.request_ref()))
                 .flatten()
         });
         backtrace
@@ -1618,11 +1610,11 @@ impl Report<Box<dyn Error>> {
     fn backtrace(&self) -> Option<&Backtrace> {
         // have to grab the backtrace on the first error directly since that error may not be
         // 'static
-        let backtrace = self.error.backtrace();
+        let backtrace = self.error.request_ref();
         let backtrace = backtrace.or_else(|| {
             self.error
                 .source()
-                .map(|source| source.chain().find_map(|source| source.backtrace()))
+                .map(|source| source.chain().find_map(|source| source.request_ref()))
                 .flatten()
         });
         backtrace
diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs
index a2a35d96ec9..ee999bd65c3 100644
--- a/library/std/src/error/tests.rs
+++ b/library/std/src/error/tests.rs
@@ -1,5 +1,6 @@
 use super::Error;
 use crate::fmt;
+use core::any::Demand;
 
 #[derive(Debug, PartialEq)]
 struct A;
@@ -198,8 +199,8 @@ where
         self.source.as_deref()
     }
 
-    fn backtrace(&self) -> Option<&Backtrace> {
-        self.backtrace.as_ref()
+    fn provide<'a>(&'a self, req: &mut Demand<'a>) {
+        self.backtrace.as_ref().map(|bt| req.provide_ref::<Backtrace>(bt));
     }
 }
 
diff --git a/library/std/src/sys/solid/fs.rs b/library/std/src/sys/solid/fs.rs
index a2cbee4dcf0..772b29f3a11 100644
--- a/library/std/src/sys/solid/fs.rs
+++ b/library/std/src/sys/solid/fs.rs
@@ -77,6 +77,9 @@ pub struct OpenOptions {
     custom_flags: i32,
 }
 
+#[derive(Copy, Clone, Debug, Default)]
+pub struct FileTimes {}
+
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct FilePermissions(c_short);
 
@@ -126,6 +129,11 @@ impl FilePermissions {
     }
 }
 
+impl FileTimes {
+    pub fn set_accessed(&mut self, _t: SystemTime) {}
+    pub fn set_modified(&mut self, _t: SystemTime) {}
+}
+
 impl FileType {
     pub fn is_dir(&self) -> bool {
         self.is(abi::S_IFDIR)
@@ -452,6 +460,10 @@ impl File {
     pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
         unsupported()
     }
+
+    pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
+        unsupported()
+    }
 }
 
 impl Drop for File {
diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs
index faeda5a854d..1b98ef993b0 100644
--- a/library/std/src/sys/solid/net.rs
+++ b/library/std/src/sys/solid/net.rs
@@ -230,8 +230,8 @@ impl Socket {
     pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
         self.set_nonblocking(true)?;
         let r = unsafe {
-            let (addrp, len) = addr.into_inner();
-            cvt(netc::connect(self.0.raw(), addrp, len))
+            let (addr, len) = addr.into_inner();
+            cvt(netc::connect(self.0.raw(), addr.as_ptr(), len))
         };
         self.set_nonblocking(false)?;
 
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 41405cbf657..b5cc8038ca4 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -544,9 +544,11 @@ impl Default for FileTimes {
     fn default() -> Self {
         // Redox doesn't appear to support `UTIME_OMIT`, so we stub it out here, and always return
         // an error in `set_times`.
-        #[cfg(target_os = "redox")]
+        // ESP-IDF does not support `futimens` at all and the behavior for that OS is therefore
+        // the same as for Redox.
+        #[cfg(any(target_os = "redox", target_os = "espidf"))]
         let omit = libc::timespec { tv_sec: 0, tv_nsec: 0 };
-        #[cfg(not(target_os = "redox"))]
+        #[cfg(not(any(target_os = "redox", target_os = "espidf")))]
         let omit = libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ };
         Self([omit; 2])
     }
@@ -1077,8 +1079,10 @@ impl File {
 
     pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
         cfg_if::cfg_if! {
-            if #[cfg(target_os = "redox")] {
+            if #[cfg(any(target_os = "redox", target_os = "espidf"))] {
                 // Redox doesn't appear to support `UTIME_OMIT`.
+                // ESP-IDF does not support `futimens` at all and the behavior for that OS is therefore
+                // the same as for Redox.
                 drop(times);
                 Err(io::const_io_error!(
                     io::ErrorKind::Unsupported,
diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs
index 55b5ad314da..4159efe2a05 100644
--- a/library/std/src/sys/wasm/mod.rs
+++ b/library/std/src/sys/wasm/mod.rs
@@ -52,9 +52,11 @@ cfg_if::cfg_if! {
         #[path = "../unix/locks"]
         pub mod locks {
             #![allow(unsafe_op_in_unsafe_fn)]
-            mod futex;
+            mod futex_condvar;
+            mod futex_mutex;
             mod futex_rwlock;
-            pub(crate) use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
+            pub(crate) use futex_condvar::{Condvar, MovableCondvar};
+            pub(crate) use futex_mutex::{Mutex, MovableMutex};
             pub(crate) use futex_rwlock::{RwLock, MovableRwLock};
         }
         #[path = "atomics/futex.rs"]
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 478068c73ba..c5a30f8bac8 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -1250,19 +1250,21 @@ compat_fn_with_fallback! {
     }
 }
 
-compat_fn_optional! {
+compat_fn_with_fallback! {
     pub static SYNCH_API: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0");
-
-    // >= Windows 8 / Server 2012
-    // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitonaddress
-    pub fn WaitOnAddress(
-        Address: LPVOID,
-        CompareAddress: LPVOID,
-        AddressSize: SIZE_T,
-        dwMilliseconds: DWORD
-    ) -> BOOL;
-    pub fn WakeByAddressSingle(Address: LPVOID) -> ();
+    #[allow(unused)]
+    fn WakeByAddressSingle(Address: LPVOID) -> () {
+        // This fallback is currently tightly coupled to its use in Parker::unpark.
+        //
+        // FIXME: If `WakeByAddressSingle` needs to be used anywhere other than
+        // Parker::unpark then this fallback will be wrong and will need to be decoupled.
+        crate::sys::windows::thread_parker::unpark_keyed_event(Address)
+    }
 }
+pub use crate::sys::compat::WaitOnAddress;
+// Change exported name of `WakeByAddressSingle` to make the strange fallback
+// behaviour clear.
+pub use WakeByAddressSingle::call as wake_by_address_single_or_unpark_keyed_event;
 
 compat_fn_with_fallback! {
     pub static NTDLL: &CStr = ansi_str!("ntdll");
diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs
index ccc90177a20..473544c4d4f 100644
--- a/library/std/src/sys/windows/compat.rs
+++ b/library/std/src/sys/windows/compat.rs
@@ -7,47 +7,17 @@
 //! `GetModuleHandle` and `GetProcAddress` to look up DLL entry points at
 //! runtime.
 //!
-//! This implementation uses a static initializer to look up the DLL entry
-//! points. The CRT (C runtime) executes static initializers before `main`
-//! is called (for binaries) and before `DllMain` is called (for DLLs).
-//! This is the ideal time to look up DLL imports, because we are guaranteed
-//! that no other threads will attempt to call these entry points. Thus,
-//! we can look up the imports and store them in `static mut` fields
-//! without any synchronization.
+//! This is implemented simply by storing a function pointer in an atomic.
+//! Loading and calling this function will have little or no overhead
+//! compared with calling any other dynamically imported function.
 //!
-//! This has an additional advantage: Because the DLL import lookup happens
-//! at module initialization, the cost of these lookups is deterministic,
-//! and is removed from the code paths that actually call the DLL imports.
-//! That is, there is no unpredictable "cache miss" that occurs when calling
-//! a DLL import. For applications that benefit from predictable delays,
-//! this is a benefit. This also eliminates the comparison-and-branch
-//! from the hot path.
-//!
-//! Currently, the standard library uses only a small number of dynamic
-//! DLL imports. If this number grows substantially, then the cost of
-//! performing all of the lookups at initialization time might become
-//! substantial.
-//!
-//! The mechanism of registering a static initializer with the CRT is
-//! documented in
-//! [CRT Initialization](https://docs.microsoft.com/en-us/cpp/c-runtime-library/crt-initialization?view=msvc-160).
-//! It works by contributing a global symbol to the `.CRT$XCU` section.
-//! The linker builds a table of all static initializer functions.
-//! The CRT startup code then iterates that table, calling each
-//! initializer function.
-//!
-//! # **WARNING!!*
-//! The environment that a static initializer function runs in is highly
-//! constrained. There are **many** restrictions on what static initializers
-//! can safely do. Static initializer functions **MUST NOT** do any of the
-//! following (this list is not comprehensive):
-//! * touch any other static field that is used by a different static
-//!   initializer, because the order that static initializers run in
-//!   is not defined.
-//! * call `LoadLibrary` or any other function that acquires the DLL
-//!   loader lock.
-//! * call any Rust function or CRT function that touches any static
-//!   (global) state.
+//! The stored function pointer starts out as an importer function which will
+//! swap itself with the real function when it's called for the first time. If
+//! the real function can't be imported then a fallback function is used in its
+//! place. While this is low cost for the happy path (where the function is
+//! already loaded) it does mean there's some overhead the first time the
+//! function is called. In the worst case, multiple threads may all end up
+//! importing the same function unnecessarily.
 
 use crate::ffi::{c_void, CStr};
 use crate::ptr::NonNull;
@@ -85,39 +55,6 @@ pub(crate) const fn const_cstr_from_bytes(bytes: &'static [u8]) -> &'static CStr
     unsafe { crate::ffi::CStr::from_bytes_with_nul_unchecked(bytes) }
 }
 
-#[used]
-#[link_section = ".CRT$XCU"]
-static INIT_TABLE_ENTRY: unsafe extern "C" fn() = init;
-
-/// This is where the magic preloading of symbols happens.
-///
-/// Note that any functions included here will be unconditionally included in
-/// the final binary, regardless of whether or not they're actually used.
-///
-/// Therefore, this is limited to `compat_fn_optional` functions which must be
-/// preloaded and any functions which may be more time sensitive, even for the first call.
-unsafe extern "C" fn init() {
-    // There is no locking here. This code is executed before main() is entered, and
-    // is guaranteed to be single-threaded.
-    //
-    // DO NOT do anything interesting or complicated in this function! DO NOT call
-    // any Rust functions or CRT functions if those functions touch any global state,
-    // because this function runs during global initialization. For example, DO NOT
-    // do any dynamic allocation, don't call LoadLibrary, etc.
-
-    if let Some(synch) = Module::new(c::SYNCH_API) {
-        // These are optional and so we must manually attempt to load them
-        // before they can be used.
-        c::WaitOnAddress::preload(synch);
-        c::WakeByAddressSingle::preload(synch);
-    }
-
-    if let Some(kernel32) = Module::new(c::KERNEL32) {
-        // Preloading this means getting a precise time will be as fast as possible.
-        c::GetSystemTimePreciseAsFileTime::preload(kernel32);
-    }
-}
-
 /// Represents a loaded module.
 ///
 /// Note that the modules std depends on must not be unloaded.
@@ -151,7 +88,7 @@ impl Module {
 macro_rules! compat_fn_with_fallback {
     (pub static $module:ident: &CStr = $name:expr; $(
         $(#[$meta:meta])*
-        pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block
+        $vis:vis fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $fallback_body:block
     )*) => (
         pub static $module: &CStr = $name;
     $(
@@ -196,11 +133,6 @@ macro_rules! compat_fn_with_fallback {
                 $fallback_body
             }
 
-            #[allow(unused)]
-            pub(in crate::sys) fn preload(module: Module) {
-                load_from_module(Some(module));
-            }
-
             #[inline(always)]
             pub unsafe fn call($($argname: $argtype),*) -> $rettype {
                 let func: F = mem::transmute(PTR.load(Ordering::Relaxed));
@@ -208,66 +140,65 @@ macro_rules! compat_fn_with_fallback {
             }
         }
         $(#[$meta])*
-        pub use $symbol::call as $symbol;
+        $vis use $symbol::call as $symbol;
     )*)
 }
 
-/// A function that either exists or doesn't.
+/// Optionally load `WaitOnAddress`.
+/// Unlike the dynamic loading described above, this does not have a fallback.
 ///
-/// NOTE: Optional functions must be preloaded in the `init` function above, or they will always be None.
-macro_rules! compat_fn_optional {
-    (pub static $module:ident: &CStr = $name:expr; $(
-        $(#[$meta:meta])*
-        pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty;
-    )*) => (
-        pub static $module: &CStr = $name;
-    $(
-        $(#[$meta])*
-        pub mod $symbol {
-            #[allow(unused_imports)]
-            use super::*;
-            use crate::mem;
-            use crate::sync::atomic::{AtomicPtr, Ordering};
-            use crate::sys::compat::Module;
-            use crate::ptr::{self, NonNull};
-
-            type F = unsafe extern "system" fn($($argtype),*) -> $rettype;
-
-            /// `PTR` will either be `null()` or set to the loaded function.
-            static PTR: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
-
-            /// Only allow access to the function if it has loaded successfully.
-            #[inline(always)]
-            #[cfg(not(miri))]
-            pub fn option() -> Option<F> {
-                unsafe {
-                    NonNull::new(PTR.load(Ordering::Relaxed)).map(|f| mem::transmute(f))
-                }
-            }
-
-            // Miri does not understand the way we do preloading
-            // therefore load the function here instead.
-            #[cfg(miri)]
-            pub fn option() -> Option<F> {
-                let mut func = NonNull::new(PTR.load(Ordering::Relaxed));
-                if func.is_none() {
-                    unsafe { Module::new($module).map(preload) };
-                    func = NonNull::new(PTR.load(Ordering::Relaxed));
-                }
-                unsafe {
-                    func.map(|f| mem::transmute(f))
-                }
-            }
+/// This is rexported from sys::c. You should prefer to import
+/// from there in case this changes again in the future.
+pub mod WaitOnAddress {
+    use super::*;
+    use crate::mem;
+    use crate::ptr;
+    use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
+    use crate::sys::c;
+
+    static MODULE_NAME: &CStr = ansi_str!("api-ms-win-core-synch-l1-2-0");
+    static SYMBOL_NAME: &CStr = ansi_str!("WaitOnAddress");
+
+    // WaitOnAddress function signature.
+    type F = unsafe extern "system" fn(
+        Address: c::LPVOID,
+        CompareAddress: c::LPVOID,
+        AddressSize: c::SIZE_T,
+        dwMilliseconds: c::DWORD,
+    );
+
+    // A place to store the loaded function atomically.
+    static WAIT_ON_ADDRESS: AtomicPtr<c_void> = AtomicPtr::new(ptr::null_mut());
+
+    // We can skip trying to load again if we already tried.
+    static LOAD_MODULE: AtomicBool = AtomicBool::new(true);
+
+    #[inline(always)]
+    pub fn option() -> Option<F> {
+        let f = WAIT_ON_ADDRESS.load(Ordering::Acquire);
+        if !f.is_null() { Some(unsafe { mem::transmute(f) }) } else { try_load() }
+    }
 
-            #[allow(unused)]
-            pub(in crate::sys) fn preload(module: Module) {
-                unsafe {
-                    static SYMBOL_NAME: &CStr = ansi_str!(sym $symbol);
-                    if let Some(f) = module.proc_address(SYMBOL_NAME) {
-                        PTR.store(f.as_ptr(), Ordering::Relaxed);
-                    }
-                }
+    #[cold]
+    fn try_load() -> Option<F> {
+        if LOAD_MODULE.load(Ordering::Acquire) {
+            // load the module
+            let mut wait_on_address = None;
+            if let Some(func) = try_load_inner() {
+                WAIT_ON_ADDRESS.store(func.as_ptr(), Ordering::Release);
+                wait_on_address = Some(unsafe { mem::transmute(func) });
             }
+            // Don't try to load the module again even if loading failed.
+            LOAD_MODULE.store(false, Ordering::Release);
+            wait_on_address
+        } else {
+            None
         }
-    )*)
+    }
+
+    // In the future this could be a `try` block but until then I think it's a
+    // little bit cleaner as a separate function.
+    fn try_load_inner() -> Option<NonNull<c_void>> {
+        unsafe { Module::new(MODULE_NAME)?.proc_address(SYMBOL_NAME) }
+    }
 }
diff --git a/library/std/src/sys/windows/rand.rs b/library/std/src/sys/windows/rand.rs
index 57248e3651b..f8fd93a7398 100644
--- a/library/std/src/sys/windows/rand.rs
+++ b/library/std/src/sys/windows/rand.rs
@@ -1,62 +1,9 @@
 use crate::io;
 use crate::mem;
-use crate::sync;
+use crate::ptr;
 use crate::sys::c;
 
-/// The kinds of HashMap RNG that may be available
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum HashMapRng {
-    Preferred,
-    Fallback,
-}
-
 pub fn hashmap_random_keys() -> (u64, u64) {
-    match get_hashmap_rng() {
-        HashMapRng::Preferred => {
-            preferred_rng().expect("couldn't generate random bytes with preferred RNG")
-        }
-        HashMapRng::Fallback => {
-            fallback_rng().expect("couldn't generate random bytes with fallback RNG")
-        }
-    }
-}
-
-/// Returns the HashMap RNG that should be used
-///
-/// Panics if they are both broken
-fn get_hashmap_rng() -> HashMapRng {
-    // Assume that if the preferred RNG is broken the first time we use it, it likely means
-    // that: the DLL has failed to load, there is no point to calling it over-and-over again,
-    // and we should cache the result
-    static VALUE: sync::OnceLock<HashMapRng> = sync::OnceLock::new();
-    *VALUE.get_or_init(choose_hashmap_rng)
-}
-
-/// Test whether we should use the preferred or fallback RNG
-///
-/// If the preferred RNG is successful, we choose it. Otherwise, if the fallback RNG is successful,
-/// we choose that
-///
-/// Panics if both the preferred and the fallback RNG are both non-functional
-fn choose_hashmap_rng() -> HashMapRng {
-    let preferred_error = match preferred_rng() {
-        Ok(_) => return HashMapRng::Preferred,
-        Err(e) => e,
-    };
-
-    match fallback_rng() {
-        Ok(_) => return HashMapRng::Fallback,
-        Err(fallback_error) => panic!(
-            "preferred RNG broken: `{}`, fallback RNG broken: `{}`",
-            preferred_error, fallback_error
-        ),
-    }
-}
-
-/// Generate random numbers using the preferred RNG function (BCryptGenRandom)
-fn preferred_rng() -> Result<(u64, u64), io::Error> {
-    use crate::ptr;
-
     let mut v = (0, 0);
     let ret = unsafe {
         c::BCryptGenRandom(
@@ -66,22 +13,23 @@ fn preferred_rng() -> Result<(u64, u64), io::Error> {
             c::BCRYPT_USE_SYSTEM_PREFERRED_RNG,
         )
     };
-
-    if ret == 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
+    if ret != 0 { fallback_rng() } else { v }
 }
 
 /// Generate random numbers using the fallback RNG function (RtlGenRandom)
 #[cfg(not(target_vendor = "uwp"))]
-fn fallback_rng() -> Result<(u64, u64), io::Error> {
+#[inline(never)]
+fn fallback_rng() -> (u64, u64) {
     let mut v = (0, 0);
     let ret =
         unsafe { c::RtlGenRandom(&mut v as *mut _ as *mut u8, mem::size_of_val(&v) as c::ULONG) };
 
-    if ret != 0 { Ok(v) } else { Err(io::Error::last_os_error()) }
+    if ret != 0 { v } else { panic!("fallback RNG broken: {}", io::Error::last_os_error()) }
 }
 
 /// We can't use RtlGenRandom with UWP, so there is no fallback
 #[cfg(target_vendor = "uwp")]
-fn fallback_rng() -> Result<(u64, u64), io::Error> {
-    Err(io::const_io_error!(io::ErrorKind::Unsupported, "RtlGenRandom() not supported on UWP"))
+#[inline(never)]
+fn fallback_rng() -> (u64, u64) {
+    panic!("fallback RNG broken: RtlGenRandom() not supported on UWP");
 }
diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs
index d876e0f6f3c..16863c9903a 100644
--- a/library/std/src/sys/windows/thread_parker.rs
+++ b/library/std/src/sys/windows/thread_parker.rs
@@ -197,21 +197,9 @@ impl Parker {
         // purpose, to make sure every unpark() has a release-acquire ordering
         // with park().
         if self.state.swap(NOTIFIED, Release) == PARKED {
-            if let Some(wake_by_address_single) = c::WakeByAddressSingle::option() {
-                unsafe {
-                    wake_by_address_single(self.ptr());
-                }
-            } else {
-                // If we run NtReleaseKeyedEvent before the waiting thread runs
-                // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
-                // If the waiting thread wakes up before we run NtReleaseKeyedEvent
-                // (e.g. due to a timeout), this blocks until we do wake up a thread.
-                // To prevent this thread from blocking indefinitely in that case,
-                // park_impl() will, after seeing the state set to NOTIFIED after
-                // waking up, call NtWaitForKeyedEvent again to unblock us.
-                unsafe {
-                    c::NtReleaseKeyedEvent(keyed_event_handle(), self.ptr(), 0, ptr::null_mut());
-                }
+            unsafe {
+                // This calls either WakeByAddressSingle or unpark_keyed_event (see below).
+                c::wake_by_address_single_or_unpark_keyed_event(self.ptr());
             }
         }
     }
@@ -221,6 +209,19 @@ impl Parker {
     }
 }
 
+// This function signature makes it compatible with c::WakeByAddressSingle
+// so that it can be used as a fallback for that function.
+pub unsafe extern "C" fn unpark_keyed_event(address: c::LPVOID) {
+    // If we run NtReleaseKeyedEvent before the waiting thread runs
+    // NtWaitForKeyedEvent, this (shortly) blocks until we can wake it up.
+    // If the waiting thread wakes up before we run NtReleaseKeyedEvent
+    // (e.g. due to a timeout), this blocks until we do wake up a thread.
+    // To prevent this thread from blocking indefinitely in that case,
+    // park_impl() will, after seeing the state set to NOTIFIED after
+    // waking up, call NtWaitForKeyedEvent again to unblock us.
+    c::NtReleaseKeyedEvent(keyed_event_handle(), address, 0, ptr::null_mut());
+}
+
 fn keyed_event_handle() -> c::HANDLE {
     const INVALID: c::HANDLE = ptr::invalid_mut(!0);
     static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index c084e77d3a9..280eba75f0c 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -547,7 +547,6 @@ mod dist {
         config.stage = 0;
         config.cmd = Subcommand::Test {
             paths: vec!["library/std".into()],
-            skip: vec![],
             test_args: vec![],
             rustc_args: vec![],
             fail_fast: true,
@@ -618,7 +617,6 @@ mod dist {
         let mut config = configure(&["A"], &["A"]);
         config.cmd = Subcommand::Test {
             paths: vec![],
-            skip: vec![],
             test_args: vec![],
             rustc_args: vec![],
             fail_fast: true,
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 394bd8b4e28..4e1e8ef9dea 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -140,7 +140,13 @@ impl Step for Std {
             cargo_subcommand(builder.kind),
         );
 
-        cargo.arg("--all-targets");
+        // If we're not in stage 0, tests and examples will fail to compile
+        // from `core` definitions being loaded from two different `libcore`
+        // .rmeta and .rlib files.
+        if compiler.stage == 0 {
+            cargo.arg("--all-targets");
+        }
+
         std_cargo(builder, target, compiler.stage, &mut cargo);
 
         // Explicitly pass -p for all dependencies krates -- this will force cargo
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 80b3bcce860..39d9ce1621b 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -115,7 +115,6 @@ pub enum Subcommand {
         compare_mode: Option<String>,
         pass: Option<String>,
         run: Option<String>,
-        skip: Vec<String>,
         test_args: Vec<String>,
         rustc_args: Vec<String>,
         fail_fast: bool,
@@ -568,7 +567,6 @@ Arguments:
                 compare_mode: matches.opt_str("compare-mode"),
                 pass: matches.opt_str("pass"),
                 run: matches.opt_str("run"),
-                skip: matches.opt_strs("skip"),
                 test_args: matches.opt_strs("test-args"),
                 rustc_args: matches.opt_strs("rustc-args"),
                 fail_fast: !matches.opt_present("no-fail-fast"),
@@ -708,16 +706,6 @@ impl Subcommand {
         let mut args = vec![];
 
         match *self {
-            Subcommand::Test { ref skip, .. } => {
-                for s in skip {
-                    args.push("--skip");
-                    args.push(s.as_str());
-                }
-            }
-            _ => (),
-        };
-
-        match *self {
             Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
                 args.extend(test_args.iter().flat_map(|s| s.split_whitespace()))
             }
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index cd421c249d8..f84de73297a 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -624,20 +624,6 @@ impl Build {
     /// If any submodule has been initialized already, sync it unconditionally.
     /// This avoids contributors checking in a submodule change by accident.
     pub fn maybe_update_submodules(&self) {
-        // WARNING: keep this in sync with the submodules hard-coded in bootstrap.py
-        let mut bootstrap_submodules: Vec<&str> = vec![
-            "src/tools/rust-installer",
-            "src/tools/cargo",
-            "src/tools/rls",
-            "src/tools/miri",
-            "library/backtrace",
-            "library/stdarch",
-        ];
-        // As in bootstrap.py, we include `rust-analyzer` if `build.vendor` was set in
-        // `config.toml`.
-        if self.config.vendor {
-            bootstrap_submodules.push("src/tools/rust-analyzer");
-        }
         // Avoid running git when there isn't a git checkout.
         if !self.config.submodules(&self.rust_info) {
             return;
@@ -653,10 +639,8 @@ impl Build {
             // Look for `submodule.$name.path = $path`
             // Sample output: `submodule.src/rust-installer.path src/tools/rust-installer`
             let submodule = Path::new(line.splitn(2, ' ').nth(1).unwrap());
-            // avoid updating submodules twice
-            if !bootstrap_submodules.iter().any(|&p| Path::new(p) == submodule)
-                && channel::GitInfo::new(false, submodule).is_git()
-            {
+            // Don't update the submodule unless it's already been cloned.
+            if channel::GitInfo::new(false, submodule).is_git() {
                 self.update_submodule(submodule);
             }
         }
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 3347246ea8f..4d548dbb638 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -345,13 +345,6 @@ impl Step for Llvm {
             cfg.define("LLVM_ENABLE_ZLIB", "OFF");
         }
 
-        if builder.config.llvm_thin_lto {
-            cfg.define("LLVM_ENABLE_LTO", "Thin");
-            if !target.contains("apple") {
-                cfg.define("LLVM_ENABLE_LLD", "ON");
-            }
-        }
-
         // This setting makes the LLVM tools link to the dynamic LLVM library,
         // which saves both memory during parallel links and overall disk space
         // for the tools. We don't do this on every platform as it doesn't work
@@ -463,15 +456,8 @@ impl Step for Llvm {
             cfg.define("LLVM_VERSION_SUFFIX", suffix);
         }
 
-        if let Some(ref linker) = builder.config.llvm_use_linker {
-            cfg.define("LLVM_USE_LINKER", linker);
-        }
-
-        if builder.config.llvm_allow_old_toolchain {
-            cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
-        }
-
         configure_cmake(builder, target, &mut cfg, true, ldflags);
+        configure_llvm(builder, target, &mut cfg);
 
         for (key, val) in &builder.config.llvm_build_config {
             cfg.define(key, val);
@@ -731,6 +717,25 @@ fn configure_cmake(
     }
 }
 
+fn configure_llvm(builder: &Builder<'_>, target: TargetSelection, cfg: &mut cmake::Config) {
+    // ThinLTO is only available when building with LLVM, enabling LLD is required.
+    // Apple's linker ld64 supports ThinLTO out of the box though, so don't use LLD on Darwin.
+    if builder.config.llvm_thin_lto {
+        cfg.define("LLVM_ENABLE_LTO", "Thin");
+        if !target.contains("apple") {
+            cfg.define("LLVM_ENABLE_LLD", "ON");
+        }
+    }
+
+    if let Some(ref linker) = builder.config.llvm_use_linker {
+        cfg.define("LLVM_USE_LINKER", linker);
+    }
+
+    if builder.config.llvm_allow_old_toolchain {
+        cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
+    }
+}
+
 // Adapted from https://github.com/alexcrichton/cc-rs/blob/fba7feded71ee4f63cfe885673ead6d7b4f2f454/src/lib.rs#L2347-L2365
 fn get_var(var_base: &str, host: &str, target: &str) -> Option<OsString> {
     let kind = if host == target { "HOST" } else { "TARGET" };
@@ -794,6 +799,7 @@ impl Step for Lld {
         }
 
         configure_cmake(builder, target, &mut cfg, true, ldflags);
+        configure_llvm(builder, target, &mut cfg);
 
         // This is an awful, awful hack. Discovered when we migrated to using
         // clang-cl to compile LLVM/LLD it turns out that LLD, when built out of
@@ -825,10 +831,6 @@ impl Step for Lld {
             .define("LLVM_CONFIG_PATH", llvm_config_shim)
             .define("LLVM_INCLUDE_TESTS", "OFF");
 
-        if builder.config.llvm_allow_old_toolchain {
-            cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
-        }
-
         // While we're using this horrible workaround to shim the execution of
         // llvm-config, let's just pile on more. I can't seem to figure out how
         // to build LLD as a standalone project and also cross-compile it at the
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 5c8034d53e3..197821f034f 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -289,8 +289,6 @@ impl Step for Cargo {
         // Don't run cross-compile tests, we may not have cross-compiled libstd libs
         // available.
         cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
-        // Disable a test that has issues with mingw.
-        cargo.env("CARGO_TEST_DISABLE_GIT_CLI", "1");
         // Forcibly disable tests using nightly features since any changes to
         // those features won't be able to land.
         cargo.env("CARGO_TEST_DISABLE_NIGHTLY", "1");
@@ -1488,6 +1486,11 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             cmd.arg("--run-clang-based-tests-with").arg(clang_exe);
         }
 
+        for exclude in &builder.config.exclude {
+            cmd.arg("--skip");
+            cmd.arg(&exclude.path);
+        }
+
         // Get paths from cmd args
         let paths = match &builder.config.cmd {
             Subcommand::Test { ref paths, .. } => &paths[..],
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index 839a6d27199..06fa5039fdf 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -158,34 +158,38 @@ impl Step for ToolBuild {
                       a transitive dependency has different features activated \
                       than in a previous build:\n"
             );
-            eprintln!(
-                "the following dependencies are duplicated although they \
-                      have the same features enabled:"
-            );
             let (same, different): (Vec<_>, Vec<_>) =
                 duplicates.into_iter().partition(|(_, cur, prev)| cur.2 == prev.2);
-            for (id, cur, prev) in same {
-                eprintln!("  {}", id);
-                // same features
-                eprintln!("    `{}` ({:?})\n    `{}` ({:?})", cur.0, cur.1, prev.0, prev.1);
-            }
-            eprintln!("the following dependencies have different features:");
-            for (id, cur, prev) in different {
-                eprintln!("  {}", id);
-                let cur_features: HashSet<_> = cur.2.into_iter().collect();
-                let prev_features: HashSet<_> = prev.2.into_iter().collect();
-                eprintln!(
-                    "    `{}` additionally enabled features {:?} at {:?}",
-                    cur.0,
-                    &cur_features - &prev_features,
-                    cur.1
-                );
+            if !same.is_empty() {
                 eprintln!(
-                    "    `{}` additionally enabled features {:?} at {:?}",
-                    prev.0,
-                    &prev_features - &cur_features,
-                    prev.1
+                    "the following dependencies are duplicated although they \
+                      have the same features enabled:"
                 );
+                for (id, cur, prev) in same {
+                    eprintln!("  {}", id);
+                    // same features
+                    eprintln!("    `{}` ({:?})\n    `{}` ({:?})", cur.0, cur.1, prev.0, prev.1);
+                }
+            }
+            if !different.is_empty() {
+                eprintln!("the following dependencies have different features:");
+                for (id, cur, prev) in different {
+                    eprintln!("  {}", id);
+                    let cur_features: HashSet<_> = cur.2.into_iter().collect();
+                    let prev_features: HashSet<_> = prev.2.into_iter().collect();
+                    eprintln!(
+                        "    `{}` additionally enabled features {:?} at {:?}",
+                        cur.0,
+                        &cur_features - &prev_features,
+                        cur.1
+                    );
+                    eprintln!(
+                        "    `{}` additionally enabled features {:?} at {:?}",
+                        prev.0,
+                        &prev_features - &cur_features,
+                        prev.1
+                    );
+                }
             }
             eprintln!();
             eprintln!(
diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md
index 4b90b890eb2..b71a348abd9 100644
--- a/src/ci/docker/README.md
+++ b/src/ci/docker/README.md
@@ -219,12 +219,15 @@ For targets: `armv7-unknown-linux-gnueabihf`
 For targets: `aarch64-unknown-linux-gnu`
 
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
 - Target options > Target Architecture = arm
 - Target options > Bitness = 64-bit
 - Operating System > Target OS = linux
-- Operating System > Linux kernel version = 4.2.6
+- Operating System > Linux kernel version = 4.1.49
+- Binary utilities > Version of binutils = 2.32
 - C-library > glibc version = 2.17 -- aarch64 support was introduced in this version
-- C compiler > gcc version = 5.2.0
+- C compiler > gcc version = 8.3.0
 - C compiler > C++ = ENABLE -- to cross compile LLVM
 
 ### `powerpc-linux-gnu.config`
@@ -232,14 +235,15 @@ For targets: `aarch64-unknown-linux-gnu`
 For targets: `powerpc-unknown-linux-gnu`
 
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
 - Target options > Target Architecture = powerpc
 - Target options > Emit assembly for CPU = powerpc -- pure 32-bit PowerPC
 - Operating System > Target OS = linux
-- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
-- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
-- C compiler > gcc version = 5.2.0
+- Operating System > Linux kernel version = 3.2.101
+- Binary utilities > Version of binutils = 2.30
+- C-library > glibc version = 2.17 -- ~RHEL7 glibc
+- C compiler > gcc version = 8.3.0
 - C compiler > C++ = ENABLE -- to cross compile LLVM
 
 ### `powerpc64-linux-gnu.config`
@@ -247,16 +251,17 @@ For targets: `powerpc-unknown-linux-gnu`
 For targets: `powerpc64-unknown-linux-gnu`
 
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
 - Target options > Target Architecture = powerpc
 - Target options > Bitness = 64-bit
 - Target options > Emit assembly for CPU = power4 -- (+)
 - Target options > Tune for CPU = power6 -- (+)
 - Operating System > Target OS = linux
-- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
-- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
-- C compiler > gcc version = 5.2.0
+- Operating System > Linux kernel version = 3.2.101
+- Binary utilities > Version of binutils = 2.32
+- C-library > glibc version = 2.17 -- ~RHEL7 glibc
+- C compiler > gcc version = 8.3.0
 - C compiler > C++ = ENABLE -- to cross compile LLVM
 
 (+) These CPU options match the configuration of the toolchains in RHEL6.
@@ -266,13 +271,14 @@ For targets: `powerpc64-unknown-linux-gnu`
 For targets: `s390x-unknown-linux-gnu`
 
 - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET}
-- Path and misc options > Patches origin = Bundled, then local
-- Path and misc options > Local patch directory = /tmp/patches
+- Path and misc options > Use a mirror = ENABLE
+- Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc
 - Target options > Target Architecture = s390
 - Target options > Bitness = 64-bit
 - Operating System > Target OS = linux
-- Operating System > Linux kernel version = 2.6.32.71 -- ~RHEL6 kernel
-- C-library > glibc version = 2.12.1 -- ~RHEL6 glibc
+- Operating System > Linux kernel version = 3.2.101
+- Binary utilities > Version of binutils = 2.32
+- C-library > glibc version = 2.17 -- ~RHEL7 glibc
 - C compiler > gcc version = 8.3.0
 - C compiler > gcc extra config = --with-arch=z10 -- LLVM's minimum support
 - C compiler > C++ = ENABLE -- to cross compile LLVM
diff --git a/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
index ab588ccc249..23fa23f0f2d 100644
--- a/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
@@ -1,28 +1,10 @@
 FROM ubuntu:20.04
-RUN apt-get update && \
-    apt-get install -y --no-install-recommends \
-        curl \
-        ca-certificates
-WORKDIR /tmp
-RUN curl -f https://curl.se/ca/cacert.pem -o cacert.pem
-
-FROM ubuntu:16.04
-
-# The ca-certificates in ubuntu-16 is too old, so update the certificates
-# with something more recent.
-COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
-ENV CURL_CA_BUNDLE /tmp/cacert.pem
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
 
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
 
 COPY scripts/rustbuild-setup.sh /scripts/
 RUN sh /scripts/rustbuild-setup.sh
@@ -37,14 +19,11 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
-ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin
+ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnu/bin
 
-ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \
-    AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-ar \
-    CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++
+ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-gcc \
+    AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-ar \
+    CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-g++
 
 ENV HOSTS=aarch64-unknown-linux-gnu
 
diff --git a/src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.config b/src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.config
index 416fa50374f..4561e2a1ec3 100644
--- a/src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.config
+++ b/src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.config
@@ -1,9 +1,30 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Crosstool-NG Configuration
-#
-CT_CONFIGURE_has_make381=y
-CT_CONFIGURE_has_xz=y
+# crosstool-NG  Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+CT_CONFIGURE_has_autoconf_2_65_or_newer=y
+CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
+CT_CONFIGURE_has_automake_1_15_or_newer=y
+CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
+CT_CONFIGURE_has_python_3_4_or_newer=y
+CT_CONFIGURE_has_bison_2_7_or_newer=y
+CT_CONFIGURE_has_python=y
+CT_CONFIGURE_has_git=y
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
 CT_MODULES=y
 
 #
@@ -20,39 +41,49 @@ CT_MODULES=y
 #
 # Paths
 #
-CT_LOCAL_TARBALLS_DIR=""
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
 CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
 CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
-CT_INSTALL_DIR="${CT_PREFIX_DIR}"
 CT_RM_RF_PREFIX_DIR=y
 CT_REMOVE_DOCS=y
-CT_INSTALL_DIR_RO=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
 CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
 # CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
 
 #
 # Downloading
 #
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
 # CT_FORBID_DOWNLOAD is not set
 # CT_FORCE_DOWNLOAD is not set
 CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
 # CT_ONLY_DOWNLOAD is not set
 CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
 CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
 
 #
 # Extracting
 #
 # CT_FORCE_EXTRACT is not set
-CT_OVERIDE_CONFIG_GUESS_SUB=y
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
 # CT_ONLY_EXTRACT is not set
 CT_PATCH_BUNDLED=y
-# CT_PATCH_LOCAL is not set
 # CT_PATCH_BUNDLED_LOCAL is not set
-# CT_PATCH_LOCAL_BUNDLED is not set
-# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set
-# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set
-# CT_PATCH_NONE is not set
 CT_PATCH_ORDER="bundled"
 
 #
@@ -76,11 +107,11 @@ CT_CONFIG_SHELL="${bash}"
 #
 # CT_LOG_ERROR is not set
 # CT_LOG_WARN is not set
-CT_LOG_INFO=y
-# CT_LOG_EXTRA is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
 # CT_LOG_ALL is not set
 # CT_LOG_DEBUG is not set
-CT_LOG_LEVEL_MAX="INFO"
+CT_LOG_LEVEL_MAX="EXTRA"
 # CT_LOG_SEE_TOOLS_WARN is not set
 CT_LOG_PROGRESS_BAR=y
 CT_LOG_TO_FILE=y
@@ -89,76 +120,76 @@ CT_LOG_FILE_COMPRESS=y
 #
 # Target options
 #
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+CT_ARCH_ARM=y
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+# CT_ARCH_MIPS is not set
+# CT_ARCH_NIOS2 is not set
+# CT_ARCH_POWERPC is not set
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
 CT_ARCH="arm"
-CT_ARCH_SUPPORTS_BOTH_MMU=y
-CT_ARCH_SUPPORTS_BOTH_ENDIAN=y
-CT_ARCH_SUPPORTS_32=y
-CT_ARCH_SUPPORTS_64=y
-CT_ARCH_SUPPORTS_WITH_ARCH=y
-CT_ARCH_SUPPORTS_WITH_CPU=y
-CT_ARCH_SUPPORTS_WITH_TUNE=y
-CT_ARCH_DEFAULT_HAS_MMU=y
-CT_ARCH_DEFAULT_LE=y
-CT_ARCH_DEFAULT_32=y
-CT_ARCH_ARCH=""
+CT_ARCH_CHOICE_KSYM="ARM"
+# CT_ARCH_ALPHA_EV4 is not set
+# CT_ARCH_ALPHA_EV45 is not set
+# CT_ARCH_ALPHA_EV5 is not set
+# CT_ARCH_ALPHA_EV56 is not set
+# CT_ARCH_ALPHA_EV6 is not set
+# CT_ARCH_ALPHA_EV67 is not set
 CT_ARCH_CPU=""
 CT_ARCH_TUNE=""
-# CT_ARCH_BE is not set
-CT_ARCH_LE=y
-# CT_ARCH_32 is not set
-CT_ARCH_64=y
-CT_ARCH_BITNESS=64
-CT_TARGET_CFLAGS=""
-CT_TARGET_LDFLAGS=""
-# CT_ARCH_alpha is not set
-CT_ARCH_arm=y
-# CT_ARCH_avr is not set
-# CT_ARCH_m68k is not set
-# CT_ARCH_mips is not set
-# CT_ARCH_nios2 is not set
-# CT_ARCH_powerpc is not set
-# CT_ARCH_s390 is not set
-# CT_ARCH_sh is not set
-# CT_ARCH_sparc is not set
-# CT_ARCH_x86 is not set
-# CT_ARCH_xtensa is not set
-CT_ARCH_alpha_AVAILABLE=y
-CT_ARCH_arm_AVAILABLE=y
-CT_ARCH_avr_AVAILABLE=y
-CT_ARCH_m68k_AVAILABLE=y
-CT_ARCH_microblaze_AVAILABLE=y
-CT_ARCH_mips_AVAILABLE=y
-CT_ARCH_nios2_AVAILABLE=y
-CT_ARCH_powerpc_AVAILABLE=y
-CT_ARCH_s390_AVAILABLE=y
-CT_ARCH_sh_AVAILABLE=y
-CT_ARCH_sparc_AVAILABLE=y
-CT_ARCH_x86_AVAILABLE=y
-CT_ARCH_xtensa_AVAILABLE=y
+CT_ARCH_ARM_SHOW=y
+
+#
+# Options for arm
+#
+CT_ARCH_ARM_PKG_KSYM=""
+# CT_ARCH_ARM_MODE_ARM is not set
+# CT_ARCH_ARM_MODE_THUMB is not set
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
 CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
 
 #
 # Generic target options
 #
 # CT_MULTILIB is not set
+CT_DEMULTILIB=y
+CT_ARCH_SUPPORTS_BOTH_MMU=y
+CT_ARCH_DEFAULT_HAS_MMU=y
 CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_FLAT_FORMAT=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_LE=y
+# CT_ARCH_BE is not set
+CT_ARCH_LE=y
 CT_ARCH_ENDIAN="little"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=64
+# CT_ARCH_32 is not set
+CT_ARCH_64=y
 
 #
 # Target optimisations
 #
+CT_ARCH_SUPPORTS_WITH_ARCH=y
+CT_ARCH_SUPPORTS_WITH_CPU=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
 CT_ARCH_EXCLUSIVE_WITH_CPU=y
-CT_ARCH_FLOAT=""
-
-#
-# arm other options
-#
-CT_ARCH_ARM_MODE="arm"
-CT_ARCH_ARM_MODE_ARM=y
-# CT_ARCH_ARM_MODE_THUMB is not set
-# CT_ARCH_ARM_INTERWORKING is not set
-CT_ARCH_ARM_EABI_FORCE=y
-CT_ARCH_ARM_EABI=y
+CT_ARCH_ARCH=""
+# CT_ARCH_FLOAT_AUTO is not set
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SOFTFP is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
 
 #
 # Toolchain options
@@ -172,7 +203,9 @@ CT_USE_SYSROOT=y
 CT_SYSROOT_NAME="sysroot"
 CT_SYSROOT_DIR_PREFIX=""
 CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
 # CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
 CT_TOOLCHAIN_PKGVERSION=""
 CT_TOOLCHAIN_BUGURL=""
 
@@ -206,127 +239,214 @@ CT_BUILD_SUFFIX=""
 # Operating System
 #
 CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
 CT_KERNEL="linux"
-CT_KERNEL_VERSION="4.2.6"
-# CT_KERNEL_bare_metal is not set
-CT_KERNEL_linux=y
-CT_KERNEL_bare_metal_AVAILABLE=y
-CT_KERNEL_linux_AVAILABLE=y
-# CT_KERNEL_V_4_3 is not set
-CT_KERNEL_V_4_2=y
-# CT_KERNEL_V_4_1 is not set
-# CT_KERNEL_V_3_18 is not set
-# CT_KERNEL_V_3_14 is not set
-# CT_KERNEL_V_3_12 is not set
-# CT_KERNEL_V_3_10 is not set
-# CT_KERNEL_V_3_4 is not set
-# CT_KERNEL_V_3_2 is not set
-# CT_KERNEL_V_2_6_32 is not set
-# CT_KERNEL_LINUX_CUSTOM is not set
-CT_KERNEL_windows_AVAILABLE=y
-
-#
-# Common kernel options
-#
-CT_SHARED_LIBS=y
-
-#
-# linux other options
-#
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+# CT_LINUX_V_4_4 is not set
+CT_LINUX_V_4_1=y
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="4.1.49"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_later_than_3_7=y
+CT_LINUX_3_7_or_later=y
+CT_LINUX_REQUIRE_3_7_or_later=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
 CT_KERNEL_LINUX_VERBOSITY_0=y
 # CT_KERNEL_LINUX_VERBOSITY_1 is not set
 # CT_KERNEL_LINUX_VERBOSITY_2 is not set
 CT_KERNEL_LINUX_VERBOSE_LEVEL=0
 CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
 
 #
 # Binary utilities
 #
 CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
 CT_BINUTILS="binutils"
-CT_BINUTILS_binutils=y
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+# CT_BINUTILS_V_2_32 is not set
+# CT_BINUTILS_V_2_31 is not set
+# CT_BINUTILS_V_2_30 is not set
+CT_BINUTILS_V_2_29=y
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.29.1"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_2_30_or_older=y
+CT_BINUTILS_older_than_2_30=y
+CT_BINUTILS_REQUIRE_older_than_2_30=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
 
 #
 # GNU binutils
 #
-# CT_CC_BINUTILS_SHOW_LINARO is not set
-CT_BINUTILS_V_2_25_1=y
-# CT_BINUTILS_V_2_25 is not set
-# CT_BINUTILS_V_2_24 is not set
-# CT_BINUTILS_V_2_23_2 is not set
-# CT_BINUTILS_V_2_23_1 is not set
-# CT_BINUTILS_V_2_22 is not set
-# CT_BINUTILS_V_2_21_53 is not set
-# CT_BINUTILS_V_2_21_1a is not set
-# CT_BINUTILS_V_2_20_1a is not set
-# CT_BINUTILS_V_2_19_1a is not set
-# CT_BINUTILS_V_2_18a is not set
-CT_BINUTILS_VERSION="2.25.1"
-CT_BINUTILS_2_25_1_or_later=y
-CT_BINUTILS_2_25_or_later=y
-CT_BINUTILS_2_24_or_later=y
-CT_BINUTILS_2_23_or_later=y
-CT_BINUTILS_2_22_or_later=y
-CT_BINUTILS_2_21_or_later=y
-CT_BINUTILS_2_20_or_later=y
-CT_BINUTILS_2_19_or_later=y
-CT_BINUTILS_2_18_or_later=y
 CT_BINUTILS_HAS_HASH_STYLE=y
 CT_BINUTILS_HAS_GOLD=y
-CT_BINUTILS_GOLD_SUPPORTS_ARCH=y
-CT_BINUTILS_GOLD_SUPPORT=y
 CT_BINUTILS_HAS_PLUGINS=y
 CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
-CT_BINUTILS_FORCE_LD_BFD=y
+CT_BINUTILS_GOLD_SUPPORTS_ARCH=y
+CT_BINUTILS_GOLD_SUPPORT=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
 CT_BINUTILS_LINKER_LD=y
 # CT_BINUTILS_LINKER_LD_GOLD is not set
-# CT_BINUTILS_LINKER_GOLD_LD is not set
 CT_BINUTILS_LINKERS_LIST="ld"
 CT_BINUTILS_LINKER_DEFAULT="bfd"
 # CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
 CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
 # CT_BINUTILS_FOR_TARGET is not set
-
-#
-# binutils other options
-#
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
 
 #
 # C-library
 #
+CT_LIBC_GLIBC=y
+# CT_LIBC_NEWLIB is not set
+# CT_LIBC_NONE is not set
+# CT_LIBC_UCLIBC is not set
 CT_LIBC="glibc"
-CT_LIBC_VERSION="2.17"
-CT_LIBC_glibc=y
-# CT_LIBC_musl is not set
-# CT_LIBC_uClibc is not set
-CT_LIBC_avr_libc_AVAILABLE=y
-CT_LIBC_glibc_AVAILABLE=y
+CT_LIBC_CHOICE_KSYM="GLIBC"
 CT_THREADS="nptl"
-# CT_CC_GLIBC_SHOW_LINARO is not set
-# CT_LIBC_GLIBC_V_2_22 is not set
-# CT_LIBC_GLIBC_V_2_21 is not set
-# CT_LIBC_GLIBC_V_2_20 is not set
-# CT_LIBC_GLIBC_V_2_19 is not set
-# CT_LIBC_GLIBC_V_2_18 is not set
-CT_LIBC_GLIBC_V_2_17=y
-# CT_LIBC_GLIBC_V_2_16_0 is not set
-# CT_LIBC_GLIBC_V_2_15 is not set
-# CT_LIBC_GLIBC_V_2_14_1 is not set
-# CT_LIBC_GLIBC_V_2_14 is not set
-# CT_LIBC_GLIBC_V_2_13 is not set
-# CT_LIBC_GLIBC_V_2_12_2 is not set
-# CT_LIBC_GLIBC_V_2_12_1 is not set
-# CT_LIBC_GLIBC_V_2_11_1 is not set
-# CT_LIBC_GLIBC_V_2_11 is not set
-# CT_LIBC_GLIBC_V_2_10_1 is not set
-# CT_LIBC_GLIBC_V_2_9 is not set
-# CT_LIBC_GLIBC_V_2_8 is not set
-CT_LIBC_GLIBC_2_17_or_later=y
-CT_LIBC_mingw_AVAILABLE=y
-CT_LIBC_musl_AVAILABLE=y
-CT_LIBC_newlib_AVAILABLE=y
-CT_LIBC_none_AVAILABLE=y
-CT_LIBC_uClibc_AVAILABLE=y
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+CT_GLIBC_USE="GLIBC"
+CT_GLIBC_PKG_NAME="glibc"
+CT_GLIBC_SRC_RELEASE=y
+CT_GLIBC_PATCH_ORDER="global"
+# CT_GLIBC_V_2_29 is not set
+# CT_GLIBC_V_2_28 is not set
+# CT_GLIBC_V_2_27 is not set
+# CT_GLIBC_V_2_26 is not set
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+# CT_GLIBC_V_2_23 is not set
+# CT_GLIBC_V_2_19 is not set
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.17"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
+CT_GLIBC_2_29_or_older=y
+CT_GLIBC_older_than_2_29=y
+CT_GLIBC_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_older_than_2_23=y
+CT_GLIBC_2_20_or_older=y
+CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_2_17_or_older=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_NPTL_ADDON=y
+CT_GLIBC_HAS_PORTS_ADDON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+CT_GLIBC_USE_PORTS_ADDON=y
+CT_GLIBC_USE_NPTL_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="4.1.49"
+# CT_GLIBC_SSP_DEFAULT is not set
+# CT_GLIBC_SSP_NO is not set
+# CT_GLIBC_SSP_YES is not set
+# CT_GLIBC_SSP_ALL is not set
+# CT_GLIBC_SSP_STRONG is not set
+# CT_NEWLIB_USE_REDHAT is not set
+CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
 CT_LIBC_SUPPORT_THREADS_ANY=y
 CT_LIBC_SUPPORT_THREADS_NATIVE=y
 
@@ -334,100 +454,71 @@ CT_LIBC_SUPPORT_THREADS_NATIVE=y
 # Common C library options
 #
 CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
 CT_LIBC_XLDD=y
 
 #
-# glibc other options
-#
-# CT_LIBC_GLIBC_PORTS_EXTERNAL is not set
-CT_LIBC_GLIBC_MAY_FORCE_PORTS=y
-CT_LIBC_glibc_familly=y
-CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY=""
-CT_LIBC_GLIBC_CONFIGPARMS=""
-CT_LIBC_GLIBC_EXTRA_CFLAGS=""
-CT_LIBC_EXTRA_CC_ARGS=""
-# CT_LIBC_DISABLE_VERSIONING is not set
-CT_LIBC_OLDEST_ABI=""
-CT_LIBC_GLIBC_FORCE_UNWIND=y
-CT_LIBC_GLIBC_USE_PORTS=y
-CT_LIBC_ADDONS_LIST=""
-
-#
-# WARNING !!!                                            
-#
-
-#
-#   For glibc >= 2.8, it can happen that the tarballs    
-#
-
-#
-#   for the addons are not available for download.       
-#
-
-#
-#   If that happens, bad luck... Try a previous version  
-#
-
-#
-#   or try again later... :-(                            
-#
-# CT_LIBC_LOCALES is not set
-# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set
-CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y
-# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_LIBC_GLIBC_MIN_KERNEL="4.2.6"
-
-#
 # C compiler
 #
-CT_CC="gcc"
 CT_CC_CORE_PASSES_NEEDED=y
 CT_CC_CORE_PASS_1_NEEDED=y
 CT_CC_CORE_PASS_2_NEEDED=y
-CT_CC_gcc=y
-# CT_CC_GCC_SHOW_LINARO is not set
-CT_CC_GCC_V_5_2_0=y
-# CT_CC_GCC_V_4_9_3 is not set
-# CT_CC_GCC_V_4_8_5 is not set
-# CT_CC_GCC_V_4_7_4 is not set
-# CT_CC_GCC_V_4_6_4 is not set
-# CT_CC_GCC_V_4_5_4 is not set
-# CT_CC_GCC_V_4_4_7 is not set
-# CT_CC_GCC_V_4_3_6 is not set
-# CT_CC_GCC_V_4_2_4 is not set
-CT_CC_GCC_4_2_or_later=y
-CT_CC_GCC_4_3_or_later=y
-CT_CC_GCC_4_4_or_later=y
-CT_CC_GCC_4_5_or_later=y
-CT_CC_GCC_4_6_or_later=y
-CT_CC_GCC_4_7_or_later=y
-CT_CC_GCC_4_8_or_later=y
-CT_CC_GCC_4_9_or_later=y
-CT_CC_GCC_5=y
-CT_CC_GCC_5_or_later=y
-CT_CC_GCC_HAS_GRAPHITE=y
-CT_CC_GCC_USE_GRAPHITE=y
-CT_CC_GCC_HAS_LTO=y
-CT_CC_GCC_USE_LTO=y
-CT_CC_GCC_HAS_PKGVERSION_BUGURL=y
-CT_CC_GCC_HAS_BUILD_ID=y
-CT_CC_GCC_HAS_LNK_HASH_STYLE=y
-CT_CC_GCC_USE_GMP_MPFR=y
-CT_CC_GCC_USE_MPC=y
-CT_CC_GCC_HAS_LIBQUADMATH=y
-CT_CC_GCC_HAS_LIBSANITIZER=y
-CT_CC_GCC_VERSION="5.2.0"
-# CT_CC_LANG_FORTRAN is not set
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
 CT_CC_GCC_ENABLE_CXX_FLAGS=""
 CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
 CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
-CT_CC_GCC_EXTRA_ENV_ARRAY=""
 CT_CC_GCC_STATIC_LIBSTDCXX=y
 # CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
 
 #
 # Optimisation features
 #
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
 
 #
 # Settings for libraries running on target
@@ -456,97 +547,208 @@ CT_CC_GCC_DEC_FLOAT_AUTO=y
 # CT_CC_GCC_DEC_FLOAT_BID is not set
 # CT_CC_GCC_DEC_FLOAT_DPD is not set
 # CT_CC_GCC_DEC_FLOATS_NO is not set
-CT_CC_SUPPORT_CXX=y
-CT_CC_SUPPORT_FORTRAN=y
-CT_CC_SUPPORT_JAVA=y
-CT_CC_SUPPORT_ADA=y
-CT_CC_SUPPORT_OBJC=y
-CT_CC_SUPPORT_OBJCXX=y
-CT_CC_SUPPORT_GOLANG=y
+CT_ALL_CC_CHOICES="GCC"
 
 #
 # Additional supported languages:
 #
 CT_CC_LANG_CXX=y
-# CT_CC_LANG_JAVA is not set
+# CT_CC_LANG_FORTRAN is not set
 
 #
 # Debug facilities
 #
-# CT_DEBUG_dmalloc is not set
-# CT_DEBUG_duma is not set
-# CT_DEBUG_gdb is not set
-# CT_DEBUG_ltrace is not set
-# CT_DEBUG_strace is not set
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
 
 #
 # Companion libraries
 #
-CT_COMPLIBS_NEEDED=y
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# CT_ISL_V_0_15 is not set
+# CT_ISL_NO_VERSIONS is not set
+CT_ISL_VERSION="0.20"
+CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
+CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
 CT_LIBICONV_NEEDED=y
 CT_GETTEXT_NEEDED=y
 CT_GMP_NEEDED=y
 CT_MPFR_NEEDED=y
 CT_ISL_NEEDED=y
 CT_MPC_NEEDED=y
-CT_COMPLIBS=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
 CT_LIBICONV=y
 CT_GETTEXT=y
 CT_GMP=y
 CT_MPFR=y
 CT_ISL=y
 CT_MPC=y
-CT_LIBICONV_V_1_14=y
-CT_LIBICONV_VERSION="1.14"
-CT_GETTEXT_V_0_19_6=y
-CT_GETTEXT_VERSION="0.19.6"
-CT_GMP_V_6_0_0=y
-# CT_GMP_V_5_1_3 is not set
-# CT_GMP_V_5_1_1 is not set
-# CT_GMP_V_5_0_2 is not set
-# CT_GMP_V_5_0_1 is not set
-# CT_GMP_V_4_3_2 is not set
-# CT_GMP_V_4_3_1 is not set
-# CT_GMP_V_4_3_0 is not set
-CT_GMP_5_0_2_or_later=y
-CT_GMP_VERSION="6.0.0a"
-CT_MPFR_V_3_1_3=y
-# CT_MPFR_V_3_1_2 is not set
-# CT_MPFR_V_3_1_0 is not set
-# CT_MPFR_V_3_0_1 is not set
-# CT_MPFR_V_3_0_0 is not set
-# CT_MPFR_V_2_4_2 is not set
-# CT_MPFR_V_2_4_1 is not set
-# CT_MPFR_V_2_4_0 is not set
-CT_MPFR_VERSION="3.1.3"
-CT_ISL_V_0_14=y
-# CT_ISL_V_0_12_2 is not set
-CT_ISL_V_0_14_or_later=y
-CT_ISL_V_0_12_or_later=y
-CT_ISL_VERSION="0.14"
-# CT_CLOOG_V_0_18_4 is not set
-# CT_CLOOG_V_0_18_1 is not set
-# CT_CLOOG_V_0_18_0 is not set
-CT_MPC_V_1_0_3=y
-# CT_MPC_V_1_0_2 is not set
-# CT_MPC_V_1_0_1 is not set
-# CT_MPC_V_1_0 is not set
-# CT_MPC_V_0_9 is not set
-# CT_MPC_V_0_8_2 is not set
-# CT_MPC_V_0_8_1 is not set
-# CT_MPC_V_0_7 is not set
-CT_MPC_VERSION="1.0.3"
-
-#
-# Companion libraries common options
-#
-# CT_COMPLIBS_CHECK is not set
+CT_NCURSES=y
+CT_ZLIB=y
 
 #
 # Companion tools
 #
-
-#
-# READ HELP before you say 'Y' below !!!
-#
-# CT_COMP_TOOLS is not set
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
index 79c2c1d93d7..0c3b9ebdc33 100644
--- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
@@ -28,9 +28,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin
 
 ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \
diff --git a/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile
index dd1c83b4132..753d6450502 100644
--- a/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile
@@ -19,9 +19,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin
 
 ENV CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \
diff --git a/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile
index 32e3bc22ad7..7eb5097aae8 100644
--- a/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile
@@ -19,9 +19,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin
 
 ENV CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \
diff --git a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile
index 2b4b78e8135..cd86d9fb584 100644
--- a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile
@@ -1,48 +1,40 @@
-# We need recent curl, OpenSSL and CA certificates, so we can download further
-# dependencies in the debian:6 image. We use an ubuntu 20.04 image download
-# those.
-FROM ubuntu:20.04
-RUN apt-get update && \
-    apt-get install -y --no-install-recommends \
-        curl \
-        ca-certificates
-WORKDIR /tmp
-COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/
-RUN ./download-openssl-curl.sh
-
-# We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
-# distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
-# SLES 11 SP4 (glibc 2.11, kernel 3.0).
-FROM debian:6
+# We document platform support for minimum glibc 2.17 and kernel 3.2.
+# CentOS 7 has headers for kernel 3.10, but that's fine as long as we don't
+# actually use newer APIs in rustc or std without a fallback. It's more
+# important that we match glibc for ELF symbol versioning.
+FROM centos:7
 
 WORKDIR /build
 
-# Debian 6 is EOL and no longer available from the usual mirrors,
-# so we'll need to switch to http://archive.debian.org/
-RUN sed -i '/updates/d' /etc/apt/sources.list && \
-    sed -i 's/httpredir/archive/' /etc/apt/sources.list
-
-RUN apt-get update && \
-    apt-get install --allow-unauthenticated -y --no-install-recommends \
+RUN yum upgrade -y && \
+    yum install -y epel-release && \
+    yum install -y \
       automake \
       bzip2 \
       file \
-      g++ \
-      g++-multilib \
+      cmake3 \
       gcc \
-      gcc-multilib \
+      gcc-c++ \
       git \
-      lib32z1-dev \
-      libedit-dev \
-      libncurses-dev \
+      glibc-devel.i686 \
+      glibc-devel.x86_64 \
+      libedit-devel \
+      libstdc++-devel.i686 \
+      libstdc++-devel.x86_64 \
       make \
+      ncurses-devel \
+      openssl-devel \
       patch \
       perl \
-      pkg-config \
+      pkgconfig \
+      python3 \
       unzip \
       wget \
-      xz-utils \
-      zlib1g-dev
+      xz \
+      zlib-devel.i686 \
+      zlib-devel.x86_64
+
+RUN mkdir -p /rustroot/bin && ln -s /usr/bin/cmake3 /rustroot/bin/cmake
 
 ENV PATH=/rustroot/bin:$PATH
 ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
@@ -51,46 +43,9 @@ WORKDIR /tmp
 RUN mkdir /home/user
 COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
 
-# We need a build of openssl which supports SNI to download artifacts from
-# static.rust-lang.org. This'll be used to link into libcurl below (and used
-# later as well), so build a copy of OpenSSL with dynamic libraries into our
-# generic root.
-COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz
-COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
-RUN ./build-openssl.sh
-
-# The `curl` binary on Debian 6 doesn't support SNI which is needed for fetching
-# some https urls we have, so install a new version of libcurl + curl which is
-# using the openssl we just built previously.
-#
-# Note that we also disable a bunch of optional features of curl that we don't
-# really need.
-COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz
-COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh
-
-# Use up-to-date curl CA bundle
-COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
-ENV CURL_CA_BUNDLE /tmp/cacert.pem
-
-# binutils < 2.22 has a bug where the 32-bit executables it generates
-# immediately segfault in Rust, so we need to install our own binutils.
-#
-# See https://github.com/rust-lang/rust/issues/20440 for more info
-COPY host-x86_64/dist-x86_64-linux/build-binutils.sh /tmp/
-RUN ./build-binutils.sh
-
 # Need at least GCC 5.1 to compile LLVM nowadays
 COPY host-x86_64/dist-x86_64-linux/build-gcc.sh /tmp/
-RUN ./build-gcc.sh && apt-get remove -y gcc g++
-
-COPY host-x86_64/dist-x86_64-linux/build-python.sh /tmp/
-# Build Python 3 needed for LLVM 12.
-RUN ./build-python.sh 3.9.1
-
-# LLVM needs cmake 3.13.4 or higher.
-COPY host-x86_64/dist-x86_64-linux/build-cmake.sh /tmp/
-RUN ./build-cmake.sh
+RUN ./build-gcc.sh && yum remove -y gcc gcc-c++
 
 # Now build LLVM+Clang, afterwards configuring further compilations to use the
 # clang/clang++ compilers.
diff --git a/src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile
index ecaa495e97a..94a837151c6 100644
--- a/src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-powerpc-linux/Dockerfile
@@ -1,22 +1,16 @@
-FROM ubuntu:16.04
+FROM ubuntu:20.04
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
 
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
 
 COPY scripts/rustbuild-setup.sh /scripts/
 RUN sh /scripts/rustbuild-setup.sh
 USER rustbuild
 WORKDIR /tmp
 
-COPY host-x86_64/dist-powerpc-linux/patches/ /tmp/patches/
 COPY host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config host-x86_64/dist-powerpc-linux/build-powerpc-toolchain.sh /tmp/
 RUN ./build-powerpc-toolchain.sh
 
@@ -25,9 +19,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin
 
 ENV \
diff --git a/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch b/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch
deleted file mode 100644
index 744eb180cd1..00000000000
--- a/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001
-From: Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
-Date: Thu, 1 Nov 2012 18:00:06 -0500
-Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics.
-
----
- sysdeps/powerpc/Makefile | 4 ----
- 1 file changed, 4 deletions(-)
-
-diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
-index 79dd6fa976d5..7442b6709ad1 100644
---- a/sysdeps/powerpc/Makefile
-+++ b/sysdeps/powerpc/Makefile
-@@ -1,7 +1,3 @@
--# We always want to use the new mnemonic syntax even if we are on a RS6000
--# machine.
--+cflags += -mnew-mnemonics
--
- ifeq ($(subdir),gmon)
- sysdep_routines += ppc-mcount
- endif
--- 
-2.9.3
-
diff --git a/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/002-newer-gcc.patch b/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/002-newer-gcc.patch
deleted file mode 100644
index a96b4882c2d..00000000000
--- a/src/ci/docker/host-x86_64/dist-powerpc-linux/patches/glibc/2.11.1/002-newer-gcc.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-diff --git a/configure b/configure
-index b6752d147c6b..6089a3403410 100755
---- a/configure
-+++ b/configure
-@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; }
-   ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
-   case $ac_prog_version in
-     '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
--    3.4* | 4.[0-9]* )
-+    3.4* | [4-9].* )
-        ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
-     *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
- 
-diff --git a/configure.in b/configure.in
-index 56849dfc489a..09677eb3d0c1 100644
---- a/configure.in
-+++ b/configure.in
-@@ -960,7 +960,7 @@ fi
- # These programs are version sensitive.
- AC_CHECK_TOOL_PREFIX
- AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v,
--  [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ],
-+  [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ],
-   critic_missing="$critic_missing gcc")
- AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
-   [GNU Make[^0-9]*\([0-9][0-9.]*\)],
diff --git a/src/ci/docker/host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config b/src/ci/docker/host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config
index 814e1fa16f8..0df859ad944 100644
--- a/src/ci/docker/host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config
+++ b/src/ci/docker/host-x86_64/dist-powerpc-linux/powerpc-linux-gnu.config
@@ -1,9 +1,30 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Crosstool-NG Configuration
-#
-CT_CONFIGURE_has_make381=y
-CT_CONFIGURE_has_xz=y
+# crosstool-NG  Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+CT_CONFIGURE_has_autoconf_2_65_or_newer=y
+CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
+CT_CONFIGURE_has_automake_1_15_or_newer=y
+CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
+CT_CONFIGURE_has_python_3_4_or_newer=y
+CT_CONFIGURE_has_bison_2_7_or_newer=y
+CT_CONFIGURE_has_python=y
+CT_CONFIGURE_has_git=y
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
 CT_MODULES=y
 
 #
@@ -20,42 +41,50 @@ CT_MODULES=y
 #
 # Paths
 #
-CT_LOCAL_TARBALLS_DIR=""
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
 CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
 CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
-CT_INSTALL_DIR="${CT_PREFIX_DIR}"
 CT_RM_RF_PREFIX_DIR=y
 CT_REMOVE_DOCS=y
-CT_INSTALL_DIR_RO=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
 CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
 # CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
 
 #
 # Downloading
 #
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
 # CT_FORBID_DOWNLOAD is not set
 # CT_FORCE_DOWNLOAD is not set
 CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
 # CT_ONLY_DOWNLOAD is not set
 CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
 CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
 
 #
 # Extracting
 #
 # CT_FORCE_EXTRACT is not set
-CT_OVERIDE_CONFIG_GUESS_SUB=y
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
 # CT_ONLY_EXTRACT is not set
-# CT_PATCH_BUNDLED is not set
-# CT_PATCH_LOCAL is not set
-CT_PATCH_BUNDLED_LOCAL=y
-# CT_PATCH_LOCAL_BUNDLED is not set
-# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set
-# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set
-# CT_PATCH_NONE is not set
-CT_PATCH_ORDER="bundled,local"
-CT_PATCH_USE_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
+CT_PATCH_BUNDLED=y
+# CT_PATCH_BUNDLED_LOCAL is not set
+CT_PATCH_ORDER="bundled"
 
 #
 # Build behavior
@@ -78,11 +107,11 @@ CT_CONFIG_SHELL="${bash}"
 #
 # CT_LOG_ERROR is not set
 # CT_LOG_WARN is not set
-CT_LOG_INFO=y
-# CT_LOG_EXTRA is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
 # CT_LOG_ALL is not set
 # CT_LOG_DEBUG is not set
-CT_LOG_LEVEL_MAX="INFO"
+CT_LOG_LEVEL_MAX="EXTRA"
 # CT_LOG_SEE_TOOLS_WARN is not set
 CT_LOG_PROGRESS_BAR=y
 CT_LOG_TO_FILE=y
@@ -91,76 +120,70 @@ CT_LOG_FILE_COMPRESS=y
 #
 # Target options
 #
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+# CT_ARCH_ARM is not set
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+# CT_ARCH_MIPS is not set
+# CT_ARCH_NIOS2 is not set
+CT_ARCH_POWERPC=y
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
 CT_ARCH="powerpc"
-CT_ARCH_SUPPORTS_BOTH_ENDIAN=y
-CT_ARCH_SUPPORTS_32=y
-CT_ARCH_SUPPORTS_64=y
-CT_ARCH_SUPPORTS_WITH_ABI=y
-CT_ARCH_SUPPORTS_WITH_CPU=y
-CT_ARCH_SUPPORTS_WITH_TUNE=y
-CT_ARCH_SUPPORTS_WITH_FLOAT=y
-CT_ARCH_DEFAULT_BE=y
-CT_ARCH_DEFAULT_32=y
-CT_ARCH_ABI=""
+CT_ARCH_CHOICE_KSYM="POWERPC"
 CT_ARCH_CPU="powerpc"
 CT_ARCH_TUNE=""
-CT_ARCH_BE=y
-# CT_ARCH_LE is not set
-CT_ARCH_32=y
-# CT_ARCH_64 is not set
-CT_ARCH_BITNESS=32
-# CT_ARCH_FLOAT_HW is not set
-# CT_ARCH_FLOAT_SW is not set
-CT_TARGET_CFLAGS=""
-CT_TARGET_LDFLAGS=""
-# CT_ARCH_alpha is not set
-# CT_ARCH_arm is not set
-# CT_ARCH_avr is not set
-# CT_ARCH_m68k is not set
-# CT_ARCH_mips is not set
-# CT_ARCH_nios2 is not set
-CT_ARCH_powerpc=y
-# CT_ARCH_s390 is not set
-# CT_ARCH_sh is not set
-# CT_ARCH_sparc is not set
-# CT_ARCH_x86 is not set
-# CT_ARCH_xtensa is not set
-CT_ARCH_alpha_AVAILABLE=y
-CT_ARCH_arm_AVAILABLE=y
-CT_ARCH_avr_AVAILABLE=y
-CT_ARCH_m68k_AVAILABLE=y
-CT_ARCH_microblaze_AVAILABLE=y
-CT_ARCH_mips_AVAILABLE=y
-CT_ARCH_nios2_AVAILABLE=y
-CT_ARCH_powerpc_AVAILABLE=y
-CT_ARCH_s390_AVAILABLE=y
-CT_ARCH_sh_AVAILABLE=y
-CT_ARCH_sparc_AVAILABLE=y
-CT_ARCH_x86_AVAILABLE=y
-CT_ARCH_xtensa_AVAILABLE=y
+CT_ARCH_POWERPC_SHOW=y
+
+#
+# Options for powerpc
+#
+CT_ARCH_POWERPC_PKG_KSYM=""
+CT_ARCH_powerpc_ABI=""
+CT_ARCH_powerpc_ABI_DEFAULT=y
+# CT_ARCH_powerpc_ABI_SPE is not set
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
 CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
 
 #
 # Generic target options
 #
 # CT_MULTILIB is not set
+CT_DEMULTILIB=y
 CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_BE=y
+CT_ARCH_BE=y
+# CT_ARCH_LE is not set
 CT_ARCH_ENDIAN="big"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=32
+CT_ARCH_32=y
+# CT_ARCH_64 is not set
 
 #
 # Target optimisations
 #
+CT_ARCH_SUPPORTS_WITH_ABI=y
+CT_ARCH_SUPPORTS_WITH_CPU=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
+CT_ARCH_SUPPORTS_WITH_FLOAT=y
+CT_ARCH_ABI=""
 CT_ARCH_FLOAT_AUTO=y
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
 CT_ARCH_FLOAT="auto"
 
 #
-# powerpc other options
-#
-CT_ARCH_powerpc_ABI=""
-CT_ARCH_powerpc_ABI_DEFAULT=y
-# CT_ARCH_powerpc_ABI_SPE is not set
-
-#
 # Toolchain options
 #
 
@@ -172,7 +195,9 @@ CT_USE_SYSROOT=y
 CT_SYSROOT_NAME="sysroot"
 CT_SYSROOT_DIR_PREFIX=""
 CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
 # CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
 CT_TOOLCHAIN_PKGVERSION=""
 CT_TOOLCHAIN_BUGURL=""
 
@@ -206,122 +231,204 @@ CT_BUILD_SUFFIX=""
 # Operating System
 #
 CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
 CT_KERNEL="linux"
-CT_KERNEL_VERSION="2.6.32.68"
-# CT_KERNEL_bare_metal is not set
-CT_KERNEL_linux=y
-CT_KERNEL_bare_metal_AVAILABLE=y
-CT_KERNEL_linux_AVAILABLE=y
-# CT_KERNEL_V_4_3 is not set
-# CT_KERNEL_V_4_2 is not set
-# CT_KERNEL_V_4_1 is not set
-# CT_KERNEL_V_3_18 is not set
-# CT_KERNEL_V_3_14 is not set
-# CT_KERNEL_V_3_12 is not set
-# CT_KERNEL_V_3_10 is not set
-# CT_KERNEL_V_3_4 is not set
-# CT_KERNEL_V_3_2 is not set
-CT_KERNEL_V_2_6_32=y
-# CT_KERNEL_LINUX_CUSTOM is not set
-CT_KERNEL_windows_AVAILABLE=y
-
-#
-# Common kernel options
-#
-CT_SHARED_LIBS=y
-
-#
-# linux other options
-#
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+# CT_LINUX_V_4_4 is not set
+# CT_LINUX_V_4_1 is not set
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_V_3_4 is not set
+CT_LINUX_V_3_2=y
+# CT_LINUX_V_2_6_32 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="3.2.101"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_3_7_or_older=y
+CT_LINUX_older_than_3_7=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
 CT_KERNEL_LINUX_VERBOSITY_0=y
 # CT_KERNEL_LINUX_VERBOSITY_1 is not set
 # CT_KERNEL_LINUX_VERBOSITY_2 is not set
 CT_KERNEL_LINUX_VERBOSE_LEVEL=0
 CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
 
 #
 # Binary utilities
 #
 CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
 CT_BINUTILS="binutils"
-CT_BINUTILS_binutils=y
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+# CT_BINUTILS_V_2_32 is not set
+# CT_BINUTILS_V_2_31 is not set
+CT_BINUTILS_V_2_30=y
+# CT_BINUTILS_V_2_29 is not set
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.30"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_2_30_or_older=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
 
 #
 # GNU binutils
 #
-# CT_CC_BINUTILS_SHOW_LINARO is not set
-CT_BINUTILS_V_2_25_1=y
-# CT_BINUTILS_V_2_25 is not set
-# CT_BINUTILS_V_2_24 is not set
-# CT_BINUTILS_V_2_23_2 is not set
-# CT_BINUTILS_V_2_23_1 is not set
-# CT_BINUTILS_V_2_22 is not set
-# CT_BINUTILS_V_2_21_53 is not set
-# CT_BINUTILS_V_2_21_1a is not set
-# CT_BINUTILS_V_2_20_1a is not set
-# CT_BINUTILS_V_2_19_1a is not set
-# CT_BINUTILS_V_2_18a is not set
-CT_BINUTILS_VERSION="2.25.1"
-CT_BINUTILS_2_25_1_or_later=y
-CT_BINUTILS_2_25_or_later=y
-CT_BINUTILS_2_24_or_later=y
-CT_BINUTILS_2_23_or_later=y
-CT_BINUTILS_2_22_or_later=y
-CT_BINUTILS_2_21_or_later=y
-CT_BINUTILS_2_20_or_later=y
-CT_BINUTILS_2_19_or_later=y
-CT_BINUTILS_2_18_or_later=y
 CT_BINUTILS_HAS_HASH_STYLE=y
 CT_BINUTILS_HAS_GOLD=y
 CT_BINUTILS_HAS_PLUGINS=y
 CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
-CT_BINUTILS_FORCE_LD_BFD=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
 CT_BINUTILS_LINKER_LD=y
 CT_BINUTILS_LINKERS_LIST="ld"
 CT_BINUTILS_LINKER_DEFAULT="bfd"
 # CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
 CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
 # CT_BINUTILS_FOR_TARGET is not set
-
-#
-# binutils other options
-#
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
 
 #
 # C-library
 #
+CT_LIBC_GLIBC=y
+# CT_LIBC_UCLIBC is not set
 CT_LIBC="glibc"
-CT_LIBC_VERSION="2.11.1"
-CT_LIBC_glibc=y
-# CT_LIBC_musl is not set
-# CT_LIBC_uClibc is not set
-CT_LIBC_avr_libc_AVAILABLE=y
-CT_LIBC_glibc_AVAILABLE=y
+CT_LIBC_CHOICE_KSYM="GLIBC"
 CT_THREADS="nptl"
-# CT_CC_GLIBC_SHOW_LINARO is not set
-# CT_LIBC_GLIBC_V_2_22 is not set
-# CT_LIBC_GLIBC_V_2_21 is not set
-# CT_LIBC_GLIBC_V_2_20 is not set
-# CT_LIBC_GLIBC_V_2_19 is not set
-# CT_LIBC_GLIBC_V_2_18 is not set
-# CT_LIBC_GLIBC_V_2_17 is not set
-# CT_LIBC_GLIBC_V_2_16_0 is not set
-# CT_LIBC_GLIBC_V_2_15 is not set
-# CT_LIBC_GLIBC_V_2_14_1 is not set
-# CT_LIBC_GLIBC_V_2_14 is not set
-# CT_LIBC_GLIBC_V_2_13 is not set
-# CT_LIBC_GLIBC_V_2_12_2 is not set
-# CT_LIBC_GLIBC_V_2_12_1 is not set
-CT_LIBC_GLIBC_V_2_11_1=y
-# CT_LIBC_GLIBC_V_2_11 is not set
-# CT_LIBC_GLIBC_V_2_10_1 is not set
-# CT_LIBC_GLIBC_V_2_9 is not set
-# CT_LIBC_GLIBC_V_2_8 is not set
-CT_LIBC_mingw_AVAILABLE=y
-CT_LIBC_musl_AVAILABLE=y
-CT_LIBC_newlib_AVAILABLE=y
-CT_LIBC_none_AVAILABLE=y
-CT_LIBC_uClibc_AVAILABLE=y
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+CT_GLIBC_USE="GLIBC"
+CT_GLIBC_PKG_NAME="glibc"
+CT_GLIBC_SRC_RELEASE=y
+CT_GLIBC_PATCH_ORDER="global"
+# CT_GLIBC_V_2_29 is not set
+# CT_GLIBC_V_2_28 is not set
+# CT_GLIBC_V_2_27 is not set
+# CT_GLIBC_V_2_26 is not set
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+# CT_GLIBC_V_2_23 is not set
+# CT_GLIBC_V_2_19 is not set
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.17"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
+CT_GLIBC_2_29_or_older=y
+CT_GLIBC_older_than_2_29=y
+CT_GLIBC_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_older_than_2_23=y
+CT_GLIBC_2_20_or_older=y
+CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_2_17_or_older=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_NPTL_ADDON=y
+CT_GLIBC_HAS_PORTS_ADDON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+CT_GLIBC_USE_PORTS_ADDON=y
+CT_GLIBC_USE_NPTL_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="3.2.101"
+CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
 CT_LIBC_SUPPORT_THREADS_ANY=y
 CT_LIBC_SUPPORT_THREADS_NATIVE=y
 
@@ -329,79 +436,71 @@ CT_LIBC_SUPPORT_THREADS_NATIVE=y
 # Common C library options
 #
 CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
 CT_LIBC_XLDD=y
 
 #
-# glibc other options
-#
-CT_LIBC_GLIBC_PORTS_EXTERNAL=y
-CT_LIBC_glibc_familly=y
-CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY=""
-CT_LIBC_GLIBC_CONFIGPARMS=""
-CT_LIBC_GLIBC_EXTRA_CFLAGS=""
-CT_LIBC_EXTRA_CC_ARGS=""
-# CT_LIBC_DISABLE_VERSIONING is not set
-CT_LIBC_OLDEST_ABI=""
-CT_LIBC_GLIBC_FORCE_UNWIND=y
-# CT_LIBC_GLIBC_USE_PORTS is not set
-CT_LIBC_ADDONS_LIST=""
-# CT_LIBC_LOCALES is not set
-# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set
-CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y
-# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_LIBC_GLIBC_MIN_KERNEL="2.6.32.68"
-
-#
 # C compiler
 #
-CT_CC="gcc"
 CT_CC_CORE_PASSES_NEEDED=y
 CT_CC_CORE_PASS_1_NEEDED=y
 CT_CC_CORE_PASS_2_NEEDED=y
-CT_CC_gcc=y
-# CT_CC_GCC_SHOW_LINARO is not set
-CT_CC_GCC_V_5_2_0=y
-# CT_CC_GCC_V_4_9_3 is not set
-# CT_CC_GCC_V_4_8_5 is not set
-# CT_CC_GCC_V_4_7_4 is not set
-# CT_CC_GCC_V_4_6_4 is not set
-# CT_CC_GCC_V_4_5_4 is not set
-# CT_CC_GCC_V_4_4_7 is not set
-# CT_CC_GCC_V_4_3_6 is not set
-# CT_CC_GCC_V_4_2_4 is not set
-CT_CC_GCC_4_2_or_later=y
-CT_CC_GCC_4_3_or_later=y
-CT_CC_GCC_4_4_or_later=y
-CT_CC_GCC_4_5_or_later=y
-CT_CC_GCC_4_6_or_later=y
-CT_CC_GCC_4_7_or_later=y
-CT_CC_GCC_4_8_or_later=y
-CT_CC_GCC_4_9_or_later=y
-CT_CC_GCC_5=y
-CT_CC_GCC_5_or_later=y
-CT_CC_GCC_HAS_GRAPHITE=y
-CT_CC_GCC_USE_GRAPHITE=y
-CT_CC_GCC_HAS_LTO=y
-CT_CC_GCC_USE_LTO=y
-CT_CC_GCC_HAS_PKGVERSION_BUGURL=y
-CT_CC_GCC_HAS_BUILD_ID=y
-CT_CC_GCC_HAS_LNK_HASH_STYLE=y
-CT_CC_GCC_USE_GMP_MPFR=y
-CT_CC_GCC_USE_MPC=y
-CT_CC_GCC_HAS_LIBQUADMATH=y
-CT_CC_GCC_HAS_LIBSANITIZER=y
-CT_CC_GCC_VERSION="5.2.0"
-# CT_CC_LANG_FORTRAN is not set
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
 CT_CC_GCC_ENABLE_CXX_FLAGS=""
 CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
 CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
-CT_CC_GCC_EXTRA_ENV_ARRAY=""
 CT_CC_GCC_STATIC_LIBSTDCXX=y
 # CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
 
 #
 # Optimisation features
 #
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
 
 #
 # Settings for libraries running on target
@@ -430,97 +529,208 @@ CT_CC_GCC_DEC_FLOAT_AUTO=y
 # CT_CC_GCC_DEC_FLOAT_BID is not set
 # CT_CC_GCC_DEC_FLOAT_DPD is not set
 # CT_CC_GCC_DEC_FLOATS_NO is not set
-CT_CC_SUPPORT_CXX=y
-CT_CC_SUPPORT_FORTRAN=y
-CT_CC_SUPPORT_JAVA=y
-CT_CC_SUPPORT_ADA=y
-CT_CC_SUPPORT_OBJC=y
-CT_CC_SUPPORT_OBJCXX=y
-CT_CC_SUPPORT_GOLANG=y
+CT_ALL_CC_CHOICES="GCC"
 
 #
 # Additional supported languages:
 #
 CT_CC_LANG_CXX=y
-# CT_CC_LANG_JAVA is not set
+# CT_CC_LANG_FORTRAN is not set
 
 #
 # Debug facilities
 #
-# CT_DEBUG_dmalloc is not set
-# CT_DEBUG_duma is not set
-# CT_DEBUG_gdb is not set
-# CT_DEBUG_ltrace is not set
-# CT_DEBUG_strace is not set
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
 
 #
 # Companion libraries
 #
-CT_COMPLIBS_NEEDED=y
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# CT_ISL_V_0_15 is not set
+# CT_ISL_NO_VERSIONS is not set
+CT_ISL_VERSION="0.20"
+CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
+CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
 CT_LIBICONV_NEEDED=y
 CT_GETTEXT_NEEDED=y
 CT_GMP_NEEDED=y
 CT_MPFR_NEEDED=y
 CT_ISL_NEEDED=y
 CT_MPC_NEEDED=y
-CT_COMPLIBS=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
 CT_LIBICONV=y
 CT_GETTEXT=y
 CT_GMP=y
 CT_MPFR=y
 CT_ISL=y
 CT_MPC=y
-CT_LIBICONV_V_1_14=y
-CT_LIBICONV_VERSION="1.14"
-CT_GETTEXT_V_0_19_6=y
-CT_GETTEXT_VERSION="0.19.6"
-CT_GMP_V_6_0_0=y
-# CT_GMP_V_5_1_3 is not set
-# CT_GMP_V_5_1_1 is not set
-# CT_GMP_V_5_0_2 is not set
-# CT_GMP_V_5_0_1 is not set
-# CT_GMP_V_4_3_2 is not set
-# CT_GMP_V_4_3_1 is not set
-# CT_GMP_V_4_3_0 is not set
-CT_GMP_5_0_2_or_later=y
-CT_GMP_VERSION="6.0.0a"
-CT_MPFR_V_3_1_3=y
-# CT_MPFR_V_3_1_2 is not set
-# CT_MPFR_V_3_1_0 is not set
-# CT_MPFR_V_3_0_1 is not set
-# CT_MPFR_V_3_0_0 is not set
-# CT_MPFR_V_2_4_2 is not set
-# CT_MPFR_V_2_4_1 is not set
-# CT_MPFR_V_2_4_0 is not set
-CT_MPFR_VERSION="3.1.3"
-CT_ISL_V_0_14=y
-# CT_ISL_V_0_12_2 is not set
-CT_ISL_V_0_14_or_later=y
-CT_ISL_V_0_12_or_later=y
-CT_ISL_VERSION="0.14"
-# CT_CLOOG_V_0_18_4 is not set
-# CT_CLOOG_V_0_18_1 is not set
-# CT_CLOOG_V_0_18_0 is not set
-CT_MPC_V_1_0_3=y
-# CT_MPC_V_1_0_2 is not set
-# CT_MPC_V_1_0_1 is not set
-# CT_MPC_V_1_0 is not set
-# CT_MPC_V_0_9 is not set
-# CT_MPC_V_0_8_2 is not set
-# CT_MPC_V_0_8_1 is not set
-# CT_MPC_V_0_7 is not set
-CT_MPC_VERSION="1.0.3"
-
-#
-# Companion libraries common options
-#
-# CT_COMPLIBS_CHECK is not set
+CT_NCURSES=y
+CT_ZLIB=y
 
 #
 # Companion tools
 #
-
-#
-# READ HELP before you say 'Y' below !!!
-#
-# CT_COMP_TOOLS is not set
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile
index a22d9a7553e..c976536cb7c 100644
--- a/src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux/Dockerfile
@@ -1,23 +1,16 @@
-FROM ubuntu:16.04
+FROM ubuntu:20.04
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
 
-
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
 
 COPY scripts/rustbuild-setup.sh /scripts/
 RUN sh /scripts/rustbuild-setup.sh
 USER rustbuild
 WORKDIR /tmp
 
-COPY host-x86_64/dist-powerpc64-linux/patches/ /tmp/patches/
 COPY host-x86_64/dist-powerpc64-linux/shared.sh host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config host-x86_64/dist-powerpc64-linux/build-powerpc64-toolchain.sh /tmp/
 RUN ./build-powerpc64-toolchain.sh
 
@@ -26,9 +19,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin
 
 ENV \
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/build-powerpc64-toolchain.sh b/src/ci/docker/host-x86_64/dist-powerpc64-linux/build-powerpc64-toolchain.sh
index fc53849a2ad..f7aa2cd3268 100755
--- a/src/ci/docker/host-x86_64/dist-powerpc64-linux/build-powerpc64-toolchain.sh
+++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux/build-powerpc64-toolchain.sh
@@ -3,29 +3,9 @@ set -ex
 
 source shared.sh
 
-BINUTILS=2.32
-TARGET=powerpc64-unknown-linux-gnu
-PREFIX=/x-tools/$TARGET
-SYSROOT=$PREFIX/$TARGET/sysroot
-
 mkdir build
 cd build
 cp ../powerpc64-linux-gnu.config .config
 hide_output ct-ng build
 cd ..
 rm -rf build
-
-chmod -R u+w $PREFIX
-
-# Next, download and build newer binutils.
-mkdir binutils-$TARGET
-pushd binutils-$TARGET
-curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf -
-mkdir binutils-build
-cd binutils-build
-hide_output ../binutils-$BINUTILS/configure --target=$TARGET \
-  --prefix=$PREFIX --with-sysroot=$SYSROOT
-hide_output make -j10
-hide_output make install
-popd
-rm -rf binutils-$TARGET
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch b/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch
deleted file mode 100644
index 744eb180cd1..00000000000
--- a/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/001-PowerPC-Remove-unnecessary-mnew-mnemonics.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001
-From: Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
-Date: Thu, 1 Nov 2012 18:00:06 -0500
-Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics.
-
----
- sysdeps/powerpc/Makefile | 4 ----
- 1 file changed, 4 deletions(-)
-
-diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
-index 79dd6fa976d5..7442b6709ad1 100644
---- a/sysdeps/powerpc/Makefile
-+++ b/sysdeps/powerpc/Makefile
-@@ -1,7 +1,3 @@
--# We always want to use the new mnemonic syntax even if we are on a RS6000
--# machine.
--+cflags += -mnew-mnemonics
--
- ifeq ($(subdir),gmon)
- sysdep_routines += ppc-mcount
- endif
--- 
-2.9.3
-
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/002-Prevent-inlining-in-PPC64-initfini.s.patch b/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/002-Prevent-inlining-in-PPC64-initfini.s.patch
deleted file mode 100644
index 47cc8b28d22..00000000000
--- a/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/002-Prevent-inlining-in-PPC64-initfini.s.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From a4f388e111ce05e2ab7912cff3c9070334bb74ae Mon Sep 17 00:00:00 2001
-From: Josh Stone <jistone@redhat.com>
-Date: Fri, 20 Jan 2017 15:41:56 -0800
-Subject: [PATCH] Prevent inlining in PPC64 initfini.s
-
-Ref: https://sourceware.org/ml/libc-alpha/2012-01/msg00195.html
----
- sysdeps/powerpc/powerpc64/Makefile | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/sysdeps/powerpc/powerpc64/Makefile b/sysdeps/powerpc/powerpc64/Makefile
-index 78d4f07e575f..fe96aae4d43e 100644
---- a/sysdeps/powerpc/powerpc64/Makefile
-+++ b/sysdeps/powerpc/powerpc64/Makefile
-@@ -28,7 +28,7 @@ elide-routines.os += hp-timing
- ifneq ($(elf),no)
- # The initfini generation code doesn't work in the presence of -fPIC, so
- # we use -fpic instead which is much better.
--CFLAGS-initfini.s += -fpic -O1
-+CFLAGS-initfini.s += -fpic -O1 -fno-inline
- endif
- endif
- 
--- 
-2.9.3
-
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/003-newer-gcc.patch b/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/003-newer-gcc.patch
deleted file mode 100644
index a96b4882c2d..00000000000
--- a/src/ci/docker/host-x86_64/dist-powerpc64-linux/patches/glibc/2.11.1/003-newer-gcc.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-diff --git a/configure b/configure
-index b6752d147c6b..6089a3403410 100755
---- a/configure
-+++ b/configure
-@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; }
-   ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
-   case $ac_prog_version in
-     '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
--    3.4* | 4.[0-9]* )
-+    3.4* | [4-9].* )
-        ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
-     *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
- 
-diff --git a/configure.in b/configure.in
-index 56849dfc489a..09677eb3d0c1 100644
---- a/configure.in
-+++ b/configure.in
-@@ -960,7 +960,7 @@ fi
- # These programs are version sensitive.
- AC_CHECK_TOOL_PREFIX
- AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v,
--  [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ],
-+  [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ],
-   critic_missing="$critic_missing gcc")
- AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
-   [GNU Make[^0-9]*\([0-9][0-9.]*\)],
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config b/src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config
index 83439bb81e2..d3293eab2be 100644
--- a/src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config
+++ b/src/ci/docker/host-x86_64/dist-powerpc64-linux/powerpc64-linux-gnu.config
@@ -1,9 +1,30 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Crosstool-NG Configuration
-#
-CT_CONFIGURE_has_make381=y
-CT_CONFIGURE_has_xz=y
+# crosstool-NG  Configuration
+#
+CT_CONFIGURE_has_static_link=y
+CT_CONFIGURE_has_cxx11=y
+CT_CONFIGURE_has_wget=y
+CT_CONFIGURE_has_curl=y
+CT_CONFIGURE_has_make_3_81_or_newer=y
+CT_CONFIGURE_has_make_4_0_or_newer=y
+CT_CONFIGURE_has_libtool_2_4_or_newer=y
+CT_CONFIGURE_has_libtoolize_2_4_or_newer=y
+CT_CONFIGURE_has_autoconf_2_65_or_newer=y
+CT_CONFIGURE_has_autoreconf_2_65_or_newer=y
+CT_CONFIGURE_has_automake_1_15_or_newer=y
+CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y
+CT_CONFIGURE_has_python_3_4_or_newer=y
+CT_CONFIGURE_has_bison_2_7_or_newer=y
+CT_CONFIGURE_has_python=y
+CT_CONFIGURE_has_git=y
+CT_CONFIGURE_has_md5sum=y
+CT_CONFIGURE_has_sha1sum=y
+CT_CONFIGURE_has_sha256sum=y
+CT_CONFIGURE_has_sha512sum=y
+CT_CONFIGURE_has_install_with_strip_program=y
+CT_CONFIG_VERSION_CURRENT="3"
+CT_CONFIG_VERSION="3"
 CT_MODULES=y
 
 #
@@ -20,42 +41,50 @@ CT_MODULES=y
 #
 # Paths
 #
-CT_LOCAL_TARBALLS_DIR=""
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
+# CT_TARBALLS_BUILDROOT_LAYOUT is not set
 CT_WORK_DIR="${CT_TOP_DIR}/.build"
+CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
 CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
-CT_INSTALL_DIR="${CT_PREFIX_DIR}"
 CT_RM_RF_PREFIX_DIR=y
 CT_REMOVE_DOCS=y
-CT_INSTALL_DIR_RO=y
+CT_INSTALL_LICENSES=y
+CT_PREFIX_DIR_RO=y
 CT_STRIP_HOST_TOOLCHAIN_EXECUTABLES=y
 # CT_STRIP_TARGET_TOOLCHAIN_EXECUTABLES is not set
 
 #
 # Downloading
 #
+CT_DOWNLOAD_AGENT_WGET=y
+# CT_DOWNLOAD_AGENT_CURL is not set
+# CT_DOWNLOAD_AGENT_NONE is not set
 # CT_FORBID_DOWNLOAD is not set
 # CT_FORCE_DOWNLOAD is not set
 CT_CONNECT_TIMEOUT=10
+CT_DOWNLOAD_WGET_OPTIONS="--passive-ftp --tries=3 -nc --progress=dot:binary"
 # CT_ONLY_DOWNLOAD is not set
 CT_USE_MIRROR=y
+# CT_FORCE_MIRROR is not set
 CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
+CT_VERIFY_DOWNLOAD_DIGEST=y
+CT_VERIFY_DOWNLOAD_DIGEST_SHA512=y
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA256 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_SHA1 is not set
+# CT_VERIFY_DOWNLOAD_DIGEST_MD5 is not set
+CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
+# CT_VERIFY_DOWNLOAD_SIGNATURE is not set
 
 #
 # Extracting
 #
 # CT_FORCE_EXTRACT is not set
-CT_OVERIDE_CONFIG_GUESS_SUB=y
+CT_OVERRIDE_CONFIG_GUESS_SUB=y
 # CT_ONLY_EXTRACT is not set
-# CT_PATCH_BUNDLED is not set
-# CT_PATCH_LOCAL is not set
-CT_PATCH_BUNDLED_LOCAL=y
-# CT_PATCH_LOCAL_BUNDLED is not set
-# CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set
-# CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set
-# CT_PATCH_NONE is not set
-CT_PATCH_ORDER="bundled,local"
-CT_PATCH_USE_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
+CT_PATCH_BUNDLED=y
+# CT_PATCH_BUNDLED_LOCAL is not set
+CT_PATCH_ORDER="bundled"
 
 #
 # Build behavior
@@ -78,11 +107,11 @@ CT_CONFIG_SHELL="${bash}"
 #
 # CT_LOG_ERROR is not set
 # CT_LOG_WARN is not set
-CT_LOG_INFO=y
-# CT_LOG_EXTRA is not set
+# CT_LOG_INFO is not set
+CT_LOG_EXTRA=y
 # CT_LOG_ALL is not set
 # CT_LOG_DEBUG is not set
-CT_LOG_LEVEL_MAX="INFO"
+CT_LOG_LEVEL_MAX="EXTRA"
 # CT_LOG_SEE_TOOLS_WARN is not set
 CT_LOG_PROGRESS_BAR=y
 CT_LOG_TO_FILE=y
@@ -91,76 +120,70 @@ CT_LOG_FILE_COMPRESS=y
 #
 # Target options
 #
+# CT_ARCH_ALPHA is not set
+# CT_ARCH_ARC is not set
+# CT_ARCH_ARM is not set
+# CT_ARCH_AVR is not set
+# CT_ARCH_M68K is not set
+# CT_ARCH_MIPS is not set
+# CT_ARCH_NIOS2 is not set
+CT_ARCH_POWERPC=y
+# CT_ARCH_S390 is not set
+# CT_ARCH_SH is not set
+# CT_ARCH_SPARC is not set
+# CT_ARCH_X86 is not set
+# CT_ARCH_XTENSA is not set
 CT_ARCH="powerpc"
-CT_ARCH_SUPPORTS_BOTH_ENDIAN=y
-CT_ARCH_SUPPORTS_32=y
-CT_ARCH_SUPPORTS_64=y
-CT_ARCH_SUPPORTS_WITH_ABI=y
-CT_ARCH_SUPPORTS_WITH_CPU=y
-CT_ARCH_SUPPORTS_WITH_TUNE=y
-CT_ARCH_SUPPORTS_WITH_FLOAT=y
-CT_ARCH_DEFAULT_BE=y
-CT_ARCH_DEFAULT_32=y
-CT_ARCH_ABI=""
+CT_ARCH_CHOICE_KSYM="POWERPC"
 CT_ARCH_CPU="power4"
 CT_ARCH_TUNE="power6"
-CT_ARCH_BE=y
-# CT_ARCH_LE is not set
-# CT_ARCH_32 is not set
-CT_ARCH_64=y
-CT_ARCH_BITNESS=64
-# CT_ARCH_FLOAT_HW is not set
-# CT_ARCH_FLOAT_SW is not set
-CT_TARGET_CFLAGS=""
-CT_TARGET_LDFLAGS=""
-# CT_ARCH_alpha is not set
-# CT_ARCH_arm is not set
-# CT_ARCH_avr is not set
-# CT_ARCH_m68k is not set
-# CT_ARCH_mips is not set
-# CT_ARCH_nios2 is not set
-CT_ARCH_powerpc=y
-# CT_ARCH_s390 is not set
-# CT_ARCH_sh is not set
-# CT_ARCH_sparc is not set
-# CT_ARCH_x86 is not set
-# CT_ARCH_xtensa is not set
-CT_ARCH_alpha_AVAILABLE=y
-CT_ARCH_arm_AVAILABLE=y
-CT_ARCH_avr_AVAILABLE=y
-CT_ARCH_m68k_AVAILABLE=y
-CT_ARCH_microblaze_AVAILABLE=y
-CT_ARCH_mips_AVAILABLE=y
-CT_ARCH_nios2_AVAILABLE=y
-CT_ARCH_powerpc_AVAILABLE=y
-CT_ARCH_s390_AVAILABLE=y
-CT_ARCH_sh_AVAILABLE=y
-CT_ARCH_sparc_AVAILABLE=y
-CT_ARCH_x86_AVAILABLE=y
-CT_ARCH_xtensa_AVAILABLE=y
+CT_ARCH_POWERPC_SHOW=y
+
+#
+# Options for powerpc
+#
+CT_ARCH_POWERPC_PKG_KSYM=""
+CT_ARCH_powerpc_ABI=""
+CT_ARCH_powerpc_ABI_DEFAULT=y
+# CT_ARCH_powerpc_ABI_SPE is not set
+CT_ALL_ARCH_CHOICES="ALPHA ARC ARM AVR M68K MICROBLAZE MIPS MOXIE MSP430 NIOS2 POWERPC RISCV S390 SH SPARC X86 XTENSA"
 CT_ARCH_SUFFIX=""
+# CT_OMIT_TARGET_VENDOR is not set
 
 #
 # Generic target options
 #
 # CT_MULTILIB is not set
+CT_DEMULTILIB=y
 CT_ARCH_USE_MMU=y
+CT_ARCH_SUPPORTS_EITHER_ENDIAN=y
+CT_ARCH_DEFAULT_BE=y
+CT_ARCH_BE=y
+# CT_ARCH_LE is not set
 CT_ARCH_ENDIAN="big"
+CT_ARCH_SUPPORTS_32=y
+CT_ARCH_SUPPORTS_64=y
+CT_ARCH_DEFAULT_32=y
+CT_ARCH_BITNESS=64
+# CT_ARCH_32 is not set
+CT_ARCH_64=y
 
 #
 # Target optimisations
 #
+CT_ARCH_SUPPORTS_WITH_ABI=y
+CT_ARCH_SUPPORTS_WITH_CPU=y
+CT_ARCH_SUPPORTS_WITH_TUNE=y
+CT_ARCH_SUPPORTS_WITH_FLOAT=y
+CT_ARCH_ABI=""
 CT_ARCH_FLOAT_AUTO=y
+# CT_ARCH_FLOAT_HW is not set
+# CT_ARCH_FLOAT_SW is not set
+CT_TARGET_CFLAGS=""
+CT_TARGET_LDFLAGS=""
 CT_ARCH_FLOAT="auto"
 
 #
-# powerpc other options
-#
-CT_ARCH_powerpc_ABI=""
-CT_ARCH_powerpc_ABI_DEFAULT=y
-# CT_ARCH_powerpc_ABI_SPE is not set
-
-#
 # Toolchain options
 #
 
@@ -172,7 +195,9 @@ CT_USE_SYSROOT=y
 CT_SYSROOT_NAME="sysroot"
 CT_SYSROOT_DIR_PREFIX=""
 CT_WANTS_STATIC_LINK=y
+CT_WANTS_STATIC_LINK_CXX=y
 # CT_STATIC_TOOLCHAIN is not set
+CT_SHOW_CT_VERSION=y
 CT_TOOLCHAIN_PKGVERSION=""
 CT_TOOLCHAIN_BUGURL=""
 
@@ -206,122 +231,204 @@ CT_BUILD_SUFFIX=""
 # Operating System
 #
 CT_KERNEL_SUPPORTS_SHARED_LIBS=y
+# CT_KERNEL_BARE_METAL is not set
+CT_KERNEL_LINUX=y
 CT_KERNEL="linux"
-CT_KERNEL_VERSION="2.6.32.68"
-# CT_KERNEL_bare_metal is not set
-CT_KERNEL_linux=y
-CT_KERNEL_bare_metal_AVAILABLE=y
-CT_KERNEL_linux_AVAILABLE=y
-# CT_KERNEL_V_4_3 is not set
-# CT_KERNEL_V_4_2 is not set
-# CT_KERNEL_V_4_1 is not set
-# CT_KERNEL_V_3_18 is not set
-# CT_KERNEL_V_3_14 is not set
-# CT_KERNEL_V_3_12 is not set
-# CT_KERNEL_V_3_10 is not set
-# CT_KERNEL_V_3_4 is not set
-# CT_KERNEL_V_3_2 is not set
-CT_KERNEL_V_2_6_32=y
-# CT_KERNEL_LINUX_CUSTOM is not set
-CT_KERNEL_windows_AVAILABLE=y
-
-#
-# Common kernel options
-#
-CT_SHARED_LIBS=y
-
-#
-# linux other options
-#
+CT_KERNEL_CHOICE_KSYM="LINUX"
+CT_KERNEL_LINUX_SHOW=y
+
+#
+# Options for linux
+#
+CT_KERNEL_LINUX_PKG_KSYM="LINUX"
+CT_LINUX_DIR_NAME="linux"
+CT_LINUX_PKG_NAME="linux"
+CT_LINUX_SRC_RELEASE=y
+CT_LINUX_PATCH_ORDER="global"
+# CT_LINUX_V_4_20 is not set
+# CT_LINUX_V_4_19 is not set
+# CT_LINUX_V_4_18 is not set
+# CT_LINUX_V_4_17 is not set
+# CT_LINUX_V_4_16 is not set
+# CT_LINUX_V_4_15 is not set
+# CT_LINUX_V_4_14 is not set
+# CT_LINUX_V_4_13 is not set
+# CT_LINUX_V_4_12 is not set
+# CT_LINUX_V_4_11 is not set
+# CT_LINUX_V_4_10 is not set
+# CT_LINUX_V_4_9 is not set
+# CT_LINUX_V_4_4 is not set
+# CT_LINUX_V_4_1 is not set
+# CT_LINUX_V_3_16 is not set
+# CT_LINUX_V_3_13 is not set
+# CT_LINUX_V_3_12 is not set
+# CT_LINUX_V_3_10 is not set
+# CT_LINUX_V_3_4 is not set
+CT_LINUX_V_3_2=y
+# CT_LINUX_V_2_6_32 is not set
+# CT_LINUX_NO_VERSIONS is not set
+CT_LINUX_VERSION="3.2.101"
+CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
+CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LINUX_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_LINUX_SIGNATURE_FORMAT="unpacked/.sign"
+CT_LINUX_4_8_or_older=y
+CT_LINUX_older_than_4_8=y
+CT_LINUX_3_7_or_older=y
+CT_LINUX_older_than_3_7=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
 CT_KERNEL_LINUX_VERBOSITY_0=y
 # CT_KERNEL_LINUX_VERBOSITY_1 is not set
 # CT_KERNEL_LINUX_VERBOSITY_2 is not set
 CT_KERNEL_LINUX_VERBOSE_LEVEL=0
 CT_KERNEL_LINUX_INSTALL_CHECK=y
+CT_ALL_KERNEL_CHOICES="BARE_METAL LINUX WINDOWS"
+
+#
+# Common kernel options
+#
+CT_SHARED_LIBS=y
 
 #
 # Binary utilities
 #
 CT_ARCH_BINFMT_ELF=y
+CT_BINUTILS_BINUTILS=y
 CT_BINUTILS="binutils"
-CT_BINUTILS_binutils=y
+CT_BINUTILS_CHOICE_KSYM="BINUTILS"
+CT_BINUTILS_BINUTILS_SHOW=y
+
+#
+# Options for binutils
+#
+CT_BINUTILS_BINUTILS_PKG_KSYM="BINUTILS"
+CT_BINUTILS_DIR_NAME="binutils"
+CT_BINUTILS_USE_GNU=y
+CT_BINUTILS_USE="BINUTILS"
+CT_BINUTILS_PKG_NAME="binutils"
+CT_BINUTILS_SRC_RELEASE=y
+CT_BINUTILS_PATCH_ORDER="global"
+CT_BINUTILS_V_2_32=y
+# CT_BINUTILS_V_2_31 is not set
+# CT_BINUTILS_V_2_30 is not set
+# CT_BINUTILS_V_2_29 is not set
+# CT_BINUTILS_V_2_28 is not set
+# CT_BINUTILS_V_2_27 is not set
+# CT_BINUTILS_V_2_26 is not set
+# CT_BINUTILS_NO_VERSIONS is not set
+CT_BINUTILS_VERSION="2.32"
+CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
+CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
+CT_BINUTILS_later_than_2_30=y
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
+CT_BINUTILS_later_than_2_25=y
+CT_BINUTILS_2_25_or_later=y
+CT_BINUTILS_later_than_2_23=y
+CT_BINUTILS_2_23_or_later=y
 
 #
 # GNU binutils
 #
-# CT_CC_BINUTILS_SHOW_LINARO is not set
-CT_BINUTILS_V_2_25_1=y
-# CT_BINUTILS_V_2_25 is not set
-# CT_BINUTILS_V_2_24 is not set
-# CT_BINUTILS_V_2_23_2 is not set
-# CT_BINUTILS_V_2_23_1 is not set
-# CT_BINUTILS_V_2_22 is not set
-# CT_BINUTILS_V_2_21_53 is not set
-# CT_BINUTILS_V_2_21_1a is not set
-# CT_BINUTILS_V_2_20_1a is not set
-# CT_BINUTILS_V_2_19_1a is not set
-# CT_BINUTILS_V_2_18a is not set
-CT_BINUTILS_VERSION="2.25.1"
-CT_BINUTILS_2_25_1_or_later=y
-CT_BINUTILS_2_25_or_later=y
-CT_BINUTILS_2_24_or_later=y
-CT_BINUTILS_2_23_or_later=y
-CT_BINUTILS_2_22_or_later=y
-CT_BINUTILS_2_21_or_later=y
-CT_BINUTILS_2_20_or_later=y
-CT_BINUTILS_2_19_or_later=y
-CT_BINUTILS_2_18_or_later=y
 CT_BINUTILS_HAS_HASH_STYLE=y
 CT_BINUTILS_HAS_GOLD=y
 CT_BINUTILS_HAS_PLUGINS=y
 CT_BINUTILS_HAS_PKGVERSION_BUGURL=y
-CT_BINUTILS_FORCE_LD_BFD=y
+CT_BINUTILS_FORCE_LD_BFD_DEFAULT=y
 CT_BINUTILS_LINKER_LD=y
 CT_BINUTILS_LINKERS_LIST="ld"
 CT_BINUTILS_LINKER_DEFAULT="bfd"
 # CT_BINUTILS_PLUGINS is not set
+CT_BINUTILS_RELRO=m
 CT_BINUTILS_EXTRA_CONFIG_ARRAY=""
 # CT_BINUTILS_FOR_TARGET is not set
-
-#
-# binutils other options
-#
+CT_ALL_BINUTILS_CHOICES="BINUTILS"
 
 #
 # C-library
 #
+CT_LIBC_GLIBC=y
+# CT_LIBC_UCLIBC is not set
 CT_LIBC="glibc"
-CT_LIBC_VERSION="2.11.1"
-CT_LIBC_glibc=y
-# CT_LIBC_musl is not set
-# CT_LIBC_uClibc is not set
-CT_LIBC_avr_libc_AVAILABLE=y
-CT_LIBC_glibc_AVAILABLE=y
+CT_LIBC_CHOICE_KSYM="GLIBC"
 CT_THREADS="nptl"
-# CT_CC_GLIBC_SHOW_LINARO is not set
-# CT_LIBC_GLIBC_V_2_22 is not set
-# CT_LIBC_GLIBC_V_2_21 is not set
-# CT_LIBC_GLIBC_V_2_20 is not set
-# CT_LIBC_GLIBC_V_2_19 is not set
-# CT_LIBC_GLIBC_V_2_18 is not set
-# CT_LIBC_GLIBC_V_2_17 is not set
-# CT_LIBC_GLIBC_V_2_16_0 is not set
-# CT_LIBC_GLIBC_V_2_15 is not set
-# CT_LIBC_GLIBC_V_2_14_1 is not set
-# CT_LIBC_GLIBC_V_2_14 is not set
-# CT_LIBC_GLIBC_V_2_13 is not set
-# CT_LIBC_GLIBC_V_2_12_2 is not set
-# CT_LIBC_GLIBC_V_2_12_1 is not set
-CT_LIBC_GLIBC_V_2_11_1=y
-# CT_LIBC_GLIBC_V_2_11 is not set
-# CT_LIBC_GLIBC_V_2_10_1 is not set
-# CT_LIBC_GLIBC_V_2_9 is not set
-# CT_LIBC_GLIBC_V_2_8 is not set
-CT_LIBC_mingw_AVAILABLE=y
-CT_LIBC_musl_AVAILABLE=y
-CT_LIBC_newlib_AVAILABLE=y
-CT_LIBC_none_AVAILABLE=y
-CT_LIBC_uClibc_AVAILABLE=y
+CT_LIBC_GLIBC_SHOW=y
+
+#
+# Options for glibc
+#
+CT_LIBC_GLIBC_PKG_KSYM="GLIBC"
+CT_GLIBC_DIR_NAME="glibc"
+CT_GLIBC_USE_GNU=y
+CT_GLIBC_USE="GLIBC"
+CT_GLIBC_PKG_NAME="glibc"
+CT_GLIBC_SRC_RELEASE=y
+CT_GLIBC_PATCH_ORDER="global"
+# CT_GLIBC_V_2_29 is not set
+# CT_GLIBC_V_2_28 is not set
+# CT_GLIBC_V_2_27 is not set
+# CT_GLIBC_V_2_26 is not set
+# CT_GLIBC_V_2_25 is not set
+# CT_GLIBC_V_2_24 is not set
+# CT_GLIBC_V_2_23 is not set
+# CT_GLIBC_V_2_19 is not set
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
+# CT_GLIBC_NO_VERSIONS is not set
+CT_GLIBC_VERSION="2.17"
+CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
+CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_GLIBC_SIGNATURE_FORMAT="packed/.sig"
+CT_GLIBC_2_29_or_older=y
+CT_GLIBC_older_than_2_29=y
+CT_GLIBC_2_27_or_older=y
+CT_GLIBC_older_than_2_27=y
+CT_GLIBC_2_26_or_older=y
+CT_GLIBC_older_than_2_26=y
+CT_GLIBC_2_25_or_older=y
+CT_GLIBC_older_than_2_25=y
+CT_GLIBC_2_24_or_older=y
+CT_GLIBC_older_than_2_24=y
+CT_GLIBC_2_23_or_older=y
+CT_GLIBC_older_than_2_23=y
+CT_GLIBC_2_20_or_older=y
+CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
+CT_GLIBC_2_17_or_older=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
+CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
+CT_GLIBC_DEP_BINUTILS=y
+CT_GLIBC_DEP_GCC=y
+CT_GLIBC_DEP_PYTHON=y
+CT_GLIBC_HAS_NPTL_ADDON=y
+CT_GLIBC_HAS_PORTS_ADDON=y
+CT_GLIBC_HAS_LIBIDN_ADDON=y
+CT_GLIBC_USE_PORTS_ADDON=y
+CT_GLIBC_USE_NPTL_ADDON=y
+# CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
+CT_GLIBC_EXTRA_CONFIG_ARRAY=""
+CT_GLIBC_CONFIGPARMS=""
+CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
+# CT_GLIBC_DISABLE_VERSIONING is not set
+CT_GLIBC_OLDEST_ABI=""
+CT_GLIBC_FORCE_UNWIND=y
+# CT_GLIBC_LOCALES is not set
+# CT_GLIBC_KERNEL_VERSION_NONE is not set
+CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
+# CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
+CT_GLIBC_MIN_KERNEL="3.2.101"
+CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
 CT_LIBC_SUPPORT_THREADS_ANY=y
 CT_LIBC_SUPPORT_THREADS_NATIVE=y
 
@@ -329,79 +436,71 @@ CT_LIBC_SUPPORT_THREADS_NATIVE=y
 # Common C library options
 #
 CT_THREADS_NATIVE=y
+# CT_CREATE_LDSO_CONF is not set
 CT_LIBC_XLDD=y
 
 #
-# glibc other options
-#
-CT_LIBC_GLIBC_PORTS_EXTERNAL=y
-CT_LIBC_glibc_familly=y
-CT_LIBC_GLIBC_EXTRA_CONFIG_ARRAY=""
-CT_LIBC_GLIBC_CONFIGPARMS=""
-CT_LIBC_GLIBC_EXTRA_CFLAGS=""
-CT_LIBC_EXTRA_CC_ARGS=""
-# CT_LIBC_DISABLE_VERSIONING is not set
-CT_LIBC_OLDEST_ABI=""
-CT_LIBC_GLIBC_FORCE_UNWIND=y
-# CT_LIBC_GLIBC_USE_PORTS is not set
-CT_LIBC_ADDONS_LIST=""
-# CT_LIBC_LOCALES is not set
-# CT_LIBC_GLIBC_KERNEL_VERSION_NONE is not set
-CT_LIBC_GLIBC_KERNEL_VERSION_AS_HEADERS=y
-# CT_LIBC_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_LIBC_GLIBC_MIN_KERNEL="2.6.32.68"
-
-#
 # C compiler
 #
-CT_CC="gcc"
 CT_CC_CORE_PASSES_NEEDED=y
 CT_CC_CORE_PASS_1_NEEDED=y
 CT_CC_CORE_PASS_2_NEEDED=y
-CT_CC_gcc=y
-# CT_CC_GCC_SHOW_LINARO is not set
-CT_CC_GCC_V_5_2_0=y
-# CT_CC_GCC_V_4_9_3 is not set
-# CT_CC_GCC_V_4_8_5 is not set
-# CT_CC_GCC_V_4_7_4 is not set
-# CT_CC_GCC_V_4_6_4 is not set
-# CT_CC_GCC_V_4_5_4 is not set
-# CT_CC_GCC_V_4_4_7 is not set
-# CT_CC_GCC_V_4_3_6 is not set
-# CT_CC_GCC_V_4_2_4 is not set
-CT_CC_GCC_4_2_or_later=y
-CT_CC_GCC_4_3_or_later=y
-CT_CC_GCC_4_4_or_later=y
-CT_CC_GCC_4_5_or_later=y
-CT_CC_GCC_4_6_or_later=y
-CT_CC_GCC_4_7_or_later=y
-CT_CC_GCC_4_8_or_later=y
-CT_CC_GCC_4_9_or_later=y
-CT_CC_GCC_5=y
-CT_CC_GCC_5_or_later=y
-CT_CC_GCC_HAS_GRAPHITE=y
-CT_CC_GCC_USE_GRAPHITE=y
-CT_CC_GCC_HAS_LTO=y
-CT_CC_GCC_USE_LTO=y
-CT_CC_GCC_HAS_PKGVERSION_BUGURL=y
-CT_CC_GCC_HAS_BUILD_ID=y
-CT_CC_GCC_HAS_LNK_HASH_STYLE=y
-CT_CC_GCC_USE_GMP_MPFR=y
-CT_CC_GCC_USE_MPC=y
-CT_CC_GCC_HAS_LIBQUADMATH=y
-CT_CC_GCC_HAS_LIBSANITIZER=y
-CT_CC_GCC_VERSION="5.2.0"
-# CT_CC_LANG_FORTRAN is not set
+CT_CC_SUPPORT_CXX=y
+CT_CC_SUPPORT_FORTRAN=y
+CT_CC_SUPPORT_ADA=y
+CT_CC_SUPPORT_OBJC=y
+CT_CC_SUPPORT_OBJCXX=y
+CT_CC_SUPPORT_GOLANG=y
+CT_CC_GCC=y
+CT_CC="gcc"
+CT_CC_CHOICE_KSYM="GCC"
+CT_CC_GCC_SHOW=y
+
+#
+# Options for gcc
+#
+CT_CC_GCC_PKG_KSYM="GCC"
+CT_GCC_DIR_NAME="gcc"
+CT_GCC_USE_GNU=y
+CT_GCC_USE="GCC"
+CT_GCC_PKG_NAME="gcc"
+CT_GCC_SRC_RELEASE=y
+CT_GCC_PATCH_ORDER="global"
+CT_GCC_V_8=y
+# CT_GCC_V_7 is not set
+# CT_GCC_V_6 is not set
+# CT_GCC_V_5 is not set
+# CT_GCC_V_4_9 is not set
+# CT_GCC_NO_VERSIONS is not set
+CT_GCC_VERSION="8.3.0"
+CT_GCC_MIRRORS="$(CT_Mirrors GNU gcc/gcc-${CT_GCC_VERSION}) $(CT_Mirrors sourceware gcc/releases/gcc-${CT_GCC_VERSION})"
+CT_GCC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GCC_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_GCC_SIGNATURE_FORMAT=""
+CT_GCC_later_than_7=y
+CT_GCC_7_or_later=y
+CT_GCC_later_than_6=y
+CT_GCC_6_or_later=y
+CT_GCC_later_than_5=y
+CT_GCC_5_or_later=y
+CT_GCC_later_than_4_9=y
+CT_GCC_4_9_or_later=y
+CT_GCC_later_than_4_8=y
+CT_GCC_4_8_or_later=y
+CT_CC_GCC_HAS_LIBMPX=y
 CT_CC_GCC_ENABLE_CXX_FLAGS=""
 CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY=""
 CT_CC_GCC_EXTRA_CONFIG_ARRAY=""
-CT_CC_GCC_EXTRA_ENV_ARRAY=""
 CT_CC_GCC_STATIC_LIBSTDCXX=y
 # CT_CC_GCC_SYSTEM_ZLIB is not set
+CT_CC_GCC_CONFIG_TLS=m
 
 #
 # Optimisation features
 #
+CT_CC_GCC_USE_GRAPHITE=y
+CT_CC_GCC_USE_LTO=y
 
 #
 # Settings for libraries running on target
@@ -430,94 +529,208 @@ CT_CC_GCC_DEC_FLOAT_AUTO=y
 # CT_CC_GCC_DEC_FLOAT_BID is not set
 # CT_CC_GCC_DEC_FLOAT_DPD is not set
 # CT_CC_GCC_DEC_FLOATS_NO is not set
-CT_CC_SUPPORT_CXX=y
-CT_CC_SUPPORT_FORTRAN=y
-CT_CC_SUPPORT_JAVA=y
-CT_CC_SUPPORT_ADA=y
-CT_CC_SUPPORT_OBJC=y
-CT_CC_SUPPORT_OBJCXX=y
-CT_CC_SUPPORT_GOLANG=y
+CT_ALL_CC_CHOICES="GCC"
 
 #
 # Additional supported languages:
 #
 CT_CC_LANG_CXX=y
-# CT_CC_LANG_JAVA is not set
+# CT_CC_LANG_FORTRAN is not set
 
 #
 # Debug facilities
 #
-# CT_DEBUG_dmalloc is not set
-# CT_DEBUG_duma is not set
-# CT_DEBUG_gdb is not set
-# CT_DEBUG_ltrace is not set
-# CT_DEBUG_strace is not set
+# CT_DEBUG_DUMA is not set
+# CT_DEBUG_GDB is not set
+# CT_DEBUG_LTRACE is not set
+# CT_DEBUG_STRACE is not set
+CT_ALL_DEBUG_CHOICES="DUMA GDB LTRACE STRACE"
 
 #
 # Companion libraries
 #
-CT_COMPLIBS_NEEDED=y
+# CT_COMPLIBS_CHECK is not set
+# CT_COMP_LIBS_CLOOG is not set
+# CT_COMP_LIBS_EXPAT is not set
+CT_COMP_LIBS_GETTEXT=y
+CT_COMP_LIBS_GETTEXT_PKG_KSYM="GETTEXT"
+CT_GETTEXT_DIR_NAME="gettext"
+CT_GETTEXT_PKG_NAME="gettext"
+CT_GETTEXT_SRC_RELEASE=y
+CT_GETTEXT_PATCH_ORDER="global"
+CT_GETTEXT_V_0_19_8_1=y
+# CT_GETTEXT_NO_VERSIONS is not set
+CT_GETTEXT_VERSION="0.19.8.1"
+CT_GETTEXT_MIRRORS="$(CT_Mirrors GNU gettext)"
+CT_GETTEXT_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GETTEXT_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.gz"
+CT_GETTEXT_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_GMP=y
+CT_COMP_LIBS_GMP_PKG_KSYM="GMP"
+CT_GMP_DIR_NAME="gmp"
+CT_GMP_PKG_NAME="gmp"
+CT_GMP_SRC_RELEASE=y
+CT_GMP_PATCH_ORDER="global"
+CT_GMP_V_6_1=y
+# CT_GMP_NO_VERSIONS is not set
+CT_GMP_VERSION="6.1.2"
+CT_GMP_MIRRORS="https://gmplib.org/download/gmp https://gmplib.org/download/gmp/archive $(CT_Mirrors GNU gmp)"
+CT_GMP_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_GMP_ARCHIVE_FORMATS=".tar.xz .tar.lz .tar.bz2"
+CT_GMP_SIGNATURE_FORMAT="packed/.sig"
+CT_GMP_later_than_5_1_0=y
+CT_GMP_5_1_0_or_later=y
+CT_GMP_later_than_5_0_0=y
+CT_GMP_5_0_0_or_later=y
+CT_GMP_REQUIRE_5_0_0_or_later=y
+CT_COMP_LIBS_ISL=y
+CT_COMP_LIBS_ISL_PKG_KSYM="ISL"
+CT_ISL_DIR_NAME="isl"
+CT_ISL_PKG_NAME="isl"
+CT_ISL_SRC_RELEASE=y
+CT_ISL_PATCH_ORDER="global"
+CT_ISL_V_0_20=y
+# CT_ISL_V_0_19 is not set
+# CT_ISL_V_0_18 is not set
+# CT_ISL_V_0_17 is not set
+# CT_ISL_V_0_16 is not set
+# CT_ISL_V_0_15 is not set
+# CT_ISL_NO_VERSIONS is not set
+CT_ISL_VERSION="0.20"
+CT_ISL_MIRRORS="http://isl.gforge.inria.fr"
+CT_ISL_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ISL_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
+CT_ISL_SIGNATURE_FORMAT=""
+CT_ISL_later_than_0_18=y
+CT_ISL_0_18_or_later=y
+CT_ISL_later_than_0_15=y
+CT_ISL_0_15_or_later=y
+CT_ISL_REQUIRE_0_15_or_later=y
+CT_ISL_later_than_0_14=y
+CT_ISL_0_14_or_later=y
+CT_ISL_REQUIRE_0_14_or_later=y
+CT_ISL_later_than_0_13=y
+CT_ISL_0_13_or_later=y
+CT_ISL_later_than_0_12=y
+CT_ISL_0_12_or_later=y
+CT_ISL_REQUIRE_0_12_or_later=y
+# CT_COMP_LIBS_LIBELF is not set
+CT_COMP_LIBS_LIBICONV=y
+CT_COMP_LIBS_LIBICONV_PKG_KSYM="LIBICONV"
+CT_LIBICONV_DIR_NAME="libiconv"
+CT_LIBICONV_PKG_NAME="libiconv"
+CT_LIBICONV_SRC_RELEASE=y
+CT_LIBICONV_PATCH_ORDER="global"
+CT_LIBICONV_V_1_15=y
+# CT_LIBICONV_NO_VERSIONS is not set
+CT_LIBICONV_VERSION="1.15"
+CT_LIBICONV_MIRRORS="$(CT_Mirrors GNU libiconv)"
+CT_LIBICONV_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_LIBICONV_ARCHIVE_FORMATS=".tar.gz"
+CT_LIBICONV_SIGNATURE_FORMAT="packed/.sig"
+CT_COMP_LIBS_MPC=y
+CT_COMP_LIBS_MPC_PKG_KSYM="MPC"
+CT_MPC_DIR_NAME="mpc"
+CT_MPC_PKG_NAME="mpc"
+CT_MPC_SRC_RELEASE=y
+CT_MPC_PATCH_ORDER="global"
+CT_MPC_V_1_1=y
+# CT_MPC_V_1_0 is not set
+# CT_MPC_NO_VERSIONS is not set
+CT_MPC_VERSION="1.1.0"
+CT_MPC_MIRRORS="http://www.multiprecision.org/downloads $(CT_Mirrors GNU mpc)"
+CT_MPC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPC_ARCHIVE_FORMATS=".tar.gz"
+CT_MPC_SIGNATURE_FORMAT="packed/.sig"
+CT_MPC_1_1_0_or_later=y
+CT_MPC_1_1_0_or_older=y
+CT_COMP_LIBS_MPFR=y
+CT_COMP_LIBS_MPFR_PKG_KSYM="MPFR"
+CT_MPFR_DIR_NAME="mpfr"
+CT_MPFR_PKG_NAME="mpfr"
+CT_MPFR_SRC_RELEASE=y
+CT_MPFR_PATCH_ORDER="global"
+CT_MPFR_V_4_0=y
+# CT_MPFR_V_3_1 is not set
+# CT_MPFR_NO_VERSIONS is not set
+CT_MPFR_VERSION="4.0.2"
+CT_MPFR_MIRRORS="http://www.mpfr.org/mpfr-${CT_MPFR_VERSION} $(CT_Mirrors GNU mpfr)"
+CT_MPFR_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_MPFR_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz .zip"
+CT_MPFR_SIGNATURE_FORMAT="packed/.asc"
+CT_MPFR_later_than_4_0_0=y
+CT_MPFR_4_0_0_or_later=y
+CT_MPFR_later_than_3_0_0=y
+CT_MPFR_3_0_0_or_later=y
+CT_MPFR_REQUIRE_3_0_0_or_later=y
+CT_COMP_LIBS_NCURSES=y
+CT_COMP_LIBS_NCURSES_PKG_KSYM="NCURSES"
+CT_NCURSES_DIR_NAME="ncurses"
+CT_NCURSES_PKG_NAME="ncurses"
+CT_NCURSES_SRC_RELEASE=y
+CT_NCURSES_PATCH_ORDER="global"
+CT_NCURSES_V_6_1=y
+# CT_NCURSES_V_6_0 is not set
+# CT_NCURSES_NO_VERSIONS is not set
+CT_NCURSES_VERSION="6.1"
+CT_NCURSES_MIRRORS="ftp://invisible-island.net/ncurses $(CT_Mirrors GNU ncurses)"
+CT_NCURSES_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_NCURSES_ARCHIVE_FORMATS=".tar.gz"
+CT_NCURSES_SIGNATURE_FORMAT="packed/.sig"
+CT_NCURSES_HOST_CONFIG_ARGS=""
+CT_NCURSES_HOST_DISABLE_DB=y
+CT_NCURSES_HOST_FALLBACKS="linux,xterm,xterm-color,xterm-256color,vt100"
+CT_NCURSES_TARGET_CONFIG_ARGS=""
+# CT_NCURSES_TARGET_DISABLE_DB is not set
+CT_NCURSES_TARGET_FALLBACKS=""
+CT_COMP_LIBS_ZLIB=y
+CT_COMP_LIBS_ZLIB_PKG_KSYM="ZLIB"
+CT_ZLIB_DIR_NAME="zlib"
+CT_ZLIB_PKG_NAME="zlib"
+CT_ZLIB_SRC_RELEASE=y
+CT_ZLIB_PATCH_ORDER="global"
+CT_ZLIB_V_1_2_11=y
+# CT_ZLIB_NO_VERSIONS is not set
+CT_ZLIB_VERSION="1.2.11"
+CT_ZLIB_MIRRORS="http://downloads.sourceforge.net/project/libpng/zlib/${CT_ZLIB_VERSION}"
+CT_ZLIB_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
+CT_ZLIB_ARCHIVE_FORMATS=".tar.xz .tar.gz"
+CT_ZLIB_SIGNATURE_FORMAT="packed/.asc"
+CT_ALL_COMP_LIBS_CHOICES="CLOOG EXPAT GETTEXT GMP ISL LIBELF LIBICONV MPC MPFR NCURSES ZLIB"
 CT_LIBICONV_NEEDED=y
 CT_GETTEXT_NEEDED=y
 CT_GMP_NEEDED=y
 CT_MPFR_NEEDED=y
 CT_ISL_NEEDED=y
 CT_MPC_NEEDED=y
-CT_COMPLIBS=y
+CT_NCURSES_NEEDED=y
+CT_ZLIB_NEEDED=y
 CT_LIBICONV=y
 CT_GETTEXT=y
 CT_GMP=y
 CT_MPFR=y
 CT_ISL=y
 CT_MPC=y
-CT_LIBICONV_V_1_14=y
-CT_LIBICONV_VERSION="1.14"
-CT_GETTEXT_V_0_19_6=y
-CT_GETTEXT_VERSION="0.19.6"
-CT_GMP_V_6_0_0=y
-# CT_GMP_V_5_1_3 is not set
-# CT_GMP_V_5_1_1 is not set
-# CT_GMP_V_5_0_2 is not set
-# CT_GMP_V_5_0_1 is not set
-# CT_GMP_V_4_3_2 is not set
-# CT_GMP_V_4_3_1 is not set
-# CT_GMP_V_4_3_0 is not set
-CT_GMP_5_0_2_or_later=y
-CT_GMP_VERSION="6.0.0a"
-CT_MPFR_V_3_1_3=y
-# CT_MPFR_V_3_1_2 is not set
-# CT_MPFR_V_3_1_0 is not set
-# CT_MPFR_V_3_0_1 is not set
-# CT_MPFR_V_3_0_0 is not set
-# CT_MPFR_V_2_4_2 is not set
-# CT_MPFR_V_2_4_1 is not set
-# CT_MPFR_V_2_4_0 is not set
-CT_MPFR_VERSION="3.1.3"
-CT_ISL_V_0_14=y
-# CT_ISL_V_0_12_2 is not set
-CT_ISL_V_0_14_or_later=y
-CT_ISL_V_0_12_or_later=y
-CT_ISL_VERSION="0.14"
-CT_MPC_V_1_0_3=y
-# CT_MPC_V_1_0_2 is not set
-# CT_MPC_V_1_0_1 is not set
-# CT_MPC_V_1_0 is not set
-# CT_MPC_V_0_9 is not set
-# CT_MPC_V_0_8_2 is not set
-# CT_MPC_V_0_8_1 is not set
-# CT_MPC_V_0_7 is not set
-CT_MPC_VERSION="1.0.3"
-
-#
-# Companion libraries common options
-#
-# CT_COMPLIBS_CHECK is not set
+CT_NCURSES=y
+CT_ZLIB=y
 
 #
 # Companion tools
 #
-
-#
-# READ HELP before you say 'Y' below !!!
-#
-# CT_COMP_TOOLS is not set
+# CT_COMP_TOOLS_FOR_HOST is not set
+# CT_COMP_TOOLS_AUTOCONF is not set
+# CT_COMP_TOOLS_AUTOMAKE is not set
+# CT_COMP_TOOLS_BISON is not set
+# CT_COMP_TOOLS_DTC is not set
+# CT_COMP_TOOLS_LIBTOOL is not set
+# CT_COMP_TOOLS_M4 is not set
+# CT_COMP_TOOLS_MAKE is not set
+CT_ALL_COMP_TOOLS_CHOICES="AUTOCONF AUTOMAKE BISON DTC LIBTOOL M4 MAKE"
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile
index 5157dd4c79b..9a290edd561 100644
--- a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux/Dockerfile
@@ -1,16 +1,8 @@
-FROM ubuntu:16.04
+FROM ubuntu:20.04
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
 
-# Ubuntu 16.04 (this container) ships with make 4, but something in the
-# toolchains we build below chokes on that, so go back to make 3
-COPY scripts/make3.sh /scripts/
-RUN sh /scripts/make3.sh
-
-COPY scripts/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
-
 COPY scripts/rustbuild-setup.sh /scripts/
 RUN sh /scripts/rustbuild-setup.sh
 USER rustbuild
@@ -25,9 +17,6 @@ RUN ./build-powerpc64le-toolchain.sh
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV \
     AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \
     CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \
diff --git a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh
index f78d2b7d1e8..56ea28b6ca5 100755
--- a/src/ci/docker/host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh
+++ b/src/ci/docker/host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh
@@ -5,7 +5,7 @@ set -ex
 source shared.sh
 
 BINUTILS=2.32
-GCC=5.3.0
+GCC=8.3.0
 TARGET=powerpc64le-linux-gnu
 SYSROOT=/usr/local/$TARGET/sysroot
 
@@ -32,7 +32,7 @@ popd
 # Next, download and build binutils.
 mkdir binutils-$TARGET
 pushd binutils-$TARGET
-curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf -
+curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.xz | tar xJf -
 mkdir binutils-build
 cd binutils-build
 hide_output ../binutils-$BINUTILS/configure --target=$TARGET --with-sysroot=$SYSROOT
@@ -44,7 +44,7 @@ rm -rf binutils-$TARGET
 # Finally, download and build gcc.
 mkdir gcc-$TARGET
 pushd gcc-$TARGET
-curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
+curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.xz | tar xJf -
 cd gcc-$GCC
 hide_output ./contrib/download_prerequisites
 
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile
index 80b7793cb7e..88b8c7ea3c7 100644
--- a/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-riscv64-linux/Dockerfile
@@ -1,10 +1,10 @@
-FROM ubuntu:18.04
+FROM ubuntu:20.04
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
 
-COPY host-x86_64/dist-riscv64-linux/crosstool-ng.sh /scripts/
-RUN sh /scripts/crosstool-ng.sh
+COPY scripts/crosstool-ng-1.24.sh /scripts/
+RUN sh /scripts/crosstool-ng-1.24.sh
 
 COPY scripts/rustbuild-setup.sh /scripts/
 RUN sh /scripts/rustbuild-setup.sh
@@ -19,9 +19,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/riscv64-unknown-linux-gnu/bin
 
 ENV CC_riscv64gc_unknown_linux_gnu=riscv64-unknown-linux-gnu-gcc \
diff --git a/src/ci/docker/host-x86_64/dist-riscv64-linux/crosstool-ng.sh b/src/ci/docker/host-x86_64/dist-riscv64-linux/crosstool-ng.sh
deleted file mode 100644
index 3a40f6cddb3..00000000000
--- a/src/ci/docker/host-x86_64/dist-riscv64-linux/crosstool-ng.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/sh
-set -ex
-
-# Mirrored from https://github.com/crosstool-ng/crosstool-ng/archive/crosstool-ng-1.24.0.tar.gz
-url="https://ci-mirrors.rust-lang.org/rustc/crosstool-ng-1.24.0.tar.gz"
-curl -Lf $url | tar xzf -
-cd crosstool-ng-crosstool-ng-1.24.0
-./bootstrap
-./configure --prefix=/usr/local
-make -j$(nproc)
-make install
-cd ..
-rm -rf crosstool-ng-crosstool-ng-1.24.0
diff --git a/src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile
index fda0f0e2f7f..7d77fdd30d1 100644
--- a/src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-s390x-linux/Dockerfile
@@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh
 USER rustbuild
 WORKDIR /tmp
 
-COPY host-x86_64/dist-s390x-linux/patches/ /tmp/patches/
 COPY host-x86_64/dist-s390x-linux/s390x-linux-gnu.config host-x86_64/dist-s390x-linux/build-s390x-toolchain.sh /tmp/
 RUN ./build-s390x-toolchain.sh
 
@@ -20,9 +19,6 @@ USER root
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-COPY scripts/cmake.sh /scripts/
-RUN /scripts/cmake.sh
-
 ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin
 
 ENV \
diff --git a/src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.12.1/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch b/src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.12.1/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch
deleted file mode 100644
index cba416ed2f7..00000000000
--- a/src/ci/docker/host-x86_64/dist-s390x-linux/patches/glibc/2.12.1/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch
+++ /dev/null
@@ -1,63 +0,0 @@
-From 2739047682590b1df473401b4febf424f857fccf Mon Sep 17 00:00:00 2001
-From: Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
-Date: Sun, 17 Apr 2011 20:43:59 -0400
-Subject: [PATCH] Use .machine to prevent AS from complaining about z9-109
- instructions in iconv modules
-
----
- sysdeps/s390/s390-64/utf16-utf32-z9.c | 5 ++++-
- sysdeps/s390/s390-64/utf8-utf16-z9.c  | 5 ++++-
- sysdeps/s390/s390-64/utf8-utf32-z9.c  | 5 ++++-
- 3 files changed, 12 insertions(+), 3 deletions(-)
-
-diff --git a/sysdeps/s390/s390-64/utf16-utf32-z9.c b/sysdeps/s390/s390-64/utf16-utf32-z9.c
-index 14daf2118fe5..5bcaaaedec9c 100644
---- a/sysdeps/s390/s390-64/utf16-utf32-z9.c
-+++ b/sysdeps/s390/s390-64/utf16-utf32-z9.c
-@@ -169,7 +169,10 @@ gconv_end (struct __gconv_step *data)
-     register unsigned long long outlen asm("11") = outend - outptr;	\
-     uint64_t cc = 0;							\
- 									\
--    asm volatile ("0: " INSTRUCTION "  \n\t"				\
-+    asm volatile (".machine push       \n\t"				\
-+                  ".machine \"z9-109\" \n\t"				\
-+		  "0: " INSTRUCTION "  \n\t"				\
-+                  ".machine pop        \n\t"				\
-                   "   jo     0b        \n\t"				\
- 		  "   ipm    %2        \n"			        \
- 		  : "+a" (pOutput), "+a" (pInput), "+d" (cc),		\
-diff --git a/sysdeps/s390/s390-64/utf8-utf16-z9.c b/sysdeps/s390/s390-64/utf8-utf16-z9.c
-index 5f73f3c59e21..812a42fae44c 100644
---- a/sysdeps/s390/s390-64/utf8-utf16-z9.c
-+++ b/sysdeps/s390/s390-64/utf8-utf16-z9.c
-@@ -151,7 +151,10 @@ gconv_end (struct __gconv_step *data)
-     register unsigned long long outlen asm("11") = outend - outptr;	\
-     uint64_t cc = 0;							\
- 									\
--    asm volatile ("0: " INSTRUCTION "  \n\t"				\
-+    asm volatile (".machine push       \n\t"				\
-+                  ".machine \"z9-109\" \n\t"				\
-+		  "0: " INSTRUCTION "  \n\t"				\
-+                  ".machine pop        \n\t"				\
-                   "   jo     0b        \n\t"				\
- 		  "   ipm    %2        \n"			        \
- 		  : "+a" (pOutput), "+a" (pInput), "+d" (cc),		\
-diff --git a/sysdeps/s390/s390-64/utf8-utf32-z9.c b/sysdeps/s390/s390-64/utf8-utf32-z9.c
-index 17ef8bc890c3..0ffd848c8124 100644
---- a/sysdeps/s390/s390-64/utf8-utf32-z9.c
-+++ b/sysdeps/s390/s390-64/utf8-utf32-z9.c
-@@ -155,7 +155,10 @@ gconv_end (struct __gconv_step *data)
-     register unsigned long long outlen asm("11") = outend - outptr;	\
-     uint64_t cc = 0;							\
- 									\
--    asm volatile ("0: " INSTRUCTION "  \n\t"				\
-+    asm volatile (".machine push       \n\t"				\
-+                  ".machine \"z9-109\" \n\t"				\
-+		  "0: " INSTRUCTION "  \n\t"				\
-+                  ".machine pop        \n\t"				\
-                   "   jo     0b        \n\t"				\
- 		  "   ipm    %2        \n"				\
- 		  : "+a" (pOutput), "+a" (pInput), "+d" (cc),		\
--- 
-2.9.3
-
diff --git a/src/ci/docker/host-x86_64/dist-s390x-linux/s390x-linux-gnu.config b/src/ci/docker/host-x86_64/dist-s390x-linux/s390x-linux-gnu.config
index d766e6e838e..51ef36b03ac 100644
--- a/src/ci/docker/host-x86_64/dist-s390x-linux/s390x-linux-gnu.config
+++ b/src/ci/docker/host-x86_64/dist-s390x-linux/s390x-linux-gnu.config
@@ -41,7 +41,8 @@ CT_MODULES=y
 #
 # Paths
 #
-CT_LOCAL_TARBALLS_DIR=""
+CT_LOCAL_TARBALLS_DIR="${HOME}/src"
+CT_SAVE_TARBALLS=y
 # CT_TARBALLS_BUILDROOT_LAYOUT is not set
 CT_WORK_DIR="${CT_TOP_DIR}/.build"
 CT_BUILD_TOP_DIR="${CT_WORK_DIR:-${CT_TOP_DIR}/.build}/${CT_HOST:+HOST-${CT_HOST}/}${CT_TARGET}"
@@ -81,11 +82,9 @@ CT_VERIFY_DOWNLOAD_DIGEST_ALG="sha512"
 # CT_FORCE_EXTRACT is not set
 CT_OVERRIDE_CONFIG_GUESS_SUB=y
 # CT_ONLY_EXTRACT is not set
-# CT_PATCH_BUNDLED is not set
-CT_PATCH_BUNDLED_LOCAL=y
-CT_PATCH_ORDER="bundled,local"
-CT_PATCH_USE_LOCAL=y
-CT_LOCAL_PATCH_DIR="/tmp/patches"
+CT_PATCH_BUNDLED=y
+# CT_PATCH_BUNDLED_LOCAL is not set
+CT_PATCH_ORDER="bundled"
 
 #
 # Build behavior
@@ -136,6 +135,12 @@ CT_ARCH_S390=y
 # CT_ARCH_XTENSA is not set
 CT_ARCH="s390"
 CT_ARCH_CHOICE_KSYM="S390"
+# CT_ARCH_ALPHA_EV4 is not set
+# CT_ARCH_ALPHA_EV45 is not set
+# CT_ARCH_ALPHA_EV5 is not set
+# CT_ARCH_ALPHA_EV56 is not set
+# CT_ARCH_ALPHA_EV6 is not set
+# CT_ARCH_ALPHA_EV67 is not set
 CT_ARCH_S390_SHOW=y
 
 #
@@ -248,10 +253,10 @@ CT_LINUX_PATCH_ORDER="global"
 # CT_LINUX_V_3_12 is not set
 # CT_LINUX_V_3_10 is not set
 # CT_LINUX_V_3_4 is not set
-# CT_LINUX_V_3_2 is not set
-CT_LINUX_V_2_6_32=y
+CT_LINUX_V_3_2=y
+# CT_LINUX_V_2_6_32 is not set
 # CT_LINUX_NO_VERSIONS is not set
-CT_LINUX_VERSION="2.6.32.71"
+CT_LINUX_VERSION="3.2.101"
 CT_LINUX_MIRRORS="$(CT_Mirrors kernel.org linux ${CT_LINUX_VERSION})"
 CT_LINUX_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
 CT_LINUX_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
@@ -261,8 +266,8 @@ CT_LINUX_4_8_or_older=y
 CT_LINUX_older_than_4_8=y
 CT_LINUX_3_7_or_older=y
 CT_LINUX_older_than_3_7=y
-CT_LINUX_3_2_or_older=y
-CT_LINUX_older_than_3_2=y
+CT_LINUX_later_than_3_2=y
+CT_LINUX_3_2_or_later=y
 CT_KERNEL_LINUX_VERBOSITY_0=y
 # CT_KERNEL_LINUX_VERBOSITY_1 is not set
 # CT_KERNEL_LINUX_VERBOSITY_2 is not set
@@ -294,24 +299,24 @@ CT_BINUTILS_USE="BINUTILS"
 CT_BINUTILS_PKG_NAME="binutils"
 CT_BINUTILS_SRC_RELEASE=y
 CT_BINUTILS_PATCH_ORDER="global"
-# CT_BINUTILS_V_2_32 is not set
+CT_BINUTILS_V_2_32=y
 # CT_BINUTILS_V_2_31 is not set
 # CT_BINUTILS_V_2_30 is not set
 # CT_BINUTILS_V_2_29 is not set
 # CT_BINUTILS_V_2_28 is not set
 # CT_BINUTILS_V_2_27 is not set
-CT_BINUTILS_V_2_26=y
+# CT_BINUTILS_V_2_26 is not set
 # CT_BINUTILS_NO_VERSIONS is not set
-CT_BINUTILS_VERSION="2.26.1"
+CT_BINUTILS_VERSION="2.32"
 CT_BINUTILS_MIRRORS="$(CT_Mirrors GNU binutils) $(CT_Mirrors sourceware binutils/releases)"
 CT_BINUTILS_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
 CT_BINUTILS_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
-CT_BINUTILS_ARCHIVE_FORMATS=".tar.bz2 .tar.gz"
+CT_BINUTILS_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz"
 CT_BINUTILS_SIGNATURE_FORMAT="packed/.sig"
-CT_BINUTILS_2_30_or_older=y
-CT_BINUTILS_older_than_2_30=y
-CT_BINUTILS_2_27_or_older=y
-CT_BINUTILS_older_than_2_27=y
+CT_BINUTILS_later_than_2_30=y
+CT_BINUTILS_2_30_or_later=y
+CT_BINUTILS_later_than_2_27=y
+CT_BINUTILS_2_27_or_later=y
 CT_BINUTILS_later_than_2_25=y
 CT_BINUTILS_2_25_or_later=y
 CT_BINUTILS_later_than_2_23=y
@@ -338,6 +343,8 @@ CT_ALL_BINUTILS_CHOICES="BINUTILS"
 # C-library
 #
 CT_LIBC_GLIBC=y
+# CT_LIBC_NEWLIB is not set
+# CT_LIBC_NONE is not set
 # CT_LIBC_UCLIBC is not set
 CT_LIBC="glibc"
 CT_LIBC_CHOICE_KSYM="GLIBC"
@@ -362,10 +369,10 @@ CT_GLIBC_PATCH_ORDER="global"
 # CT_GLIBC_V_2_24 is not set
 # CT_GLIBC_V_2_23 is not set
 # CT_GLIBC_V_2_19 is not set
-# CT_GLIBC_V_2_17 is not set
-CT_GLIBC_V_2_12_1=y
+CT_GLIBC_V_2_17=y
+# CT_GLIBC_V_2_12_1 is not set
 # CT_GLIBC_NO_VERSIONS is not set
-CT_GLIBC_VERSION="2.12.1"
+CT_GLIBC_VERSION="2.17"
 CT_GLIBC_MIRRORS="$(CT_Mirrors GNU glibc)"
 CT_GLIBC_ARCHIVE_FILENAME="@{pkg_name}-@{version}"
 CT_GLIBC_ARCHIVE_DIRNAME="@{pkg_name}-@{version}"
@@ -385,23 +392,24 @@ CT_GLIBC_2_23_or_older=y
 CT_GLIBC_older_than_2_23=y
 CT_GLIBC_2_20_or_older=y
 CT_GLIBC_older_than_2_20=y
+CT_GLIBC_2_17_or_later=y
 CT_GLIBC_2_17_or_older=y
-CT_GLIBC_older_than_2_17=y
-CT_GLIBC_2_14_or_older=y
-CT_GLIBC_older_than_2_14=y
+CT_GLIBC_later_than_2_14=y
+CT_GLIBC_2_14_or_later=y
 CT_GLIBC_DEP_KERNEL_HEADERS_VERSION=y
 CT_GLIBC_DEP_BINUTILS=y
 CT_GLIBC_DEP_GCC=y
 CT_GLIBC_DEP_PYTHON=y
 CT_GLIBC_HAS_NPTL_ADDON=y
 CT_GLIBC_HAS_PORTS_ADDON=y
-CT_GLIBC_HAS_PORTS_ADDON_EXTERNAL=y
 CT_GLIBC_HAS_LIBIDN_ADDON=y
 CT_GLIBC_USE_NPTL_ADDON=y
 # CT_GLIBC_USE_LIBIDN_ADDON is not set
+CT_GLIBC_HAS_OBSOLETE_RPC=y
 CT_GLIBC_EXTRA_CONFIG_ARRAY=""
 CT_GLIBC_CONFIGPARMS=""
 CT_GLIBC_EXTRA_CFLAGS=""
+CT_GLIBC_ENABLE_OBSOLETE_RPC=y
 # CT_GLIBC_DISABLE_VERSIONING is not set
 CT_GLIBC_OLDEST_ABI=""
 CT_GLIBC_FORCE_UNWIND=y
@@ -409,7 +417,13 @@ CT_GLIBC_FORCE_UNWIND=y
 # CT_GLIBC_KERNEL_VERSION_NONE is not set
 CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y
 # CT_GLIBC_KERNEL_VERSION_CHOSEN is not set
-CT_GLIBC_MIN_KERNEL="2.6.32.71"
+CT_GLIBC_MIN_KERNEL="3.2.101"
+# CT_GLIBC_SSP_DEFAULT is not set
+# CT_GLIBC_SSP_NO is not set
+# CT_GLIBC_SSP_YES is not set
+# CT_GLIBC_SSP_ALL is not set
+# CT_GLIBC_SSP_STRONG is not set
+# CT_NEWLIB_USE_REDHAT is not set
 CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC"
 CT_LIBC_SUPPORT_THREADS_ANY=y
 CT_LIBC_SUPPORT_THREADS_NATIVE=y
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index b56776df1cb..973c43072bf 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -1,48 +1,40 @@
-# We need recent curl, OpenSSL and CA certificates, so we can download further
-# dependencies in the debian:6 image. We use an ubuntu 20.04 image download
-# those.
-FROM ubuntu:20.04
-RUN apt-get update && \
-    apt-get install -y --no-install-recommends \
-        curl \
-        ca-certificates
-WORKDIR /tmp
-COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/
-RUN ./download-openssl-curl.sh
-
-# We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
-# distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
-# SLES 11 SP4 (glibc 2.11, kernel 3.0).
-FROM debian:6
+# We document platform support for minimum glibc 2.17 and kernel 3.2.
+# CentOS 7 has headers for kernel 3.10, but that's fine as long as we don't
+# actually use newer APIs in rustc or std without a fallback. It's more
+# important that we match glibc for ELF symbol versioning.
+FROM centos:7
 
 WORKDIR /build
 
-# Debian 6 is EOL and no longer available from the usual mirrors,
-# so we'll need to switch to http://archive.debian.org/
-RUN sed -i '/updates/d' /etc/apt/sources.list && \
-    sed -i 's/httpredir/archive/' /etc/apt/sources.list
-
-RUN apt-get update && \
-    apt-get install --allow-unauthenticated -y --no-install-recommends \
+RUN yum upgrade -y && \
+    yum install -y epel-release && \
+    yum install -y \
       automake \
       bzip2 \
       file \
-      g++ \
-      g++-multilib \
+      cmake3 \
       gcc \
-      gcc-multilib \
+      gcc-c++ \
       git \
-      lib32z1-dev \
-      libedit-dev \
-      libncurses-dev \
+      glibc-devel.i686 \
+      glibc-devel.x86_64 \
+      libedit-devel \
+      libstdc++-devel.i686 \
+      libstdc++-devel.x86_64 \
       make \
+      ncurses-devel \
+      openssl-devel \
       patch \
       perl \
-      pkg-config \
+      pkgconfig \
+      python3 \
       unzip \
       wget \
-      xz-utils \
-      zlib1g-dev
+      xz \
+      zlib-devel.i686 \
+      zlib-devel.x86_64
+
+RUN mkdir -p /rustroot/bin && ln -s /usr/bin/cmake3 /rustroot/bin/cmake
 
 ENV PATH=/rustroot/bin:$PATH
 ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
@@ -51,46 +43,9 @@ WORKDIR /tmp
 RUN mkdir /home/user
 COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
 
-# We need a build of openssl which supports SNI to download artifacts from
-# static.rust-lang.org. This'll be used to link into libcurl below (and used
-# later as well), so build a copy of OpenSSL with dynamic libraries into our
-# generic root.
-COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz
-COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
-RUN ./build-openssl.sh
-
-# The `curl` binary on Debian 6 doesn't support SNI which is needed for fetching
-# some https urls we have, so install a new version of libcurl + curl which is
-# using the openssl we just built previously.
-#
-# Note that we also disable a bunch of optional features of curl that we don't
-# really need.
-COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz
-COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh
-
-# Use up-to-date curl CA bundle
-COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
-ENV CURL_CA_BUNDLE /tmp/cacert.pem
-
-# binutils < 2.22 has a bug where the 32-bit executables it generates
-# immediately segfault in Rust, so we need to install our own binutils.
-#
-# See https://github.com/rust-lang/rust/issues/20440 for more info
-COPY host-x86_64/dist-x86_64-linux/build-binutils.sh /tmp/
-RUN ./build-binutils.sh
-
 # Need at least GCC 5.1 to compile LLVM nowadays
 COPY host-x86_64/dist-x86_64-linux/build-gcc.sh /tmp/
-RUN ./build-gcc.sh && apt-get remove -y gcc g++
-
-COPY host-x86_64/dist-x86_64-linux/build-python.sh /tmp/
-# Build Python 3 needed for LLVM 12.
-RUN ./build-python.sh 3.9.1
-
-# LLVM needs cmake 3.13.4 or higher.
-COPY host-x86_64/dist-x86_64-linux/build-cmake.sh /tmp/
-RUN ./build-cmake.sh
+RUN ./build-gcc.sh && yum remove -y gcc gcc-c++
 
 # Now build LLVM+Clang, afterwards configuring further compilations to use the
 # clang/clang++ compilers.
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-binutils.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-binutils.sh
deleted file mode 100755
index b5378244b79..00000000000
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-binutils.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-
-source shared.sh
-
-VERSION=2.26.1
-
-curl https://ftp.gnu.org/gnu/binutils/binutils-$VERSION.tar.bz2 | tar xfj -
-
-mkdir binutils-build
-cd binutils-build
-hide_output ../binutils-$VERSION/configure --prefix=/rustroot
-hide_output make -j$(nproc)
-hide_output make install
-
-cd ..
-rm -rf binutils-build
-rm -rf binutils-$VERSION
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-cmake.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-cmake.sh
deleted file mode 100755
index 2f6b1fa9b8e..00000000000
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-cmake.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-CMAKE=3.13.4
-curl -L https://github.com/Kitware/CMake/releases/download/v$CMAKE/cmake-$CMAKE.tar.gz | tar xzf -
-
-mkdir cmake-build
-cd cmake-build
-hide_output ../cmake-$CMAKE/configure --prefix=/rustroot
-hide_output make -j$(nproc)
-hide_output make install
-
-cd ..
-rm -rf cmake-build
-rm -rf cmake-$CMAKE
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh
deleted file mode 100755
index 88ee96eaa89..00000000000
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-curl.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-tar xJf curl.tar.xz
-
-mkdir curl-build
-cd curl-build
-hide_output ../curl-*/configure \
-      --prefix=/rustroot \
-      --with-ssl=/rustroot \
-      --disable-sspi \
-      --disable-gopher \
-      --disable-smtp \
-      --disable-smb \
-      --disable-imap \
-      --disable-pop3 \
-      --disable-tftp \
-      --disable-telnet \
-      --disable-manual \
-      --disable-dict \
-      --disable-rtsp \
-      --disable-ldaps \
-      --disable-ldap
-hide_output make -j$(nproc)
-hide_output make install
-
-cd ..
-rm -rf curl-build
-rm -rf curl-*
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh
index 7992ec3b991..9932b250566 100755
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh
@@ -39,3 +39,8 @@ ln -s gcc /rustroot/bin/cc
 cd ..
 rm -rf gcc-build
 rm -rf gcc-$GCC
+
+# FIXME: clang doesn't find 32-bit libraries in /rustroot/lib,
+# but it does look all the way under /rustroot/lib/[...]/32,
+# so we can link stuff there to help it out.
+ln /rustroot/lib/*.{a,so} -rst /rustroot/lib/gcc/x86_64-pc-linux-gnu/$GCC/32/
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh
deleted file mode 100755
index b48b5c4c00a..00000000000
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-openssl.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-tar xzf openssl.tar.gz
-
-cd openssl-*
-hide_output ./config --prefix=/rustroot shared -fPIC
-hide_output make -j$(nproc)
-hide_output make install
-cd ..
-rm -rf openssl-*
-
-# Make the system cert collection available to the new install.
-ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-python.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-python.sh
deleted file mode 100755
index 9a203beadd1..00000000000
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-python.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-VERSION=$1
-curl https://www.python.org/ftp/python/$VERSION/Python-$VERSION.tgz | \
-  tar xzf -
-
-mkdir python-build
-cd python-build
-
-# Gotta do some hackery to tell python about our custom OpenSSL build, but other
-# than that fairly normal.
-CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \
-    hide_output ../Python-$VERSION/configure --prefix=/rustroot
-hide_output make -j$(nproc)
-hide_output make install
-
-cd ..
-rm -rf python-build
-rm -rf Python-$VERSION
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh
deleted file mode 100755
index ca40a8cf7da..00000000000
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/download-openssl-curl.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env bash
-
-set -ex
-
-OPENSSL_VERSION=1.0.2k
-CURL_VERSION=7.66.0
-
-curl -f https://ci-mirrors.rust-lang.org/rustc/openssl-$OPENSSL_VERSION.tar.gz -o openssl.tar.gz
-curl -f https://ci-mirrors.rust-lang.org/rustc/curl-$CURL_VERSION.tar.xz -o curl.tar.xz
-curl -f https://curl.se/ca/cacert.pem -o cacert.pem
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/llvm-project-centos.patch b/src/ci/docker/host-x86_64/dist-x86_64-linux/llvm-project-centos.patch
deleted file mode 100644
index 52650062cc4..00000000000
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/llvm-project-centos.patch
+++ /dev/null
@@ -1,18 +0,0 @@
-diff --git a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
-index 176d6d6abf3..a6d63bf24b8 100644
---- a/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
-+++ b/clang/lib/DirectoryWatcher/linux/DirectoryWatcher-linux.cpp
-@@ -33,6 +33,13 @@ namespace {
- using namespace llvm;
- using namespace clang;
- 
-+#define EPOLL_CLOEXEC -1
-+#define IN_CLOEXEC -1
-+#define O_CLOEXEC -1
-+static int epoll_create1(int flags) { return -1; }
-+static int inotify_init1(int flags) { return -1; }
-+static int pipe2(int *fds, int flags) { return -1; }
-+
- /// Pipe for inter-thread synchronization - for epoll-ing on multiple
- /// conditions. It is meant for uni-directional 1:1 signalling - specifically:
- /// no multiple consumers, no data passing. Thread waiting for signal should
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index cb660881b07..3ad4e3f97a3 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -134,7 +134,7 @@ x--expand-yaml-anchors--remove:
         uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
         with:
           github_token: "${{ secrets.github_token }}"
-        if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'
+        if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && github.ref != 'refs/heads/try-perf'
         <<: *step
 
       - name: collect CPU statistics
diff --git a/src/ci/scripts/checkout-submodules.sh b/src/ci/scripts/checkout-submodules.sh
index 3eb4b8f9058..f6cb8f8a6da 100755
--- a/src/ci/scripts/checkout-submodules.sh
+++ b/src/ci/scripts/checkout-submodules.sh
@@ -36,10 +36,7 @@ function fetch_github_commit_archive {
     rm $cached
 }
 
-# Archive downloads are temporarily disabled due to sudden 504
-# gateway timeout errors.
-# included="src/llvm-project src/doc/book src/doc/rust-by-example"
-included=""
+included="src/llvm-project src/doc/book src/doc/rust-by-example"
 modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)"
 modules=($modules)
 use_git=""
@@ -63,9 +60,9 @@ done
 retry sh -c "git submodule deinit -f $use_git && \
     git submodule sync && \
     git submodule update -j 16 --init --recursive --depth 1 $use_git"
-# STATUS=0
-# for pid in ${bg_pids[*]}
-# do
-#     wait $pid || STATUS=1
-# done
-# exit ${STATUS}
+STATUS=0
+for pid in ${bg_pids[*]}
+do
+    wait $pid || STATUS=1
+done
+exit ${STATUS}
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject 766979590da8100998f0d662499d4a901d8d164
+Subproject befe6840874311635c417cf731377f07234ee37
diff --git a/src/doc/man/rustc.1 b/src/doc/man/rustc.1
index ff41324ef26..534af3f85bb 100644
--- a/src/doc/man/rustc.1
+++ b/src/doc/man/rustc.1
@@ -44,18 +44,18 @@ The optional \fIKIND\fR can be one of \fIstatic\fR, \fIdylib\fR, or
 \fIframework\fR.
 If omitted, \fIdylib\fR is assumed.
 .TP
-\fB\-\-crate\-type\fR [bin|lib|rlib|dylib|cdylib|staticlib]
+\fB\-\-crate\-type\fR [bin|lib|rlib|dylib|cdylib|staticlib|proc\-macro]
 Comma separated list of types of crates for the compiler to emit.
 .TP
 \fB\-\-crate\-name\fR \fINAME\fR
 Specify the name of the crate being built.
 .TP
-\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info|mir][=\fIPATH\fR]
+\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|metadata|link|dep\-info|mir][=\fIPATH\fR]
 Configure the output that \fBrustc\fR will produce. Each emission may also have
 an optional explicit output \fIPATH\fR specified for that particular emission
 kind. This path takes precedence over the \fB-o\fR option.
 .TP
-\fB\-\-print\fR [crate\-name|\:file\-names|\:sysroot|\:cfg|\:target\-list|\:target\-cpus|\:target\-features|\:relocation\-models|\:code\-models|\:tls\-models|\:target\-spec\-json|\:native\-static\-libs]
+\fB\-\-print\fR [crate\-name|\:file\-names|\:sysroot|\:target\-libdir|\:cfg|\:target\-list|\:target\-cpus|\:target\-features|\:relocation\-models|\:code\-models|\:tls\-models|\:target\-spec\-json|\:native\-static\-libs|\:stack\-protector\-strategies|\:link\-args]
 Comma separated list of compiler information to print on stdout.
 .TP
 \fB\-g\fR
diff --git a/src/doc/reference b/src/doc/reference
-Subproject a92be0fef439b3d8e0468d82cb24812d303520a
+Subproject f3d3953bf3b158d596c96d55ce5366f9f3f972e
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 3155db49b0d57cd82c65456ac210b69ecec5ccb
+Subproject ee342dc91e1ba1bb1e1f1318f84bbe3bfac0479
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject d5201cddace979b299ec1bf9fd8997338151aa9
+Subproject 04f3cf0bb2f5a6ee2bfc4b1a6a6cd8c11d1c553
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index bc04dfd4433..f05ff3f1b6b 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -89,9 +89,9 @@ but it is not guaranteed. If you need whole archive semantics use `+whole-archiv
 This modifier is only compatible with the `static` linking kind.
 Using any other kind will result in a compiler error.
 
-When building a rlib or staticlib `+bundle` means that all object files from the native static
-library will be added to the rlib or staticlib archive, and then used from it during linking of
-the final binary.
+When building a rlib or staticlib `+bundle` means that the native static library
+will be packed into the rlib or staticlib archive, and then retrieved from there
+during linking of the final binary.
 
 When building a rlib `-bundle` means that the native static library is registered as a dependency
 of that rlib "by name", and object files from it are included only during linking of the final
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 7a03238f13d..01489e9aafb 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -30,14 +30,14 @@ All tier 1 targets with host tools support the full standard library.
 
 target | notes
 -------|-------
-`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
+`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+) [^missing-stack-probes]
 `i686-pc-windows-gnu` | 32-bit MinGW (Windows 7+) [^windows-support]
 `i686-pc-windows-msvc` | 32-bit MSVC (Windows 7+) [^windows-support]
-`i686-unknown-linux-gnu` | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
+`i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+)
 `x86_64-apple-darwin` | 64-bit macOS (10.7+, Lion+)
 `x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 7+) [^windows-support]
 `x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 7+) [^windows-support]
-`x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
+`x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+)
 
 [^missing-stack-probes]: Stack probes support is missing on
   `aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near
@@ -90,11 +90,11 @@ target | notes
 `mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23)
 `mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23)
 `mipsel-unknown-linux-gnu` | MIPS (LE) Linux (kernel 4.4, glibc 2.23)
-`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 2.6.32, glibc 2.11)
-`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 2.6.32, glibc 2.11)
+`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17)
+`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17)
 `powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17)
 `riscv64gc-unknown-linux-gnu` | RISC-V Linux (kernel 4.20, glibc 2.29)
-`s390x-unknown-linux-gnu` | S390x Linux (kernel 2.6.32, glibc 2.12)
+`s390x-unknown-linux-gnu` | S390x Linux (kernel 3.2, glibc 2.17)
 `x86_64-unknown-freebsd` | 64-bit FreeBSD
 `x86_64-unknown-illumos` | illumos
 `x86_64-unknown-linux-musl` | 64-bit Linux with MUSL
@@ -283,7 +283,7 @@ target | std | host | notes
 `riscv32imc-esp-espidf` | ✓ |  | RISC-V ESP-IDF
 `riscv64gc-unknown-freebsd` |   |   | RISC-V FreeBSD
 `riscv64gc-unknown-linux-musl` |   |   | RISC-V Linux (kernel 4.20, musl 1.2.0)
-`s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 2.6.32, MUSL)
+`s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 3.2, MUSL)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
 `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 5fe2c9ab4e3..71f070f2678 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -24,7 +24,10 @@ pub(crate) struct AutoTraitFinder<'a, 'tcx> {
     pub(crate) cx: &'a mut core::DocContext<'tcx>,
 }
 
-impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
+impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx>
+where
+    'tcx: 'a, // should be an implied bound; rustc bug #98852.
+{
     pub(crate) fn new(cx: &'a mut core::DocContext<'tcx>) -> Self {
         AutoTraitFinder { cx }
     }
@@ -120,7 +123,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
             kind: Box::new(ImplItem(Box::new(Impl {
                 unsafety: hir::Unsafety::Normal,
                 generics: new_generics,
-                trait_: Some(trait_ref.clean(self.cx)),
+                trait_: Some(clean_trait_ref_with_bindings(self.cx, trait_ref, &[])),
                 for_: clean_middle_ty(ty, self.cx, None),
                 items: Vec::new(),
                 polarity,
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 8aecd9b15e8..01dd95e6e40 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -115,7 +115,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                             ),
                             // FIXME(eddyb) compute both `trait_` and `for_` from
                             // the post-inference `trait_ref`, as it's more accurate.
-                            trait_: Some(trait_ref.0.clean(cx)),
+                            trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref.0, &[])),
                             for_: clean_middle_ty(ty.0, cx, None),
                             items: cx.tcx
                                 .associated_items(impl_def_id)
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 838283e32da..f644ecb88b9 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -16,9 +16,9 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 
 use crate::clean::{
-    self, clean_fn_decl_from_did_and_sig, clean_middle_field, clean_middle_ty, clean_ty,
-    clean_ty_generics, clean_variant_def, clean_visibility, utils, Attributes, AttributesExt,
-    Clean, ImplKind, ItemId, Type, Visibility,
+    self, clean_fn_decl_from_did_and_sig, clean_middle_field, clean_middle_ty,
+    clean_trait_ref_with_bindings, clean_ty, clean_ty_generics, clean_variant_def,
+    clean_visibility, utils, Attributes, AttributesExt, Clean, ImplKind, ItemId, Type, Visibility,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -304,14 +304,14 @@ fn merge_attrs(
         both.extend_from_slice(old_attrs);
         (
             if let Some(new_id) = parent_module {
-                Attributes::from_ast(old_attrs, Some((inner, new_id)))
+                Attributes::from_ast_with_additional(old_attrs, (inner, new_id))
             } else {
-                Attributes::from_ast(&both, None)
+                Attributes::from_ast(&both)
             },
             both.cfg(cx.tcx, &cx.cache.hidden_cfg),
         )
     } else {
-        (old_attrs.clean(cx), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg))
+        (Attributes::from_ast(&old_attrs), old_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg))
     }
 }
 
@@ -439,7 +439,7 @@ pub(crate) fn build_impl(
                             .unwrap(); // corresponding associated item has to exist
                         !tcx.is_doc_hidden(trait_item.def_id)
                     } else {
-                        item.vis.is_public()
+                        item.visibility(tcx).is_public()
                     }
                 })
                 .map(|item| item.clean(cx))
@@ -450,7 +450,7 @@ pub(crate) fn build_impl(
         ),
     };
     let polarity = tcx.impl_polarity(did);
-    let trait_ = associated_trait.map(|t| t.clean(cx));
+    let trait_ = associated_trait.map(|t| clean_trait_ref_with_bindings(cx, t, &[]));
     if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
         super::build_deref_target_impls(cx, &trait_items, ret);
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 5071581e5dc..5fb9747a944 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -51,19 +51,24 @@ pub(crate) trait Clean<'tcx, T> {
 impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
         let mut items: Vec<Item> = vec![];
-        items.extend(
-            self.foreigns
-                .iter()
-                .map(|(item, renamed)| clean_maybe_renamed_foreign_item(cx, item, *renamed)),
-        );
-        items.extend(self.mods.iter().map(|x| x.clean(cx)));
+        let mut inserted = FxHashSet::default();
+        items.extend(self.foreigns.iter().map(|(item, renamed)| {
+            let item = clean_maybe_renamed_foreign_item(cx, item, *renamed);
+            if let Some(name) = item.name {
+                inserted.insert((item.type_(), name));
+            }
+            item
+        }));
+        items.extend(self.mods.iter().map(|x| {
+            inserted.insert((ItemType::Module, x.name));
+            x.clean(cx)
+        }));
 
         // Split up imports from all other items.
         //
         // This covers the case where somebody does an import which should pull in an item,
         // but there's already an item with the same namespace and same name. Rust gives
         // priority to the not-imported one, so we should, too.
-        let mut inserted = FxHashSet::default();
         items.extend(self.items.iter().flat_map(|(item, renamed)| {
             // First, lower everything other than imports.
             if matches!(item.kind, hir::ItemKind::Use(..)) {
@@ -121,49 +126,43 @@ impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
     }
 }
 
-impl<'tcx> Clean<'tcx, Attributes> for [ast::Attribute] {
-    fn clean(&self, _cx: &mut DocContext<'_>) -> Attributes {
-        Attributes::from_ast(self, None)
-    }
-}
-
-impl<'tcx> Clean<'tcx, Option<GenericBound>> for hir::GenericBound<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<GenericBound> {
-        Some(match *self {
-            hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
-            hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
-                let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
-
-                let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
-
-                let generic_args = generic_args.clean(cx);
-                let GenericArgs::AngleBracketed { bindings, .. } = generic_args
-                else {
-                    bug!("clean: parenthesized `GenericBound::LangItemTrait`");
-                };
+fn clean_generic_bound<'tcx>(
+    bound: &hir::GenericBound<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Option<GenericBound> {
+    Some(match *bound {
+        hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
+        hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
+            let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
+
+            let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
+
+            let generic_args = generic_args.clean(cx);
+            let GenericArgs::AngleBracketed { bindings, .. } = generic_args
+            else {
+                bug!("clean: parenthesized `GenericBound::LangItemTrait`");
+            };
 
-                let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
-                GenericBound::TraitBound(
-                    PolyTrait { trait_, generic_params: vec![] },
-                    hir::TraitBoundModifier::None,
-                )
+            let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
+            GenericBound::TraitBound(
+                PolyTrait { trait_, generic_params: vec![] },
+                hir::TraitBoundModifier::None,
+            )
+        }
+        hir::GenericBound::Trait(ref t, modifier) => {
+            // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
+            if modifier == hir::TraitBoundModifier::MaybeConst
+                && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
+            {
+                return None;
             }
-            hir::GenericBound::Trait(ref t, modifier) => {
-                // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
-                if modifier == hir::TraitBoundModifier::MaybeConst
-                    && cx.tcx.lang_items().destruct_trait()
-                        == Some(t.trait_ref.trait_def_id().unwrap())
-                {
-                    return None;
-                }
 
-                GenericBound::TraitBound(t.clean(cx), modifier)
-            }
-        })
-    }
+            GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier)
+        }
+    })
 }
 
-fn clean_trait_ref_with_bindings<'tcx>(
+pub(crate) fn clean_trait_ref_with_bindings<'tcx>(
     cx: &mut DocContext<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
     bindings: &[TypeBinding],
@@ -180,12 +179,6 @@ fn clean_trait_ref_with_bindings<'tcx>(
     path
 }
 
-impl<'tcx> Clean<'tcx, Path> for ty::TraitRef<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Path {
-        clean_trait_ref_with_bindings(cx, *self, &[])
-    }
-}
-
 fn clean_poly_trait_ref_with_bindings<'tcx>(
     cx: &mut DocContext<'tcx>,
     poly_trait_ref: ty::PolyTraitRef<'tcx>,
@@ -214,27 +207,19 @@ fn clean_poly_trait_ref_with_bindings<'tcx>(
     )
 }
 
-impl<'tcx> Clean<'tcx, GenericBound> for ty::PolyTraitRef<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericBound {
-        clean_poly_trait_ref_with_bindings(cx, *self, &[])
-    }
-}
-
-impl<'tcx> Clean<'tcx, Lifetime> for hir::Lifetime {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Lifetime {
-        let def = cx.tcx.named_region(self.hir_id);
-        if let Some(
-            rl::Region::EarlyBound(_, node_id)
-            | rl::Region::LateBound(_, _, node_id)
-            | rl::Region::Free(_, node_id),
-        ) = def
-        {
-            if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
-                return lt;
-            }
+fn clean_lifetime<'tcx>(lifetime: hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
+    let def = cx.tcx.named_region(lifetime.hir_id);
+    if let Some(
+        rl::Region::EarlyBound(_, node_id)
+        | rl::Region::LateBound(_, _, node_id)
+        | rl::Region::Free(_, node_id),
+    ) = def
+    {
+        if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
+            return lt;
         }
-        Lifetime(self.name.ident().name)
     }
+    Lifetime(lifetime.name.ident().name)
 }
 
 pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'tcx>) -> Constant {
@@ -256,30 +241,28 @@ pub(crate) fn clean_middle_const<'tcx>(
     }
 }
 
-impl<'tcx> Clean<'tcx, Option<Lifetime>> for ty::Region<'tcx> {
-    fn clean(&self, _cx: &mut DocContext<'_>) -> Option<Lifetime> {
-        match **self {
-            ty::ReStatic => Some(Lifetime::statik()),
-            ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
-                if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None }
-            }
-            ty::ReEarlyBound(ref data) => {
-                if data.name != kw::UnderscoreLifetime {
-                    Some(Lifetime(data.name))
-                } else {
-                    None
-                }
-            }
-            ty::ReLateBound(..)
-            | ty::ReFree(..)
-            | ty::ReVar(..)
-            | ty::RePlaceholder(..)
-            | ty::ReEmpty(_)
-            | ty::ReErased => {
-                debug!("cannot clean region {:?}", self);
+pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Lifetime> {
+    match *region {
+        ty::ReStatic => Some(Lifetime::statik()),
+        ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
+            if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None }
+        }
+        ty::ReEarlyBound(ref data) => {
+            if data.name != kw::UnderscoreLifetime {
+                Some(Lifetime(data.name))
+            } else {
                 None
             }
         }
+        ty::ReLateBound(..)
+        | ty::ReFree(..)
+        | ty::ReVar(..)
+        | ty::RePlaceholder(..)
+        | ty::ReEmpty(_)
+        | ty::ReErased => {
+            debug!("cannot clean region {:?}", region);
+            None
+        }
     }
 }
 
@@ -305,14 +288,14 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
                     .collect();
                 WherePredicate::BoundPredicate {
                     ty: clean_ty(wbp.bounded_ty, cx),
-                    bounds: wbp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
+                    bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
                     bound_params,
                 }
             }
 
             hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
-                lifetime: wrp.lifetime.clean(cx),
-                bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
+                lifetime: clean_lifetime(wrp.lifetime, cx),
+                bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
             },
 
             hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
@@ -330,7 +313,7 @@ impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::Predicate<'tcx> {
             ty::PredicateKind::Trait(pred) => {
                 clean_poly_trait_predicate(bound_predicate.rebind(pred), cx)
             }
-            ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred, cx),
+            ty::PredicateKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
             ty::PredicateKind::TypeOutlives(pred) => clean_type_outlives_predicate(pred, cx),
             ty::PredicateKind::Projection(pred) => Some(clean_projection_predicate(pred, cx)),
             ty::PredicateKind::ConstEvaluatable(..) => None,
@@ -360,14 +343,13 @@ fn clean_poly_trait_predicate<'tcx>(
     let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref);
     Some(WherePredicate::BoundPredicate {
         ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
-        bounds: vec![poly_trait_ref.clean(cx)],
+        bounds: vec![clean_poly_trait_ref_with_bindings(cx, poly_trait_ref, &[])],
         bound_params: Vec::new(),
     })
 }
 
 fn clean_region_outlives_predicate<'tcx>(
     pred: ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>,
-    cx: &mut DocContext<'tcx>,
 ) -> Option<WherePredicate> {
     let ty::OutlivesPredicate(a, b) = pred;
 
@@ -376,8 +358,10 @@ fn clean_region_outlives_predicate<'tcx>(
     }
 
     Some(WherePredicate::RegionPredicate {
-        lifetime: a.clean(cx).expect("failed to clean lifetime"),
-        bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))],
+        lifetime: clean_middle_region(a).expect("failed to clean lifetime"),
+        bounds: vec![GenericBound::Outlives(
+            clean_middle_region(b).expect("failed to clean bounds"),
+        )],
     })
 }
 
@@ -393,7 +377,9 @@ fn clean_type_outlives_predicate<'tcx>(
 
     Some(WherePredicate::BoundPredicate {
         ty: clean_middle_ty(ty, cx, None),
-        bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
+        bounds: vec![GenericBound::Outlives(
+            clean_middle_region(lt).expect("failed to clean lifetimes"),
+        )],
         bound_params: Vec::new(),
     })
 }
@@ -432,7 +418,7 @@ fn clean_projection<'tcx>(
     def_id: Option<DefId>,
 ) -> Type {
     let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
-    let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
+    let trait_ = clean_trait_ref_with_bindings(cx, lifted.trait_ref(cx.tcx), &[]);
     let self_type = clean_middle_ty(ty.self_ty(), cx, None);
     let self_def_id = if let Some(def_id) = def_id {
         cx.tcx.opt_parent(def_id).or(Some(def_id))
@@ -524,7 +510,7 @@ fn clean_generic_param<'tcx>(
                     .filter(|bp| !bp.in_where_clause)
                     .flat_map(|bp| bp.bounds)
                     .map(|bound| match bound {
-                        hir::GenericBound::Outlives(lt) => lt.clean(cx),
+                        hir::GenericBound::Outlives(lt) => clean_lifetime(*lt, cx),
                         _ => panic!(),
                     })
                     .collect()
@@ -539,7 +525,7 @@ fn clean_generic_param<'tcx>(
                     .bounds_for_param(did)
                     .filter(|bp| bp.origin != PredicateOrigin::WhereClause)
                     .flat_map(|bp| bp.bounds)
-                    .filter_map(|x| x.clean(cx))
+                    .filter_map(|x| clean_generic_bound(x, cx))
                     .collect()
             } else {
                 Vec::new()
@@ -964,7 +950,11 @@ fn clean_fn_decl_with_args<'tcx>(
     decl: &hir::FnDecl<'tcx>,
     args: Arguments,
 ) -> FnDecl {
-    FnDecl { inputs: args, output: decl.output.clean(cx), c_variadic: decl.c_variadic }
+    let output = match decl.output {
+        hir::FnRetTy::Return(typ) => Return(clean_ty(typ, cx)),
+        hir::FnRetTy::DefaultReturn(..) => DefaultReturn,
+    };
+    FnDecl { inputs: args, output, c_variadic: decl.c_variadic }
 }
 
 fn clean_fn_decl_from_did_and_sig<'tcx>(
@@ -999,95 +989,74 @@ fn clean_fn_decl_from_did_and_sig<'tcx>(
     }
 }
 
-impl<'tcx> Clean<'tcx, FnRetTy> for hir::FnRetTy<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> FnRetTy {
-        match *self {
-            Self::Return(typ) => Return(clean_ty(typ, cx)),
-            Self::DefaultReturn(..) => DefaultReturn,
-        }
-    }
-}
-
-impl<'tcx> Clean<'tcx, bool> for hir::IsAuto {
-    fn clean(&self, _: &mut DocContext<'tcx>) -> bool {
-        match *self {
-            hir::IsAuto::Yes => true,
-            hir::IsAuto::No => false,
-        }
-    }
-}
-
-impl<'tcx> Clean<'tcx, Path> for hir::TraitRef<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Path {
-        let path = clean_path(self.path, cx);
-        register_res(cx, path.res);
-        path
-    }
+fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
+    let path = clean_path(trait_ref.path, cx);
+    register_res(cx, path.res);
+    path
 }
 
-impl<'tcx> Clean<'tcx, PolyTrait> for hir::PolyTraitRef<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> PolyTrait {
-        PolyTrait {
-            trait_: self.trait_ref.clean(cx),
-            generic_params: self
-                .bound_generic_params
-                .iter()
-                .filter(|p| !is_elided_lifetime(p))
-                .map(|x| clean_generic_param(cx, None, x))
-                .collect(),
-        }
+fn clean_poly_trait_ref<'tcx>(
+    poly_trait_ref: &hir::PolyTraitRef<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> PolyTrait {
+    PolyTrait {
+        trait_: clean_trait_ref(&poly_trait_ref.trait_ref, cx),
+        generic_params: poly_trait_ref
+            .bound_generic_params
+            .iter()
+            .filter(|p| !is_elided_lifetime(p))
+            .map(|x| clean_generic_param(cx, None, x))
+            .collect(),
     }
 }
 
-impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let local_did = self.def_id.to_def_id();
-        cx.with_param_env(local_did, |cx| {
-            let inner = match self.kind {
-                hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
-                    clean_ty(ty, cx),
-                    ConstantKind::Local { def_id: local_did, body: default },
-                ),
-                hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
-                hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
-                    let m = clean_function(cx, sig, self.generics, body);
-                    MethodItem(m, None)
-                }
-                hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
-                    let (generics, decl) = enter_impl_trait(cx, |cx| {
-                        // NOTE: generics must be cleaned before args
-                        let generics = self.generics.clean(cx);
-                        let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
-                        let decl = clean_fn_decl_with_args(cx, sig.decl, args);
-                        (generics, decl)
-                    });
-                    TyMethodItem(Box::new(Function { decl, generics }))
-                }
-                hir::TraitItemKind::Type(bounds, Some(default)) => {
-                    let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
-                    let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
-                    let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
-                    AssocTypeItem(
-                        Box::new(Typedef {
-                            type_: clean_ty(default, cx),
-                            generics,
-                            item_type: Some(item_type),
-                        }),
-                        bounds,
-                    )
-                }
-                hir::TraitItemKind::Type(bounds, None) => {
-                    let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
-                    let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
-                    TyAssocTypeItem(Box::new(generics), bounds)
-                }
-            };
-            let what_rustc_thinks =
-                Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
-            // Trait items always inherit the trait's visibility -- we don't want to show `pub`.
-            Item { visibility: Inherited, ..what_rustc_thinks }
-        })
-    }
+fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
+    let local_did = trait_item.def_id.to_def_id();
+    cx.with_param_env(local_did, |cx| {
+        let inner = match trait_item.kind {
+            hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
+                clean_ty(ty, cx),
+                ConstantKind::Local { def_id: local_did, body: default },
+            ),
+            hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
+            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
+                let m = clean_function(cx, sig, trait_item.generics, body);
+                MethodItem(m, None)
+            }
+            hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
+                let (generics, decl) = enter_impl_trait(cx, |cx| {
+                    // NOTE: generics must be cleaned before args
+                    let generics = trait_item.generics.clean(cx);
+                    let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
+                    let decl = clean_fn_decl_with_args(cx, sig.decl, args);
+                    (generics, decl)
+                });
+                TyMethodItem(Box::new(Function { decl, generics }))
+            }
+            hir::TraitItemKind::Type(bounds, Some(default)) => {
+                let generics = enter_impl_trait(cx, |cx| trait_item.generics.clean(cx));
+                let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
+                let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
+                AssocTypeItem(
+                    Box::new(Typedef {
+                        type_: clean_ty(default, cx),
+                        generics,
+                        item_type: Some(item_type),
+                    }),
+                    bounds,
+                )
+            }
+            hir::TraitItemKind::Type(bounds, None) => {
+                let generics = enter_impl_trait(cx, |cx| trait_item.generics.clean(cx));
+                let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
+                TyAssocTypeItem(Box::new(generics), bounds)
+            }
+        };
+        let what_rustc_thinks =
+            Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx);
+        // Trait items always inherit the trait's visibility -- we don't want to show `pub`.
+        Item { visibility: Inherited, ..what_rustc_thinks }
+    })
 }
 
 impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> {
@@ -1101,7 +1070,7 @@ impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> {
                 }
                 hir::ImplItemKind::Fn(ref sig, body) => {
                     let m = clean_function(cx, sig, self.generics, body);
-                    let defaultness = cx.tcx.associated_item(self.def_id).defaultness;
+                    let defaultness = cx.tcx.impl_defaultness(self.def_id);
                     MethodItem(m, Some(defaultness))
                 }
                 hir::ImplItemKind::TyAlias(hir_ty) => {
@@ -1139,8 +1108,8 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
                 let ty = clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id));
 
                 let provided = match self.container {
-                    ty::ImplContainer(_) => true,
-                    ty::TraitContainer(_) => self.defaultness.has_value(),
+                    ty::ImplContainer => true,
+                    ty::TraitContainer => tcx.impl_defaultness(self.def_id).has_value(),
                 };
                 if provided {
                     AssocConstItem(ty, ConstantKind::Extern { def_id: self.def_id })
@@ -1159,8 +1128,8 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
 
                 if self.fn_has_self_parameter {
                     let self_ty = match self.container {
-                        ty::ImplContainer(def_id) => tcx.type_of(def_id),
-                        ty::TraitContainer(_) => tcx.types.self_param,
+                        ty::ImplContainer => tcx.type_of(self.container_id(tcx)),
+                        ty::TraitContainer => tcx.types.self_param,
                     };
                     let self_arg_ty = sig.input(0).skip_binder();
                     if self_arg_ty == self_ty {
@@ -1178,13 +1147,13 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
                 }
 
                 let provided = match self.container {
-                    ty::ImplContainer(_) => true,
-                    ty::TraitContainer(_) => self.defaultness.has_value(),
+                    ty::ImplContainer => true,
+                    ty::TraitContainer => self.defaultness(tcx).has_value(),
                 };
                 if provided {
                     let defaultness = match self.container {
-                        ty::ImplContainer(_) => Some(self.defaultness),
-                        ty::TraitContainer(_) => None,
+                        ty::ImplContainer => Some(self.defaultness(tcx)),
+                        ty::TraitContainer => None,
                     };
                     MethodItem(Box::new(Function { generics, decl }), defaultness)
                 } else {
@@ -1215,7 +1184,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
                     }
                 }
 
-                if let ty::TraitContainer(_) = self.container {
+                if let ty::TraitContainer = self.container {
                     let bounds = tcx.explicit_item_bounds(self.def_id);
                     let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
                     let mut generics =
@@ -1232,7 +1201,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
                                 if assoc.name != my_name {
                                     return false;
                                 }
-                                if trait_.def_id() != self.container.id() {
+                                if trait_.def_id() != self.container_id(tcx) {
                                     return false;
                                 }
                                 match **self_type {
@@ -1280,7 +1249,7 @@ impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
                         None => bounds.push(GenericBound::maybe_sized(cx)),
                     }
 
-                    if self.defaultness.has_value() {
+                    if tcx.impl_defaultness(self.def_id).has_value() {
                         AssocTypeItem(
                             Box::new(Typedef {
                                 type_: clean_middle_ty(
@@ -1356,7 +1325,7 @@ fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type
             }
 
             let trait_segments = &p.segments[..p.segments.len() - 1];
-            let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id();
+            let trait_def = cx.tcx.associated_item(p.res.def_id()).container_id(cx.tcx);
             let trait_ = self::Path {
                 res: Res::Def(DefKind::Trait, trait_def),
                 segments: trait_segments.iter().map(|x| x.clean(cx)).collect(),
@@ -1431,7 +1400,8 @@ fn maybe_expand_private_type_alias<'tcx>(
                 });
                 if let Some(lt) = lifetime.cloned() {
                     let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
-                    let cleaned = if !lt.is_elided() { lt.clean(cx) } else { Lifetime::elided() };
+                    let cleaned =
+                        if !lt.is_elided() { clean_lifetime(lt, cx) } else { Lifetime::elided() };
                     substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
                 }
                 indices.lifetimes += 1;
@@ -1503,7 +1473,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
             // there's no case where it could cause the function to fail to compile.
             let elided =
                 l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
-            let lifetime = if elided { None } else { Some(l.clean(cx)) };
+            let lifetime = if elided { None } else { Some(clean_lifetime(*l, cx)) };
             BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
         }
         TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
@@ -1531,15 +1501,16 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
         TyKind::OpaqueDef(item_id, _) => {
             let item = cx.tcx.hir().item(item_id);
             if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
-                ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect())
+                ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
             } else {
                 unreachable!()
             }
         }
         TyKind::Path(_) => clean_qpath(ty, cx),
         TyKind::TraitObject(bounds, ref lifetime, _) => {
-            let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
-            let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
+            let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
+            let lifetime =
+                if !lifetime.is_elided() { Some(clean_lifetime(*lifetime, cx)) } else { None };
             DynTrait(bounds, lifetime)
         }
         TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))),
@@ -1604,7 +1575,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
         }
         ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))),
         ty::Ref(r, ty, mutbl) => BorrowedRef {
-            lifetime: r.clean(cx),
+            lifetime: clean_middle_region(r),
             mutability: mutbl,
             type_: Box::new(clean_middle_ty(ty, cx, None)),
         },
@@ -1639,9 +1610,10 @@ pub(crate) fn clean_middle_ty<'tcx>(
             // HACK: pick the first `did` as the `did` of the trait object. Someone
             // might want to implement "native" support for marker-trait-only
             // trait objects.
-            let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits());
-            let did = dids
-                .next()
+            let mut dids = obj.auto_traits();
+            let did = obj
+                .principal_def_id()
+                .or_else(|| dids.next())
                 .unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", this));
             let substs = match obj.principal() {
                 Some(principal) => principal.skip_binder().substs,
@@ -1651,20 +1623,19 @@ pub(crate) fn clean_middle_ty<'tcx>(
 
             inline::record_extern_fqn(cx, did, ItemType::Trait);
 
-            let lifetime = reg.clean(cx);
-            let mut bounds = vec![];
-
-            for did in dids {
-                let empty = cx.tcx.intern_substs(&[]);
-                let path = external_path(cx, did, false, vec![], empty);
-                inline::record_extern_fqn(cx, did, ItemType::Trait);
-                let bound = PolyTrait { trait_: path, generic_params: Vec::new() };
-                bounds.push(bound);
-            }
+            let lifetime = clean_middle_region(*reg);
+            let mut bounds = dids
+                .map(|did| {
+                    let empty = cx.tcx.intern_substs(&[]);
+                    let path = external_path(cx, did, false, vec![], empty);
+                    inline::record_extern_fqn(cx, did, ItemType::Trait);
+                    PolyTrait { trait_: path, generic_params: Vec::new() }
+                })
+                .collect::<Vec<_>>();
 
-            let mut bindings = vec![];
-            for pb in obj.projection_bounds() {
-                bindings.push(TypeBinding {
+            let bindings = obj
+                .projection_bounds()
+                .map(|pb| TypeBinding {
                     assoc: projection_to_path_segment(
                         pb.skip_binder()
                             .lift_to_tcx(cx.tcx)
@@ -1678,8 +1649,8 @@ pub(crate) fn clean_middle_ty<'tcx>(
                     kind: TypeBindingKind::Equality {
                         term: clean_middle_term(pb.skip_binder().term, cx),
                     },
-                });
-            }
+                })
+                .collect();
 
             let path = external_path(cx, did, false, bindings, substs);
             bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
@@ -1717,7 +1688,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
                     let trait_ref = match bound_predicate.skip_binder() {
                         ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
                         ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
-                            if let Some(r) = reg.clean(cx) {
+                            if let Some(r) = clean_middle_region(reg) {
                                 regions.push(GenericBound::Outlives(r));
                             }
                             return None;
@@ -1875,7 +1846,7 @@ impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> {
                 .iter()
                 .map(|arg| match arg {
                     hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
-                        GenericArg::Lifetime(lt.clean(cx))
+                        GenericArg::Lifetime(clean_lifetime(*lt, cx))
                     }
                     hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
                     hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
@@ -1934,7 +1905,7 @@ fn clean_maybe_renamed_item<'tcx>(
                 kind: ConstantKind::Local { body: body_id, def_id },
             }),
             ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
-                bounds: ty.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
+                bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
                 generics: ty.generics.clean(cx),
             }),
             ItemKind::TyAlias(hir_ty, generics) => {
@@ -1952,7 +1923,7 @@ fn clean_maybe_renamed_item<'tcx>(
             }),
             ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias {
                 generics: generics.clean(cx),
-                bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
+                bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
             }),
             ItemKind::Union(ref variant_data, generics) => UnionItem(Union {
                 generics: generics.clean(cx),
@@ -1975,14 +1946,16 @@ fn clean_maybe_renamed_item<'tcx>(
                 })
             }
             ItemKind::Trait(_, _, generics, bounds, item_ids) => {
-                let items =
-                    item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect();
+                let items = item_ids
+                    .iter()
+                    .map(|ti| clean_trait_item(cx.tcx.hir().trait_item(ti.id), cx))
+                    .collect();
 
                 TraitItem(Trait {
                     def_id,
                     items,
                     generics: generics.clean(cx),
-                    bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
+                    bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
                 })
             }
             ItemKind::ExternCrate(orig_name) => {
@@ -2015,7 +1988,7 @@ fn clean_impl<'tcx>(
 ) -> Vec<Item> {
     let tcx = cx.tcx;
     let mut ret = Vec::new();
-    let trait_ = impl_.of_trait.as_ref().map(|t| t.clean(cx));
+    let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx));
     let items =
         impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
     let def_id = tcx.hir().local_def_id(hir_id);
@@ -2096,7 +2069,7 @@ fn clean_extern_crate<'tcx>(
     // FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason
     vec![Item {
         name: Some(name),
-        attrs: Box::new(attrs.clean(cx)),
+        attrs: Box::new(Attributes::from_ast(attrs)),
         item_id: crate_def_id.into(),
         visibility: clean_visibility(ty_vis),
         kind: Box::new(ExternCrateItem { src: orig_name }),
@@ -2262,7 +2235,7 @@ fn clean_type_binding<'tcx>(
                 TypeBindingKind::Equality { term: clean_hir_term(term, cx) }
             }
             hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint {
-                bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
+                bounds: bounds.iter().filter_map(|b| clean_generic_bound(b, cx)).collect(),
             },
         },
     }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index d022ce9696a..0e6de842cc2 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -34,10 +34,10 @@ use rustc_target::spec::abi::Abi;
 use rustc_typeck::check::intrinsic::intrinsic_operation_unsafety;
 
 use crate::clean::cfg::Cfg;
+use crate::clean::clean_visibility;
 use crate::clean::external_path;
 use crate::clean::inline::{self, print_inlined_const};
 use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
-use crate::clean::{clean_visibility, Clean};
 use crate::core::DocContext;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
@@ -122,10 +122,6 @@ pub(crate) struct Crate {
     pub(crate) external_traits: Rc<RefCell<FxHashMap<DefId, TraitWithExtraInfo>>>,
 }
 
-// `Crate` is frequently moved by-value. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Crate, 72);
-
 impl Crate {
     pub(crate) fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
         ExternalCrate::LOCAL.name(tcx)
@@ -389,10 +385,6 @@ impl fmt::Debug for Item {
     }
 }
 
-// `Item` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Item, 56);
-
 pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span {
     Span::new(def_id.as_local().map_or_else(
         || tcx.def_span(def_id),
@@ -477,7 +469,7 @@ impl Item {
             def_id,
             name,
             kind,
-            Box::new(ast_attrs.clean(cx)),
+            Box::new(Attributes::from_ast(ast_attrs)),
             cx,
             ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
         )
@@ -771,10 +763,6 @@ pub(crate) enum ItemKind {
     KeywordItem,
 }
 
-// `ItemKind` is an enum and large variants can bloat up memory usage even for smaller ones
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ItemKind, 112);
-
 impl ItemKind {
     /// Some items contain others such as structs (for their fields) and Enums
     /// (for their variants). This method returns those contained items.
@@ -994,10 +982,6 @@ pub(crate) struct DocFragment {
     pub(crate) indent: usize,
 }
 
-// `DocFragment` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(DocFragment, 32);
-
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub(crate) enum DocFragmentKind {
     /// A doc fragment created from a `///` or `//!` doc comment.
@@ -1177,14 +1161,16 @@ impl Attributes {
         false
     }
 
-    pub(crate) fn from_ast(
+    pub(crate) fn from_ast(attrs: &[ast::Attribute]) -> Attributes {
+        Attributes::from_ast_iter(attrs.iter().map(|attr| (attr, None)), false)
+    }
+
+    pub(crate) fn from_ast_with_additional(
         attrs: &[ast::Attribute],
-        additional_attrs: Option<(&[ast::Attribute], DefId)>,
+        (additional_attrs, def_id): (&[ast::Attribute], DefId),
     ) -> Attributes {
         // Additional documentation should be shown before the original documentation.
-        let attrs1 = additional_attrs
-            .into_iter()
-            .flat_map(|(attrs, def_id)| attrs.iter().map(move |attr| (attr, Some(def_id))));
+        let attrs1 = additional_attrs.iter().map(|attr| (attr, Some(def_id)));
         let attrs2 = attrs.iter().map(|attr| (attr, None));
         Attributes::from_ast_iter(attrs1.chain(attrs2), false)
     }
@@ -1382,10 +1368,6 @@ pub(crate) struct GenericParamDef {
     pub(crate) kind: GenericParamDefKind,
 }
 
-// `GenericParamDef` is used in many places. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(GenericParamDef, 56);
-
 impl GenericParamDef {
     pub(crate) fn is_synthetic_type_param(&self) -> bool {
         match self.kind {
@@ -1590,10 +1572,6 @@ pub(crate) enum Type {
     ImplTrait(Vec<GenericBound>),
 }
 
-// `Type` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Type, 72);
-
 impl Type {
     /// When comparing types for equality, it can help to ignore `&` wrapping.
     pub(crate) fn without_borrowed_ref(&self) -> &Type {
@@ -2230,33 +2208,18 @@ pub(crate) enum GenericArg {
     Infer,
 }
 
-// `GenericArg` can occur many times in a single `Path`, so make sure it
-// doesn't increase in size unexpectedly.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(GenericArg, 80);
-
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) enum GenericArgs {
     AngleBracketed { args: Box<[GenericArg]>, bindings: ThinVec<TypeBinding> },
     Parenthesized { inputs: Box<[Type]>, output: Option<Box<Type>> },
 }
 
-// `GenericArgs` is in every `PathSegment`, so its size can significantly
-// affect rustdoc's memory usage.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(GenericArgs, 32);
-
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) struct PathSegment {
     pub(crate) name: Symbol,
     pub(crate) args: GenericArgs,
 }
 
-// `PathSegment` usually occurs multiple times in every `Path`, so its size can
-// significantly affect rustdoc's memory usage.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(PathSegment, 40);
-
 #[derive(Clone, Debug)]
 pub(crate) struct Typedef {
     pub(crate) type_: Type,
@@ -2527,3 +2490,19 @@ impl SubstParam {
         if let Self::Lifetime(lt) = self { Some(lt) } else { None }
     }
 }
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+mod size_asserts {
+    use super::*;
+    // These are in alphabetical order, which is easy to maintain.
+    rustc_data_structures::static_assert_size!(Crate, 72); // frequently moved by-value
+    rustc_data_structures::static_assert_size!(DocFragment, 32);
+    rustc_data_structures::static_assert_size!(GenericArg, 80);
+    rustc_data_structures::static_assert_size!(GenericArgs, 32);
+    rustc_data_structures::static_assert_size!(GenericParamDef, 56);
+    rustc_data_structures::static_assert_size!(Item, 56);
+    rustc_data_structures::static_assert_size!(ItemKind, 112);
+    rustc_data_structures::static_assert_size!(PathSegment, 40);
+    rustc_data_structures::static_assert_size!(Type, 72);
+}
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 621f70f0da9..43e71e90a6f 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -2,9 +2,9 @@ use crate::clean::auto_trait::AutoTraitFinder;
 use crate::clean::blanket_impl::BlanketImplFinder;
 use crate::clean::render_macro_matchers::render_macro_matcher;
 use crate::clean::{
-    clean_middle_const, clean_middle_ty, inline, Clean, Crate, ExternalCrate, Generic, GenericArg,
-    GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path, PathSegment, Primitive,
-    PrimitiveType, Type, TypeBinding, Visibility,
+    clean_middle_const, clean_middle_region, clean_middle_ty, inline, Clean, Crate, ExternalCrate,
+    Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path, PathSegment,
+    Primitive, PrimitiveType, Type, TypeBinding, Visibility,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -86,7 +86,7 @@ pub(crate) fn substs_to_args<'tcx>(
         Vec::with_capacity(substs.len().saturating_sub(if skip_first { 1 } else { 0 }));
     ret_val.extend(substs.iter().filter_map(|kind| match kind.unpack() {
         GenericArgKind::Lifetime(lt) => {
-            Some(GenericArg::Lifetime(lt.clean(cx).unwrap_or(Lifetime::elided())))
+            Some(GenericArg::Lifetime(clean_middle_region(lt).unwrap_or(Lifetime::elided())))
         }
         GenericArgKind::Type(_) if skip_first => {
             skip_first = false;
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 213f564ce2d..35964e3ba38 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1222,7 +1222,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
 
         // The collapse-docs pass won't combine sugared/raw doc attributes, or included files with
         // anything else, this will combine them for us.
-        let attrs = Attributes::from_ast(ast_attrs, None);
+        let attrs = Attributes::from_ast(ast_attrs);
         if let Some(doc) = attrs.collapsed_doc_value() {
             // Use the outermost invocation, so that doctest names come from where the docs were written.
             let span = ast_attrs
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index d2ef89078bf..05547ea1515 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -213,7 +213,7 @@ impl<'a> Iterator for TokenIter<'a> {
             return None;
         }
         let token = rustc_lexer::first_token(self.src);
-        let (text, rest) = self.src.split_at(token.len);
+        let (text, rest) = self.src.split_at(token.len as usize);
         self.src = rest;
         Some((token.kind, text))
     }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 547d6696a43..99cf4291927 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -345,7 +345,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
             clean::ImportItem(ref import) => {
                 let (stab, stab_tags) = if let Some(import_def_id) = import.source.did {
                     let ast_attrs = cx.tcx().get_attrs_unchecked(import_def_id);
-                    let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs, None));
+                    let import_attrs = Box::new(clean::Attributes::from_ast(ast_attrs));
 
                     // Just need an item with the correct def_id and attrs
                     let import_item = clean::Item {
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 27ad91d09e0..6fb41ff3279 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -366,13 +366,15 @@ pub(super) fn write_shared(
                 .collect::<Vec<_>>();
             files.sort_unstable();
             let subs = subs.iter().map(|s| s.to_json_string()).collect::<Vec<_>>().join(",");
-            let dirs =
-                if subs.is_empty() { String::new() } else { format!(",\"dirs\":[{}]", subs) };
+            let dirs = if subs.is_empty() && files.is_empty() {
+                String::new()
+            } else {
+                format!(",[{}]", subs)
+            };
             let files = files.join(",");
-            let files =
-                if files.is_empty() { String::new() } else { format!(",\"files\":[{}]", files) };
+            let files = if files.is_empty() { String::new() } else { format!(",[{}]", files) };
             format!(
-                "{{\"name\":\"{name}\"{dirs}{files}}}",
+                "[\"{name}\"{dirs}{files}]",
                 name = self.elem.to_str().expect("invalid osstring conversion"),
                 dirs = dirs,
                 files = files
@@ -411,18 +413,23 @@ pub(super) fn write_shared(
         let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix));
         let make_sources = || {
             let (mut all_sources, _krates) =
-                try_err!(collect(&dst, krate.name(cx.tcx()).as_str(), "sourcesIndex"), &dst);
+                try_err!(collect_json(&dst, krate.name(cx.tcx()).as_str()), &dst);
             all_sources.push(format!(
-                "sourcesIndex[\"{}\"] = {};",
+                r#""{}":{}"#,
                 &krate.name(cx.tcx()),
-                hierarchy.to_json_string()
+                hierarchy
+                    .to_json_string()
+                    // All these `replace` calls are because we have to go through JS string for JSON content.
+                    .replace('\\', r"\\")
+                    .replace('\'', r"\'")
+                    // We need to escape double quotes for the JSON.
+                    .replace("\\\"", "\\\\\"")
             ));
             all_sources.sort();
-            Ok(format!(
-                "var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();\n",
-                all_sources.join("\n")
-            )
-            .into_bytes())
+            let mut v = String::from("var sourcesIndex = JSON.parse('{\\\n");
+            v.push_str(&all_sources.join(",\\\n"));
+            v.push_str("\\\n}');\ncreateSourceSidebar();\n");
+            Ok(v.into_bytes())
         };
         write_crate("source-files.js", &make_sources)?;
     }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index aecc9aa879a..83fe14550cc 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -1111,7 +1111,14 @@ table,
 }
 
 .item-info .stab {
-	display: inline-block;
+	width: fit-content;
+	/* This min-height is needed to unify the height of the stab elements because some of them
+	   have emojis.
+	*/
+	min-height: 36px;
+	display: flex;
+	align-items: center;
+	white-space: pre-wrap;
 }
 .stab {
 	padding: 3px;
@@ -1121,6 +1128,7 @@ table,
 }
 .stab p {
 	display: inline;
+	margin: 0;
 }
 
 .stab .emoji {
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 2aef978a072..0702b2b0b7c 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -816,7 +816,7 @@ function loadCss(cssFileName) {
              <code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \
              and <code>const</code>.",
             "Search functions by type signature (e.g., <code>vec -&gt; usize</code> or \
-             <code>* -&gt; vec</code>)",
+             <code>-&gt; vec</code>)",
             "Search multiple things at once by splitting your query with comma (e.g., \
              <code>str,u8</code> or <code>String,struct:Vec,test</code>)",
             "You can look for items with an exact name by putting double quotes around \
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index a6a0b09ef31..c45d614293a 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -12,6 +12,10 @@
 const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
 let oldScrollPosition = 0;
 
+const NAME_OFFSET = 0;
+const DIRS_OFFSET = 1;
+const FILES_OFFSET = 2;
+
 function closeSidebarIfMobile() {
     if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
         updateLocalStorage("source-sidebar-show", "false");
@@ -24,15 +28,15 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
 
     dirEntry.className = "dir-entry";
 
-    fullPath += elem["name"] + "/";
+    fullPath += elem[NAME_OFFSET] + "/";
 
-    summary.innerText = elem["name"];
+    summary.innerText = elem[NAME_OFFSET];
     dirEntry.appendChild(summary);
 
     const folders = document.createElement("div");
     folders.className = "folders";
-    if (elem.dirs) {
-        for (const dir of elem.dirs) {
+    if (elem[DIRS_OFFSET]) {
+        for (const dir of elem[DIRS_OFFSET]) {
             if (createDirEntry(dir, folders, fullPath, false)) {
                 dirEntry.open = true;
                 hasFoundFile = true;
@@ -43,8 +47,8 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
 
     const files = document.createElement("div");
     files.className = "files";
-    if (elem.files) {
-        for (const file_text of elem.files) {
+    if (elem[FILES_OFFSET]) {
+        for (const file_text of elem[FILES_OFFSET]) {
             const file = document.createElement("a");
             file.innerText = file_text;
             file.href = rootPath + "src/" + fullPath + file_text + ".html";
@@ -125,7 +129,7 @@ function createSourceSidebar() {
     title.innerText = "Files";
     sidebar.appendChild(title);
     Object.keys(sourcesIndex).forEach(key => {
-        sourcesIndex[key].name = key;
+        sourcesIndex[key][NAME_OFFSET] = key;
         hasFoundFile = createDirEntry(sourcesIndex[key], sidebar, "",
             hasFoundFile);
     });
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 1751249fa62..7d7a63c5384 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -234,7 +234,7 @@ impl UrlFragment {
             &UrlFragment::Item(def_id) => {
                 let kind = match tcx.def_kind(def_id) {
                     DefKind::AssocFn => {
-                        if tcx.associated_item(def_id).defaultness.has_value() {
+                        if tcx.impl_defaultness(def_id).has_value() {
                             "method."
                         } else {
                             "tymethod."
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index fd0b19034a2..0d968402503 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -304,6 +304,12 @@ pub(crate) fn run(
         let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
         tcx.hir().visit_all_item_likes_in_crate(&mut finder);
 
+        // The visitor might have found a type error, which we need to
+        // promote to a fatal error
+        if tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() {
+            return Err(String::from("Compilation failed, aborting rustdoc"));
+        }
+
         // Sort call locations within a given file in document order
         for fn_calls in calls.values_mut() {
             for file_calls in fn_calls.values_mut() {
diff --git a/src/test/assembly/asm/riscv-types.rs b/src/test/assembly/asm/riscv-types.rs
index 0f9f61bd6d9..68dc186ea0c 100644
--- a/src/test/assembly/asm/riscv-types.rs
+++ b/src/test/assembly/asm/riscv-types.rs
@@ -56,7 +56,7 @@ pub unsafe fn sym_fn() {
 // CHECK-LABEL: sym_static:
 // CHECK: #APP
 // CHECK: auipc t0, %pcrel_hi(extern_static)
-// CHECK: lb t0, %pcrel_lo(.Lpcrel_hi0)(t0)
+// CHECK: lb t0, %pcrel_lo(.Lpcrel_hi{{[0-9]+}})(t0)
 // CHECK: #NO_APP
 #[no_mangle]
 pub unsafe fn sym_static() {
diff --git a/src/test/codegen-units/item-collection/generic-drop-glue.rs b/src/test/codegen-units/item-collection/generic-drop-glue.rs
index 25cf5dad614..6df4ff7e58b 100644
--- a/src/test/codegen-units/item-collection/generic-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/generic-drop-glue.rs
@@ -34,9 +34,9 @@ enum EnumNoDrop<T1, T2> {
 }
 
 
-struct NonGenericNoDrop(i32);
+struct NonGenericNoDrop(#[allow(unused_tuple_struct_fields)] i32);
 
-struct NonGenericWithDrop(i32);
+struct NonGenericWithDrop(#[allow(unused_tuple_struct_fields)] i32);
 //~ MONO_ITEM fn std::ptr::drop_in_place::<NonGenericWithDrop> - shim(Some(NonGenericWithDrop)) @@ generic_drop_glue-cgu.0[Internal]
 
 impl Drop for NonGenericWithDrop {
diff --git a/src/test/codegen-units/item-collection/transitive-drop-glue.rs b/src/test/codegen-units/item-collection/transitive-drop-glue.rs
index 8249e7cba94..e286c800b7c 100644
--- a/src/test/codegen-units/item-collection/transitive-drop-glue.rs
+++ b/src/test/codegen-units/item-collection/transitive-drop-glue.rs
@@ -6,9 +6,9 @@
 #![feature(start)]
 
 //~ MONO_ITEM fn std::ptr::drop_in_place::<Root> - shim(Some(Root)) @@ transitive_drop_glue-cgu.0[Internal]
-struct Root(Intermediate);
+struct Root(#[allow(unused_tuple_struct_fields)] Intermediate);
 //~ MONO_ITEM fn std::ptr::drop_in_place::<Intermediate> - shim(Some(Intermediate)) @@ transitive_drop_glue-cgu.0[Internal]
-struct Intermediate(Leaf);
+struct Intermediate(#[allow(unused_tuple_struct_fields)] Leaf);
 //~ MONO_ITEM fn std::ptr::drop_in_place::<Leaf> - shim(Some(Leaf)) @@ transitive_drop_glue-cgu.0[Internal]
 struct Leaf;
 
@@ -17,9 +17,9 @@ impl Drop for Leaf {
     fn drop(&mut self) {}
 }
 
-struct RootGen<T>(IntermediateGen<T>);
-struct IntermediateGen<T>(LeafGen<T>);
-struct LeafGen<T>(T);
+struct RootGen<T>(#[allow(unused_tuple_struct_fields)] IntermediateGen<T>);
+struct IntermediateGen<T>(#[allow(unused_tuple_struct_fields)] LeafGen<T>);
+struct LeafGen<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T> Drop for LeafGen<T> {
     fn drop(&mut self) {}
diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs
index 81675377941..111a7231209 100644
--- a/src/test/codegen-units/item-collection/unsizing.rs
+++ b/src/test/codegen-units/item-collection/unsizing.rs
@@ -40,7 +40,7 @@ impl Trait for u32 {
 }
 
 #[derive(Clone, Copy)]
-struct Wrapper<T: ?Sized>(*const T);
+struct Wrapper<T: ?Sized>(#[allow(unused_tuple_struct_fields)] *const T);
 
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
 
diff --git a/src/test/codegen/merge-functions.rs b/src/test/codegen/merge-functions.rs
index 5eefc0f98f1..d6caeeee896 100644
--- a/src/test/codegen/merge-functions.rs
+++ b/src/test/codegen/merge-functions.rs
@@ -1,7 +1,9 @@
-// compile-flags: -O
+// revisions: O Os
+//[Os] compile-flags: -Copt-level=s
+//[O] compile-flags: -O
 #![crate_type = "lib"]
 
-// CHECK: @func2 = {{.*}}alias{{.*}}@func1
+// CHECK: @func{{2|1}} = {{.*}}alias{{.*}}@func{{1|2}}
 
 #[no_mangle]
 pub fn func1(c: char) -> bool {
diff --git a/src/test/debuginfo/no_mangle-info.rs b/src/test/debuginfo/no_mangle-info.rs
new file mode 100644
index 00000000000..e22d368745f
--- /dev/null
+++ b/src/test/debuginfo/no_mangle-info.rs
@@ -0,0 +1,40 @@
+// compile-flags:-g
+// min-gdb-version: 10.1
+
+// === GDB TESTS ===================================================================================
+// gdb-command:run
+// gdb-command:p TEST
+// gdb-check:$1 = 3735928559
+// gdb-command:p no_mangle_info::namespace::OTHER_TEST
+// gdb-check:$2 = 42
+
+// === LLDB TESTS ==================================================================================
+// lldb-command:run
+// lldb-command:p TEST
+// lldb-check: (unsigned long) $0 = 3735928559
+// lldb-command:p OTHER_TEST
+// lldb-check: (unsigned long) $1 = 42
+
+// === CDB TESTS ==================================================================================
+// cdb-command: g
+// Note: LLDB and GDB allow referring to items that are in the same namespace of the symbol
+// we currently have a breakpoint on in an unqualified way. CDB does not, and thus we need to
+// refer to it in a fully qualified way.
+// cdb-command: dx a!no_mangle_info::TEST
+// cdb-check: a!no_mangle_info::TEST : 0xdeadbeef [Type: unsigned __int64]
+// cdb-command: dx a!no_mangle_info::namespace::OTHER_TEST
+// cdb-check: a!no_mangle_info::namespace::OTHER_TEST : 0x2a [Type: unsigned __int64]
+
+#[no_mangle]
+pub static TEST: u64 = 0xdeadbeef;
+
+// FIXME(rylev, wesleywiser): uncommenting this item breaks the test, and we're not sure why
+// pub static OTHER_TEST: u64 = 43;
+pub mod namespace {
+    pub static OTHER_TEST: u64 = 42;
+}
+
+pub fn main() {
+    println!("TEST: {}", TEST);
+    println!("OTHER TEST: {}", namespace::OTHER_TEST); // #break
+}
diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs
index 69883058335..1abbff32c6f 100644
--- a/src/test/incremental/hashes/inherent_impls.rs
+++ b/src/test/incremental/hashes/inherent_impls.rs
@@ -116,9 +116,9 @@ impl Foo {
 // Change Method Privacy -------------------------------------------------------
 #[cfg(any(cfail1,cfail4))]
 impl Foo {
-    //----------------------------------------------------
     //--------------------------
-    //------------------------------------------------------------------------------
+    //--------------------------
+    //--------------------------------------------------------------
     //--------------------------
     pub fn method_privacy() { }
 }
@@ -129,9 +129,9 @@ impl Foo {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
-    #[rustc_clean(cfg="cfail2", except="associated_item")]
+    #[rustc_clean(cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,associated_item")]
+    #[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
     #[rustc_clean(cfg="cfail6")]
     fn     method_privacy() { }
 }
diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs
index 9b79fd8a0a1..1988f3f3541 100644
--- a/src/test/incremental/hashes/trait_defs.rs
+++ b/src/test/incremental/hashes/trait_defs.rs
@@ -277,22 +277,22 @@ trait TraitChangeMethodParametersOrder {
 // Add default implementation to method
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddMethodAutoImplementation {
-    // -----------------------------------------------------------------------------
+    // -------------------------------------------------------------
     // -------------------------
-    // -----------------------------------------------------------------------------
+    // -------------------------------------------------------------
     // -------------------------
     fn method()  ;
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddMethodAutoImplementation {
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method() {}
 }
@@ -795,20 +795,24 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> {
 // Add default to associated type
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddDefaultToAssociatedType {
-    type Associated;
+    //--------------------------------------------------------------
+    //--------------------------
+    //--------------------------------------------------------------
+    //--------------------------
+    type Associated                 ;
 
     fn method();
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddDefaultToAssociatedType {
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     type Associated = ReferenceType0;
 
@@ -839,20 +843,28 @@ trait TraitAddAssociatedConstant {
 // Add initializer to associated constant
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddInitializerToAssociatedConstant {
-    const Value: u32;
+    //--------------------------------------------------------------
+    //--------------------------
+    //--------------------------------------------------------------
+    //--------------------------
+    const Value: u32    ;
 
+    //--------------------------
+    //--------------------------
+    //--------------------------
+    //--------------------------
     fn method();
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddInitializerToAssociatedConstant {
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     const Value: u32 = 1;
 
diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs
index cc63aa4f556..f555f555f92 100644
--- a/src/test/incremental/hashes/trait_impls.rs
+++ b/src/test/incremental/hashes/trait_impls.rs
@@ -320,7 +320,11 @@ impl AddItemTrait for Foo {
 
 #[cfg(any(cfail1,cfail4))]
 pub trait ChangeHasValueTrait {
-    fn method_name();
+    //--------------------------------------------------------------
+    //--------------------------
+    //--------------------------------------------------------------
+    //--------------------------
+    fn method_name()   ;
 }
 
 #[cfg(any(cfail1,cfail4))]
@@ -329,14 +333,14 @@ impl ChangeHasValueTrait for Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 pub trait ChangeHasValueTrait {
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method_name() { }
 }
@@ -358,22 +362,22 @@ pub trait AddDefaultTrait {
 
 #[cfg(any(cfail1,cfail4))]
 impl AddDefaultTrait for Foo {
-    // ----------------------------------------------------
+    // -------------------------------------------------------------
     // -------------------------
-    // ----------------------------------------------------
+    // -------------------------------------------------------------
     // -------------------------
     fn         method_name() { }
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl AddDefaultTrait for Foo {
-    #[rustc_clean(except="associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     default fn method_name() { }
 }
diff --git a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
index 548b94d17f5..de0c03bb70b 100644
--- a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
@@ -102,10 +102,6 @@
           StorageDead(_6);                 // scope 1 at $DIR/derefer_complex_case.rs:+1:39: +1:40
           _5 = const ();                   // scope 1 at $DIR/derefer_complex_case.rs:+1:5: +1:40
           goto -> bb2;                     // scope 1 at $DIR/derefer_complex_case.rs:+1:5: +1:40
-+     }
-+ 
-+     bb8 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_complex_case.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
index 51df13bdfd0..0a56ee5e454 100644
--- a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
@@ -94,10 +94,6 @@
           StorageDead(_2);                 // scope 1 at $DIR/derefer_terminator_test.rs:+8:1: +8:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_terminator_test.rs:+8:1: +8:2
           return;                          // scope 0 at $DIR/derefer_terminator_test.rs:+8:2: +8:2
-+     }
-+ 
-+     bb6 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_terminator_test.rs:+0:1: +8:2
       }
   }
   
diff --git a/src/test/mir-opt/derefer_test.main.Derefer.diff b/src/test/mir-opt/derefer_test.main.Derefer.diff
index cf8211c1ed0..6c2047e216c 100644
--- a/src/test/mir-opt/derefer_test.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_test.main.Derefer.diff
@@ -49,10 +49,6 @@
           StorageDead(_2);                 // scope 1 at $DIR/derefer_test.rs:+5:1: +5:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_test.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/derefer_test.rs:+5:2: +5:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_test.rs:+0:1: +5:2
       }
   }
   
diff --git a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
index 91c9d551224..e2dceecfd7c 100644
--- a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
@@ -87,10 +87,6 @@
           StorageDead(_2);                 // scope 1 at $DIR/derefer_test_multiple.rs:+7:1: +7:2
           StorageDead(_1);                 // scope 0 at $DIR/derefer_test_multiple.rs:+7:1: +7:2
           return;                          // scope 0 at $DIR/derefer_test_multiple.rs:+7:2: +7:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/derefer_test_multiple.rs:+0:1: +7:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff
index 49c91e956e7..8eae04c4dd4 100644
--- a/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff
+++ b/src/test/mir-opt/inline/dyn_trait.get_query.Inline.diff
@@ -57,10 +57,6 @@
           StorageDead(_4);                 // scope 1 at $DIR/dyn-trait.rs:+2:24: +2:25
           StorageDead(_2);                 // scope 0 at $DIR/dyn-trait.rs:+3:1: +3:2
           return;                          // scope 0 at $DIR/dyn-trait.rs:+3:2: +3:2
-+     }
-+ 
-+     bb3 (cleanup): {
-+         resume;                          // scope 0 at $DIR/dyn-trait.rs:+0:1: +3:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
index 805354d2804..e7c5972f429 100644
--- a/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
+++ b/src/test/mir-opt/inline/dyn_trait.try_execute_query.Inline.diff
@@ -32,10 +32,6 @@
 +         StorageDead(_4);                 // scope 1 at $DIR/dyn-trait.rs:+0:21: +0:22
           StorageDead(_2);                 // scope 0 at $DIR/dyn-trait.rs:+1:15: +1:16
           return;                          // scope 0 at $DIR/dyn-trait.rs:+2:2: +2:2
-+     }
-+ 
-+     bb2 (cleanup): {
-+         resume;                          // scope 0 at $DIR/dyn-trait.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
index 77b5df943a3..63022525818 100644
--- a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir
@@ -41,8 +41,4 @@ fn bar() -> bool {
         StorageDead(_1);                 // scope 0 at $DIR/inline-any-operand.rs:+3:1: +3:2
         return;                          // scope 0 at $DIR/inline-any-operand.rs:+3:2: +3:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-any-operand.rs:+0:1: +3:2
-    }
 }
diff --git a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir
index d746e1a093a..1fadd246479 100644
--- a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir
@@ -46,8 +46,4 @@ fn foo(_1: T, _2: i32) -> i32 {
         StorageDead(_3);                 // scope 0 at $DIR/inline-closure.rs:+3:1: +3:2
         return;                          // scope 0 at $DIR/inline-closure.rs:+3:2: +3:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-closure.rs:+0:1: +3:2
-    }
 }
diff --git a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
index 84b3fb92cd5..4069e9f89c8 100644
--- a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir
@@ -53,8 +53,4 @@ fn foo(_1: T, _2: &i32) -> i32 {
         StorageDead(_3);                 // scope 0 at $DIR/inline-closure-borrows-arg.rs:+6:1: +6:2
         return;                          // scope 0 at $DIR/inline-closure-borrows-arg.rs:+6:2: +6:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-closure-borrows-arg.rs:+0:1: +6:2
-    }
 }
diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
index 75693dc384b..d60b064600f 100644
--- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir
@@ -66,8 +66,4 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
         StorageDead(_3);                 // scope 0 at $DIR/inline-closure-captures.rs:+3:1: +3:2
         return;                          // scope 0 at $DIR/inline-closure-captures.rs:+3:2: +3:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-closure-captures.rs:+0:1: +3:2
-    }
 }
diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff
index 556d587a472..cf800ba1129 100644
--- a/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff
+++ b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff
@@ -19,10 +19,6 @@
           StorageDead(_1);                 // scope 0 at $DIR/inline-compatibility.rs:+1:18: +1:19
           _0 = const ();                   // scope 0 at $DIR/inline-compatibility.rs:+0:37: +2:2
           return;                          // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-compatibility.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff
index b1ee4307358..a45f959026d 100644
--- a/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff
+++ b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff
@@ -19,10 +19,6 @@
           StorageDead(_1);                 // scope 0 at $DIR/inline-compatibility.rs:+1:21: +1:22
           _0 = const ();                   // scope 0 at $DIR/inline-compatibility.rs:+0:40: +2:2
           return;                          // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-compatibility.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff
index a6d65928da7..b1c476362de 100644
--- a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff
+++ b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff
@@ -25,10 +25,6 @@
           StorageDead(_1);                 // scope 0 at $DIR/inline-cycle.rs:+1:24: +1:25
           _0 = const ();                   // scope 0 at $DIR/inline-cycle.rs:+0:10: +2:2
           return;                          // scope 0 at $DIR/inline-cycle.rs:+2:2: +2:2
-+     }
-+ 
-+     bb2 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-cycle.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_cycle.two.Inline.diff b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff
index 0fea4121f8d..dc890a36511 100644
--- a/src/test/mir-opt/inline/inline_cycle.two.Inline.diff
+++ b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff
@@ -50,10 +50,6 @@
           StorageDead(_1);                 // scope 0 at $DIR/inline-cycle.rs:+1:12: +1:13
           _0 = const ();                   // scope 0 at $DIR/inline-cycle.rs:+0:10: +2:2
           return;                          // scope 0 at $DIR/inline-cycle.rs:+2:2: +2:2
-+     }
-+ 
-+     bb2 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-cycle.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
index d5709f1b47a..082f57e59a0 100644
--- a/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
+++ b/src/test/mir-opt/inline/inline_cycle_generic.main.Inline.diff
@@ -27,10 +27,6 @@
           StorageDead(_1);                 // scope 0 at $DIR/inline-cycle-generic.rs:+1:24: +1:25
           _0 = const ();                   // scope 0 at $DIR/inline-cycle-generic.rs:+0:11: +2:2
           return;                          // scope 0 at $DIR/inline-cycle-generic.rs:+2:2: +2:2
-+     }
-+ 
-+     bb2 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-cycle-generic.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_diverging.f.Inline.diff b/src/test/mir-opt/inline/inline_diverging.f.Inline.diff
index 7ebc2ff5c45..6b24b3e1697 100644
--- a/src/test/mir-opt/inline/inline_diverging.f.Inline.diff
+++ b/src/test/mir-opt/inline/inline_diverging.f.Inline.diff
@@ -19,10 +19,6 @@
 + 
 +     bb1: {
 +         goto -> bb1;                     // scope 1 at $DIR/inline-diverging.rs:+32:5: +32:12
-+     }
-+ 
-+     bb2 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-diverging.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_diverging.g.Inline.diff b/src/test/mir-opt/inline/inline_diverging.g.Inline.diff
index acdd0f87901..a25f1454fac 100644
--- a/src/test/mir-opt/inline/inline_diverging.g.Inline.diff
+++ b/src/test/mir-opt/inline/inline_diverging.g.Inline.diff
@@ -44,10 +44,6 @@
 +                                          // mir::Constant
 +                                          // + span: $SRC_DIR/std/src/panic.rs:LL:COL
 +                                          // + literal: Const { ty: &str, val: Value(Slice(..)) }
-+     }
-+ 
-+     bb3 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-diverging.rs:+0:1: +6:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
index 8fda8673c95..8759f3d02fc 100644
--- a/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
+++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
@@ -51,10 +51,6 @@
 + 
 +     bb1: {
 +         goto -> bb1;                     // scope 5 at $DIR/inline-diverging.rs:+18:5: +18:12
-+     }
-+ 
-+     bb2 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-diverging.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff b/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff
index e3375e9e15c..076509df349 100644
--- a/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff
+++ b/src/test/mir-opt/inline/inline_instruction_set.default.Inline.diff
@@ -39,10 +39,6 @@
           StorageDead(_3);                 // scope 0 at $DIR/inline-instruction-set.rs:+3:30: +3:31
           _0 = const ();                   // scope 0 at $DIR/inline-instruction-set.rs:+0:18: +4:2
           return;                          // scope 0 at $DIR/inline-instruction-set.rs:+4:2: +4:2
-+     }
-+ 
-+     bb3 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-instruction-set.rs:+0:1: +4:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff b/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff
index ce294db02fd..b275d08e05f 100644
--- a/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff
+++ b/src/test/mir-opt/inline/inline_instruction_set.t32.Inline.diff
@@ -41,10 +41,6 @@
           StorageDead(_3);                 // scope 0 at $DIR/inline-instruction-set.rs:+5:30: +5:31
           _0 = const ();                   // scope 0 at $DIR/inline-instruction-set.rs:+0:14: +6:2
           return;                          // scope 0 at $DIR/inline-instruction-set.rs:+6:2: +6:2
-+     }
-+ 
-+     bb3 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-instruction-set.rs:+0:1: +6:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_options.main.Inline.after.mir b/src/test/mir-opt/inline/inline_options.main.Inline.after.mir
index 49c72b7196c..275493066ee 100644
--- a/src/test/mir-opt/inline/inline_options.main.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_options.main.Inline.after.mir
@@ -52,8 +52,4 @@ fn main() -> () {
         _0 = const ();                   // scope 0 at $DIR/inline-options.rs:+0:11: +3:2
         return;                          // scope 0 at $DIR/inline-options.rs:+3:2: +3:2
     }
-
-    bb5 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-options.rs:+0:1: +3:2
-    }
 }
diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
index 0ea8823156c..768608564d6 100644
--- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
@@ -69,8 +69,4 @@ fn bar() -> bool {
         StorageDead(_4);                 // scope 0 at $DIR/inline-retag.rs:+3:1: +3:2
         return;                          // scope 0 at $DIR/inline-retag.rs:+3:2: +3:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-retag.rs:+0:1: +3:2
-    }
 }
diff --git a/src/test/mir-opt/inline/inline_shims.clone.Inline.diff b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff
index e69af791622..25ca05893b2 100644
--- a/src/test/mir-opt/inline/inline_shims.clone.Inline.diff
+++ b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff
@@ -21,10 +21,6 @@
 +         _0 = (*_2);                      // scope 1 at $SRC_DIR/core/src/clone.rs:LL:COL
           StorageDead(_2);                 // scope 0 at $DIR/inline-shims.rs:+1:13: +1:14
           return;                          // scope 0 at $DIR/inline-shims.rs:+2:2: +2:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-shims.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_shims.drop.Inline.diff b/src/test/mir-opt/inline/inline_shims.drop.Inline.diff
index 8c1c383ee25..f7b1cde80bd 100644
--- a/src/test/mir-opt/inline/inline_shims.drop.Inline.diff
+++ b/src/test/mir-opt/inline/inline_shims.drop.Inline.diff
@@ -51,10 +51,6 @@
 + 
 +     bb3: {
 +         drop((((*_5) as Some).0: B)) -> bb2; // scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
-+     }
-+ 
-+     bb4 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-shims.rs:+0:1: +3:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff
index 6c71311c7d4..106291b36e3 100644
--- a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff
+++ b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff
@@ -23,10 +23,6 @@
           _0 = const ();                   // scope 0 at $DIR/inline-specialization.rs:+0:11: +2:2
           StorageDead(_1);                 // scope 0 at $DIR/inline-specialization.rs:+2:1: +2:2
           return;                          // scope 0 at $DIR/inline-specialization.rs:+2:2: +2:2
-+     }
-+ 
-+     bb1 (cleanup): {
-+         resume;                          // scope 0 at $DIR/inline-specialization.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
index 36875d07ca4..116ae4e361b 100644
--- a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir
@@ -29,8 +29,4 @@ fn test2(_1: &dyn X) -> bool {
         StorageDead(_2);                 // scope 0 at $DIR/inline-trait-method_2.rs:+1:11: +1:12
         return;                          // scope 0 at $DIR/inline-trait-method_2.rs:+2:2: +2:2
     }
-
-    bb2 (cleanup): {
-        resume;                          // scope 0 at $DIR/inline-trait-method_2.rs:+0:1: +2:2
-    }
 }
diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir
index e715ff83598..5168ae031f0 100644
--- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir
+++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.a.Inline.after.mir
@@ -27,8 +27,4 @@ fn a(_1: &mut [T]) -> &mut [T] {
         StorageDead(_2);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
         return;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2
-    }
 }
diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
index 8bacced23bd..4006dd15a42 100644
--- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
+++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
@@ -39,8 +39,4 @@ fn b(_1: &mut Box<T>) -> &mut T {
         StorageDead(_2);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
         return;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2
-    }
 }
diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir
index 233a1788288..c7f20ff98ff 100644
--- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir
+++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.c.Inline.after.mir
@@ -19,8 +19,4 @@ fn c(_1: &[T]) -> &[T] {
         StorageDead(_2);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
         return;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2
-    }
 }
diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
index 5b4aeee9e2b..e516269c140 100644
--- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
+++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
@@ -27,8 +27,4 @@ fn d(_1: &Box<T>) -> &T {
         StorageDead(_2);                 // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
         return;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:1: +2:2
-    }
 }
diff --git a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
index 769ff89fdb7..fca53a72f88 100644
--- a/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
+++ b/src/test/mir-opt/inline/issue_76997_inline_scopes_parenting.main.Inline.after.mir
@@ -39,8 +39,4 @@ fn main() -> () {
         StorageDead(_1);                 // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+3:1: +3:2
         return;                          // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+3:2: +3:2
     }
-
-    bb1 (cleanup): {
-        resume;                          // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+0:1: +3:2
-    }
 }
diff --git a/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff
index 6866bcf9b8a..5c635e2220e 100644
--- a/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.diff
@@ -16,9 +16,5 @@
       bb1: {
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
       }
-  
-      bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2
-      }
   }
   
diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
index 032a6a01b7f..8a80de32f3a 100644
--- a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
@@ -111,9 +111,5 @@
       bb5: {
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+5:2: +5:2
       }
-  
-      bb6 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +5:2
-      }
   }
   
diff --git a/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff
index 50c86e61949..e6a2f6512f5 100644
--- a/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.forget.LowerIntrinsics.diff
@@ -25,9 +25,5 @@
       bb2: {
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
       }
-  
-      bb3 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2
-      }
   }
   
diff --git a/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff
index 01591e17624..1ab2f2a0a04 100644
--- a/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.non_const.LowerIntrinsics.diff
@@ -27,9 +27,5 @@
           StorageDead(_1);                 // scope 0 at $DIR/lower_intrinsics.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2
       }
-  
-      bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +4:2
-      }
   }
   
diff --git a/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff
index 7bc24fe7d67..11b27976b55 100644
--- a/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.size_of.LowerIntrinsics.diff
@@ -16,9 +16,5 @@
       bb1: {
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+2:2: +2:2
       }
-  
-      bb2 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2
-      }
   }
   
diff --git a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff
index 581926ab163..ac077e85b04 100644
--- a/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff
@@ -18,9 +18,5 @@
 -                                          // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(<ZST>) }
 +         unreachable;                     // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
       }
-  
-      bb1 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +2:2
-      }
   }
   
diff --git a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
index b0fa55bdd4c..e0a5416b22b 100644
--- a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
@@ -79,9 +79,5 @@
           StorageDead(_3);                 // scope 0 at $DIR/lower_intrinsics.rs:+4:1: +4:2
           return;                          // scope 0 at $DIR/lower_intrinsics.rs:+4:2: +4:2
       }
-  
-      bb4 (cleanup): {
-          resume;                          // scope 0 at $DIR/lower_intrinsics.rs:+0:1: +4:2
-      }
   }
   
diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
index a17a0776437..750aaa88b1c 100644
--- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
+++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
@@ -96,9 +96,5 @@
           _10 = discriminant(_7);          // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           switchInt(move _10) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
       }
-  
-      bb5 (cleanup): {
-          resume;                          // scope 0 at $DIR/remove_storage_markers.rs:+0:1: +5:2
-      }
   }
   
diff --git a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff
index b29b08f836d..087f76dbda8 100644
--- a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff
+++ b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff
@@ -22,10 +22,6 @@
           StorageDead(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
 -         nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+0:17: +2:2
           return;                          // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2
--     }
-- 
--     bb2 (cleanup): {
--         resume;                          // scope 0 at $DIR/remove_unneeded_drops.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff
index 9058ddbd7ec..933d6895f45 100644
--- a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff
+++ b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff
@@ -22,10 +22,6 @@
           StorageDead(_2);                 // scope 0 at $DIR/remove_unneeded_drops.rs:+1:12: +1:13
 -         nop;                             // scope 0 at $DIR/remove_unneeded_drops.rs:+0:36: +2:2
           return;                          // scope 0 at $DIR/remove_unneeded_drops.rs:+2:2: +2:2
--     }
-- 
--     bb2 (cleanup): {
--         resume;                          // scope 0 at $DIR/remove_unneeded_drops.rs:+0:1: +2:2
       }
   }
   
diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
index 229046b51fc..452cc8a9c26 100644
--- a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
@@ -85,9 +85,5 @@
       bb4: {
           return;                          // scope 0 at $DIR/simplify-arm.rs:+6:2: +6:2
       }
-  
-      bb5 (cleanup): {
-          resume;                          // scope 0 at $DIR/simplify-arm.rs:+0:1: +6:2
-      }
   }
   
diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
index 22a2f85c09a..5d7d4ba7c3d 100644
--- a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
+++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
@@ -85,9 +85,5 @@
       bb4: {
           return;                          // scope 0 at $DIR/simplify-arm.rs:+6:2: +6:2
       }
-  
-      bb5 (cleanup): {
-          resume;                          // scope 0 at $DIR/simplify-arm.rs:+0:1: +6:2
-      }
   }
   
diff --git a/src/test/run-make-fulldeps/issues-41478-43796/a.rs b/src/test/run-make-fulldeps/issues-41478-43796/a.rs
index fd67221144a..b072235b5bc 100644
--- a/src/test/run-make-fulldeps/issues-41478-43796/a.rs
+++ b/src/test/run-make-fulldeps/issues-41478-43796/a.rs
@@ -1,5 +1,5 @@
 #![crate_type = "lib"]
-pub struct V<S>(S);
+pub struct V<S>(#[allow(unused_tuple_struct_fields)] S);
 pub trait An {
     type U;
 }
diff --git a/src/test/run-make/native-link-modifier-whole-archive/Makefile b/src/test/run-make/native-link-modifier-whole-archive/Makefile
index 3b49d1188ae..967cb065cad 100644
--- a/src/test/run-make/native-link-modifier-whole-archive/Makefile
+++ b/src/test/run-make/native-link-modifier-whole-archive/Makefile
@@ -1,7 +1,7 @@
 # ignore-cross-compile -- compiling C++ code does not work well when cross-compiling
 
-# This test case makes sure that native libraries are linked with --whole-archive semantics
-# when the `-bundle,+whole-archive` modifiers are applied to them.
+# This test case makes sure that native libraries are linked with appropriate semantics
+# when the `[+-]bundle,[+-]whole-archive` modifiers are applied to them.
 #
 # The test works by checking that the resulting executables produce the expected output,
 # part of which is emitted by otherwise unreferenced C code. If +whole-archive didn't work
@@ -10,8 +10,14 @@
 
 -include ../../run-make-fulldeps/tools.mk
 
-all: $(TMPDIR)/$(call BIN,directly_linked) $(TMPDIR)/$(call BIN,indirectly_linked) $(TMPDIR)/$(call BIN,indirectly_linked_via_attr)
+all: $(TMPDIR)/$(call BIN,directly_linked) \
+     $(TMPDIR)/$(call BIN,directly_linked_test_plus_whole_archive) \
+     $(TMPDIR)/$(call BIN,directly_linked_test_minus_whole_archive) \
+     $(TMPDIR)/$(call BIN,indirectly_linked) \
+     $(TMPDIR)/$(call BIN,indirectly_linked_via_attr)
 	$(call RUN,directly_linked) | $(CGREP) 'static-initializer.directly_linked.'
+	$(call RUN,directly_linked_test_plus_whole_archive) --nocapture | $(CGREP) 'static-initializer.'
+	$(call RUN,directly_linked_test_minus_whole_archive) --nocapture | $(CGREP) -v 'static-initializer.'
 	$(call RUN,indirectly_linked) | $(CGREP) 'static-initializer.indirectly_linked.'
 	$(call RUN,indirectly_linked_via_attr) | $(CGREP) 'static-initializer.native_lib_in_src.'
 
@@ -19,6 +25,13 @@ all: $(TMPDIR)/$(call BIN,directly_linked) $(TMPDIR)/$(call BIN,indirectly_linke
 $(TMPDIR)/$(call BIN,directly_linked): $(call NATIVE_STATICLIB,c_static_lib_with_constructor)
 	$(RUSTC) directly_linked.rs -l static:+whole-archive=c_static_lib_with_constructor
 
+# Native lib linked into test executable, +whole-archive
+$(TMPDIR)/$(call BIN,directly_linked_test_plus_whole_archive): $(call NATIVE_STATICLIB,c_static_lib_with_constructor)
+	$(RUSTC) directly_linked_test_plus_whole_archive.rs --test -l static:+whole-archive=c_static_lib_with_constructor
+# Native lib linked into test executable, -whole-archive
+$(TMPDIR)/$(call BIN,directly_linked_test_minus_whole_archive): $(call NATIVE_STATICLIB,c_static_lib_with_constructor)
+	$(RUSTC) directly_linked_test_minus_whole_archive.rs --test -l static:-whole-archive=c_static_lib_with_constructor
+
 # Native lib linked into RLIB via `-l static:-bundle,+whole-archive`, RLIB linked into executable
 $(TMPDIR)/$(call BIN,indirectly_linked): $(TMPDIR)/librlib_with_cmdline_native_lib.rlib
 	$(RUSTC) indirectly_linked.rs
diff --git a/src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_minus_whole_archive.rs b/src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_minus_whole_archive.rs
new file mode 100644
index 00000000000..20ed8d9d4cd
--- /dev/null
+++ b/src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_minus_whole_archive.rs
@@ -0,0 +1,7 @@
+use std::io::Write;
+
+#[test]
+fn test_thing() {
+    print!("ran the test");
+    std::io::stdout().flush().unwrap();
+}
diff --git a/src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_plus_whole_archive.rs b/src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_plus_whole_archive.rs
new file mode 100644
index 00000000000..20ed8d9d4cd
--- /dev/null
+++ b/src/test/run-make/native-link-modifier-whole-archive/directly_linked_test_plus_whole_archive.rs
@@ -0,0 +1,7 @@
+use std::io::Write;
+
+#[test]
+fn test_thing() {
+    print!("ran the test");
+    std::io::stdout().flush().unwrap();
+}
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/Makefile b/src/test/run-make/raw-dylib-alt-calling-convention/Makefile
index 1badde54112..a254285ab76 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/Makefile
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/Makefile
@@ -14,10 +14,19 @@ ifdef IS_MSVC
 else
 	$(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll
 endif
-	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
 
+	"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
 ifdef RUSTC_BLESS_TEST
 	cp "$(TMPDIR)"/output.txt output.txt
 else
 	$(DIFF) output.txt "$(TMPDIR)"/output.txt
 endif
+
+ifdef IS_MSVC
+	"$(TMPDIR)"/driver true > "$(TMPDIR)"/output.msvc.txt
+ifdef RUSTC_BLESS_TEST
+	cp "$(TMPDIR)"/output.msvc.txt output.msvc.txt
+else
+	$(DIFF) output.msvc.txt "$(TMPDIR)"/output.msvc.txt
+endif
+endif
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/driver.rs b/src/test/run-make/raw-dylib-alt-calling-convention/driver.rs
index 3710507f5e4..b7f372c6b2b 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/driver.rs
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/driver.rs
@@ -1,5 +1,8 @@
 extern crate raw_dylib_alt_calling_convention_test;
 
 fn main() {
-    raw_dylib_alt_calling_convention_test::library_function();
+    raw_dylib_alt_calling_convention_test::library_function(
+        std::env::args().skip(1).next().map_or(
+            false,
+            |s| std::str::FromStr::from_str(&s).unwrap()));
 }
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/extern.c b/src/test/run-make/raw-dylib-alt-calling-convention/extern.c
index 8f64abf2fb5..0c4d12af9b2 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/extern.c
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/extern.c
@@ -121,3 +121,58 @@ __declspec(dllexport) void __fastcall fastcall_fn_9(uint8_t x, double y) {
     printf("fastcall_fn_9(%d, %.1f)\n", x, y);
     fflush(stdout);
 }
+
+// GCC doesn't support vectorcall: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
+#ifdef _MSC_VER
+__declspec(dllexport) void __vectorcall vectorcall_fn_1(int i) {
+    printf("vectorcall_fn_1(%d)\n", i);
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_2(uint8_t i, float f) {
+    printf("vectorcall_fn_2(%d, %.1f)\n", i, f);
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_3(double d) {
+    printf("vectorcall_fn_3(%.1f)\n", d);
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_4(uint8_t i, uint8_t j, float f) {
+    printf("vectorcall_fn_4(%d, %d, %.1f)\n", i, j, f);
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_5(struct S s, int i) {
+    printf("vectorcall_fn_5(S { x: %d, y: %d }, %d)\n", s.x, s.y, i);
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_6(struct S* s) {
+    if (s) {
+        printf("vectorcall_fn_6(S { x: %d, y: %d })\n", s->x, s->y);
+    } else {
+        printf("vectorcall_fn_6(null)\n");
+    }
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_7(struct S2 s, int i) {
+    printf("vectorcall_fn_7(S2 { x: %d, y: %d }, %d)\n", s.x, s.y, i);
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_8(struct S3 s, struct S3 t) {
+    printf("vectorcall_fn_8(S3 { x: [%d, %d, %d, %d, %d] }, S3 { x: [%d, %d, %d, %d, %d] })\n",
+           s.x[0], s.x[1], s.x[2], s.x[3], s.x[4],
+           t.x[0], t.x[1], t.x[2], t.x[3], t.x[4]
+        );
+    fflush(stdout);
+}
+
+__declspec(dllexport) void __vectorcall vectorcall_fn_9(uint8_t x, double y) {
+    printf("vectorcall_fn_9(%d, %.1f)\n", x, y);
+    fflush(stdout);
+}
+#endif
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs b/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
index 165792b0490..b5e9415b2be 100644
--- a/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/lib.rs
@@ -1,4 +1,5 @@
 #![feature(raw_dylib)]
+#![feature(abi_vectorcall)]
 
 #[repr(C)]
 #[derive(Clone)]
@@ -46,29 +47,60 @@ extern "fastcall" {
     fn fastcall_fn_9(x: u8, y: f64);
 }
 
-pub fn library_function() {
+#[cfg(target_env = "msvc")]
+#[link(name = "extern", kind = "raw-dylib")]
+extern "vectorcall" {
+    fn vectorcall_fn_1(i: i32);
+    fn vectorcall_fn_2(c: u8, f: f32);
+    fn vectorcall_fn_3(d: f64);
+    fn vectorcall_fn_4(i: u8, j: u8, f: f32);
+    fn vectorcall_fn_5(a: S, b: i32);
+    fn vectorcall_fn_6(a: Option<&S>);
+    fn vectorcall_fn_7(a: S2, b: i32);
+    fn vectorcall_fn_8(a: S3, b: S3);
+    fn vectorcall_fn_9(x: u8, y: f64);
+}
+
+pub fn library_function(run_msvc_only: bool) {
     unsafe {
-        stdcall_fn_1(14);
-        stdcall_fn_2(16, 3.5);
-        stdcall_fn_3(3.5);
-        stdcall_fn_4(1, 2, 3.0);
-        stdcall_fn_5(S { x: 1, y: 2 }, 16);
-        stdcall_fn_6(Some(&S { x: 10, y: 12 }));
-        stdcall_fn_7(S2 { x: 15, y: 16 }, 3);
-        stdcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
-        stdcall_fn_9(1, 3.0);
+        if !run_msvc_only {
+            stdcall_fn_1(14);
+            stdcall_fn_2(16, 3.5);
+            stdcall_fn_3(3.5);
+            stdcall_fn_4(1, 2, 3.0);
+            stdcall_fn_5(S { x: 1, y: 2 }, 16);
+            stdcall_fn_6(Some(&S { x: 10, y: 12 }));
+            stdcall_fn_7(S2 { x: 15, y: 16 }, 3);
+            stdcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
+            stdcall_fn_9(1, 3.0);
+
+            fastcall_fn_1(14);
+            fastcall_fn_2(16, 3.5);
+            fastcall_fn_3(3.5);
+            fastcall_fn_4(1, 2, 3.0);
+            fastcall_fn_6(Some(&S { x: 10, y: 12 }));
+            fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
+            fastcall_fn_9(1, 3.0);
+        } else {
+            // FIXME: 91167
+            // rustc generates incorrect code for the calls to fastcall_fn_5 and fastcall_fn_7
+            // on i686-pc-windows-gnu; disabling these until the indicated issue is fixed.
+            fastcall_fn_5(S { x: 1, y: 2 }, 16);
+            fastcall_fn_7(S2 { x: 15, y: 16 }, 3);
 
-        fastcall_fn_1(14);
-        fastcall_fn_2(16, 3.5);
-        fastcall_fn_3(3.5);
-        fastcall_fn_4(1, 2, 3.0);
-        // FIXME: 91167
-        // rustc generates incorrect code for the calls to fastcall_fn_5 and fastcall_fn_7
-        // on i686-pc-windows-gnu; commenting these out until the indicated issue is fixed.
-        //fastcall_fn_5(S { x: 1, y: 2 }, 16);
-        fastcall_fn_6(Some(&S { x: 10, y: 12 }));
-        //fastcall_fn_7(S2 { x: 15, y: 16 }, 3);
-        fastcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
-        fastcall_fn_9(1, 3.0);
+            // GCC doesn't support vectorcall: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89485
+            #[cfg(target_env = "msvc")]
+            {
+                vectorcall_fn_1(14);
+                vectorcall_fn_2(16, 3.5);
+                vectorcall_fn_3(3.5);
+                vectorcall_fn_4(1, 2, 3.0);
+                vectorcall_fn_5(S { x: 1, y: 2 }, 16);
+                vectorcall_fn_6(Some(&S { x: 10, y: 12 }));
+                vectorcall_fn_7(S2 { x: 15, y: 16 }, 3);
+                vectorcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] });
+                vectorcall_fn_9(1, 3.0);
+            }
+        }
     }
 }
diff --git a/src/test/run-make/raw-dylib-alt-calling-convention/output.msvc.txt b/src/test/run-make/raw-dylib-alt-calling-convention/output.msvc.txt
new file mode 100644
index 00000000000..9ddd1b11016
--- /dev/null
+++ b/src/test/run-make/raw-dylib-alt-calling-convention/output.msvc.txt
@@ -0,0 +1,11 @@
+fastcall_fn_5(S { x: 1, y: 2 }, 16)
+fastcall_fn_7(S2 { x: 15, y: 16 }, 3)
+vectorcall_fn_1(14)
+vectorcall_fn_2(16, 3.5)
+vectorcall_fn_3(3.5)
+vectorcall_fn_4(1, 2, 3.0)
+vectorcall_fn_5(S { x: 1, y: 2 }, 16)
+vectorcall_fn_6(S { x: 10, y: 12 })
+vectorcall_fn_7(S2 { x: 15, y: 16 }, 3)
+vectorcall_fn_8(S3 { x: [1, 2, 3, 4, 5] }, S3 { x: [6, 7, 8, 9, 10] })
+vectorcall_fn_9(1, 3.0)
diff --git a/src/test/run-make/raw-dylib-c/extern_1.c b/src/test/run-make/raw-dylib-c/extern_1.c
index 72737c086eb..ab1dc3a4105 100644
--- a/src/test/run-make/raw-dylib-c/extern_1.c
+++ b/src/test/run-make/raw-dylib-c/extern_1.c
@@ -1,5 +1,7 @@
 #include <stdio.h>
 
+__declspec(dllexport) int extern_variable = 0;
+
 __declspec(dllexport) void extern_fn_1() {
     printf("extern_fn_1\n");
     fflush(stdout);
@@ -10,6 +12,11 @@ __declspec(dllexport) void extern_fn_2() {
     fflush(stdout);
 }
 
+__declspec(dllexport) void print_extern_variable() {
+    printf("extern_variable value: %d\n", extern_variable);
+    fflush(stdout);
+}
+
 __declspec(dllexport) void extern_fn_with_long_name() {
     printf("extern_fn_with_long_name; got the rename\n");
     fflush(stdout);
diff --git a/src/test/run-make/raw-dylib-c/lib.rs b/src/test/run-make/raw-dylib-c/lib.rs
index 58f7ccb38ce..74e0d3813d9 100644
--- a/src/test/run-make/raw-dylib-c/lib.rs
+++ b/src/test/run-make/raw-dylib-c/lib.rs
@@ -12,12 +12,20 @@ extern {
 
 pub fn library_function() {
     #[link(name = "extern_1", kind = "raw-dylib")]
-    extern { fn extern_fn_2(); }
+    extern {
+        fn extern_fn_2();
+        fn print_extern_variable();
+        static mut extern_variable: i32;
+    }
 
     unsafe {
         extern_fn_1();
         extern_fn_2();
         extern_fn_3();
+        extern_variable = 42;
+        print_extern_variable();
+        extern_variable = -42;
+        print_extern_variable();
     }
 }
 
diff --git a/src/test/run-make/raw-dylib-c/output.txt b/src/test/run-make/raw-dylib-c/output.txt
index 7800cba1872..cd9fe47bee4 100644
--- a/src/test/run-make/raw-dylib-c/output.txt
+++ b/src/test/run-make/raw-dylib-c/output.txt
@@ -1,3 +1,5 @@
 extern_fn_1
 extern_fn_2; didn't get the rename
 extern_fn_3
+extern_variable value: 42
+extern_variable value: -42
diff --git a/src/test/run-make/raw-dylib-link-ordinal/exporter.c b/src/test/run-make/raw-dylib-link-ordinal/exporter.c
index a9dd6da6616..aabf32ff19f 100644
--- a/src/test/run-make/raw-dylib-link-ordinal/exporter.c
+++ b/src/test/run-make/raw-dylib-link-ordinal/exporter.c
@@ -3,3 +3,10 @@
 void exported_function() {
     printf("exported_function\n");
 }
+
+int exported_variable = 0;
+
+void print_exported_variable() {
+    printf("exported_variable value: %d\n", exported_variable);
+    fflush(stdout);
+}
diff --git a/src/test/run-make/raw-dylib-link-ordinal/exporter.def b/src/test/run-make/raw-dylib-link-ordinal/exporter.def
index 1a4b4c941b6..5d87c580a54 100644
--- a/src/test/run-make/raw-dylib-link-ordinal/exporter.def
+++ b/src/test/run-make/raw-dylib-link-ordinal/exporter.def
@@ -1,3 +1,5 @@
 LIBRARY exporter
 EXPORTS
     exported_function @13 NONAME
+    exported_variable @5 NONAME
+    print_exported_variable @9 NONAME
diff --git a/src/test/run-make/raw-dylib-link-ordinal/lib.rs b/src/test/run-make/raw-dylib-link-ordinal/lib.rs
index 20609caa5be..5efce4e938c 100644
--- a/src/test/run-make/raw-dylib-link-ordinal/lib.rs
+++ b/src/test/run-make/raw-dylib-link-ordinal/lib.rs
@@ -4,10 +4,18 @@
 extern {
     #[link_ordinal(13)]
     fn imported_function();
+    #[link_ordinal(5)]
+    static mut imported_variable: i32;
+    #[link_ordinal(9)]
+    fn print_imported_variable();
 }
 
 pub fn library_function() {
     unsafe {
         imported_function();
+        imported_variable = 42;
+        print_imported_variable();
+        imported_variable = -42;
+        print_imported_variable();
     }
 }
diff --git a/src/test/run-make/raw-dylib-link-ordinal/output.txt b/src/test/run-make/raw-dylib-link-ordinal/output.txt
index 2d0ed60f216..a4b2031d98b 100644
--- a/src/test/run-make/raw-dylib-link-ordinal/output.txt
+++ b/src/test/run-make/raw-dylib-link-ordinal/output.txt
@@ -1 +1,3 @@
 exported_function
+exported_variable value: 42
+exported_variable value: -42
diff --git a/src/test/rustdoc-gui/item-info-width.goml b/src/test/rustdoc-gui/item-info-width.goml
deleted file mode 100644
index 8b6d355a8f1..00000000000
--- a/src/test/rustdoc-gui/item-info-width.goml
+++ /dev/null
@@ -1,8 +0,0 @@
-// This test ensures that the item information don't take 100% of the width if unnecessary.
-goto: file://|DOC_PATH|/lib2/struct.Foo.html
-// We set a fixed size so there is no chance of "random" resize.
-size: (1100, 800)
-// We check that ".item-info" is bigger than its content.
-assert-css: (".item-info", {"width": "790px"})
-assert-css: (".item-info .stab", {"width": "289px"})
-assert-position: (".item-info .stab", {"x": 295})
diff --git a/src/test/rustdoc-gui/item-info.goml b/src/test/rustdoc-gui/item-info.goml
new file mode 100644
index 00000000000..50c45b76bd6
--- /dev/null
+++ b/src/test/rustdoc-gui/item-info.goml
@@ -0,0 +1,32 @@
+// This test ensures a few things for item info elements.
+goto: file://|DOC_PATH|/lib2/struct.Foo.html
+// Ensuring that the item information don't take 100% of the width if unnecessary.
+// We set a fixed size so there is no chance of "random" resize.
+size: (1100, 800)
+// We check that ".item-info" is bigger than its content.
+assert-css: (".item-info", {"width": "790px"})
+assert-css: (".item-info .stab", {"width": "289px"})
+assert-position: (".item-info .stab", {"x": 295})
+
+// Now we ensure that they're not rendered on the same line.
+goto: file://|DOC_PATH|/lib2/trait.Trait.html
+// We first ensure that there are two item info on the trait.
+assert-count: ("#main-content > .item-info .stab", 2)
+// They should not have the same `y` position!
+compare-elements-position-false: (
+    "#main-content > .item-info .stab:nth-of-type(1)",
+    "#main-content > .item-info .stab:nth-of-type(2)",
+    ("y"),
+)
+// But they should have the same `x` position.
+compare-elements-position: (
+    "#main-content > .item-info .stab:nth-of-type(1)",
+    "#main-content > .item-info .stab:nth-of-type(2)",
+    ("x"),
+)
+// They are supposed to have the same height too.
+compare-elements-css: (
+    "#main-content > .item-info .stab:nth-of-type(1)",
+    "#main-content > .item-info .stab:nth-of-type(2)",
+    ["height"],
+)
diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs
index 4546449e102..87f91be3ac8 100644
--- a/src/test/rustdoc-gui/src/lib2/lib.rs
+++ b/src/test/rustdoc-gui/src/lib2/lib.rs
@@ -30,10 +30,13 @@ impl Foo {
     pub fn a_method(&self) {}
 }
 
+#[doc(cfg(feature = "foo-method"))]
+#[deprecated = "Whatever [`Foo::a_method`](#method.a_method)"]
 pub trait Trait {
     type X;
     const Y: u32;
 
+    #[deprecated = "Whatever [`Foo`](#tadam)"]
     fn foo() {}
 }
 
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr-location.stderr b/src/test/rustdoc-ui/check-doc-alias-attr-location.stderr
index 175626f49dc..85c9516236c 100644
--- a/src/test/rustdoc-ui/check-doc-alias-attr-location.stderr
+++ b/src/test/rustdoc-ui/check-doc-alias-attr-location.stderr
@@ -1,4 +1,4 @@
-error: `#[doc(alias = "...")]` isn't allowed on extern block
+error: `#[doc(alias = "...")]` isn't allowed on foreign module
   --> $DIR/check-doc-alias-attr-location.rs:7:7
    |
 LL | #[doc(alias = "foo")]
diff --git a/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs
new file mode 100644
index 00000000000..8f4fde96d7e
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.rs
@@ -0,0 +1,7 @@
+// check-fail
+// compile-flags: -Z unstable-options --scrape-examples-output-path {{build-base}}/t.calls --scrape-examples-target-crate foobar
+
+pub fn foo() {
+  INVALID_FUNC();
+  //~^ ERROR could not resolve path
+}
diff --git a/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr
new file mode 100644
index 00000000000..750aa320719
--- /dev/null
+++ b/src/test/rustdoc-ui/scrape-examples-fail-if-type-error.stderr
@@ -0,0 +1,14 @@
+error[E0433]: failed to resolve: could not resolve path `INVALID_FUNC`
+  --> $DIR/scrape-examples-fail-if-type-error.rs:5:3
+   |
+LL |   INVALID_FUNC();
+   |   ^^^^^^^^^^^^ could not resolve path `INVALID_FUNC`
+   |
+   = note: this error was originally ignored because you are running `rustdoc`
+   = note: try running again with `rustc` or `cargo check` and you may get a more detailed error
+
+error: Compilation failed, aborting rustdoc
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
diff --git a/src/test/rustdoc/auxiliary/issue-99734-aux.rs b/src/test/rustdoc/auxiliary/issue-99734-aux.rs
new file mode 100644
index 00000000000..234d55efb55
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/issue-99734-aux.rs
@@ -0,0 +1,11 @@
+pub struct Option;
+impl Option {
+    pub fn unwrap(self) {}
+}
+
+/// [`Option::unwrap`]
+pub mod task {}
+
+extern "C" {
+    pub fn main() -> std::ffi::c_int;
+}
diff --git a/src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs b/src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs
new file mode 100644
index 00000000000..3208fea05b3
--- /dev/null
+++ b/src/test/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs
@@ -0,0 +1,16 @@
+// aux-build:issue-99734-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate issue_99734_aux;
+
+pub use issue_99734_aux::*;
+
+// @count foo/index.html '//a[@class="fn"][@title="foo::main fn"]' 1
+
+extern "C" {
+    pub fn main() -> std::ffi::c_int;
+}
diff --git a/src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs b/src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs
new file mode 100644
index 00000000000..b2f9b8b4657
--- /dev/null
+++ b/src/test/rustdoc/issue-99734-multiple-mods-w-same-name.rs
@@ -0,0 +1,14 @@
+// aux-build:issue-99734-aux.rs
+// build-aux-docs
+// ignore-cross-compile
+
+#![crate_name = "foo"]
+
+#[macro_use]
+extern crate issue_99734_aux;
+
+pub use issue_99734_aux::*;
+
+// @count foo/index.html '//a[@class="mod"][@title="foo::task mod"]' 1
+
+pub mod task {}
diff --git a/src/test/ui/align-with-extern-c-fn.rs b/src/test/ui/align-with-extern-c-fn.rs
index f77f40998de..9e490e27ad1 100644
--- a/src/test/ui/align-with-extern-c-fn.rs
+++ b/src/test/ui/align-with-extern-c-fn.rs
@@ -8,7 +8,7 @@
 #![feature(repr_align)]
 
 #[repr(align(16))]
-pub struct A(i64);
+pub struct A(#[allow(unused_tuple_struct_fields)] i64);
 
 #[allow(improper_ctypes_definitions)]
 pub extern "C" fn foo(x: A) {}
diff --git a/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs b/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs
index c9b4abbfd3f..54b7c8bb9c6 100644
--- a/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs
+++ b/src/test/ui/allocator/no_std-alloc-error-handler-custom.rs
@@ -92,7 +92,7 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
 extern fn rust_eh_personality() {}
 
 #[derive(Debug)]
-struct Page([[u64; 32]; 16]);
+struct Page(#[allow(unused_tuple_struct_fields)] [[u64; 32]; 16]);
 
 #[start]
 pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
diff --git a/src/test/ui/allocator/no_std-alloc-error-handler-default.rs b/src/test/ui/allocator/no_std-alloc-error-handler-default.rs
index d6cd4a6af85..ffa331a992c 100644
--- a/src/test/ui/allocator/no_std-alloc-error-handler-default.rs
+++ b/src/test/ui/allocator/no_std-alloc-error-handler-default.rs
@@ -79,7 +79,7 @@ fn panic(panic_info: &core::panic::PanicInfo) -> ! {
 extern fn rust_eh_personality() {}
 
 #[derive(Debug)]
-struct Page([[u64; 32]; 16]);
+struct Page(#[allow(unused_tuple_struct_fields)] [[u64; 32]; 16]);
 
 #[start]
 pub fn main(_argc: isize, _argv: *const *const u8) -> isize {
diff --git a/src/test/ui/argument-suggestions/issue-100154.rs b/src/test/ui/argument-suggestions/issue-100154.rs
new file mode 100644
index 00000000000..4446b4bc2fc
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-100154.rs
@@ -0,0 +1,7 @@
+fn foo(i: impl std::fmt::Display) {}
+
+fn main() {
+    foo::<()>(());
+    //~^ ERROR this function takes 0 generic arguments but 1 generic argument was supplied
+    //~| ERROR `()` doesn't implement `std::fmt::Display`
+}
diff --git a/src/test/ui/argument-suggestions/issue-100154.stderr b/src/test/ui/argument-suggestions/issue-100154.stderr
new file mode 100644
index 00000000000..1499229c3ce
--- /dev/null
+++ b/src/test/ui/argument-suggestions/issue-100154.stderr
@@ -0,0 +1,35 @@
+error[E0107]: this function takes 0 generic arguments but 1 generic argument was supplied
+  --> $DIR/issue-100154.rs:4:5
+   |
+LL |     foo::<()>(());
+   |     ^^^------ help: remove these generics
+   |     |
+   |     expected 0 generic arguments
+   |
+note: function defined here, with 0 generic parameters
+  --> $DIR/issue-100154.rs:1:4
+   |
+LL | fn foo(i: impl std::fmt::Display) {}
+   |    ^^^
+   = note: `impl Trait` cannot be explicitly specified as a generic argument
+
+error[E0277]: `()` doesn't implement `std::fmt::Display`
+  --> $DIR/issue-100154.rs:4:15
+   |
+LL |     foo::<()>(());
+   |     --------- ^^ `()` cannot be formatted with the default formatter
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `std::fmt::Display` is not implemented for `()`
+   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+note: required by a bound in `foo`
+  --> $DIR/issue-100154.rs:1:16
+   |
+LL | fn foo(i: impl std::fmt::Display) {}
+   |                ^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0107, E0277.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/array-slice-vec/show-boxed-slice.rs b/src/test/ui/array-slice-vec/show-boxed-slice.rs
index dfa4c720bb0..c10f779b1f6 100644
--- a/src/test/ui/array-slice-vec/show-boxed-slice.rs
+++ b/src/test/ui/array-slice-vec/show-boxed-slice.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 #[derive(Debug)]
-struct Foo(Box<[u8]>);
+struct Foo(#[allow(unused_tuple_struct_fields)] Box<[u8]>);
 
 pub fn main() {
     println!("{:?}", Foo(Box::new([0, 1, 2])));
diff --git a/src/test/ui/asm/aarch64/bad-options.stderr b/src/test/ui/asm/aarch64/bad-options.stderr
index 867e0433eae..21bcc4a9c7b 100644
--- a/src/test/ui/asm/aarch64/bad-options.stderr
+++ b/src/test/ui/asm/aarch64/bad-options.stderr
@@ -36,41 +36,41 @@ LL |         asm!("{}", out(reg) foo, clobber_abi("C"));
    |                    |
    |                    generic outputs
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
   --> $DIR/bad-options.rs:28:25
    |
 LL | global_asm!("", options(nomem));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `readonly`
+error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
   --> $DIR/bad-options.rs:30:25
    |
 LL | global_asm!("", options(readonly));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `noreturn`
+error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
   --> $DIR/bad-options.rs:32:25
    |
 LL | global_asm!("", options(noreturn));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `pure`
+error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
   --> $DIR/bad-options.rs:34:25
    |
 LL | global_asm!("", options(pure));
-   |                         ^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nostack`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
   --> $DIR/bad-options.rs:36:25
    |
 LL | global_asm!("", options(nostack));
-   |                         ^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `preserves_flags`
+error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
   --> $DIR/bad-options.rs:38:25
    |
 LL | global_asm!("", options(preserves_flags));
-   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: invalid ABI for `clobber_abi`
   --> $DIR/bad-options.rs:20:18
diff --git a/src/test/ui/asm/aarch64/parse-error.stderr b/src/test/ui/asm/aarch64/parse-error.stderr
index f2013046cda..804966b06ba 100644
--- a/src/test/ui/asm/aarch64/parse-error.stderr
+++ b/src/test/ui/asm/aarch64/parse-error.stderr
@@ -260,23 +260,23 @@ error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
 LL | global_asm!("{}", const(reg) FOO);
    |                              ^^^ expected one of `,`, `.`, `?`, or an operator
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `FOO`
+error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
   --> $DIR/parse-error.rs:102:25
    |
 LL | global_asm!("", options(FOO));
-   |                         ^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
   --> $DIR/parse-error.rs:104:25
    |
 LL | global_asm!("", options(nomem FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
   --> $DIR/parse-error.rs:106:25
    |
 LL | global_asm!("", options(nomem, FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: arguments are not allowed after options
   --> $DIR/parse-error.rs:108:30
diff --git a/src/test/ui/asm/x86_64/bad-options.stderr b/src/test/ui/asm/x86_64/bad-options.stderr
index a63c42aac27..e2351840eef 100644
--- a/src/test/ui/asm/x86_64/bad-options.stderr
+++ b/src/test/ui/asm/x86_64/bad-options.stderr
@@ -45,41 +45,41 @@ LL |         asm!("{}", out(reg) foo, clobber_abi("C"), clobber_abi("C"));
    |                    |             clobber_abi
    |                    generic outputs
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
   --> $DIR/bad-options.rs:31:25
    |
 LL | global_asm!("", options(nomem));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `readonly`
+error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
   --> $DIR/bad-options.rs:33:25
    |
 LL | global_asm!("", options(readonly));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `noreturn`
+error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
   --> $DIR/bad-options.rs:35:25
    |
 LL | global_asm!("", options(noreturn));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `pure`
+error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
   --> $DIR/bad-options.rs:37:25
    |
 LL | global_asm!("", options(pure));
-   |                         ^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nostack`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
   --> $DIR/bad-options.rs:39:25
    |
 LL | global_asm!("", options(nostack));
-   |                         ^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `preserves_flags`
+error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
   --> $DIR/bad-options.rs:41:25
    |
 LL | global_asm!("", options(preserves_flags));
-   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: invalid ABI for `clobber_abi`
   --> $DIR/bad-options.rs:20:18
diff --git a/src/test/ui/asm/x86_64/parse-error.stderr b/src/test/ui/asm/x86_64/parse-error.stderr
index 1fd317a96a8..57702c37b7c 100644
--- a/src/test/ui/asm/x86_64/parse-error.stderr
+++ b/src/test/ui/asm/x86_64/parse-error.stderr
@@ -266,23 +266,23 @@ error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
 LL | global_asm!("{}", const(reg) FOO);
    |                              ^^^ expected one of `,`, `.`, `?`, or an operator
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `FOO`
+error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
   --> $DIR/parse-error.rs:104:25
    |
 LL | global_asm!("", options(FOO));
-   |                         ^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
   --> $DIR/parse-error.rs:106:25
    |
 LL | global_asm!("", options(nomem FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
-error: expected one of `)`, `att_syntax`, `may_unwind`, or `raw`, found `nomem`
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
   --> $DIR/parse-error.rs:108:25
    |
 LL | global_asm!("", options(nomem, FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, `may_unwind`, or `raw`
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
 
 error: arguments are not allowed after options
   --> $DIR/parse-error.rs:110:30
diff --git a/src/test/ui/associated-consts/associated-const-type-parameters.rs b/src/test/ui/associated-consts/associated-const-type-parameters.rs
index 47c3313ec28..e7ead1045e6 100644
--- a/src/test/ui/associated-consts/associated-const-type-parameters.rs
+++ b/src/test/ui/associated-consts/associated-const-type-parameters.rs
@@ -17,7 +17,7 @@ impl Foo for Def {
     const X: i32 = 97;
 }
 
-struct Proxy<T>(T);
+struct Proxy<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T: Foo> Foo for Proxy<T> {
     const X: i32 = T::X;
diff --git a/src/test/ui/associated-type-bounds/enum-bounds.rs b/src/test/ui/associated-type-bounds/enum-bounds.rs
index a6b0bb7070b..193f2efe199 100644
--- a/src/test/ui/associated-type-bounds/enum-bounds.rs
+++ b/src/test/ui/associated-type-bounds/enum-bounds.rs
@@ -1,6 +1,7 @@
 // run-pass
 
 #![feature(associated_type_bounds)]
+#![allow(dead_code)]
 
 trait Tr1 { type As1; }
 trait Tr2 { type As2; }
diff --git a/src/test/ui/associated-types/associated-types-method.rs b/src/test/ui/associated-types/associated-types-method.rs
index 64132cfeed7..45df3ac20c2 100644
--- a/src/test/ui/associated-types/associated-types-method.rs
+++ b/src/test/ui/associated-types/associated-types-method.rs
@@ -5,6 +5,7 @@
 trait Device {
     type Resources;
 }
+#[allow(unused_tuple_struct_fields)]
 struct Foo<D, R>(D, R);
 
 trait Tr {
diff --git a/src/test/ui/associated-types/associated-types-struct-field-numbered.rs b/src/test/ui/associated-types/associated-types-struct-field-numbered.rs
index fa59060629d..8612911d8f8 100644
--- a/src/test/ui/associated-types/associated-types-struct-field-numbered.rs
+++ b/src/test/ui/associated-types/associated-types-struct-field-numbered.rs
@@ -9,7 +9,7 @@ pub trait UnifyKey {
     fn dummy(&self) { }
 }
 
-pub struct Node<K:UnifyKey>(K, K::Value);
+pub struct Node<K:UnifyKey>(#[allow(unused_tuple_struct_fields)] K, K::Value);
 
 fn foo<K : UnifyKey<Value=Option<V>>,V : Clone>(node: &Node<K>) -> Option<V> {
     node.1.clone()
diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs
index a603ebd6e85..15566256600 100644
--- a/src/test/ui/async-await/async-fn-size-moved-locals.rs
+++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs
@@ -17,7 +17,7 @@ use std::pin::Pin;
 use std::task::{Context, Poll};
 
 const BIG_FUT_SIZE: usize = 1024;
-struct BigFut([u8; BIG_FUT_SIZE]);
+struct BigFut(#[allow(unused_tuple_struct_fields)] [u8; BIG_FUT_SIZE]);
 
 impl BigFut {
     fn new() -> Self {
diff --git a/src/test/ui/async-await/async-fn-size-uninit-locals.rs b/src/test/ui/async-await/async-fn-size-uninit-locals.rs
index d5d7b3fc3f0..31a086ba975 100644
--- a/src/test/ui/async-await/async-fn-size-uninit-locals.rs
+++ b/src/test/ui/async-await/async-fn-size-uninit-locals.rs
@@ -16,7 +16,7 @@ use std::pin::Pin;
 use std::task::{Context, Poll};
 
 const BIG_FUT_SIZE: usize = 1024;
-struct Big([u8; BIG_FUT_SIZE]);
+struct Big(#[allow(unused_tuple_struct_fields)] [u8; BIG_FUT_SIZE]);
 
 impl Big {
     fn new() -> Self {
diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr
index fd76c282f96..e6f6e9e9f65 100644
--- a/src/test/ui/async-await/no-const-async.stderr
+++ b/src/test/ui/async-await/no-const-async.stderr
@@ -35,7 +35,7 @@ note: cycle used when checking item types in top-level module
   --> $DIR/no-const-async.rs:4:1
    |
 LL | pub const async fn x() {}
-   | ^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/attributes/issue-90873.stderr b/src/test/ui/attributes/issue-90873.stderr
index 0852bb7ca8b..894ec8341f8 100644
--- a/src/test/ui/attributes/issue-90873.stderr
+++ b/src/test/ui/attributes/issue-90873.stderr
@@ -34,10 +34,10 @@ LL | #![a={impl std::ops::Neg for i8 {}}]
    |                                     ^ consider adding a `main` function to `$DIR/issue-90873.rs`
 
 error: missing type for `static` item
-  --> $DIR/issue-90873.rs:1:16
+  --> $DIR/issue-90873.rs:1:17
    |
 LL | #![u=||{static d=||1;}]
-   |                ^ help: provide a type for the item: `d: <type>`
+   |                 ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/auto-traits/auto-traits.rs b/src/test/ui/auto-traits/auto-traits.rs
index 567b86c2762..7b52d9c176e 100644
--- a/src/test/ui/auto-traits/auto-traits.rs
+++ b/src/test/ui/auto-traits/auto-traits.rs
@@ -9,7 +9,7 @@ unsafe auto trait AutoUnsafe {}
 impl !Auto for bool {}
 impl !AutoUnsafe for bool {}
 
-struct AutoBool(bool);
+struct AutoBool(#[allow(unused_tuple_struct_fields)] bool);
 
 impl Auto for AutoBool {}
 unsafe impl AutoUnsafe for AutoBool {}
diff --git a/src/test/ui/bench/issue-32062.rs b/src/test/ui/bench/issue-32062.rs
index dc45061da5b..7eb52196e16 100644
--- a/src/test/ui/bench/issue-32062.rs
+++ b/src/test/ui/bench/issue-32062.rs
@@ -15,7 +15,7 @@ trait Parser {
     }
 }
 
-struct Token<T>(T::Item) where T: Iterator;
+struct Token<T>(#[allow(unused_tuple_struct_fields)] T::Item) where T: Iterator;
 
 impl<T> Parser for Token<T> where T: Iterator {
     type Input = T;
@@ -25,7 +25,7 @@ impl<T> Parser for Token<T> where T: Iterator {
     }
 }
 
-struct Chain<L, R>(L, R);
+struct Chain<L, R>(#[allow(unused_tuple_struct_fields)] L, #[allow(unused_tuple_struct_fields)] R);
 
 impl<L, R> Parser for Chain<L, R> where L: Parser, R: Parser<Input = L::Input> {
     type Input = L::Input;
diff --git a/src/test/ui/binding/match-tag.rs b/src/test/ui/binding/match-tag.rs
index eceb6467784..407716aa28a 100644
--- a/src/test/ui/binding/match-tag.rs
+++ b/src/test/ui/binding/match-tag.rs
@@ -3,7 +3,7 @@
 #![allow(non_camel_case_types)]
 
 
-
+#[allow(unused_tuple_struct_fields)]
 enum color {
     rgb(isize, isize, isize),
     rgba(isize, isize, isize, isize),
diff --git a/src/test/ui/binding/or-pattern.rs b/src/test/ui/binding/or-pattern.rs
index 2ab44a96c3a..47623a3d722 100644
--- a/src/test/ui/binding/or-pattern.rs
+++ b/src/test/ui/binding/or-pattern.rs
@@ -1,7 +1,7 @@
 // run-pass
 #![allow(non_camel_case_types)]
 
-enum blah { a(isize, isize, usize), b(isize, isize), c, }
+enum blah { a(isize, isize, #[allow(unused_tuple_struct_fields)] usize), b(isize, isize), c, }
 
 fn or_alt(q: blah) -> isize {
     match q { blah::a(x, y, _) | blah::b(x, y) => { return x + y; } blah::c => { return 0; } }
diff --git a/src/test/ui/binding/simple-generic-match.rs b/src/test/ui/binding/simple-generic-match.rs
index 50cfe19fef4..2cf050d011d 100644
--- a/src/test/ui/binding/simple-generic-match.rs
+++ b/src/test/ui/binding/simple-generic-match.rs
@@ -3,6 +3,6 @@
 
 // pretty-expanded FIXME #23616
 
-enum clam<T> { a(T), }
+enum clam<T> { a(#[allow(unused_tuple_struct_fields)] T), }
 
 pub fn main() { let c = clam::a(2); match c { clam::a::<isize>(_) => { } } }
diff --git a/src/test/ui/borrowck/access-mode-in-closures.stderr b/src/test/ui/borrowck/access-mode-in-closures.stderr
index c32e944afe3..13a6277da14 100644
--- a/src/test/ui/borrowck/access-mode-in-closures.stderr
+++ b/src/test/ui/borrowck/access-mode-in-closures.stderr
@@ -1,4 +1,4 @@
-error[E0507]: cannot move out of `s.0` which is behind a shared reference
+error[E0507]: cannot move out of `s` which is behind a shared reference
   --> $DIR/access-mode-in-closures.rs:8:15
    |
 LL |         match *s { S(v) => v }
diff --git a/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr b/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr
index c08c93f3617..fc1a44c3ca0 100644
--- a/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr
+++ b/src/test/ui/borrowck/borrowck-for-loop-uninitialized-binding.stderr
@@ -4,7 +4,7 @@ error[E0381]: used binding `x` is possibly-uninitialized
 LL |     let mut x: isize;
    |         ----- binding declared here but left uninitialized
 LL |     for _ in 0..0 { x = 10; }
-   |              ---- if the `for` loop runs 0 times, `x` is not initialized 
+   |              ---- if the `for` loop runs 0 times, `x` is not initialized
 LL |     return x;
    |            ^ `x` used here but it is possibly-uninitialized
 
diff --git a/src/test/ui/borrowck/borrowck-move-error-with-note.stderr b/src/test/ui/borrowck/borrowck-move-error-with-note.stderr
index ead02414a62..96246d9ae1a 100644
--- a/src/test/ui/borrowck/borrowck-move-error-with-note.stderr
+++ b/src/test/ui/borrowck/borrowck-move-error-with-note.stderr
@@ -1,4 +1,4 @@
-error[E0507]: cannot move out of `f.0` which is behind a shared reference
+error[E0507]: cannot move out of `f` as enum variant `Foo1` which is behind a shared reference
   --> $DIR/borrowck-move-error-with-note.rs:11:11
    |
 LL |     match *f {
diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs
index 117014b44ee..cdde48871ea 100644
--- a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs
+++ b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata2.rs
@@ -12,7 +12,7 @@ use trait_superkinds_in_metadata::RequiresCopy;
 use std::marker;
 
 #[derive(Copy, Clone)]
-struct X<T>(T);
+struct X<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T:Sync> RequiresShare for X<T> { }
 
diff --git a/src/test/ui/chalkify/builtin-copy-clone.rs b/src/test/ui/chalkify/builtin-copy-clone.rs
index 4323e87b08d..7712e946542 100644
--- a/src/test/ui/chalkify/builtin-copy-clone.rs
+++ b/src/test/ui/chalkify/builtin-copy-clone.rs
@@ -4,7 +4,7 @@
 // Test that `Clone` is correctly implemented for builtin types.
 
 #[derive(Copy, Clone)]
-struct S(i32);
+struct S(#[allow(unused_tuple_struct_fields)] i32);
 
 fn test_clone<T: Clone>(arg: T) {
     let _ = arg.clone();
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed
index 2b86b0ddade..173dd2e2cff 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed
@@ -18,10 +18,10 @@ impl Foo {
     }
 }
 
-struct S(Foo);
+struct S(#[allow(unused_tuple_struct_fields)] Foo);
 
 #[derive(Clone)]
-struct T(i32);
+struct T(#[allow(unused_tuple_struct_fields)] i32);
 
 struct U(S, T);
 
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs
index 3cac4abfad7..cfc4555ca03 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs
@@ -18,10 +18,10 @@ impl Foo {
     }
 }
 
-struct S(Foo);
+struct S(#[allow(unused_tuple_struct_fields)] Foo);
 
 #[derive(Clone)]
-struct T(i32);
+struct T(#[allow(unused_tuple_struct_fields)] i32);
 
 struct U(S, T);
 
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed
index 63e4000e833..e99dbb5ab3a 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed
@@ -13,7 +13,7 @@ impl Drop for Foo {
 }
 
 #[derive(Debug)]
-struct ConstainsDropField(Foo, Foo);
+struct ConstainsDropField(Foo, #[allow(unused_tuple_struct_fields)] Foo);
 
 // `t` needs Drop because one of its elements needs drop,
 // therefore precise capture might affect drop ordering
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs
index 9d9c54298cf..62a984c9eeb 100644
--- a/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs
+++ b/src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs
@@ -13,7 +13,7 @@ impl Drop for Foo {
 }
 
 #[derive(Debug)]
-struct ConstainsDropField(Foo, Foo);
+struct ConstainsDropField(Foo, #[allow(unused_tuple_struct_fields)] Foo);
 
 // `t` needs Drop because one of its elements needs drop,
 // therefore precise capture might affect drop ordering
diff --git a/src/test/ui/closures/issue-84128.stderr b/src/test/ui/closures/issue-84128.stderr
index 09c44d261af..59607afec8f 100644
--- a/src/test/ui/closures/issue-84128.stderr
+++ b/src/test/ui/closures/issue-84128.stderr
@@ -6,11 +6,6 @@ LL |         Foo(())
    |         |
    |         arguments to this struct are incorrect
    |
-note: return type inferred to be `{integer}` here
-  --> $DIR/issue-84128.rs:10:20
-   |
-LL |             return Foo(0);
-   |                    ^^^^^^
 note: tuple struct defined here
   --> $DIR/issue-84128.rs:5:8
    |
diff --git a/src/test/ui/closures/issue-90871.rs b/src/test/ui/closures/issue-90871.rs
new file mode 100644
index 00000000000..9c70bbc85ac
--- /dev/null
+++ b/src/test/ui/closures/issue-90871.rs
@@ -0,0 +1,5 @@
+fn main() {
+    2: n([u8; || 1])
+    //~^ ERROR cannot find type `n` in this scope
+    //~| ERROR mismatched types
+}
diff --git a/src/test/ui/closures/issue-90871.stderr b/src/test/ui/closures/issue-90871.stderr
new file mode 100644
index 00000000000..1e102cc9805
--- /dev/null
+++ b/src/test/ui/closures/issue-90871.stderr
@@ -0,0 +1,23 @@
+error[E0412]: cannot find type `n` in this scope
+  --> $DIR/issue-90871.rs:2:8
+   |
+LL |     2: n([u8; || 1])
+   |        ^ expecting a type here because of type ascription
+
+error[E0308]: mismatched types
+  --> $DIR/issue-90871.rs:2:15
+   |
+LL |     2: n([u8; || 1])
+   |               ^^^^ expected `usize`, found closure
+   |
+   = note: expected type `usize`
+           found closure `[closure@$DIR/issue-90871.rs:2:15: 2:17]`
+help: use parentheses to call this closure
+   |
+LL |     2: n([u8; (|| 1)()])
+   |               +    +++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0412.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/codegen/issue-16602-3.rs b/src/test/ui/codegen/issue-16602-3.rs
index dbfeef053da..ca1ab3cc7fe 100644
--- a/src/test/ui/codegen/issue-16602-3.rs
+++ b/src/test/ui/codegen/issue-16602-3.rs
@@ -2,6 +2,7 @@
 #![allow(unused_variables)]
 #![allow(unused_assignments)]
 #[derive(Debug)]
+#[allow(unused_tuple_struct_fields)]
 enum Foo {
     Bar(u32, u32),
     Baz(&'static u32, &'static u32)
diff --git a/src/test/ui/coercion/issue-14589.rs b/src/test/ui/coercion/issue-14589.rs
index 5d8aab2ce74..d35ee5c731e 100644
--- a/src/test/ui/coercion/issue-14589.rs
+++ b/src/test/ui/coercion/issue-14589.rs
@@ -20,5 +20,5 @@ impl<T> Test<T> {
 }
 
 trait Foo { fn dummy(&self) { }}
-struct Output(isize);
+struct Output(#[allow(unused_tuple_struct_fields)] isize);
 impl Foo for Output {}
diff --git a/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs b/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs
index aa0f9131aa7..c9e26c302bf 100644
--- a/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs
+++ b/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-1.rs
@@ -9,6 +9,7 @@ trait Foo {
     const ASSOC: usize = 1;
 }
 
+#[allow(unused_tuple_struct_fields)]
 struct Iced<T: Foo>(T, [(); T::ASSOC])
 where
     [(); T::ASSOC]: ;
diff --git a/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs b/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs
index d0864414cc1..3017920fc98 100644
--- a/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs
+++ b/src/test/ui/const-generics/conservative_is_privately_uninhabited_uses_correct_param_env-2.rs
@@ -9,6 +9,7 @@ trait Foo {
     const ASSOC: usize = 1;
 }
 
+#[allow(unused_tuple_struct_fields)]
 struct Iced<T: Foo>(T, [(); T::ASSOC])
 where
     [(); T::ASSOC]: ;
diff --git a/src/test/ui/const-generics/const-argument-cross-crate.rs b/src/test/ui/const-generics/const-argument-cross-crate.rs
index fda3ec3eef7..5693409e992 100644
--- a/src/test/ui/const-generics/const-argument-cross-crate.rs
+++ b/src/test/ui/const-generics/const-argument-cross-crate.rs
@@ -4,7 +4,7 @@
 
 extern crate const_generic_lib;
 
-struct Container(const_generic_lib::Alias);
+struct Container(#[allow(unused_tuple_struct_fields)] const_generic_lib::Alias);
 
 fn main() {
     let res = const_generic_lib::function(const_generic_lib::Struct([14u8, 1u8, 2u8]));
diff --git a/src/test/ui/const-generics/generic_const_exprs/associated-consts.rs b/src/test/ui/const-generics/generic_const_exprs/associated-consts.rs
index 4d89f188ad7..b839008d424 100644
--- a/src/test/ui/const-generics/generic_const_exprs/associated-consts.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/associated-consts.rs
@@ -16,7 +16,7 @@ impl BlockCipher for BarCipher {
     const BLOCK_SIZE: usize = 32;
 }
 
-pub struct Block<C>(C);
+pub struct Block<C>(#[allow(unused_tuple_struct_fields)] C);
 
 pub fn test<C: BlockCipher, const M: usize>()
 where
diff --git a/src/test/ui/consts/assoc-const.rs b/src/test/ui/consts/assoc-const.rs
index b70479d255b..f542f2dcb52 100644
--- a/src/test/ui/consts/assoc-const.rs
+++ b/src/test/ui/consts/assoc-const.rs
@@ -6,7 +6,7 @@ trait Nat {
 }
 
 struct Zero;
-struct Succ<N>(N);
+struct Succ<N>(#[allow(unused_tuple_struct_fields)] N);
 
 impl Nat for Zero {
     const VALUE: usize = 0;
diff --git a/src/test/ui/consts/const-needs_drop.rs b/src/test/ui/consts/const-needs_drop.rs
index 58e80116442..11ee7084ce8 100644
--- a/src/test/ui/consts/const-needs_drop.rs
+++ b/src/test/ui/consts/const-needs_drop.rs
@@ -2,8 +2,10 @@
 
 use std::mem;
 
+#[allow(unused_tuple_struct_fields)]
 struct Trivial(u8, f32);
 
+#[allow(unused_tuple_struct_fields)]
 struct NonTrivial(u8, String);
 
 const CONST_U8: bool = mem::needs_drop::<u8>();
diff --git a/src/test/ui/consts/const-size_of_val-align_of_val.rs b/src/test/ui/consts/const-size_of_val-align_of_val.rs
index c3de6dc2075..e8323e4ae60 100644
--- a/src/test/ui/consts/const-size_of_val-align_of_val.rs
+++ b/src/test/ui/consts/const-size_of_val-align_of_val.rs
@@ -5,7 +5,7 @@
 
 use std::{mem, ptr};
 
-struct Foo(u32);
+struct Foo(#[allow(unused_tuple_struct_fields)] u32);
 
 #[derive(Clone, Copy)]
 struct Bar {
diff --git a/src/test/ui/consts/const_in_pattern/warn_corner_cases.rs b/src/test/ui/consts/const_in_pattern/warn_corner_cases.rs
index 51e1af359cd..15cf3c84d85 100644
--- a/src/test/ui/consts/const_in_pattern/warn_corner_cases.rs
+++ b/src/test/ui/consts/const_in_pattern/warn_corner_cases.rs
@@ -15,7 +15,7 @@
 #![warn(indirect_structural_match)]
 
 #[derive(Copy, Clone, Debug)]
-struct NoDerive(u32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] u32);
 
 // This impl makes `NoDerive` irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
diff --git a/src/test/ui/consts/issue-44415.stderr b/src/test/ui/consts/issue-44415.stderr
index c085beb0ea5..57f94f8c6ab 100644
--- a/src/test/ui/consts/issue-44415.stderr
+++ b/src/test/ui/consts/issue-44415.stderr
@@ -2,18 +2,18 @@ error[E0391]: cycle detected when evaluating type-level constant
   --> $DIR/issue-44415.rs:6:17
    |
 LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
-   |                 ^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
   --> $DIR/issue-44415.rs:6:17
    |
 LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
-   |                 ^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
   --> $DIR/issue-44415.rs:6:17
    |
 LL |     bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
-   |                 ^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires computing layout of `Foo`...
    = note: ...which requires computing layout of `[u8; _]`...
    = note: ...which requires normalizing `[u8; _]`...
diff --git a/src/test/ui/consts/issue-70773-mir-typeck-lt-norm.rs b/src/test/ui/consts/issue-70773-mir-typeck-lt-norm.rs
index 9d44aa1361c..dd56faa3185 100644
--- a/src/test/ui/consts/issue-70773-mir-typeck-lt-norm.rs
+++ b/src/test/ui/consts/issue-70773-mir-typeck-lt-norm.rs
@@ -1,7 +1,7 @@
 // run-pass
 
 const HASH_LEN: usize = 20;
-struct Hash([u8; HASH_LEN]);
+struct Hash(#[allow(unused_tuple_struct_fields)] [u8; HASH_LEN]);
 fn init_hash(_: &mut [u8; HASH_LEN]) {}
 
 fn foo<'a>() -> &'a () {
diff --git a/src/test/ui/consts/rvalue-static-promotion.rs b/src/test/ui/consts/rvalue-static-promotion.rs
index 2d7e4ab3989..c48d9eae928 100644
--- a/src/test/ui/consts/rvalue-static-promotion.rs
+++ b/src/test/ui/consts/rvalue-static-promotion.rs
@@ -4,7 +4,7 @@ use std::cell::Cell;
 
 const NONE_CELL_STRING: Option<Cell<String>> = None;
 
-struct Foo<T>(T);
+struct Foo<T>(#[allow(unused_tuple_struct_fields)] T);
 impl<T> Foo<T> {
     const FOO: Option<Box<T>> = None;
 }
diff --git a/src/test/ui/consts/transmute-const.rs b/src/test/ui/consts/transmute-const.rs
index 5044d99ec51..c5c3dfc4cc7 100644
--- a/src/test/ui/consts/transmute-const.rs
+++ b/src/test/ui/consts/transmute-const.rs
@@ -3,7 +3,7 @@
 use std::mem;
 
 #[repr(transparent)]
-struct Foo(u32);
+struct Foo(#[allow(unused_tuple_struct_fields)] u32);
 
 const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) };
 
diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr
index fc842fada5a..d4976a0f9c9 100644
--- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr
+++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr
@@ -8,8 +8,13 @@ LL | trait Foo<X = Box<dyn Foo>> {
 note: cycle used when collecting item types in top-level module
   --> $DIR/cycle-trait-default-type-trait.rs:4:1
    |
-LL | trait Foo<X = Box<dyn Foo>> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<X = Box<dyn Foo>> {
+LL | |
+LL | |
+LL | | }
+LL | |
+LL | | fn main() { }
+   | |_____________^
 
 error[E0391]: cycle detected when computing type of `Foo::X`
   --> $DIR/cycle-trait-default-type-trait.rs:4:23
@@ -21,8 +26,13 @@ LL | trait Foo<X = Box<dyn Foo>> {
 note: cycle used when collecting item types in top-level module
   --> $DIR/cycle-trait-default-type-trait.rs:4:1
    |
-LL | trait Foo<X = Box<dyn Foo>> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Foo<X = Box<dyn Foo>> {
+LL | |
+LL | |
+LL | | }
+LL | |
+LL | | fn main() { }
+   | |_____________^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr
index ee54b2fd151..f6ffcc4b5aa 100644
--- a/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr
+++ b/src/test/ui/cycle-trait/cycle-trait-supertrait-direct.stderr
@@ -13,8 +13,10 @@ LL | trait Chromosome: Chromosome {
 note: cycle used when collecting item types in top-level module
   --> $DIR/cycle-trait-supertrait-direct.rs:3:1
    |
-LL | trait Chromosome: Chromosome {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | / trait Chromosome: Chromosome {
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/deriving/deriving-clone-generic-tuple-struct.rs b/src/test/ui/deriving/deriving-clone-generic-tuple-struct.rs
index 8b9840de172..3480ccc1089 100644
--- a/src/test/ui/deriving/deriving-clone-generic-tuple-struct.rs
+++ b/src/test/ui/deriving/deriving-clone-generic-tuple-struct.rs
@@ -2,6 +2,7 @@
 // pretty-expanded FIXME #23616
 
 #[derive(Clone)]
+#[allow(unused_tuple_struct_fields)]
 struct S<T>(T, ());
 
 pub fn main() {
diff --git a/src/test/ui/deriving/deriving-copyclone.rs b/src/test/ui/deriving/deriving-copyclone.rs
index 78d74a11ffc..f8403b1feac 100644
--- a/src/test/ui/deriving/deriving-copyclone.rs
+++ b/src/test/ui/deriving/deriving-copyclone.rs
@@ -23,7 +23,7 @@ impl Clone for Liar {
 
 /// This struct is actually Copy... at least, it thinks it is!
 #[derive(Copy, Clone)]
-struct Innocent(Liar);
+struct Innocent(#[allow(unused_tuple_struct_fields)] Liar);
 
 impl Innocent {
     fn new() -> Self {
diff --git a/src/test/ui/deriving/issue-58319.rs b/src/test/ui/deriving/issue-58319.rs
index 757307d944f..8041bd5bb3c 100644
--- a/src/test/ui/deriving/issue-58319.rs
+++ b/src/test/ui/deriving/issue-58319.rs
@@ -3,6 +3,7 @@ fn main() {}
 #[derive(Clone)]
 pub struct Little;
 #[derive(Clone)]
+#[allow(unused_tuple_struct_fields)]
 pub struct Big(
     Little,
     Little,
diff --git a/src/test/ui/did_you_mean/use_instead_of_import.fixed b/src/test/ui/did_you_mean/use_instead_of_import.fixed
index 87d453e1565..a8aae76f4fc 100644
--- a/src/test/ui/did_you_mean/use_instead_of_import.fixed
+++ b/src/test/ui/did_you_mean/use_instead_of_import.fixed
@@ -6,10 +6,18 @@ use std::{
     rc::Rc,
 };
 
+use std::time::Duration;
+//~^ ERROR expected item, found `require`
+
+use std::time::Instant;
+//~^ ERROR expected item, found `include`
+
 pub use std::io;
 //~^ ERROR expected item, found `using`
 
 fn main() {
     let x = Rc::new(1);
     let _ = write!(io::stdout(), "{:?}", x);
+    let _ = Duration::new(5, 0);
+    let _ = Instant::now();
 }
diff --git a/src/test/ui/did_you_mean/use_instead_of_import.rs b/src/test/ui/did_you_mean/use_instead_of_import.rs
index 59e83732328..2db7c240752 100644
--- a/src/test/ui/did_you_mean/use_instead_of_import.rs
+++ b/src/test/ui/did_you_mean/use_instead_of_import.rs
@@ -6,10 +6,18 @@ import std::{
     rc::Rc,
 };
 
+require std::time::Duration;
+//~^ ERROR expected item, found `require`
+
+include std::time::Instant;
+//~^ ERROR expected item, found `include`
+
 pub using std::io;
 //~^ ERROR expected item, found `using`
 
 fn main() {
     let x = Rc::new(1);
     let _ = write!(io::stdout(), "{:?}", x);
+    let _ = Duration::new(5, 0);
+    let _ = Instant::now();
 }
diff --git a/src/test/ui/did_you_mean/use_instead_of_import.stderr b/src/test/ui/did_you_mean/use_instead_of_import.stderr
index b22954af80f..2aac8f68c5e 100644
--- a/src/test/ui/did_you_mean/use_instead_of_import.stderr
+++ b/src/test/ui/did_you_mean/use_instead_of_import.stderr
@@ -4,11 +4,23 @@ error: expected item, found `import`
 LL | import std::{
    | ^^^^^^ help: items are imported using the `use` keyword
 
+error: expected item, found `require`
+  --> $DIR/use_instead_of_import.rs:9:1
+   |
+LL | require std::time::Duration;
+   | ^^^^^^^ help: items are imported using the `use` keyword
+
+error: expected item, found `include`
+  --> $DIR/use_instead_of_import.rs:12:1
+   |
+LL | include std::time::Instant;
+   | ^^^^^^^ help: items are imported using the `use` keyword
+
 error: expected item, found `using`
-  --> $DIR/use_instead_of_import.rs:9:5
+  --> $DIR/use_instead_of_import.rs:15:5
    |
 LL | pub using std::io;
    |     ^^^^^ help: items are imported using the `use` keyword
 
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/drop/dropck-eyepatch-reorder.rs b/src/test/ui/drop/dropck-eyepatch-reorder.rs
index b4605878a54..0d7af3d4f61 100644
--- a/src/test/ui/drop/dropck-eyepatch-reorder.rs
+++ b/src/test/ui/drop/dropck-eyepatch-reorder.rs
@@ -12,10 +12,10 @@ trait Foo { fn foo(&self, _: &str); }
 
 struct Dt<A: Foo>(&'static str, A);
 struct Dr<'a, B:'a+Foo>(&'static str, &'a B);
-struct Pt<A: Foo, B: Foo>(&'static str, A, B);
-struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B);
-struct St<A: Foo>(&'static str, A);
-struct Sr<'a, B:'a+Foo>(&'static str, &'a B);
+struct Pt<A: Foo, B: Foo>(&'static str, #[allow(unused_tuple_struct_fields)] A, B);
+struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, #[allow(unused_tuple_struct_fields)] &'a B, &'b B);
+struct St<A: Foo>(&'static str, #[allow(unused_tuple_struct_fields)] A);
+struct Sr<'a, B:'a+Foo>(&'static str, #[allow(unused_tuple_struct_fields)] &'a B);
 
 impl<A: Foo> Drop for Dt<A> {
     fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
diff --git a/src/test/ui/drop/dropck-eyepatch.rs b/src/test/ui/drop/dropck-eyepatch.rs
index 9255391e412..3c4840d5c7a 100644
--- a/src/test/ui/drop/dropck-eyepatch.rs
+++ b/src/test/ui/drop/dropck-eyepatch.rs
@@ -35,10 +35,10 @@ trait Foo { fn foo(&self, _: &str); }
 
 struct Dt<A: Foo>(&'static str, A);
 struct Dr<'a, B:'a+Foo>(&'static str, &'a B);
-struct Pt<A,B: Foo>(&'static str, A, B);
-struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, &'a B, &'b B);
-struct St<A: Foo>(&'static str, A);
-struct Sr<'a, B:'a+Foo>(&'static str, &'a B);
+struct Pt<A,B: Foo>(&'static str, #[allow(unused_tuple_struct_fields)] A, B);
+struct Pr<'a, 'b, B:'a+'b+Foo>(&'static str, #[allow(unused_tuple_struct_fields)] &'a B, &'b B);
+struct St<A: Foo>(&'static str, #[allow(unused_tuple_struct_fields)] A);
+struct Sr<'a, B:'a+Foo>(&'static str, #[allow(unused_tuple_struct_fields)] &'a B);
 
 impl<A: Foo> Drop for Dt<A> {
     fn drop(&mut self) { println!("drop {}", self.0); self.1.foo(self.0); }
diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs
index 736123ed119..e7068677423 100644
--- a/src/test/ui/drop/dynamic-drop.rs
+++ b/src/test/ui/drop/dynamic-drop.rs
@@ -103,7 +103,7 @@ fn dynamic_drop(a: &Allocator, c: bool) {
     };
 }
 
-struct TwoPtrs<'a>(Ptr<'a>, Ptr<'a>);
+struct TwoPtrs<'a>(Ptr<'a>, #[allow(unused_tuple_struct_fields)] Ptr<'a>);
 fn struct_dynamic_drop(a: &Allocator, c0: bool, c1: bool, c: bool) {
     for i in 0..2 {
         let x;
diff --git a/src/test/ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs b/src/test/ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs
index 23fd86a093b..04d0d32033a 100644
--- a/src/test/ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs
+++ b/src/test/ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs
@@ -21,7 +21,7 @@ impl Drop for ScribbleOnDrop {
     }
 }
 
-struct Foo<T>(u32, T, Box<for <'r> fn(&'r T) -> String>);
+struct Foo<T>(u32, T, #[allow(unused_tuple_struct_fields)] Box<for <'r> fn(&'r T) -> String>);
 
 unsafe impl<#[may_dangle] T> Drop for Foo<T> {
     fn drop(&mut self) {
diff --git a/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs b/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs
index 65dc9166330..8e162d5c455 100644
--- a/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs
+++ b/src/test/ui/enum-discriminant/discriminant_value-wrapper.rs
@@ -4,6 +4,7 @@
 
 use std::mem;
 
+#[allow(unused_tuple_struct_fields)]
 enum ADT {
     First(u32, u32),
     Second(u64)
diff --git a/src/test/ui/enum-discriminant/discriminant_value.rs b/src/test/ui/enum-discriminant/discriminant_value.rs
index eb60aaf4b2d..65ab411dbcb 100644
--- a/src/test/ui/enum-discriminant/discriminant_value.rs
+++ b/src/test/ui/enum-discriminant/discriminant_value.rs
@@ -27,13 +27,14 @@ enum CLike3 {
     D
 }
 
+#[allow(unused_tuple_struct_fields)]
 enum ADT {
     First(u32, u32),
     Second(u64)
 }
 
 enum NullablePointer {
-    Something(&'static u32),
+    Something(#[allow(unused_tuple_struct_fields)] &'static u32),
     Nothing
 }
 
diff --git a/src/test/ui/expr/if/if-branch-types.stderr b/src/test/ui/expr/if/if-branch-types.stderr
index 14f02163a83..d2bba88211e 100644
--- a/src/test/ui/expr/if/if-branch-types.stderr
+++ b/src/test/ui/expr/if/if-branch-types.stderr
@@ -5,6 +5,11 @@ LL |     let x = if true { 10i32 } else { 10u32 };
    |                       -----          ^^^^^ expected `i32`, found `u32`
    |                       |
    |                       expected because of this
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |     let x = if true { 10i32 } else { 10i32 };
+   |                                        ~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/expr/if/if-else-type-mismatch.stderr b/src/test/ui/expr/if/if-else-type-mismatch.stderr
index 9fa190d6c9d..f1fffdb1e7e 100644
--- a/src/test/ui/expr/if/if-else-type-mismatch.stderr
+++ b/src/test/ui/expr/if/if-else-type-mismatch.stderr
@@ -10,6 +10,11 @@ LL | |         2u32
    | |         ^^^^ expected `i32`, found `u32`
 LL | |     };
    | |_____- `if` and `else` have incompatible types
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         2i32
+   |          ~~~
 
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/if-else-type-mismatch.rs:8:38
@@ -18,6 +23,11 @@ LL |     let _ = if true { 42i32 } else { 42u32 };
    |                       -----          ^^^^^ expected `i32`, found `u32`
    |                       |
    |                       expected because of this
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |     let _ = if true { 42i32 } else { 42i32 };
+   |                                        ~~~
 
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/if-else-type-mismatch.rs:13:9
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs
index 518aa20dd68..0594b1384ec 100644
--- a/src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs
+++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-2.rs
@@ -3,6 +3,9 @@ extern "C" {
     #[link_ordinal(42)]
     //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
     fn foo();
+    #[link_ordinal(5)]
+    //~^ ERROR: the `#[link_ordinal]` attribute is an experimental feature
+    static mut imported_variable: i32;
 }
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr
index dbee5f316b0..d39969b61ca 100644
--- a/src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr
+++ b/src/test/ui/feature-gates/feature-gate-raw-dylib-2.stderr
@@ -7,6 +7,15 @@ LL |     #[link_ordinal(42)]
    = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
    = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
 
-error: aborting due to previous error
+error[E0658]: the `#[link_ordinal]` attribute is an experimental feature
+  --> $DIR/feature-gate-raw-dylib-2.rs:6:5
+   |
+LL |     #[link_ordinal(5)]
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
index 5d6796b4944..310d1f720eb 100644
--- a/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
+++ b/src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
@@ -212,7 +212,7 @@ note: the lint level is defined here
 LL | #![warn(unused_attributes, unknown_lints)]
    |         ^^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:1
    |
 LL | #[automatically_derived]
@@ -515,25 +515,25 @@ warning: `#[path]` only has an effect on modules
 LL |     #[path = "3800"] impl S { }
    |     ^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:17
    |
 LL |     mod inner { #![automatically_derived] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5
    |
 LL |     #[automatically_derived] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:5
    |
 LL |     #[automatically_derived] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: `#[automatically_derived]` only has an effect on items
+warning: `#[automatically_derived]` only has an effect on implementation blocks
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:278:5
    |
 LL |     #[automatically_derived] type T = S;
@@ -923,7 +923,7 @@ warning: `#[must_use]` has no effect when applied to a type alias
 LL |     #[must_use] type T = S;
    |     ^^^^^^^^^^^
 
-warning: `#[must_use]` has no effect when applied to an item
+warning: `#[must_use]` has no effect when applied to an implementation block
   --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:5
    |
 LL |     #[must_use] impl S { }
diff --git a/src/test/ui/fmt/struct-field-as-captured-argument.fixed b/src/test/ui/fmt/struct-field-as-captured-argument.fixed
new file mode 100644
index 00000000000..f7244f6744f
--- /dev/null
+++ b/src/test/ui/fmt/struct-field-as-captured-argument.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#[derive(Debug)]
+struct Foo {
+    field: usize,
+}
+
+fn main() {
+    let foo = Foo { field: 0 };
+    let bar = 3;
+    format!("{0}", foo.field); //~ ERROR invalid format string: field access isn't supported
+    format!("{1} {} {bar}", "aa", foo.field); //~ ERROR invalid format string: field access isn't supported
+    format!("{2} {} {1} {bar}", "aa", "bb", foo.field); //~ ERROR invalid format string: field access isn't supported
+    format!("{1} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+    format!("{1:?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+    format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+    format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3); //~ ERROR invalid format string: field access isn't supported
+}
diff --git a/src/test/ui/fmt/struct-field-as-captured-argument.rs b/src/test/ui/fmt/struct-field-as-captured-argument.rs
new file mode 100644
index 00000000000..ab5f2552bd3
--- /dev/null
+++ b/src/test/ui/fmt/struct-field-as-captured-argument.rs
@@ -0,0 +1,18 @@
+// run-rustfix
+
+#[derive(Debug)]
+struct Foo {
+    field: usize,
+}
+
+fn main() {
+    let foo = Foo { field: 0 };
+    let bar = 3;
+    format!("{foo.field}"); //~ ERROR invalid format string: field access isn't supported
+    format!("{foo.field} {} {bar}", "aa"); //~ ERROR invalid format string: field access isn't supported
+    format!("{foo.field} {} {1} {bar}", "aa", "bb"); //~ ERROR invalid format string: field access isn't supported
+    format!("{foo.field} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+    format!("{foo.field:?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+    format!("{foo.field:#?} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+    format!("{foo.field:.3} {} {baz}", "aa", baz = 3); //~ ERROR invalid format string: field access isn't supported
+}
diff --git a/src/test/ui/fmt/struct-field-as-captured-argument.stderr b/src/test/ui/fmt/struct-field-as-captured-argument.stderr
new file mode 100644
index 00000000000..7ea8b4068f2
--- /dev/null
+++ b/src/test/ui/fmt/struct-field-as-captured-argument.stderr
@@ -0,0 +1,79 @@
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:11:15
+   |
+LL |     format!("{foo.field}");
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{0}", foo.field);
+   |               ~  +++++++++++
+
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:12:15
+   |
+LL |     format!("{foo.field} {} {bar}", "aa");
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{1} {} {bar}", "aa", foo.field);
+   |               ~                 +++++++++++
+
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:13:15
+   |
+LL |     format!("{foo.field} {} {1} {bar}", "aa", "bb");
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{2} {} {1} {bar}", "aa", "bb", foo.field);
+   |               ~                           +++++++++++
+
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:14:15
+   |
+LL |     format!("{foo.field} {} {baz}", "aa", baz = 3);
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{1} {} {baz}", "aa", foo.field, baz = 3);
+   |               ~                 +++++++++++
+
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:15:15
+   |
+LL |     format!("{foo.field:?} {} {baz}", "aa", baz = 3);
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{1:?} {} {baz}", "aa", foo.field, baz = 3);
+   |               ~                   +++++++++++
+
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:16:15
+   |
+LL |     format!("{foo.field:#?} {} {baz}", "aa", baz = 3);
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{1:#?} {} {baz}", "aa", foo.field, baz = 3);
+   |               ~                    +++++++++++
+
+error: invalid format string: field access isn't supported
+  --> $DIR/struct-field-as-captured-argument.rs:17:15
+   |
+LL |     format!("{foo.field:.3} {} {baz}", "aa", baz = 3);
+   |               ^^^^^^^^^ not supported in format string
+   |
+help: consider using a positional formatting argument instead
+   |
+LL |     format!("{1:.3} {} {baz}", "aa", foo.field, baz = 3);
+   |               ~                    +++++++++++
+
+error: aborting due to 7 previous errors
+
diff --git a/src/test/ui/for-loop-while/break-while-condition.stderr b/src/test/ui/for-loop-while/break-while-condition.stderr
index 6960c4fd867..e79f6a75fde 100644
--- a/src/test/ui/for-loop-while/break-while-condition.stderr
+++ b/src/test/ui/for-loop-while/break-while-condition.stderr
@@ -31,6 +31,14 @@ LL | |             }
    |
    = note:   expected type `!`
            found unit type `()`
+note: the function expects a value to always be returned, but loops might run zero times
+  --> $DIR/break-while-condition.rs:24:13
+   |
+LL |             while false {
+   |             ^^^^^^^^^^^ this might have zero elements to iterate on
+LL |                 return
+   |                 ------ if the loop doesn't execute, this value would never get returned
+   = help: return a value for the case when the loop has zero elements to iterate on, or consider changing the return type to account for that possibility
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/generator/size-moved-locals.rs b/src/test/ui/generator/size-moved-locals.rs
index 74c60d98154..3c756a86fc5 100644
--- a/src/test/ui/generator/size-moved-locals.rs
+++ b/src/test/ui/generator/size-moved-locals.rs
@@ -18,7 +18,7 @@
 use std::ops::Generator;
 
 const FOO_SIZE: usize = 1024;
-struct Foo([u8; FOO_SIZE]);
+struct Foo(#[allow(unused_tuple_struct_fields)] [u8; FOO_SIZE]);
 
 impl Drop for Foo {
     fn drop(&mut self) {}
diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
index 7938fc8097c..b98da1ed8be 100644
--- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr
+++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
@@ -11,6 +11,12 @@ note: return type inferred to be `Result<{integer}, _>` here
    |
 LL |             return Ok(6);
    |                    ^^^^^
+help: try wrapping the expression in a variant of `Result`
+   |
+LL |         Ok(5)
+   |         +++ +
+LL |         Err(5)
+   |         ++++ +
 
 error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:7:5: 7:7] as Generator>::Return == i32`
   --> $DIR/type-mismatch-signature-deduction.rs:5:13
diff --git a/src/test/ui/generics/generic-default-type-params-cross-crate.rs b/src/test/ui/generics/generic-default-type-params-cross-crate.rs
index 9e5eaa72c15..834b15be1c5 100644
--- a/src/test/ui/generics/generic-default-type-params-cross-crate.rs
+++ b/src/test/ui/generics/generic-default-type-params-cross-crate.rs
@@ -5,7 +5,7 @@
 
 extern crate default_type_params_xc;
 
-struct Vec<T, A = default_type_params_xc::Heap>(Option<(T,A)>);
+struct Vec<T, A = default_type_params_xc::Heap>(#[allow(unused_tuple_struct_fields)] Option<(T,A)>);
 
 struct Foo;
 
diff --git a/src/test/ui/generics/generic-ivec-leak.rs b/src/test/ui/generics/generic-ivec-leak.rs
index a8ea1d5069b..9610bdcb338 100644
--- a/src/test/ui/generics/generic-ivec-leak.rs
+++ b/src/test/ui/generics/generic-ivec-leak.rs
@@ -1,5 +1,5 @@
 // run-pass
 #![allow(non_camel_case_types)]
-enum wrapper<T> { wrapped(T), }
+enum wrapper<T> { wrapped(#[allow(unused_tuple_struct_fields)] T), }
 
 pub fn main() { let _w = wrapper::wrapped(vec![1, 2, 3, 4, 5]); }
diff --git a/src/test/ui/generics/generic-newtype-struct.rs b/src/test/ui/generics/generic-newtype-struct.rs
index 570c982cc87..aa879f01a58 100644
--- a/src/test/ui/generics/generic-newtype-struct.rs
+++ b/src/test/ui/generics/generic-newtype-struct.rs
@@ -1,7 +1,7 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-struct S<T>(T);
+struct S<T>(#[allow(unused_tuple_struct_fields)] T);
 
 pub fn main() {
     let _s = S(2);
diff --git a/src/test/ui/generics/generic-no-mangle.fixed b/src/test/ui/generics/generic-no-mangle.fixed
index 9126ac167cf..501acb6e163 100644
--- a/src/test/ui/generics/generic-no-mangle.fixed
+++ b/src/test/ui/generics/generic-no-mangle.fixed
@@ -76,7 +76,7 @@ impl<T> Trait2<T> for Foo {
     fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
 }
 
-pub struct Bar<T>(T);
+pub struct Bar<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T> Bar<T> {
     
@@ -111,7 +111,7 @@ impl<T> Trait3 for Bar<T> {
     fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
 }
 
-pub struct Baz<'a>(&'a i32);
+pub struct Baz<'a>(#[allow(unused_tuple_struct_fields)] &'a i32);
 
 impl<'a> Baz<'a> {
     #[no_mangle]
diff --git a/src/test/ui/generics/generic-no-mangle.rs b/src/test/ui/generics/generic-no-mangle.rs
index e283cf4bfe5..74e407078e8 100644
--- a/src/test/ui/generics/generic-no-mangle.rs
+++ b/src/test/ui/generics/generic-no-mangle.rs
@@ -76,7 +76,7 @@ impl<T> Trait2<T> for Foo {
     fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled
 }
 
-pub struct Bar<T>(T);
+pub struct Bar<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T> Bar<T> {
     #[no_mangle]
@@ -111,7 +111,7 @@ impl<T> Trait3 for Bar<T> {
     fn baz<U>() {} //~ ERROR functions generic over types or consts must be mangled
 }
 
-pub struct Baz<'a>(&'a i32);
+pub struct Baz<'a>(#[allow(unused_tuple_struct_fields)] &'a i32);
 
 impl<'a> Baz<'a> {
     #[no_mangle]
diff --git a/src/test/ui/generics/generic-recursive-tag.rs b/src/test/ui/generics/generic-recursive-tag.rs
index 74f5b701d98..b344da1c7dd 100644
--- a/src/test/ui/generics/generic-recursive-tag.rs
+++ b/src/test/ui/generics/generic-recursive-tag.rs
@@ -1,7 +1,7 @@
 // run-pass
 #![allow(non_camel_case_types)]
 
-enum list<T> { cons(Box<T>, Box<list<T>>), nil, }
+enum list<T> { #[allow(unused_tuple_struct_fields)] cons(Box<T>, Box<list<T>>), nil, }
 
 pub fn main() {
     let _a: list<isize> =
diff --git a/src/test/ui/generics/generic-tag-corruption.rs b/src/test/ui/generics/generic-tag-corruption.rs
index aa26183a0d4..35de3c1f712 100644
--- a/src/test/ui/generics/generic-tag-corruption.rs
+++ b/src/test/ui/generics/generic-tag-corruption.rs
@@ -5,6 +5,6 @@
 // This used to cause memory corruption in stage 0.
 // pretty-expanded FIXME #23616
 
-enum thing<K> { some(K), }
+enum thing<K> { some(#[allow(unused_tuple_struct_fields)] K), }
 
 pub fn main() { let _x = thing::some("hi".to_string()); }
diff --git a/src/test/ui/generics/generic-tag-local.rs b/src/test/ui/generics/generic-tag-local.rs
index cc85e6e0f0a..c5772e84193 100644
--- a/src/test/ui/generics/generic-tag-local.rs
+++ b/src/test/ui/generics/generic-tag-local.rs
@@ -3,6 +3,6 @@
 
 // pretty-expanded FIXME #23616
 
-enum clam<T> { a(T), }
+enum clam<T> { a(#[allow(unused_tuple_struct_fields)] T), }
 
 pub fn main() { let _c = clam::a(3); }
diff --git a/src/test/ui/generics/generic-tag.rs b/src/test/ui/generics/generic-tag.rs
index 67f2ccdde34..31fc2178d6d 100644
--- a/src/test/ui/generics/generic-tag.rs
+++ b/src/test/ui/generics/generic-tag.rs
@@ -6,7 +6,7 @@
 
 #![allow(unused_variables)]
 
-enum option<T> { some(Box<T>), none, }
+enum option<T> { some(#[allow(unused_tuple_struct_fields)] Box<T>), none, }
 
 pub fn main() {
     let mut a: option<isize> = option::some::<isize>(Box::new(10));
diff --git a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr
index 68da46d46bd..1461e7fd2dd 100644
--- a/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr
+++ b/src/test/ui/hrtb/hrtb-perfect-forwarding.stderr
@@ -4,12 +4,10 @@ warning: function cannot return without recursing
 LL | / fn no_hrtb<'b, T>(mut t: T)
 LL | | where
 LL | |     T: Bar<&'b isize>,
-LL | | {
-...  |
-LL | |     no_hrtb(&mut t);
-   | |     --------------- recursive call site
-LL | | }
-   | |_^ cannot return without recursing
+   | |______________________^ cannot return without recursing
+...
+LL |       no_hrtb(&mut t);
+   |       --------------- recursive call site
    |
    = note: `#[warn(unconditional_recursion)]` on by default
    = help: a `loop` may express intention better if this is on purpose
@@ -20,12 +18,10 @@ warning: function cannot return without recursing
 LL | / fn bar_hrtb<T>(mut t: T)
 LL | | where
 LL | |     T: for<'b> Bar<&'b isize>,
-LL | | {
-...  |
-LL | |     bar_hrtb(&mut t);
-   | |     ---------------- recursive call site
-LL | | }
-   | |_^ cannot return without recursing
+   | |______________________________^ cannot return without recursing
+...
+LL |       bar_hrtb(&mut t);
+   |       ---------------- recursive call site
    |
    = help: a `loop` may express intention better if this is on purpose
 
@@ -35,14 +31,10 @@ warning: function cannot return without recursing
 LL | / fn foo_hrtb_bar_not<'b, T>(mut t: T)
 LL | | where
 LL | |     T: for<'a> Foo<&'a isize> + Bar<&'b isize>,
-LL | | {
-...  |
-LL | |     foo_hrtb_bar_not(&mut t);
-   | |     ------------------------ recursive call site
-LL | |
-LL | |
-LL | | }
-   | |_^ cannot return without recursing
+   | |_______________________________________________^ cannot return without recursing
+...
+LL |       foo_hrtb_bar_not(&mut t);
+   |       ------------------------ recursive call site
    |
    = help: a `loop` may express intention better if this is on purpose
 
@@ -70,12 +62,10 @@ warning: function cannot return without recursing
 LL | / fn foo_hrtb_bar_hrtb<T>(mut t: T)
 LL | | where
 LL | |     T: for<'a> Foo<&'a isize> + for<'b> Bar<&'b isize>,
-LL | | {
-LL | |     // OK -- now we have `T : for<'b> Bar<&'b isize>`.
-LL | |     foo_hrtb_bar_hrtb(&mut t);
-   | |     ------------------------- recursive call site
-LL | | }
-   | |_^ cannot return without recursing
+   | |_______________________________________________________^ cannot return without recursing
+...
+LL |       foo_hrtb_bar_hrtb(&mut t);
+   |       ------------------------- recursive call site
    |
    = help: a `loop` may express intention better if this is on purpose
 
diff --git a/src/test/ui/impl-trait/bounds_regression.rs b/src/test/ui/impl-trait/bounds_regression.rs
index 0fdeb6bdee1..31fc46203d3 100644
--- a/src/test/ui/impl-trait/bounds_regression.rs
+++ b/src/test/ui/impl-trait/bounds_regression.rs
@@ -15,7 +15,7 @@ pub fn future_from_generator<
     GenFuture(x)
 }
 
-struct GenFuture<T: FakeGenerator<Yield = ()>>(T);
+struct GenFuture<T: FakeGenerator<Yield = ()>>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T: FakeGenerator<Yield = ()>> FakeFuture for GenFuture<T> {
     type Output = T::Return;
diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr
index f14b447b077..d4a3495515c 100644
--- a/src/test/ui/impl-trait/equality.stderr
+++ b/src/test/ui/impl-trait/equality.stderr
@@ -12,10 +12,15 @@ error[E0308]: mismatched types
   --> $DIR/equality.rs:15:5
    |
 LL | fn two(x: bool) -> impl Foo {
-   |                    -------- expected `_` because of return type
+   |                    -------- expected `i32` because of return type
 ...
 LL |     0_u32
    |     ^^^^^ expected `i32`, found `u32`
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |     0_i32
+   |       ~~~
 
 error[E0277]: cannot add `impl Foo` to `u32`
   --> $DIR/equality.rs:24:11
diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr
index 5ca01a59376..d6f5a1ac25b 100644
--- a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr
+++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:36:5
    |
 LL | fn can() -> impl NotObjectSafe {
-   |             ------------------ expected `_` because of return type
+   |             ------------------ expected `A` because of return type
 ...
 LL |     B
    |     ^ expected struct `A`, found struct `B`
@@ -11,7 +11,7 @@ error[E0308]: mismatched types
   --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5
    |
 LL | fn cat() -> impl ObjectSafe {
-   |             --------------- expected `_` because of return type
+   |             --------------- expected `A` because of return type
 ...
 LL |     B
    |     ^ expected struct `A`, found struct `B`
diff --git a/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr
index 10510c1754e..11c1072f02c 100644
--- a/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr
+++ b/src/test/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr
@@ -2,28 +2,43 @@ error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5
    |
 LL | fn foo() -> impl std::fmt::Display {
-   |             ---------------------- expected `_` because of return type
+   |             ---------------------- expected `i32` because of return type
 ...
 LL |     1u32
    |     ^^^^ expected `i32`, found `u32`
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |     1i32
+   |      ~~~
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16
    |
 LL | fn bar() -> impl std::fmt::Display {
-   |             ---------------------- expected `_` because of return type
+   |             ---------------------- expected `i32` because of return type
 ...
 LL |         return 1u32;
    |                ^^^^ expected `i32`, found `u32`
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         return 1i32;
+   |                 ~~~
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9
    |
 LL | fn baz() -> impl std::fmt::Display {
-   |             ---------------------- expected `_` because of return type
+   |             ---------------------- expected `i32` because of return type
 ...
 LL |         1u32
    |         ^^^^ expected `i32`, found `u32`
+   |
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
+   |
+LL |     }.try_into().unwrap()
+   |      ++++++++++++++++++++
 
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9
@@ -36,36 +51,56 @@ LL | |         1u32
    | |         ^^^^ expected `i32`, found `u32`
 LL | |     }
    | |_____- `if` and `else` have incompatible types
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         1i32
+   |          ~~~
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14
    |
 LL | fn bat() -> impl std::fmt::Display {
-   |             ---------------------- expected `_` because of return type
+   |             ---------------------- expected `i32` because of return type
 ...
 LL |         _ => 1u32,
    |              ^^^^ expected `i32`, found `u32`
+   |
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
+   |
+LL |     }.try_into().unwrap()
+   |      ++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5
    |
 LL |   fn can() -> impl std::fmt::Display {
-   |               ---------------------- expected `_` because of return type
+   |               ---------------------- expected `i32` because of return type
 LL | /     match 13 {
 LL | |         0 => return 0i32,
 LL | |         1 => 1u32,
 LL | |         _ => 2u32,
 LL | |     }
    | |_____^ expected `i32`, found `u32`
+   |
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
+   |
+LL |     }.try_into().unwrap()
+   |      ++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13
    |
 LL | fn cat() -> impl std::fmt::Display {
-   |             ---------------------- expected `_` because of return type
+   |             ---------------------- expected `i32` because of return type
 ...
 LL |             1u32
    |             ^^^^ expected `i32`, found `u32`
+   |
+help: you can convert a `u32` to an `i32` and panic if the converted value doesn't fit
+   |
+LL |     }.try_into().unwrap()
+   |      ++++++++++++++++++++
 
 error[E0308]: `match` arms have incompatible types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14
@@ -78,6 +113,11 @@ LL | |         1 => 1u32,
 LL | |         _ => 2u32,
 LL | |     }
    | |_____- `match` arms have incompatible types
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         1 => 1i32,
+   |               ~~~
 
 error[E0308]: `if` and `else` have incompatible types
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9
@@ -90,6 +130,11 @@ LL | |         1u32
    | |         ^^^^ expected `i32`, found `u32`
 LL | |     }
    | |_____- `if` and `else` have incompatible types
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         1i32
+   |          ~~~
 
 error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13
@@ -125,6 +170,11 @@ LL | |         1 => 1u32,
 LL | |         _ => 2u32,
 LL | |     }
    | |_____- `match` arms have incompatible types
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         1 => 1i32,
+   |               ~~~
 
 error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13
@@ -164,6 +214,11 @@ LL | |         1u32
    | |         ^^^^ expected `i32`, found `u32`
 LL | |     }
    | |_____- `if` and `else` have incompatible types
+   |
+help: change the type of the numeric literal from `u32` to `i32`
+   |
+LL |         1i32
+   |          ~~~
 
 error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13
diff --git a/src/test/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs b/src/test/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
new file mode 100644
index 00000000000..a4e603de1ac
--- /dev/null
+++ b/src/test/ui/impl-trait/rpit-assoc-pair-with-lifetime.rs
@@ -0,0 +1,7 @@
+// check-pass
+
+pub fn iter<'a>(v: Vec<(u32, &'a u32)>) -> impl DoubleEndedIterator<Item = (u32, &u32)> {
+    v.into_iter()
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-12511.stderr b/src/test/ui/issues/issue-12511.stderr
index 5f2b98c5237..789a1141c04 100644
--- a/src/test/ui/issues/issue-12511.stderr
+++ b/src/test/ui/issues/issue-12511.stderr
@@ -23,8 +23,10 @@ LL | trait T2 : T1 {
 note: cycle used when collecting item types in top-level module
   --> $DIR/issue-12511.rs:1:1
    |
-LL | trait T1 : T2 {
-   | ^^^^^^^^^^^^^
+LL | / trait T1 : T2 {
+LL | |
+LL | | }
+   | |_^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-13027.rs b/src/test/ui/issues/issue-13027.rs
index 1bab82a543f..64bf2a11d0e 100644
--- a/src/test/ui/issues/issue-13027.rs
+++ b/src/test/ui/issues/issue-13027.rs
@@ -164,7 +164,7 @@ fn range_shadow_multi_pats() {
 
 fn misc() {
     enum Foo {
-        Bar(usize, bool)
+        Bar(#[allow(unused_tuple_struct_fields)] usize, bool)
     }
     // This test basically mimics how trace_macros! macro is implemented,
     // which is a rare combination of vector patterns, multiple wild-card
diff --git a/src/test/ui/issues/issue-14382.rs b/src/test/ui/issues/issue-14382.rs
index 671e7a22667..dca24d0be8a 100644
--- a/src/test/ui/issues/issue-14382.rs
+++ b/src/test/ui/issues/issue-14382.rs
@@ -1,6 +1,6 @@
 // run-pass
 #[derive(Debug)]
-struct Matrix4<S>(S);
+struct Matrix4<S>(#[allow(unused_tuple_struct_fields)] S);
 trait POrd<S> {}
 
 fn translate<S: POrd<S>>(s: S) -> Matrix4<S> { Matrix4(s) }
diff --git a/src/test/ui/issues/issue-15858.rs b/src/test/ui/issues/issue-15858.rs
index 41d2f13952a..8d65afc4883 100644
--- a/src/test/ui/issues/issue-15858.rs
+++ b/src/test/ui/issues/issue-15858.rs
@@ -12,7 +12,7 @@ impl Bar for BarImpl {
 }
 
 
-struct Foo<B: Bar>(B);
+struct Foo<B: Bar>(#[allow(unused_tuple_struct_fields)] B);
 
 impl<B: Bar> Drop for Foo<B> {
     fn drop(&mut self) {
diff --git a/src/test/ui/issues/issue-17905.rs b/src/test/ui/issues/issue-17905.rs
index 95133a45844..dae9648b917 100644
--- a/src/test/ui/issues/issue-17905.rs
+++ b/src/test/ui/issues/issue-17905.rs
@@ -1,6 +1,7 @@
 // run-pass
 
 #[derive(Debug)]
+#[allow(unused_tuple_struct_fields)]
 struct Pair<T, V> (T, V);
 
 impl Pair<
diff --git a/src/test/ui/issues/issue-2063.rs b/src/test/ui/issues/issue-2063.rs
index 9dbac6ccee1..f08f9d4cfe4 100644
--- a/src/test/ui/issues/issue-2063.rs
+++ b/src/test/ui/issues/issue-2063.rs
@@ -3,7 +3,7 @@
 // cause compiler to loop.  Note that no instances
 // of such a type could ever be constructed.
 
-struct T(Box<T>);
+struct T(#[allow(unused_tuple_struct_fields)] Box<T>);
 
 trait ToStr2 {
     fn my_to_string(&self) -> String;
diff --git a/src/test/ui/issues/issue-23491.rs b/src/test/ui/issues/issue-23491.rs
index d2ded88aeff..1cb969731e2 100644
--- a/src/test/ui/issues/issue-23491.rs
+++ b/src/test/ui/issues/issue-23491.rs
@@ -2,7 +2,7 @@
 #![allow(unused_variables)]
 #![feature(box_syntax)]
 
-struct Node<T: ?Sized>(T);
+struct Node<T: ?Sized>(#[allow(unused_tuple_struct_fields)] T);
 
 fn main() {
     let x: Box<Node<[isize]>> = box Node([]);
diff --git a/src/test/ui/issues/issue-24308.rs b/src/test/ui/issues/issue-24308.rs
index 9c39a5d2238..4a582c68efc 100644
--- a/src/test/ui/issues/issue-24308.rs
+++ b/src/test/ui/issues/issue-24308.rs
@@ -4,7 +4,7 @@ pub trait Foo {
     fn method2();
 }
 
-struct Slice<'a, T: 'a>(&'a [T]);
+struct Slice<'a, T: 'a>(#[allow(unused_tuple_struct_fields)] &'a [T]);
 
 impl<'a, T: 'a> Foo for Slice<'a, T> {
     fn method2() {
diff --git a/src/test/ui/issues/issue-24805-dropck-itemless.rs b/src/test/ui/issues/issue-24805-dropck-itemless.rs
index 555eefeb3a1..45761b61c3e 100644
--- a/src/test/ui/issues/issue-24805-dropck-itemless.rs
+++ b/src/test/ui/issues/issue-24805-dropck-itemless.rs
@@ -19,7 +19,7 @@ impl<'a, T> UserDefined for &'a T { }
 //   ```
 macro_rules! impl_drop {
     ($Bound:ident, $Id:ident) => {
-        struct $Id<T: $Bound>(T);
+        struct $Id<T: $Bound>(#[allow(unused_tuple_struct_fields)] T);
         unsafe impl <#[may_dangle] T: $Bound> Drop for $Id<T> {
             fn drop(&mut self) { }
         }
diff --git a/src/test/ui/issues/issue-25089.rs b/src/test/ui/issues/issue-25089.rs
index 0f0f78623a2..c988f8f55fa 100644
--- a/src/test/ui/issues/issue-25089.rs
+++ b/src/test/ui/issues/issue-25089.rs
@@ -4,7 +4,7 @@
 
 use std::thread;
 
-struct Foo(i32);
+struct Foo(#[allow(unused_tuple_struct_fields)] i32);
 
 impl Drop for Foo {
     fn drop(&mut self) {
diff --git a/src/test/ui/issues/issue-25679.rs b/src/test/ui/issues/issue-25679.rs
index 89544c9eb88..b548da98888 100644
--- a/src/test/ui/issues/issue-25679.rs
+++ b/src/test/ui/issues/issue-25679.rs
@@ -2,6 +2,7 @@
 trait Device {
     type Resources;
 }
+#[allow(unused_tuple_struct_fields)]
 struct Foo<D, R>(D, R);
 
 impl<D: Device> Foo<D, D::Resources> {
diff --git a/src/test/ui/issues/issue-25700-1.rs b/src/test/ui/issues/issue-25700-1.rs
index 7bc9673a5be..5e71a52ba4e 100644
--- a/src/test/ui/issues/issue-25700-1.rs
+++ b/src/test/ui/issues/issue-25700-1.rs
@@ -1,5 +1,5 @@
 // run-pass
-struct S<T: 'static>(Option<&'static T>);
+struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
 
 trait Tr { type Out; }
 impl<T> Tr for T { type Out = T; }
diff --git a/src/test/ui/issues/issue-25700-2.rs b/src/test/ui/issues/issue-25700-2.rs
index b161e68abaf..89b1db496f9 100644
--- a/src/test/ui/issues/issue-25700-2.rs
+++ b/src/test/ui/issues/issue-25700-2.rs
@@ -3,8 +3,9 @@ pub trait Parser {
     type Input;
 }
 
-pub struct Iter<P: Parser>(P, P::Input);
+pub struct Iter<P: Parser>(#[allow(unused_tuple_struct_fields)] P, P::Input);
 
+#[allow(unused_tuple_struct_fields)]
 pub struct Map<P, F>(P, F);
 impl<P, F> Parser for Map<P, F> where F: FnMut(P) {
     type Input = u8;
diff --git a/src/test/ui/issues/issue-25700.rs b/src/test/ui/issues/issue-25700.rs
index 45c452d618d..e5b9a97523d 100644
--- a/src/test/ui/issues/issue-25700.rs
+++ b/src/test/ui/issues/issue-25700.rs
@@ -1,4 +1,4 @@
-struct S<T: 'static>(Option<&'static T>);
+struct S<T: 'static>(#[allow(unused_tuple_struct_fields)] Option<&'static T>);
 
 trait Tr { type Out; }
 impl<T> Tr for T { type Out = T; }
diff --git a/src/test/ui/issues/issue-26127.rs b/src/test/ui/issues/issue-26127.rs
index cb479a23085..f3f9c1d9ae8 100644
--- a/src/test/ui/issues/issue-26127.rs
+++ b/src/test/ui/issues/issue-26127.rs
@@ -1,7 +1,7 @@
 // run-pass
 trait Tr { type T; }
 impl Tr for u8 { type T=(); }
-struct S<I: Tr>(I::T);
+struct S<I: Tr>(#[allow(unused_tuple_struct_fields)] I::T);
 
 fn foo<I: Tr>(i: I::T) {
     S::<I>(i);
diff --git a/src/test/ui/issues/issue-26641.rs b/src/test/ui/issues/issue-26641.rs
index 4b6f2c2b3bc..e08edd0b5cb 100644
--- a/src/test/ui/issues/issue-26641.rs
+++ b/src/test/ui/issues/issue-26641.rs
@@ -1,5 +1,5 @@
 // run-pass
-struct Parser<'a>(Box<dyn FnMut(Parser) + 'a>);
+struct Parser<'a>(#[allow(unused_tuple_struct_fields)] Box<dyn FnMut(Parser) + 'a>);
 
 fn main() {
     let _x = Parser(Box::new(|_|{}));
diff --git a/src/test/ui/issues/issue-26709.rs b/src/test/ui/issues/issue-26709.rs
index 281ae13399d..1bd2651dd6c 100644
--- a/src/test/ui/issues/issue-26709.rs
+++ b/src/test/ui/issues/issue-26709.rs
@@ -1,5 +1,5 @@
 // run-pass
-struct Wrapper<'a, T: ?Sized>(&'a mut i32, T);
+struct Wrapper<'a, T: ?Sized>(&'a mut i32, #[allow(unused_tuple_struct_fields)] T);
 
 impl<'a, T: ?Sized> Drop for Wrapper<'a, T> {
     fn drop(&mut self) {
diff --git a/src/test/ui/issues/issue-27240.rs b/src/test/ui/issues/issue-27240.rs
index a22db76b9bc..eaf254f3361 100644
--- a/src/test/ui/issues/issue-27240.rs
+++ b/src/test/ui/issues/issue-27240.rs
@@ -2,12 +2,12 @@
 #![allow(unused_assignments)]
 #![allow(unused_variables)]
 use std::fmt;
-struct NoisyDrop<T: fmt::Debug>(T);
+struct NoisyDrop<T: fmt::Debug>(#[allow(unused_tuple_struct_fields)] T);
 impl<T: fmt::Debug> Drop for NoisyDrop<T> {
     fn drop(&mut self) {}
 }
 
-struct Bar<T: fmt::Debug>([*const NoisyDrop<T>; 2]);
+struct Bar<T: fmt::Debug>(#[allow(unused_tuple_struct_fields)] [*const NoisyDrop<T>; 2]);
 
 fn fine() {
     let (u,b);
@@ -15,6 +15,7 @@ fn fine() {
     b = Bar([&NoisyDrop(&u), &NoisyDrop(&u)]);
 }
 
+#[allow(unused_tuple_struct_fields)]
 struct Bar2<T: fmt::Debug>(*const NoisyDrop<T>, *const NoisyDrop<T>);
 
 fn lolwut() {
diff --git a/src/test/ui/issues/issue-28498-must-work-ex1.rs b/src/test/ui/issues/issue-28498-must-work-ex1.rs
index 4699d3352ad..ab6d190e0a1 100644
--- a/src/test/ui/issues/issue-28498-must-work-ex1.rs
+++ b/src/test/ui/issues/issue-28498-must-work-ex1.rs
@@ -6,7 +6,7 @@
 
 use std::cell::Cell;
 
-struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+struct Concrete<'a>(#[allow(unused_tuple_struct_fields)] u32, Cell<Option<&'a Concrete<'a>>>);
 
 fn main() {
     let mut data = Vec::new();
diff --git a/src/test/ui/issues/issue-28498-must-work-ex2.rs b/src/test/ui/issues/issue-28498-must-work-ex2.rs
index cadf62461fd..378d736ee3d 100644
--- a/src/test/ui/issues/issue-28498-must-work-ex2.rs
+++ b/src/test/ui/issues/issue-28498-must-work-ex2.rs
@@ -6,7 +6,7 @@
 
 use std::cell::Cell;
 
-struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+struct Concrete<'a>(#[allow(unused_tuple_struct_fields)] u32, Cell<Option<&'a Concrete<'a>>>);
 
 struct Foo<T> { data: Vec<T> }
 
diff --git a/src/test/ui/issues/issue-28498-ugeh-ex1.rs b/src/test/ui/issues/issue-28498-ugeh-ex1.rs
index 90cf2cddcf0..24bf706cef9 100644
--- a/src/test/ui/issues/issue-28498-ugeh-ex1.rs
+++ b/src/test/ui/issues/issue-28498-ugeh-ex1.rs
@@ -8,7 +8,7 @@
 #![feature(dropck_eyepatch)]
 use std::cell::Cell;
 
-struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+struct Concrete<'a>(#[allow(unused_tuple_struct_fields)] u32, Cell<Option<&'a Concrete<'a>>>);
 
 struct Foo<T> { data: Vec<T> }
 
diff --git a/src/test/ui/issues/issue-29147-rpass.rs b/src/test/ui/issues/issue-29147-rpass.rs
index 101bca307f1..439f8bb5308 100644
--- a/src/test/ui/issues/issue-29147-rpass.rs
+++ b/src/test/ui/issues/issue-29147-rpass.rs
@@ -1,5 +1,6 @@
 // run-pass
 #![recursion_limit="1024"]
+#![allow(dead_code)]
 
 use std::mem;
 
diff --git a/src/test/ui/issues/issue-29147.rs b/src/test/ui/issues/issue-29147.rs
index 271bc526033..190ecf46009 100644
--- a/src/test/ui/issues/issue-29147.rs
+++ b/src/test/ui/issues/issue-29147.rs
@@ -1,4 +1,5 @@
 #![recursion_limit="1024"]
+#![allow(dead_code)]
 
 pub struct S0<T>(T,T);
 pub struct S1<T>(Option<Box<S0<S0<T>>>>,Option<Box<S0<S0<T>>>>);
diff --git a/src/test/ui/issues/issue-29147.stderr b/src/test/ui/issues/issue-29147.stderr
index 5570e887edc..138d477dc6b 100644
--- a/src/test/ui/issues/issue-29147.stderr
+++ b/src/test/ui/issues/issue-29147.stderr
@@ -1,11 +1,11 @@
 error[E0283]: type annotations needed
-  --> $DIR/issue-29147.rs:21:13
+  --> $DIR/issue-29147.rs:22:13
    |
 LL |     let _ = <S5<_>>::xxx;
    |             ^^^^^^^^^^^^ cannot infer type for struct `S5<_>`
    |
 note: multiple `impl`s satisfying `S5<_>: Foo` found
-  --> $DIR/issue-29147.rs:17:1
+  --> $DIR/issue-29147.rs:18:1
    |
 LL | impl Foo for S5<u32> { fn xxx(&self) {} }
    | ^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/issues/issue-31267-additional.rs b/src/test/ui/issues/issue-31267-additional.rs
index 70dce2c9490..7f0cbd658f1 100644
--- a/src/test/ui/issues/issue-31267-additional.rs
+++ b/src/test/ui/issues/issue-31267-additional.rs
@@ -6,7 +6,7 @@ struct Bar;
 const BAZ: Bar = Bar;
 
 #[derive(Debug)]
-struct Foo([Bar; 1]);
+struct Foo(#[allow(unused_tuple_struct_fields)] [Bar; 1]);
 
 struct Biz;
 
diff --git a/src/test/ui/issues/issue-31299.rs b/src/test/ui/issues/issue-31299.rs
index d93ffcb2262..78c3252d32e 100644
--- a/src/test/ui/issues/issue-31299.rs
+++ b/src/test/ui/issues/issue-31299.rs
@@ -25,9 +25,9 @@ impl<T> Front for Vec<T> {
     type Back = Vec<T>;
 }
 
-struct PtrBack<T: Front>(Vec<T::Back>);
+struct PtrBack<T: Front>(#[allow(unused_tuple_struct_fields)] Vec<T::Back>);
 
-struct M(PtrBack<Vec<M>>);
+struct M(#[allow(unused_tuple_struct_fields)] PtrBack<Vec<M>>);
 
 #[allow(unused_must_use)]
 fn main() {
diff --git a/src/test/ui/issues/issue-34571.rs b/src/test/ui/issues/issue-34571.rs
index bad1bebc697..5498091da58 100644
--- a/src/test/ui/issues/issue-34571.rs
+++ b/src/test/ui/issues/issue-34571.rs
@@ -1,7 +1,7 @@
 // run-pass
 #[repr(u8)]
 enum Foo {
-    Foo(u8),
+    Foo(#[allow(unused_tuple_struct_fields)] u8),
 }
 
 fn main() {
diff --git a/src/test/ui/issues/issue-36053.rs b/src/test/ui/issues/issue-36053.rs
index a61c02c0a12..5c6d0780416 100644
--- a/src/test/ui/issues/issue-36053.rs
+++ b/src/test/ui/issues/issue-36053.rs
@@ -7,7 +7,7 @@
 
 use std::iter::FusedIterator;
 
-struct Thing<'a>(&'a str);
+struct Thing<'a>(#[allow(unused_tuple_struct_fields)] &'a str);
 impl<'a> Iterator for Thing<'a> {
     type Item = &'a str;
     fn next(&mut self) -> Option<&'a str> {
diff --git a/src/test/ui/issues/issue-36278-prefix-nesting.rs b/src/test/ui/issues/issue-36278-prefix-nesting.rs
index 62d1f5f8258..a809f7f1329 100644
--- a/src/test/ui/issues/issue-36278-prefix-nesting.rs
+++ b/src/test/ui/issues/issue-36278-prefix-nesting.rs
@@ -5,6 +5,7 @@
 use std::mem;
 
 const SZ: usize = 100;
+#[allow(unused_tuple_struct_fields)]
 struct P<T: ?Sized>([u8; SZ], T);
 
 type Ack<T> = P<P<T>>;
diff --git a/src/test/ui/issues/issue-40003.rs b/src/test/ui/issues/issue-40003.rs
index 642de6b8fe3..5e61361f987 100644
--- a/src/test/ui/issues/issue-40003.rs
+++ b/src/test/ui/issues/issue-40003.rs
@@ -153,7 +153,7 @@ mod stream {
     }
 
     enum Slot<T> {
-        Next(usize),
+        Next(#[allow(unused_tuple_struct_fields)] usize),
         _Data { _a: T },
     }
 
diff --git a/src/test/ui/issues/issue-4252.rs b/src/test/ui/issues/issue-4252.rs
index 48e617fd7eb..0d47a7f0c16 100644
--- a/src/test/ui/issues/issue-4252.rs
+++ b/src/test/ui/issues/issue-4252.rs
@@ -7,7 +7,7 @@ trait X {
 }
 
 #[derive(Debug)]
-struct Y(isize);
+struct Y(#[allow(unused_tuple_struct_fields)] isize);
 
 #[derive(Debug)]
 struct Z<T: X+std::fmt::Debug> {
diff --git a/src/test/ui/issues/issue-46069.rs b/src/test/ui/issues/issue-46069.rs
index 1d4f789828d..c418128c186 100644
--- a/src/test/ui/issues/issue-46069.rs
+++ b/src/test/ui/issues/issue-46069.rs
@@ -2,7 +2,7 @@
 use std::iter::{Fuse, Cloned};
 use std::slice::Iter;
 
-struct Foo<'a, T: 'a>(&'a T);
+struct Foo<'a, T: 'a>(#[allow(unused_tuple_struct_fields)] &'a T);
 impl<'a, T: 'a> Copy for Foo<'a, T> {}
 impl<'a, T: 'a> Clone for Foo<'a, T> {
     fn clone(&self) -> Self { *self }
diff --git a/src/test/ui/issues/issue-5315.rs b/src/test/ui/issues/issue-5315.rs
index 38c98254b93..0c121a5eee6 100644
--- a/src/test/ui/issues/issue-5315.rs
+++ b/src/test/ui/issues/issue-5315.rs
@@ -1,7 +1,7 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-struct A(bool);
+struct A(#[allow(unused_tuple_struct_fields)] bool);
 
 pub fn main() {
     let f = A;
diff --git a/src/test/ui/issues/issue-61894.rs b/src/test/ui/issues/issue-61894.rs
index c018ac73fb5..776fdbb7466 100644
--- a/src/test/ui/issues/issue-61894.rs
+++ b/src/test/ui/issues/issue-61894.rs
@@ -4,7 +4,7 @@
 
 use std::any::type_name;
 
-struct Bar<M>(M);
+struct Bar<M>(#[allow(unused_tuple_struct_fields)] M);
 
 impl<M> Bar<M> {
     fn foo(&self) -> &'static str {
diff --git a/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr b/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr
index e5ab65169ce..f581429a281 100644
--- a/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr
+++ b/src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr
@@ -17,10 +17,10 @@ LL | | }
    = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: missing type for `const` item
-  --> $DIR/issue-69396-const-no-type-in-macro.rs:4:19
+  --> $DIR/issue-69396-const-no-type-in-macro.rs:4:20
    |
 LL |               const A = "A".$fn();
-   |                     ^ help: provide a type for the constant: `A: usize`
+   |                      ^ help: provide a type for the constant: `: usize`
 ...
 LL | / suite! {
 LL | |     len;
@@ -31,13 +31,13 @@ LL | | }
    = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
-  --> $DIR/issue-69396-const-no-type-in-macro.rs:4:19
+  --> $DIR/issue-69396-const-no-type-in-macro.rs:4:20
    |
 LL |               const A = "A".$fn();
-   |                     ^
-   |                     |
-   |                     not allowed in type signatures
-   |                     help: replace with the correct type: `bool`
+   |                      ^
+   |                      |
+   |                      not allowed in type signatures
+   |                      help: replace with the correct type: `bool`
 ...
 LL | / suite! {
 LL | |     len;
diff --git a/src/test/ui/issues/issue-7911.rs b/src/test/ui/issues/issue-7911.rs
index de833324bd2..f64887136ca 100644
--- a/src/test/ui/issues/issue-7911.rs
+++ b/src/test/ui/issues/issue-7911.rs
@@ -6,7 +6,7 @@
 trait FooBar {
     fn dummy(&self) { }
 }
-struct Bar(i32);
+struct Bar(#[allow(unused_tuple_struct_fields)] i32);
 struct Foo { bar: Bar }
 
 impl FooBar for Bar {}
diff --git a/src/test/ui/issues/issue-99838.rs b/src/test/ui/issues/issue-99838.rs
new file mode 100644
index 00000000000..eaeeac72b25
--- /dev/null
+++ b/src/test/ui/issues/issue-99838.rs
@@ -0,0 +1,40 @@
+// run-pass
+#![feature(bench_black_box)]
+use std::hint;
+
+struct U16(u16);
+
+impl Drop for U16 {
+    fn drop(&mut self) {
+        // Prevent LLVM from optimizing away our alignment check.
+        assert!(hint::black_box(self as *mut U16 as usize) % 2 == 0);
+    }
+}
+
+struct HasDrop;
+
+impl Drop for HasDrop {
+    fn drop(&mut self) {}
+}
+
+struct Wrapper {
+    _a: U16,
+    b: HasDrop,
+}
+
+#[repr(packed)]
+struct Misalign(u8, Wrapper);
+
+fn main() {
+    let m = Misalign(
+        0,
+        Wrapper {
+            _a: U16(10),
+            b: HasDrop,
+        },
+    );
+    // Put it somewhere definitely even (so the `a` field is definitely at an odd address).
+    let m: ([u16; 0], Misalign) = ([], m);
+    // Move out one field, so we run custom per-field drop logic below.
+    let _x = m.1.1.b;
+}
diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs
index 73b32066fad..68bcc3c1aff 100644
--- a/src/test/ui/layout/unsafe-cell-hides-niche.rs
+++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs
@@ -14,10 +14,10 @@ use std::mem::size_of;
 use std::num::NonZeroU32 as N32;
 use std::sync::{Mutex, RwLock};
 
-struct Wrapper<T>(T);
+struct Wrapper<T>(#[allow(unused_tuple_struct_fields)] T);
 
 #[repr(transparent)]
-struct Transparent<T>(T);
+struct Transparent<T>(#[allow(unused_tuple_struct_fields)] T);
 
 struct NoNiche<T>(UnsafeCell<T>);
 
diff --git a/src/test/ui/let-else/issue-100103.rs b/src/test/ui/let-else/issue-100103.rs
new file mode 100644
index 00000000000..e393deab764
--- /dev/null
+++ b/src/test/ui/let-else/issue-100103.rs
@@ -0,0 +1,15 @@
+// edition:2021
+// check-pass
+
+#![feature(try_blocks)]
+#![feature(let_else)]
+
+fn main() {
+    let _: Result<i32, i32> = try {
+        let Some(x) = Some(0) else {
+            Err(1)?
+        };
+
+        x
+    };
+}
diff --git a/src/test/ui/lifetimes/elided-lifetime-in-path-in-type-relative-expression.rs b/src/test/ui/lifetimes/elided-lifetime-in-path-in-type-relative-expression.rs
new file mode 100644
index 00000000000..b9d2711fd9c
--- /dev/null
+++ b/src/test/ui/lifetimes/elided-lifetime-in-path-in-type-relative-expression.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+struct Sqlite {}
+
+trait HasArguments<'q> {
+    type Arguments;
+}
+
+impl<'q> HasArguments<'q> for Sqlite {
+    type Arguments = std::marker::PhantomData<&'q ()>;
+}
+
+fn foo() {
+    let _ = <Sqlite as HasArguments>::Arguments::default();
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/dead-code/tuple-struct-field.rs b/src/test/ui/lint/dead-code/tuple-struct-field.rs
index c8fd32c64d6..b15d7063686 100644
--- a/src/test/ui/lint/dead-code/tuple-struct-field.rs
+++ b/src/test/ui/lint/dead-code/tuple-struct-field.rs
@@ -1,12 +1,37 @@
-// check-pass
+#![deny(unused_tuple_struct_fields)]
+//~^ NOTE: the lint level is defined here
 
-#![deny(dead_code)]
+use std::marker::PhantomData;
 
 const LEN: usize = 4;
 
-#[derive(Debug)]
-struct Wrapper([u8; LEN]);
+struct SingleUnused(i32, [u8; LEN], String);
+//~^ ERROR: field `1` is never read
+//~| NOTE: field in this struct
+//~| HELP: consider changing the field to be of unit type
+
+struct MultipleUnused(i32, f32, String, u8);
+//~^ ERROR: fields `0`, `1`, `2` and `3` are never read
+//~| NOTE: fields in this struct
+//~| HELP: consider changing the fields to be of unit type
+
+struct GoodUnit(());
+
+struct GoodPhantom(PhantomData<i32>);
+
+struct Void;
+struct GoodVoid(Void);
 
 fn main() {
-    println!("{:?}", Wrapper([0, 1, 2, 3]));
+    let w = SingleUnused(42, [0, 1, 2, 3], "abc".to_string());
+    let _ = w.0;
+    let _ = w.2;
+
+    let m = MultipleUnused(42, 3.14, "def".to_string(), 4u8);
+
+    let gu = GoodUnit(());
+    let gp = GoodPhantom(PhantomData);
+    let gv = GoodVoid(Void);
+
+    let _ = (gu, gp, gv, m);
 }
diff --git a/src/test/ui/lint/dead-code/tuple-struct-field.stderr b/src/test/ui/lint/dead-code/tuple-struct-field.stderr
new file mode 100644
index 00000000000..ca0989f5b98
--- /dev/null
+++ b/src/test/ui/lint/dead-code/tuple-struct-field.stderr
@@ -0,0 +1,33 @@
+error: field `1` is never read
+  --> $DIR/tuple-struct-field.rs:8:26
+   |
+LL | struct SingleUnused(i32, [u8; LEN], String);
+   |        ------------      ^^^^^^^^^
+   |        |
+   |        field in this struct
+   |
+note: the lint level is defined here
+  --> $DIR/tuple-struct-field.rs:1:9
+   |
+LL | #![deny(unused_tuple_struct_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider changing the field to be of unit type to suppress this warning while preserving the field numbering, or remove the field
+   |
+LL | struct SingleUnused(i32, (), String);
+   |                          ~~
+
+error: fields `0`, `1`, `2` and `3` are never read
+  --> $DIR/tuple-struct-field.rs:13:23
+   |
+LL | struct MultipleUnused(i32, f32, String, u8);
+   |        -------------- ^^^  ^^^  ^^^^^^  ^^
+   |        |
+   |        fields in this struct
+   |
+help: consider changing the fields to be of unit type to suppress this warning while preserving the field numbering, or remove the fields
+   |
+LL | struct MultipleUnused((), (), (), ());
+   |                       ~~  ~~  ~~  ~~
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lint/dead-code/with-impl.rs b/src/test/ui/lint/dead-code/with-impl.rs
index 84829c98e57..812fcdd09b6 100644
--- a/src/test/ui/lint/dead-code/with-impl.rs
+++ b/src/test/ui/lint/dead-code/with-impl.rs
@@ -2,7 +2,7 @@
 
 #![deny(dead_code)]
 
-pub struct GenericFoo<T>(T);
+pub struct GenericFoo<T>(#[allow(unused_tuple_struct_fields)] T);
 
 type Foo = GenericFoo<u32>;
 
diff --git a/src/test/ui/lint/issue-99387.rs b/src/test/ui/lint/issue-99387.rs
new file mode 100644
index 00000000000..616eb935e93
--- /dev/null
+++ b/src/test/ui/lint/issue-99387.rs
@@ -0,0 +1,24 @@
+// check-pass
+
+#![feature(type_alias_impl_trait)]
+#![allow(private_in_public)]
+
+pub type Successors<'a> = impl Iterator<Item = &'a ()>;
+
+pub fn f<'a>() -> Successors<'a> {
+    None.into_iter()
+}
+
+trait Tr {
+    type Item;
+}
+
+impl<'a> Tr for &'a () {
+    type Item = Successors<'a>;
+}
+
+pub fn ohno<'a>() -> <&'a () as Tr>::Item {
+    None.into_iter()
+}
+
+fn main() {}
diff --git a/src/test/ui/lint/unaligned_references.rs b/src/test/ui/lint/unaligned_references.rs
index d06b06b504f..e547f031a9c 100644
--- a/src/test/ui/lint/unaligned_references.rs
+++ b/src/test/ui/lint/unaligned_references.rs
@@ -47,4 +47,57 @@ fn main() {
         let _ = &packed2.y; // ok, has align 2 in packed(2) struct
         let _ = &packed2.z; // ok, has align 1
     }
+
+    unsafe {
+        struct U16(u16);
+
+        impl Drop for U16 {
+            fn drop(&mut self) {
+                println!("{:p}", self);
+            }
+        }
+
+        struct HasDrop;
+
+        impl Drop for HasDrop {
+            fn drop(&mut self) {}
+        }
+
+        #[allow(unused)]
+        struct Wrapper {
+            a: U16,
+            b: HasDrop,
+        }
+        #[allow(unused)]
+        #[repr(packed(2))]
+        struct Wrapper2 {
+            a: U16,
+            b: HasDrop,
+        }
+
+        // An outer struct with more restrictive packing than the inner struct -- make sure we
+        // notice that!
+        #[repr(packed)]
+        struct Misalign<T>(u8, T);
+
+        let m1 = Misalign(
+            0,
+            Wrapper {
+                a: U16(10),
+                b: HasDrop,
+            },
+        );
+        let _ref = &m1.1.a; //~ ERROR reference to packed field
+        //~^ previously accepted
+
+        let m2 = Misalign(
+            0,
+            Wrapper2 {
+                a: U16(10),
+                b: HasDrop,
+            },
+        );
+        let _ref = &m2.1.a; //~ ERROR reference to packed field
+        //~^ previously accepted
+    }
 }
diff --git a/src/test/ui/lint/unaligned_references.stderr b/src/test/ui/lint/unaligned_references.stderr
index ed5dd2ec011..97dbec2861c 100644
--- a/src/test/ui/lint/unaligned_references.stderr
+++ b/src/test/ui/lint/unaligned_references.stderr
@@ -80,7 +80,29 @@ LL |         let _ = &packed2.x;
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
-error: aborting due to 7 previous errors
+error: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:90:20
+   |
+LL |         let _ref = &m1.1.a;
+   |                    ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
+   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:100:20
+   |
+LL |         let _ref = &m2.1.a;
+   |                    ^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
+   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+error: aborting due to 9 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
 error: reference to packed field is unaligned
@@ -201,3 +223,37 @@ LL | #![deny(unaligned_references)]
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
    = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
+Future breakage diagnostic:
+error: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:90:20
+   |
+LL |         let _ref = &m1.1.a;
+   |                    ^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unaligned_references.rs:1:9
+   |
+LL | #![deny(unaligned_references)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
+   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+Future breakage diagnostic:
+error: reference to packed field is unaligned
+  --> $DIR/unaligned_references.rs:100:20
+   |
+LL |         let _ref = &m2.1.a;
+   |                    ^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unaligned_references.rs:1:9
+   |
+LL | #![deny(unaligned_references)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
+   = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
diff --git a/src/test/ui/lint/unreachable_pub.stderr b/src/test/ui/lint/unreachable_pub.stderr
index ce22eca1b8c..e021f500c66 100644
--- a/src/test/ui/lint/unreachable_pub.stderr
+++ b/src/test/ui/lint/unreachable_pub.stderr
@@ -1,8 +1,8 @@
 warning: unreachable `pub` item
-  --> $DIR/unreachable_pub.rs:8:5
+  --> $DIR/unreachable_pub.rs:8:13
    |
 LL |     pub use std::fmt;
-   |     ---^^^^^^^^^^^^^^
+   |     ---     ^^^^^^^^
    |     |
    |     help: consider restricting its visibility: `pub(crate)`
    |
@@ -93,7 +93,7 @@ warning: unreachable `pub` item
   --> $DIR/unreachable_pub.rs:33:5
    |
 LL |     pub const CARBON: usize = 1;
-   |     ---^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ---^^^^^^^^^^^^^^^^^^^^
    |     |
    |     help: consider restricting its visibility: `pub(crate)`
    |
@@ -103,7 +103,7 @@ warning: unreachable `pub` item
   --> $DIR/unreachable_pub.rs:34:5
    |
 LL |     pub static NITROGEN: usize = 2;
-   |     ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ---^^^^^^^^^^^^^^^^^^^^^^^
    |     |
    |     help: consider restricting its visibility: `pub(crate)`
    |
@@ -113,7 +113,7 @@ warning: unreachable `pub` item
   --> $DIR/unreachable_pub.rs:35:5
    |
 LL |     pub type Oxygen = bool;
-   |     ---^^^^^^^^^^^^^^^^^^^^
+   |     ---^^^^^^^^^^^^
    |     |
    |     help: consider restricting its visibility: `pub(crate)`
    |
@@ -123,7 +123,7 @@ warning: unreachable `pub` item
   --> $DIR/unreachable_pub.rs:38:47
    |
 LL |         ($visibility: vis, $name: ident) => { $visibility struct $name {} }
-   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL |     define_empty_struct_with_visibility!(pub, Fluorine);
    |     ---------------------------------------------------
@@ -138,7 +138,7 @@ warning: unreachable `pub` item
   --> $DIR/unreachable_pub.rs:44:9
    |
 LL |         pub fn catalyze() -> bool;
-   |         ---^^^^^^^^^^^^^^^^^^^^^^^
+   |         ---^^^^^^^^^^^^^^^^^^^^^^
    |         |
    |         help: consider restricting its visibility: `pub(crate)`
    |
diff --git a/src/test/ui/lint/unused/issue-92751.rs b/src/test/ui/lint/unused/issue-92751.rs
new file mode 100644
index 00000000000..2fb292736d1
--- /dev/null
+++ b/src/test/ui/lint/unused/issue-92751.rs
@@ -0,0 +1,9 @@
+#[deny(unused)]
+pub fn broken(x: Option<()>) -> i32 {
+    match x {
+        Some(()) => (1), //~ ERROR unnecessary parentheses around match arm expression
+        None => (2), //~ ERROR unnecessary parentheses around match arm expression
+    }
+}
+
+fn main() { }
diff --git a/src/test/ui/lint/unused/issue-92751.stderr b/src/test/ui/lint/unused/issue-92751.stderr
new file mode 100644
index 00000000000..0a8d8e6729c
--- /dev/null
+++ b/src/test/ui/lint/unused/issue-92751.stderr
@@ -0,0 +1,32 @@
+error: unnecessary parentheses around match arm expression
+  --> $DIR/issue-92751.rs:4:21
+   |
+LL |         Some(()) => (1),
+   |                     ^ ^
+   |
+note: the lint level is defined here
+  --> $DIR/issue-92751.rs:1:8
+   |
+LL | #[deny(unused)]
+   |        ^^^^^^
+   = note: `#[deny(unused_parens)]` implied by `#[deny(unused)]`
+help: remove these parentheses
+   |
+LL -         Some(()) => (1),
+LL +         Some(()) => 1,
+   |
+
+error: unnecessary parentheses around match arm expression
+  --> $DIR/issue-92751.rs:5:17
+   |
+LL |         None => (2),
+   |                 ^ ^
+   |
+help: remove these parentheses
+   |
+LL -         None => (2),
+LL +         None => 2,
+   |
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lint/unused/unused_attributes-must_use.stderr b/src/test/ui/lint/unused/unused_attributes-must_use.stderr
index 27269580e52..317d81c591d 100644
--- a/src/test/ui/lint/unused/unused_attributes-must_use.stderr
+++ b/src/test/ui/lint/unused/unused_attributes-must_use.stderr
@@ -45,7 +45,7 @@ error: `#[must_use]` has no effect when applied to a static item
 LL | #[must_use]
    | ^^^^^^^^^^^
 
-error: `#[must_use]` has no effect when applied to an item
+error: `#[must_use]` has no effect when applied to an implementation block
   --> $DIR/unused_attributes-must_use.rs:33:1
    |
 LL | #[must_use]
@@ -69,7 +69,7 @@ error: `#[must_use]` has no effect when applied to a type parameter
 LL | fn qux<#[must_use] T>(_: T) {}
    |        ^^^^^^^^^^^
 
-error: `#[must_use]` has no effect when applied to an item
+error: `#[must_use]` has no effect when applied to an implementation block
   --> $DIR/unused_attributes-must_use.rs:79:1
    |
 LL | #[must_use]
diff --git a/src/test/ui/list.rs b/src/test/ui/list.rs
index cb83d4103dc..ffe9f93860a 100644
--- a/src/test/ui/list.rs
+++ b/src/test/ui/list.rs
@@ -3,7 +3,7 @@
 #![allow(non_camel_case_types)]
 // pretty-expanded FIXME #23616
 
-enum list { cons(isize, Box<list>), nil, }
+enum list { #[allow(unused_tuple_struct_fields)] cons(isize, Box<list>), nil, }
 
 pub fn main() {
     list::cons(10, Box::new(list::cons(11, Box::new(list::cons(12, Box::new(list::nil))))));
diff --git a/src/test/ui/macros/html-literals.rs b/src/test/ui/macros/html-literals.rs
index ae45e97c8b0..26f00fed9c4 100644
--- a/src/test/ui/macros/html-literals.rs
+++ b/src/test/ui/macros/html-literals.rs
@@ -88,6 +88,7 @@ pub fn main() {
     );
 }
 
+#[allow(unused_tuple_struct_fields)]
 enum HTMLFragment {
     tag(String, Vec<HTMLFragment> ),
     text(String),
diff --git a/src/test/ui/macros/issue-98466.stderr b/src/test/ui/macros/issue-98466.stderr
index 4a39dd1440b..c93451c761a 100644
--- a/src/test/ui/macros/issue-98466.stderr
+++ b/src/test/ui/macros/issue-98466.stderr
@@ -2,9 +2,9 @@ warning: named argument `_x` is not used by name
   --> $DIR/issue-98466.rs:7:26
    |
 LL |     println!("_x is {}", _x = 5);
-   |                      -   ^^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `_x` by position
+   |                     --   ^^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `_x` by position
    |
    = note: `#[warn(named_arguments_used_positionally)]` on by default
 help: use the named argument by name to avoid ambiguity
@@ -16,9 +16,9 @@ warning: named argument `y` is not used by name
   --> $DIR/issue-98466.rs:10:26
    |
 LL |     println!("_x is {}", y = _x);
-   |                      -   ^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `y` by position
+   |                     --   ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `y` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -29,9 +29,9 @@ warning: named argument `y` is not used by name
   --> $DIR/issue-98466.rs:13:83
    |
 LL |     println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
-   |                                                                         -         ^ this named argument is only referred to by position in formatting string
-   |                                                                         |
-   |                                                                         this formatting argument uses named argument `y` by position
+   |                                                                        --         ^ this named argument is referred to by position in formatting string
+   |                                                                        |
+   |                                                                        this formatting argument uses named argument `y` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -42,9 +42,9 @@ warning: named argument `_x` is not used by name
   --> $DIR/issue-98466.rs:19:34
    |
 LL |     let _f = format!("_x is {}", _x = 5);
-   |                              -   ^^ this named argument is only referred to by position in formatting string
-   |                              |
-   |                              this formatting argument uses named argument `_x` by position
+   |                             --   ^^ this named argument is referred to by position in formatting string
+   |                             |
+   |                             this formatting argument uses named argument `_x` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -55,9 +55,9 @@ warning: named argument `y` is not used by name
   --> $DIR/issue-98466.rs:22:34
    |
 LL |     let _f = format!("_x is {}", y = _x);
-   |                              -   ^ this named argument is only referred to by position in formatting string
-   |                              |
-   |                              this formatting argument uses named argument `y` by position
+   |                             --   ^ this named argument is referred to by position in formatting string
+   |                             |
+   |                             this formatting argument uses named argument `y` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -68,9 +68,9 @@ warning: named argument `y` is not used by name
   --> $DIR/issue-98466.rs:25:91
    |
 LL |     let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x);
-   |                                                                                 -         ^ this named argument is only referred to by position in formatting string
-   |                                                                                 |
-   |                                                                                 this formatting argument uses named argument `y` by position
+   |                                                                                --         ^ this named argument is referred to by position in formatting string
+   |                                                                                |
+   |                                                                                this formatting argument uses named argument `y` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
diff --git a/src/test/ui/macros/issue-99265.stderr b/src/test/ui/macros/issue-99265.stderr
index 0798ad8dc51..2bfeedd7d07 100644
--- a/src/test/ui/macros/issue-99265.stderr
+++ b/src/test/ui/macros/issue-99265.stderr
@@ -2,9 +2,9 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:5:24
    |
 LL |     println!("{b} {}", a=1, b=2);
-   |                    -   ^ this named argument is only referred to by position in formatting string
-   |                    |
-   |                    this formatting argument uses named argument `a` by position
+   |                   --   ^ this named argument is referred to by position in formatting string
+   |                   |
+   |                   this formatting argument uses named argument `a` by position
    |
    = note: `#[warn(named_arguments_used_positionally)]` on by default
 help: use the named argument by name to avoid ambiguity
@@ -16,9 +16,9 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:9:35
    |
 LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
-   |                   -               ^ this named argument is only referred to by position in formatting string
-   |                   |
-   |                   this formatting argument uses named argument `a` by position
+   |                  --               ^ this named argument is referred to by position in formatting string
+   |                  |
+   |                  this formatting argument uses named argument `a` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -29,9 +29,9 @@ warning: named argument `b` is not used by name
   --> $DIR/issue-99265.rs:9:40
    |
 LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
-   |                      -                 ^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `b` by position
+   |                     --                 ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `b` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -42,9 +42,9 @@ warning: named argument `c` is not used by name
   --> $DIR/issue-99265.rs:9:45
    |
 LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
-   |                         -                   ^ this named argument is only referred to by position in formatting string
-   |                         |
-   |                         this formatting argument uses named argument `c` by position
+   |                        --                   ^ this named argument is referred to by position in formatting string
+   |                        |
+   |                        this formatting argument uses named argument `c` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -55,9 +55,9 @@ warning: named argument `d` is not used by name
   --> $DIR/issue-99265.rs:9:50
    |
 LL |     println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4);
-   |                            -                     ^ this named argument is only referred to by position in formatting string
-   |                            |
-   |                            this formatting argument uses named argument `d` by position
+   |                           --                     ^ this named argument is referred to by position in formatting string
+   |                           |
+   |                           this formatting argument uses named argument `d` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -68,9 +68,9 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:19:35
    |
 LL |     println!("Hello {:1$}!", "x", width = 5);
-   |                       --          ^^^^^ this named argument is only referred to by position in formatting string
+   |                       --          ^^^^^ this named argument is referred to by position in formatting string
    |                       |
-   |                       this formatting argument uses named argument `width$` by position
+   |                       this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -81,9 +81,9 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:23:46
    |
 LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                       --                     ^^^^^ this named argument is only referred to by position in formatting string
+   |                       --                     ^^^^^ this named argument is referred to by position in formatting string
    |                       |
-   |                       this formatting argument uses named argument `width$` by position
+   |                       this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -94,9 +94,9 @@ warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:23:57
    |
 LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                          --                             ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |                          --                             ^^^^^^^^^ this named argument is referred to by position in formatting string
    |                          |
-   |                          this formatting argument uses named argument `precision$` by position
+   |                          this formatting argument uses named argument `precision` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -107,9 +107,9 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:23:33
    |
 LL |     println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                      -          ^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `f` by position
+   |                     --          ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -120,9 +120,9 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:31:47
    |
 LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                        --                     ^^^^^ this named argument is only referred to by position in formatting string
+   |                        --                     ^^^^^ this named argument is referred to by position in formatting string
    |                        |
-   |                        this formatting argument uses named argument `width$` by position
+   |                        this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -133,9 +133,9 @@ warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:31:58
    |
 LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                           --                             ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |                           --                             ^^^^^^^^^ this named argument is referred to by position in formatting string
    |                           |
-   |                           this formatting argument uses named argument `precision$` by position
+   |                           this formatting argument uses named argument `precision` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -146,7 +146,7 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:31:34
    |
 LL |     println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2);
-   |                      -           ^ this named argument is only referred to by position in formatting string
+   |                      -           ^ this named argument is referred to by position in formatting string
    |                      |
    |                      this formatting argument uses named argument `f` by position
    |
@@ -159,10 +159,10 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:52:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                       -- this formatting argument uses named argument `width$` by position
+   |                       -- this formatting argument uses named argument `width` by position
 ...
 LL |         width = 5,
-   |         ^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -173,10 +173,10 @@ warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:54:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                          -- this formatting argument uses named argument `precision$` by position
+   |                          -- this formatting argument uses named argument `precision` by position
 ...
 LL |         precision = 2,
-   |         ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -190,7 +190,7 @@ LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
    |                     - this formatting argument uses named argument `f` by position
 ...
 LL |         f = 0.02f32,
-   |         ^ this named argument is only referred to by position in formatting string
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -201,10 +201,10 @@ warning: named argument `width2` is not used by name
   --> $DIR/issue-99265.rs:58:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                                 -- this formatting argument uses named argument `width2$` by position
+   |                                 -- this formatting argument uses named argument `width2` by position
 ...
 LL |         width2 = 5,
-   |         ^^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -215,10 +215,10 @@ warning: named argument `precision2` is not used by name
   --> $DIR/issue-99265.rs:60:9
    |
 LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
-   |                                    -- this formatting argument uses named argument `precision2$` by position
+   |                                    -- this formatting argument uses named argument `precision2` by position
 ...
 LL |         precision2 = 2
-   |         ^^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -232,7 +232,7 @@ LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
    |                               - this formatting argument uses named argument `g` by position
 ...
 LL |         g = 0.02f32,
-   |         ^ this named argument is only referred to by position in formatting string
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -246,7 +246,7 @@ LL |         "{}, Hello {1:2$.3$} {4:5$.6$}! {1}",
    |                                          - this formatting argument uses named argument `f` by position
 ...
 LL |         f = 0.02f32,
-   |         ^ this named argument is only referred to by position in formatting string
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -257,9 +257,9 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:64:31
    |
 LL |     println!("Hello {:0.1}!", f = 0.02f32);
-   |                      -        ^ this named argument is only referred to by position in formatting string
-   |                      |
-   |                      this formatting argument uses named argument `f` by position
+   |                     --        ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -270,7 +270,7 @@ warning: named argument `f` is not used by name
   --> $DIR/issue-99265.rs:68:32
    |
 LL |     println!("Hello {0:0.1}!", f = 0.02f32);
-   |                      -         ^ this named argument is only referred to by position in formatting string
+   |                      -         ^ this named argument is referred to by position in formatting string
    |                      |
    |                      this formatting argument uses named argument `f` by position
    |
@@ -283,9 +283,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:79:23
    |
 LL |     println!("{:0$}", v = val);
-   |                 --    ^ this named argument is only referred to by position in formatting string
+   |                 --    ^ this named argument is referred to by position in formatting string
    |                 |
-   |                 this formatting argument uses named argument `v$` by position
+   |                 this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -296,9 +296,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:79:23
    |
 LL |     println!("{:0$}", v = val);
-   |                -      ^ this named argument is only referred to by position in formatting string
-   |                |
-   |                this formatting argument uses named argument `v` by position
+   |               --      ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -309,9 +309,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:84:24
    |
 LL |     println!("{0:0$}", v = val);
-   |                  --    ^ this named argument is only referred to by position in formatting string
+   |                  --    ^ this named argument is referred to by position in formatting string
    |                  |
-   |                  this formatting argument uses named argument `v$` by position
+   |                  this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -322,7 +322,7 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:84:24
    |
 LL |     println!("{0:0$}", v = val);
-   |                -       ^ this named argument is only referred to by position in formatting string
+   |                -       ^ this named argument is referred to by position in formatting string
    |                |
    |                this formatting argument uses named argument `v` by position
    |
@@ -335,9 +335,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:89:26
    |
 LL |     println!("{:0$.0$}", v = val);
-   |                 --       ^ this named argument is only referred to by position in formatting string
+   |                 --       ^ this named argument is referred to by position in formatting string
    |                 |
-   |                 this formatting argument uses named argument `v$` by position
+   |                 this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -348,9 +348,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:89:26
    |
 LL |     println!("{:0$.0$}", v = val);
-   |                    --    ^ this named argument is only referred to by position in formatting string
+   |                    --    ^ this named argument is referred to by position in formatting string
    |                    |
-   |                    this formatting argument uses named argument `v$` by position
+   |                    this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -361,9 +361,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:89:26
    |
 LL |     println!("{:0$.0$}", v = val);
-   |                -         ^ this named argument is only referred to by position in formatting string
-   |                |
-   |                this formatting argument uses named argument `v` by position
+   |               --         ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -374,9 +374,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:96:27
    |
 LL |     println!("{0:0$.0$}", v = val);
-   |                  --       ^ this named argument is only referred to by position in formatting string
+   |                  --       ^ this named argument is referred to by position in formatting string
    |                  |
-   |                  this formatting argument uses named argument `v$` by position
+   |                  this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -387,9 +387,9 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:96:27
    |
 LL |     println!("{0:0$.0$}", v = val);
-   |                     --    ^ this named argument is only referred to by position in formatting string
+   |                     --    ^ this named argument is referred to by position in formatting string
    |                     |
-   |                     this formatting argument uses named argument `v$` by position
+   |                     this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -400,7 +400,7 @@ warning: named argument `v` is not used by name
   --> $DIR/issue-99265.rs:96:27
    |
 LL |     println!("{0:0$.0$}", v = val);
-   |                -          ^ this named argument is only referred to by position in formatting string
+   |                -          ^ this named argument is referred to by position in formatting string
    |                |
    |                this formatting argument uses named argument `v` by position
    |
@@ -413,9 +413,9 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:104:28
    |
 LL |     println!("{} {a} {0}", a = 1);
-   |                -           ^ this named argument is only referred to by position in formatting string
-   |                |
-   |                this formatting argument uses named argument `a` by position
+   |               --           ^ this named argument is referred to by position in formatting string
+   |               |
+   |               this formatting argument uses named argument `a` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -426,7 +426,7 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:104:28
    |
 LL |     println!("{} {a} {0}", a = 1);
-   |                       -    ^ this named argument is only referred to by position in formatting string
+   |                       -    ^ this named argument is referred to by position in formatting string
    |                       |
    |                       this formatting argument uses named argument `a` by position
    |
@@ -439,10 +439,10 @@ warning: named argument `b` is not used by name
   --> $DIR/issue-99265.rs:115:23
    |
 LL |                 {:1$.2$}",
-   |                   -- this formatting argument uses named argument `b$` by position
+   |                   -- this formatting argument uses named argument `b` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                       ^ this named argument is only referred to by position in formatting string
+   |                       ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -453,10 +453,10 @@ warning: named argument `c` is not used by name
   --> $DIR/issue-99265.rs:115:30
    |
 LL |                 {:1$.2$}",
-   |                      -- this formatting argument uses named argument `c$` by position
+   |                      -- this formatting argument uses named argument `c` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                              ^ this named argument is only referred to by position in formatting string
+   |                              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -467,10 +467,10 @@ warning: named argument `a` is not used by name
   --> $DIR/issue-99265.rs:115:14
    |
 LL |                 {:1$.2$}",
-   |                  - this formatting argument uses named argument `a` by position
+   |                 -- this formatting argument uses named argument `a` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |              ^ this named argument is only referred to by position in formatting string
+   |              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -481,10 +481,10 @@ warning: named argument `b` is not used by name
   --> $DIR/issue-99265.rs:126:23
    |
 LL |                 {0:1$.2$}",
-   |                    -- this formatting argument uses named argument `b$` by position
+   |                    -- this formatting argument uses named argument `b` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                       ^ this named argument is only referred to by position in formatting string
+   |                       ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -495,10 +495,10 @@ warning: named argument `c` is not used by name
   --> $DIR/issue-99265.rs:126:30
    |
 LL |                 {0:1$.2$}",
-   |                       -- this formatting argument uses named argument `c$` by position
+   |                       -- this formatting argument uses named argument `c` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |                              ^ this named argument is only referred to by position in formatting string
+   |                              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -512,7 +512,7 @@ LL |                 {0:1$.2$}",
    |                  - this formatting argument uses named argument `a` by position
 ...
 LL |              a = 1.0, b = 1, c = 2,
-   |              ^ this named argument is only referred to by position in formatting string
+   |              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -523,9 +523,9 @@ warning: named argument `width` is not used by name
   --> $DIR/issue-99265.rs:132:39
    |
 LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                   --                  ^^^^^ this named argument is only referred to by position in formatting string
+   |                   --                  ^^^^^ this named argument is referred to by position in formatting string
    |                   |
-   |                   this formatting argument uses named argument `width$` by position
+   |                   this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -536,9 +536,9 @@ warning: named argument `precision` is not used by name
   --> $DIR/issue-99265.rs:132:50
    |
 LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                      --                          ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |                      --                          ^^^^^^^^^ this named argument is referred to by position in formatting string
    |                      |
-   |                      this formatting argument uses named argument `precision$` by position
+   |                      this formatting argument uses named argument `precision` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -549,9 +549,9 @@ warning: named argument `x` is not used by name
   --> $DIR/issue-99265.rs:132:30
    |
 LL |     println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2);
-   |                  -           ^ this named argument is only referred to by position in formatting string
-   |                  |
-   |                  this formatting argument uses named argument `x` by position
+   |                 --           ^ this named argument is referred to by position in formatting string
+   |                 |
+   |                 this formatting argument uses named argument `x` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
diff --git a/src/test/ui/macros/issue-99907.fixed b/src/test/ui/macros/issue-99907.fixed
new file mode 100644
index 00000000000..9e0e1b80ee5
--- /dev/null
+++ b/src/test/ui/macros/issue-99907.fixed
@@ -0,0 +1,24 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    println!("Hello {f:.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f:1.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {f}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+}
diff --git a/src/test/ui/macros/issue-99907.rs b/src/test/ui/macros/issue-99907.rs
new file mode 100644
index 00000000000..eebcfc2efec
--- /dev/null
+++ b/src/test/ui/macros/issue-99907.rs
@@ -0,0 +1,24 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    println!("Hello {:.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {:1.1}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {}!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello { }!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+
+    println!("Hello {  }!", f = 0.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+}
diff --git a/src/test/ui/macros/issue-99907.stderr b/src/test/ui/macros/issue-99907.stderr
new file mode 100644
index 00000000000..4786ce003b4
--- /dev/null
+++ b/src/test/ui/macros/issue-99907.stderr
@@ -0,0 +1,68 @@
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:5:30
+   |
+LL |     println!("Hello {:.1}!", f = 0.02f32);
+   |                     --       ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+   = note: `#[warn(named_arguments_used_positionally)]` on by default
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:.1}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:9:31
+   |
+LL |     println!("Hello {:1.1}!", f = 0.02f32);
+   |                     --        ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:1.1}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:13:27
+   |
+LL |     println!("Hello {}!", f = 0.02f32);
+   |                     --    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:17:28
+   |
+LL |     println!("Hello { }!", f = 0.02f32);
+   |                     ---    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:21:29
+   |
+LL |     println!("Hello {  }!", f = 0.02f32);
+   |                     ----    ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f}!", f = 0.02f32);
+   |                      +
+
+warning: 5 warnings emitted
+
diff --git a/src/test/ui/macros/macro-tt-followed-by-seq.rs b/src/test/ui/macros/macro-tt-followed-by-seq.rs
index 90131ebd920..080dbcfdd41 100644
--- a/src/test/ui/macros/macro-tt-followed-by-seq.rs
+++ b/src/test/ui/macros/macro-tt-followed-by-seq.rs
@@ -5,6 +5,7 @@
 use self::Join::*;
 
 #[derive(Debug)]
+#[allow(unused_tuple_struct_fields)]
 enum Join<A,B> {
   Keep(A,B),
   Skip(A,B),
diff --git a/src/test/ui/methods/method-argument-inference-associated-type.rs b/src/test/ui/methods/method-argument-inference-associated-type.rs
index acd4a8465b0..a3c31fab1c2 100644
--- a/src/test/ui/methods/method-argument-inference-associated-type.rs
+++ b/src/test/ui/methods/method-argument-inference-associated-type.rs
@@ -7,7 +7,7 @@ pub trait Service {
     fn call(&self, _req: Self::Request);
 }
 
-pub struct S<T>(T);
+pub struct S<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl Service for ClientMap {
     type Request = S<Box<dyn Fn(i32)>>;
diff --git a/src/test/ui/methods/method-probe-no-guessing-dyn-trait.rs b/src/test/ui/methods/method-probe-no-guessing-dyn-trait.rs
index af362efe15c..ec41b711709 100644
--- a/src/test/ui/methods/method-probe-no-guessing-dyn-trait.rs
+++ b/src/test/ui/methods/method-probe-no-guessing-dyn-trait.rs
@@ -15,7 +15,7 @@ trait MyTrait1 {
 
 impl MyTrait1 for Foo<u32> {}
 
-struct Foo<T>(T);
+struct Foo<T>(#[allow(unused_tuple_struct_fields)] T);
 
 impl Deref for Foo<()> {
     type Target = dyn MyTrait1 + 'static;
@@ -33,7 +33,7 @@ trait MyTrait2 {
 }
 
 impl MyTrait2 for u32 {}
-struct Bar<T>(T, u32);
+struct Bar<T>(#[allow(unused_tuple_struct_fields)] T, u32);
 impl Deref for Bar<u8> {
     type Target = dyn MyTrait2 + 'static;
     fn deref(&self) -> &(dyn MyTrait2 + 'static) {
diff --git a/src/test/ui/mir/mir_codegen_switch.rs b/src/test/ui/mir/mir_codegen_switch.rs
index d2589ae4ad2..9c93499d948 100644
--- a/src/test/ui/mir/mir_codegen_switch.rs
+++ b/src/test/ui/mir/mir_codegen_switch.rs
@@ -1,7 +1,7 @@
 // run-pass
 enum Abc {
-    A(u8),
-    B(i8),
+    A(#[allow(unused_tuple_struct_fields)] u8),
+    B(#[allow(unused_tuple_struct_fields)] i8),
     C,
     D,
 }
diff --git a/src/test/ui/mir/mir_fat_ptr.rs b/src/test/ui/mir/mir_fat_ptr.rs
index fb34de62f31..7c3e07c9e34 100644
--- a/src/test/ui/mir/mir_fat_ptr.rs
+++ b/src/test/ui/mir/mir_fat_ptr.rs
@@ -1,7 +1,7 @@
 // run-pass
 // test that ordinary fat pointer operations work.
 
-struct Wrapper<T: ?Sized>(u32, T);
+struct Wrapper<T: ?Sized>(#[allow(unused_tuple_struct_fields)] u32, T);
 
 struct FatPtrContainer<'a> {
     ptr: &'a [u8]
diff --git a/src/test/ui/mir/mir_raw_fat_ptr.rs b/src/test/ui/mir/mir_raw_fat_ptr.rs
index aa2b499b027..6aceefbe715 100644
--- a/src/test/ui/mir/mir_raw_fat_ptr.rs
+++ b/src/test/ui/mir/mir_raw_fat_ptr.rs
@@ -103,6 +103,7 @@ impl<T> Foo for T {
     }
 }
 
+#[allow(unused_tuple_struct_fields)]
 struct S<T:?Sized>(u32, T);
 
 fn main_ref() {
diff --git a/src/test/ui/mir/mir_refs_correct.rs b/src/test/ui/mir/mir_refs_correct.rs
index 729db2d25f5..6cd9526b749 100644
--- a/src/test/ui/mir/mir_refs_correct.rs
+++ b/src/test/ui/mir/mir_refs_correct.rs
@@ -3,7 +3,7 @@
 
 extern crate mir_external_refs as ext;
 
-struct S(u8);
+struct S(#[allow(unused_tuple_struct_fields)] u8);
 #[derive(Debug, PartialEq, Eq)]
 struct Unit;
 
@@ -46,7 +46,7 @@ impl<I, O> T<I, O> for O {}
 impl X for S {}
 
 enum E {
-    U(u8)
+    U(#[allow(unused_tuple_struct_fields)] u8)
 }
 
 #[derive(PartialEq, Debug, Eq)]
diff --git a/src/test/ui/mismatched_types/E0409.stderr b/src/test/ui/mismatched_types/E0409.stderr
index ef03b67b1b0..7fec6ecd725 100644
--- a/src/test/ui/mismatched_types/E0409.stderr
+++ b/src/test/ui/mismatched_types/E0409.stderr
@@ -17,6 +17,10 @@ LL |         (0, ref y) | (y, 0) => {}
    |             first introduced with type `&{integer}` here
    |
    = note: in the same arm, a binding must have the same type in all alternatives
+help: consider adding `ref`
+   |
+LL |         (0, ref y) | (ref y, 0) => {}
+   |                       +++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/mismatched_types/dont-point-return-on-E0308.rs b/src/test/ui/mismatched_types/dont-point-return-on-E0308.rs
new file mode 100644
index 00000000000..f2ba610e2d1
--- /dev/null
+++ b/src/test/ui/mismatched_types/dont-point-return-on-E0308.rs
@@ -0,0 +1,18 @@
+// edition:2021
+
+async fn f(_: &()) {}
+//~^ NOTE function defined here
+//~| NOTE
+// Second note is the span of the underlined argument, I think...
+
+fn main() {
+    (|| async {
+        Err::<(), ()>(())?;
+        f(());
+        //~^ ERROR mismatched types
+        //~| NOTE arguments to this function are incorrect
+        //~| NOTE expected `&()`, found `()`
+        //~| HELP consider borrowing here
+        Ok::<(), ()>(())
+    })();
+}
diff --git a/src/test/ui/mismatched_types/dont-point-return-on-E0308.stderr b/src/test/ui/mismatched_types/dont-point-return-on-E0308.stderr
new file mode 100644
index 00000000000..13942682d28
--- /dev/null
+++ b/src/test/ui/mismatched_types/dont-point-return-on-E0308.stderr
@@ -0,0 +1,19 @@
+error[E0308]: mismatched types
+  --> $DIR/dont-point-return-on-E0308.rs:11:11
+   |
+LL |         f(());
+   |         - ^^
+   |         | |
+   |         | expected `&()`, found `()`
+   |         | help: consider borrowing here: `&()`
+   |         arguments to this function are incorrect
+   |
+note: function defined here
+  --> $DIR/dont-point-return-on-E0308.rs:3:10
+   |
+LL | async fn f(_: &()) {}
+   |          ^ ------
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/mismatched_types/issue-84976.stderr b/src/test/ui/mismatched_types/issue-84976.stderr
index f8f2b1f0f57..9157566e3a7 100644
--- a/src/test/ui/mismatched_types/issue-84976.stderr
+++ b/src/test/ui/mismatched_types/issue-84976.stderr
@@ -3,6 +3,11 @@ error[E0308]: mismatched types
    |
 LL |     length = { foo(&length) };
    |                ^^^^^^^^^^^^ expected `u32`, found `i32`
+   |
+help: you can convert an `i32` to a `u32` and panic if the converted value doesn't fit
+   |
+LL |     length = { foo(&length).try_into().unwrap() };
+   |                            ++++++++++++++++++++
 
 error[E0308]: mismatched types
   --> $DIR/issue-84976.rs:17:14
diff --git a/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.fixed b/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.fixed
new file mode 100644
index 00000000000..56f93cfbfdc
--- /dev/null
+++ b/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.fixed
@@ -0,0 +1,21 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+
+fn main() {
+    enum Blah {
+        A(isize, isize, usize),
+        B(isize, usize),
+    }
+
+    match Blah::A(1, 1, 2) {
+        Blah::A(_, x, ref y) | Blah::B(x, ref y) => {}
+        //~^ ERROR mismatched types
+        //~| ERROR variable `y` is bound inconsistently across alternatives separated by `|`
+    }
+
+    match Blah::A(1, 1, 2) {
+        Blah::A(_, x, y) | Blah::B(x, y) => {}
+        //~^ ERROR mismatched types
+        //~| variable `y` is bound inconsistently across alternatives separated by `|`
+    }
+}
diff --git a/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.rs b/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.rs
new file mode 100644
index 00000000000..0c33f99a42e
--- /dev/null
+++ b/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.rs
@@ -0,0 +1,21 @@
+// run-rustfix
+#![allow(dead_code, unused_variables)]
+
+fn main() {
+    enum Blah {
+        A(isize, isize, usize),
+        B(isize, usize),
+    }
+
+    match Blah::A(1, 1, 2) {
+        Blah::A(_, x, ref y) | Blah::B(x, y) => {}
+        //~^ ERROR mismatched types
+        //~| ERROR variable `y` is bound inconsistently across alternatives separated by `|`
+    }
+
+    match Blah::A(1, 1, 2) {
+        Blah::A(_, x, y) | Blah::B(x, ref y) => {}
+        //~^ ERROR mismatched types
+        //~| variable `y` is bound inconsistently across alternatives separated by `|`
+    }
+}
diff --git a/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.stderr b/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.stderr
new file mode 100644
index 00000000000..e8357f9a37f
--- /dev/null
+++ b/src/test/ui/mismatched_types/suggest-adding-or-removing-ref-for-binding-pattern.stderr
@@ -0,0 +1,49 @@
+error[E0409]: variable `y` is bound inconsistently across alternatives separated by `|`
+  --> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:11:43
+   |
+LL |         Blah::A(_, x, ref y) | Blah::B(x, y) => {}
+   |                           - first binding ^ bound in different ways
+
+error[E0409]: variable `y` is bound inconsistently across alternatives separated by `|`
+  --> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:17:43
+   |
+LL |         Blah::A(_, x, y) | Blah::B(x, ref y) => {}
+   |                       - first binding     ^ bound in different ways
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:11:43
+   |
+LL |     match Blah::A(1, 1, 2) {
+   |           ---------------- this expression has type `Blah`
+LL |         Blah::A(_, x, ref y) | Blah::B(x, y) => {}
+   |                       -----               ^ expected `&usize`, found `usize`
+   |                       |
+   |                       first introduced with type `&usize` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
+help: consider adding `ref`
+   |
+LL |         Blah::A(_, x, ref y) | Blah::B(x, ref y) => {}
+   |                                           +++
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-adding-or-removing-ref-for-binding-pattern.rs:17:39
+   |
+LL |     match Blah::A(1, 1, 2) {
+   |           ---------------- this expression has type `Blah`
+LL |         Blah::A(_, x, y) | Blah::B(x, ref y) => {}
+   |                       -               ^^^^^ expected `usize`, found `&usize`
+   |                       |
+   |                       first introduced with type `usize` here
+   |
+   = note: in the same arm, a binding must have the same type in all alternatives
+help: consider removing `ref`
+   |
+LL -         Blah::A(_, x, y) | Blah::B(x, ref y) => {}
+LL +         Blah::A(_, x, y) | Blah::B(x, y) => {}
+   |
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0308, E0409.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/moves/issue-99470-move-out-of-some.rs b/src/test/ui/moves/issue-99470-move-out-of-some.rs
new file mode 100644
index 00000000000..f404cd3cd71
--- /dev/null
+++ b/src/test/ui/moves/issue-99470-move-out-of-some.rs
@@ -0,0 +1,9 @@
+fn main() {
+    let x: &Option<Box<i32>> = &Some(Box::new(0));
+
+    match x {
+    //~^ ERROR cannot move out of `x` as enum variant `Some` which is behind a shared reference
+        &Some(_y) => (),
+        &None => (),
+    }
+}
diff --git a/src/test/ui/moves/issue-99470-move-out-of-some.stderr b/src/test/ui/moves/issue-99470-move-out-of-some.stderr
new file mode 100644
index 00000000000..6e4a4e5ba22
--- /dev/null
+++ b/src/test/ui/moves/issue-99470-move-out-of-some.stderr
@@ -0,0 +1,16 @@
+error[E0507]: cannot move out of `x` as enum variant `Some` which is behind a shared reference
+  --> $DIR/issue-99470-move-out-of-some.rs:4:11
+   |
+LL |     match x {
+   |           ^
+LL |
+LL |         &Some(_y) => (),
+   |         ---------
+   |         |     |
+   |         |     data moved here
+   |         |     move occurs because `_y` has type `Box<i32>`, which does not implement the `Copy` trait
+   |         help: consider removing the `&`: `Some(_y)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/moves/moves-based-on-type-block-bad.stderr b/src/test/ui/moves/moves-based-on-type-block-bad.stderr
index a9ac9d63a95..5ed91a0d559 100644
--- a/src/test/ui/moves/moves-based-on-type-block-bad.stderr
+++ b/src/test/ui/moves/moves-based-on-type-block-bad.stderr
@@ -1,4 +1,4 @@
-error[E0507]: cannot move out of `hellothere.x.0` which is behind a shared reference
+error[E0507]: cannot move out of `hellothere.x` as enum variant `Bar` which is behind a shared reference
   --> $DIR/moves-based-on-type-block-bad.rs:22:19
    |
 LL |             match hellothere.x {
diff --git a/src/test/ui/nll/issue-98589-closures-relate-named-regions.rs b/src/test/ui/nll/issue-98589-closures-relate-named-regions.rs
new file mode 100644
index 00000000000..6cc4340bbd7
--- /dev/null
+++ b/src/test/ui/nll/issue-98589-closures-relate-named-regions.rs
@@ -0,0 +1,36 @@
+// Regression test for #98589.
+// Previously, named lifetime `'a` that appears in the closure was unrelated to `'a`
+// that appears in the parent function iff `'a` is early-bound.
+// This made the following tests pass borrowck.
+
+// check-fail
+
+// The bound `'a: 'a` ensures that `'a` is early-bound.
+fn test_early_early<'a: 'a, 'b: 'b>() {
+    || { None::<&'a &'b ()>; };
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn test_early_late<'a: 'a, 'b>() {
+    || { None::<&'a &'b ()>; };
+    //~^ ERROR lifetime may not live long enough
+}
+
+// No early-bound lifetime; included for completeness.
+fn test_late_late<'a, 'b>() {
+    || { None::<&'a &'b ()>; };
+    //~^ ERROR lifetime may not live long enough
+}
+
+fn test_early_type<'a: 'a, T>() {
+    || { None::<&'a T>; };
+    //~^ ERROR the parameter type `T` may not live long enough
+}
+
+// No early-bound lifetime; included for completeness.
+fn test_late_type<'a, T>() {
+    || { None::<&'a T>; };
+    //~^ ERROR the parameter type `T` may not live long enough
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/issue-98589-closures-relate-named-regions.stderr b/src/test/ui/nll/issue-98589-closures-relate-named-regions.stderr
new file mode 100644
index 00000000000..6def5602e70
--- /dev/null
+++ b/src/test/ui/nll/issue-98589-closures-relate-named-regions.stderr
@@ -0,0 +1,61 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-98589-closures-relate-named-regions.rs:10:5
+   |
+LL | fn test_early_early<'a: 'a, 'b: 'b>() {
+   |                     --      -- lifetime `'b` defined here
+   |                     |
+   |                     lifetime `'a` defined here
+LL |     || { None::<&'a &'b ()>; };
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-98589-closures-relate-named-regions.rs:15:10
+   |
+LL | fn test_early_late<'a: 'a, 'b>() {
+   |                    --      -- lifetime `'b` defined here
+   |                    |
+   |                    lifetime `'a` defined here
+LL |     || { None::<&'a &'b ()>; };
+   |          ^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-98589-closures-relate-named-regions.rs:21:10
+   |
+LL | fn test_late_late<'a, 'b>() {
+   |                   --  -- lifetime `'b` defined here
+   |                   |
+   |                   lifetime `'a` defined here
+LL |     || { None::<&'a &'b ()>; };
+   |          ^^^^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/issue-98589-closures-relate-named-regions.rs:26:5
+   |
+LL |     || { None::<&'a T>; };
+   |     ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn test_early_type<'a: 'a, T: 'a>() {
+   |                             ++++
+
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/issue-98589-closures-relate-named-regions.rs:32:5
+   |
+LL |     || { None::<&'a T>; };
+   |     ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+   |
+help: consider adding an explicit lifetime bound...
+   |
+LL | fn test_late_type<'a, T: 'a>() {
+   |                        ++++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/nll/move-errors.stderr b/src/test/ui/nll/move-errors.stderr
index 0df326425ad..b03fcf70bab 100644
--- a/src/test/ui/nll/move-errors.stderr
+++ b/src/test/ui/nll/move-errors.stderr
@@ -45,7 +45,7 @@ LL |     let a = [A("".to_string())][0];
    |             move occurs because value has type `A`, which does not implement the `Copy` trait
    |             help: consider borrowing here: `&[A("".to_string())][0]`
 
-error[E0507]: cannot move out of `a.0` which is behind a shared reference
+error[E0507]: cannot move out of `a` which is behind a shared reference
   --> $DIR/move-errors.rs:38:16
    |
 LL |     let A(s) = *a;
@@ -134,7 +134,7 @@ LL |         F(s, mut t) => (),
    |
    = note: move occurs because these variables have types that don't implement the `Copy` trait
 
-error[E0507]: cannot move out of `x.0` which is behind a shared reference
+error[E0507]: cannot move out of `x` as enum variant `Err` which is behind a shared reference
   --> $DIR/move-errors.rs:110:11
    |
 LL |     match *x {
diff --git a/src/test/ui/nullable-pointer-iotareduction.rs b/src/test/ui/nullable-pointer-iotareduction.rs
index f9edba67434..d345fec8118 100644
--- a/src/test/ui/nullable-pointer-iotareduction.rs
+++ b/src/test/ui/nullable-pointer-iotareduction.rs
@@ -8,7 +8,7 @@
 // trying to get assert failure messages that at least identify which case
 // failed.
 
-enum E<T> { Thing(isize, T), Nothing((), ((), ()), [i8; 0]) }
+enum E<T> { Thing(isize, T), #[allow(unused_tuple_struct_fields)] Nothing((), ((), ()), [i8; 0]) }
 impl<T> E<T> {
     fn is_none(&self) -> bool {
         match *self {
diff --git a/src/test/ui/optimization-fuel-0.rs b/src/test/ui/optimization-fuel-0.rs
index a97c5750f94..2643dbea1c4 100644
--- a/src/test/ui/optimization-fuel-0.rs
+++ b/src/test/ui/optimization-fuel-0.rs
@@ -6,7 +6,9 @@ use std::mem::size_of;
 
 // compile-flags: -Z fuel=foo=0
 
+#[allow(unused_tuple_struct_fields)]
 struct S1(u8, u16, u8);
+#[allow(unused_tuple_struct_fields)]
 struct S2(u8, u16, u8);
 
 fn main() {
diff --git a/src/test/ui/optimization-fuel-1.rs b/src/test/ui/optimization-fuel-1.rs
index a09f91c68ab..d5e2255d9f0 100644
--- a/src/test/ui/optimization-fuel-1.rs
+++ b/src/test/ui/optimization-fuel-1.rs
@@ -6,7 +6,9 @@ use std::mem::size_of;
 
 // compile-flags: -Z fuel=foo=1
 
+#[allow(unused_tuple_struct_fields)]
 struct S1(u8, u16, u8);
+#[allow(unused_tuple_struct_fields)]
 struct S2(u8, u16, u8);
 
 fn main() {
diff --git a/src/test/ui/packed/packed-struct-drop-aligned.rs b/src/test/ui/packed/packed-struct-drop-aligned.rs
index b95cdbbbaad..9f9f41e2515 100644
--- a/src/test/ui/packed/packed-struct-drop-aligned.rs
+++ b/src/test/ui/packed/packed-struct-drop-aligned.rs
@@ -24,7 +24,7 @@ impl<'a> Drop for Aligned<'a> {
 }
 
 #[repr(transparent)]
-struct NotCopy(u8);
+struct NotCopy(#[allow(unused_tuple_struct_fields)] u8);
 
 #[repr(packed)]
 struct Packed<'a>(NotCopy, Aligned<'a>);
diff --git a/src/test/ui/packed/packed-struct-optimized-enum.rs b/src/test/ui/packed/packed-struct-optimized-enum.rs
index 7ce62464ef0..5e1a1f518c5 100644
--- a/src/test/ui/packed/packed-struct-optimized-enum.rs
+++ b/src/test/ui/packed/packed-struct-optimized-enum.rs
@@ -1,6 +1,6 @@
 // run-pass
 #[repr(packed)]
-struct Packed<T: Copy>(T);
+struct Packed<T: Copy>(#[allow(unused_tuple_struct_fields)] T);
 
 impl<T: Copy> Copy for Packed<T> {}
 impl<T: Copy> Clone for Packed<T> {
diff --git a/src/test/ui/packed/packed-tuple-struct-layout.rs b/src/test/ui/packed/packed-tuple-struct-layout.rs
index b88637fbe56..931be5b9414 100644
--- a/src/test/ui/packed/packed-tuple-struct-layout.rs
+++ b/src/test/ui/packed/packed-tuple-struct-layout.rs
@@ -2,9 +2,11 @@
 use std::mem;
 
 #[repr(packed)]
+#[allow(unused_tuple_struct_fields)]
 struct S4(u8,[u8; 3]);
 
 #[repr(packed)]
+#[allow(unused_tuple_struct_fields)]
 struct S5(u8,u32);
 
 pub fn main() {
diff --git a/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.fixed b/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.fixed
new file mode 100644
index 00000000000..4b4a416b1ac
--- /dev/null
+++ b/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.fixed
@@ -0,0 +1,13 @@
+// run-rustfix
+
+pub enum Range {
+    //~^ ERROR `enum` and `struct` are mutually exclusive
+    Valid {
+        begin: u32,
+        len: u32,
+    },
+    Out,
+}
+
+fn main() {
+}
diff --git a/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.rs b/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.rs
new file mode 100644
index 00000000000..9cc88664129
--- /dev/null
+++ b/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.rs
@@ -0,0 +1,13 @@
+// run-rustfix
+
+pub enum struct Range {
+    //~^ ERROR `enum` and `struct` are mutually exclusive
+    Valid {
+        begin: u32,
+        len: u32,
+    },
+    Out,
+}
+
+fn main() {
+}
diff --git a/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.stderr b/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.stderr
new file mode 100644
index 00000000000..edc640bf5ec
--- /dev/null
+++ b/src/test/ui/parser/issue-99625-enum-struct-mutually-exclusive.stderr
@@ -0,0 +1,8 @@
+error: `enum` and `struct` are mutually exclusive
+  --> $DIR/issue-99625-enum-struct-mutually-exclusive.rs:3:5
+   |
+LL | pub enum struct Range {
+   |     ^^^^^^^^^^^ help: replace `enum struct` with: `enum`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/issues/issue-70388-without-witness.fixed b/src/test/ui/parser/issues/issue-70388-without-witness.fixed
index 464e78fd035..8d981405ea1 100644
--- a/src/test/ui/parser/issues/issue-70388-without-witness.fixed
+++ b/src/test/ui/parser/issues/issue-70388-without-witness.fixed
@@ -1,7 +1,7 @@
 // run-rustfix
 // This is for checking if we can apply suggestions as-is.
 
-pub struct Foo(i32);
+pub struct Foo(#[allow(unused_tuple_struct_fields)] i32);
 
 fn main() {
     let Foo(..) = Foo(0); //~ ERROR unexpected `...`
diff --git a/src/test/ui/parser/issues/issue-70388-without-witness.rs b/src/test/ui/parser/issues/issue-70388-without-witness.rs
index 9e35e4c38aa..bf36073083a 100644
--- a/src/test/ui/parser/issues/issue-70388-without-witness.rs
+++ b/src/test/ui/parser/issues/issue-70388-without-witness.rs
@@ -1,7 +1,7 @@
 // run-rustfix
 // This is for checking if we can apply suggestions as-is.
 
-pub struct Foo(i32);
+pub struct Foo(#[allow(unused_tuple_struct_fields)] i32);
 
 fn main() {
     let Foo(...) = Foo(0); //~ ERROR unexpected `...`
diff --git a/src/test/ui/parser/issues/issue-88770.rs b/src/test/ui/parser/issues/issue-88770.rs
index bf89033f560..bb69951c7b4 100644
--- a/src/test/ui/parser/issues/issue-88770.rs
+++ b/src/test/ui/parser/issues/issue-88770.rs
@@ -3,7 +3,7 @@
 // error-pattern:this file contains an unclosed delimiter
 // error-pattern:expected one of
 // error-pattern:missing `in` in `for` loop
-// error-pattern:expected `;`, found `e`
+// error-pattern:expected one of `!`, `)`, `,`, `.`, `::`, `;`, `?`, `{`, or an operator, found `e`
 
 fn m(){print!("",(c for&g
 u
diff --git a/src/test/ui/parser/issues/issue-88770.stderr b/src/test/ui/parser/issues/issue-88770.stderr
index c7e24155d16..4e3a21613ec 100644
--- a/src/test/ui/parser/issues/issue-88770.stderr
+++ b/src/test/ui/parser/issues/issue-88770.stderr
@@ -48,19 +48,13 @@ error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found
 LL | fn m(){print!("",(c for&g
    |                     ^^^ expected one of 8 possible tokens
 
-error: expected `;`, found `e`
-  --> $DIR/issue-88770.rs:10:2
+error: expected one of `!`, `)`, `,`, `.`, `::`, `;`, `?`, `{`, or an operator, found `e`
+  --> $DIR/issue-88770.rs:11:1
    |
 LL | e
-   |  ^ help: add `;` here
+   |  - expected one of 9 possible tokens
 LL | e
-   | - unexpected token
+   | ^ unexpected token
 
-error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `)`
-  --> $DIR/issue-88770.rs:11:3
-   |
-LL | e
-   |   ^ expected one of 7 possible tokens
-
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/parser/issues/issue-89574.stderr b/src/test/ui/parser/issues/issue-89574.stderr
index cbee3d35155..fb1312c782a 100644
--- a/src/test/ui/parser/issues/issue-89574.stderr
+++ b/src/test/ui/parser/issues/issue-89574.stderr
@@ -1,8 +1,8 @@
 error: missing type for `const` item
-  --> $DIR/issue-89574.rs:2:11
+  --> $DIR/issue-89574.rs:2:22
    |
 LL |     const EMPTY_ARRAY = [];
-   |           ^^^^^^^^^^^ help: provide a type for the item: `EMPTY_ARRAY: <type>`
+   |                      ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr
index c340e958ee5..5365b0a1f82 100644
--- a/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr
+++ b/src/test/ui/parser/item-free-const-no-body-semantic-fail.stderr
@@ -15,10 +15,10 @@ LL | const B;
    |        help: provide a definition for the constant: `= <expr>;`
 
 error: missing type for `const` item
-  --> $DIR/item-free-const-no-body-semantic-fail.rs:6:7
+  --> $DIR/item-free-const-no-body-semantic-fail.rs:6:8
    |
 LL | const B;
-   |       ^ help: provide a type for the item: `B: <type>`
+   |        ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr
index 4d542b79861..1b61e430546 100644
--- a/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr
+++ b/src/test/ui/parser/item-free-static-no-body-semantic-fail.stderr
@@ -31,16 +31,16 @@ LL | static mut D;
    |             help: provide a definition for the static: `= <expr>;`
 
 error: missing type for `static` item
-  --> $DIR/item-free-static-no-body-semantic-fail.rs:6:8
+  --> $DIR/item-free-static-no-body-semantic-fail.rs:6:9
    |
 LL | static B;
-   |        ^ help: provide a type for the item: `B: <type>`
+   |         ^ help: provide a type for the item: `: <type>`
 
 error: missing type for `static mut` item
-  --> $DIR/item-free-static-no-body-semantic-fail.rs:10:12
+  --> $DIR/item-free-static-no-body-semantic-fail.rs:10:13
    |
 LL | static mut D;
-   |            ^ help: provide a type for the item: `D: <type>`
+   |             ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/parser/removed-syntax-static-fn.stderr b/src/test/ui/parser/removed-syntax-static-fn.stderr
index 04e34dc16a8..52e0658949d 100644
--- a/src/test/ui/parser/removed-syntax-static-fn.stderr
+++ b/src/test/ui/parser/removed-syntax-static-fn.stderr
@@ -16,10 +16,10 @@ LL | }
    | - the item list ends here
 
 error: missing type for `static` item
-  --> $DIR/removed-syntax-static-fn.rs:4:12
+  --> $DIR/removed-syntax-static-fn.rs:4:14
    |
 LL |     static fn f() {}
-   |            ^^ help: provide a type for the item: `r#fn: <type>`
+   |              ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser/suggest-semi-in-array.rs b/src/test/ui/parser/suggest-semi-in-array.rs
new file mode 100644
index 00000000000..9ce2e59e53b
--- /dev/null
+++ b/src/test/ui/parser/suggest-semi-in-array.rs
@@ -0,0 +1,5 @@
+fn main() {
+    let v = [1
+    2];
+    //~^ ERROR expected one of `,`, `.`, `;`, `?`, `]`, or an operator, found `2`
+}
diff --git a/src/test/ui/parser/suggest-semi-in-array.stderr b/src/test/ui/parser/suggest-semi-in-array.stderr
new file mode 100644
index 00000000000..d7cd6efae41
--- /dev/null
+++ b/src/test/ui/parser/suggest-semi-in-array.stderr
@@ -0,0 +1,10 @@
+error: expected one of `,`, `.`, `;`, `?`, `]`, or an operator, found `2`
+  --> $DIR/suggest-semi-in-array.rs:3:5
+   |
+LL |     let v = [1
+   |               - expected one of `,`, `.`, `;`, `?`, `]`, or an operator
+LL |     2];
+   |     ^ unexpected token
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/range_inclusive.rs b/src/test/ui/range_inclusive.rs
index 7e7a15924b7..c9107d24ed0 100644
--- a/src/test/ui/range_inclusive.rs
+++ b/src/test/ui/range_inclusive.rs
@@ -11,7 +11,7 @@ fn foo() -> isize { 42 }
 pub fn return_range_to() -> RangeToInclusive<i32> { return ..=1; }
 
 #[derive(Debug)]
-struct P(u8);
+struct P(#[allow(unused_tuple_struct_fields)] u8);
 
 pub fn main() {
     let mut count = 0;
diff --git a/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs b/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs
index 366ea7d3b3f..91958dffcf4 100644
--- a/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs
+++ b/src/test/ui/recursion/issue-26548-recursion-via-normalize.rs
@@ -1,9 +1,8 @@
-//~ ERROR cycle detected when computing layout of `S`
+//~ ERROR cycle detected when computing layout of `core::option::Option<S>`
+//~| NOTE ...which requires computing layout of `S`...
 //~| NOTE ...which requires computing layout of `core::option::Option<<S as Mirror>::It>`...
-//~| NOTE ...which requires computing layout of `core::option::Option<S>`...
-//~| NOTE ...which again requires computing layout of `S`, completing the cycle
-
-// build-fail
+//~| NOTE ...which again requires computing layout of `core::option::Option<S>`, completing the cycle
+//~| NOTE cycle used when computing layout of `core::option::Option<<S as Mirror>::It>`
 
 trait Mirror {
     type It: ?Sized;
@@ -14,6 +13,5 @@ impl<T: ?Sized> Mirror for T {
 struct S(Option<<S as Mirror>::It>);
 
 fn main() {
-    //~^ NOTE cycle used when elaborating drops for `main`
     let _s = S(None);
 }
diff --git a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr
index 5b675dc9f81..a75097cdbfb 100644
--- a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr
+++ b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr
@@ -1,13 +1,9 @@
-error[E0391]: cycle detected when computing layout of `S`
+error[E0391]: cycle detected when computing layout of `core::option::Option<S>`
    |
+   = note: ...which requires computing layout of `S`...
    = note: ...which requires computing layout of `core::option::Option<<S as Mirror>::It>`...
-   = note: ...which requires computing layout of `core::option::Option<S>`...
-   = note: ...which again requires computing layout of `S`, completing the cycle
-note: cycle used when elaborating drops for `main`
-  --> $DIR/issue-26548-recursion-via-normalize.rs:16:1
-   |
-LL | fn main() {
-   | ^^^^^^^^^
+   = note: ...which again requires computing layout of `core::option::Option<S>`, completing the cycle
+   = note: cycle used when computing layout of `core::option::Option<<S as Mirror>::It>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/reify-intrinsic.stderr b/src/test/ui/reify-intrinsic.stderr
index 360557fb520..f78f1d822bf 100644
--- a/src/test/ui/reify-intrinsic.stderr
+++ b/src/test/ui/reify-intrinsic.stderr
@@ -23,6 +23,9 @@ LL |         std::intrinsics::unlikely,
    |
    = note: expected fn item `extern "rust-intrinsic" fn(_) -> _ {likely}`
               found fn item `extern "rust-intrinsic" fn(_) -> _ {unlikely}`
+   = note: different `fn` items always have unique types, even if their signatures are the same
+   = help: change the expected type to be function pointer `extern "rust-intrinsic" fn(bool) -> bool`
+   = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `likely as extern "rust-intrinsic" fn(bool) -> bool`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/resolve/issue-23305.stderr b/src/test/ui/resolve/issue-23305.stderr
index f839bd42432..20aeb7b995a 100644
--- a/src/test/ui/resolve/issue-23305.stderr
+++ b/src/test/ui/resolve/issue-23305.stderr
@@ -8,8 +8,14 @@ LL | impl dyn ToNbt<Self> {}
 note: cycle used when collecting item types in top-level module
   --> $DIR/issue-23305.rs:1:1
    |
-LL | pub trait ToNbt<T> {
-   | ^^^^^^^^^^^^^^^^^^
+LL | / pub trait ToNbt<T> {
+LL | |     fn new(val: T) -> Self;
+LL | | }
+LL | |
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr
index 96c1869b4e7..c805c9eb125 100644
--- a/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr
+++ b/src/test/ui/resolve/resolve-inconsistent-binding-mode.stderr
@@ -31,6 +31,10 @@ LL |         Opts::A(ref i) | Opts::B(i) => {}
    |                 first introduced with type `&isize` here
    |
    = note: in the same arm, a binding must have the same type in all alternatives
+help: consider adding `ref`
+   |
+LL |         Opts::A(ref i) | Opts::B(ref i) => {}
+   |                                  +++
 
 error[E0308]: mismatched types
   --> $DIR/resolve-inconsistent-binding-mode.rs:18:34
@@ -43,6 +47,10 @@ LL |         Opts::A(ref i) | Opts::B(i) => {}
    |                 first introduced with type `&isize` here
    |
    = note: in the same arm, a binding must have the same type in all alternatives
+help: consider adding `ref`
+   |
+LL |         Opts::A(ref i) | Opts::B(ref i) => {}
+   |                                  +++
 
 error[E0308]: mismatched types
   --> $DIR/resolve-inconsistent-binding-mode.rs:27:38
diff --git a/src/test/ui/resolve/resolve-inconsistent-names.rs b/src/test/ui/resolve/resolve-inconsistent-names.rs
index 989d2d45230..9a40b20346c 100644
--- a/src/test/ui/resolve/resolve-inconsistent-names.rs
+++ b/src/test/ui/resolve/resolve-inconsistent-names.rs
@@ -23,6 +23,7 @@ fn main() {
         //~| ERROR mismatched types
         //~| ERROR variable `c` is not bound in all patterns
         //~| HELP if you meant to match on unit variant `E::A`, use the full path in the pattern
+        //~| HELP consider removing `ref`
     }
 
     let z = (10, 20);
diff --git a/src/test/ui/resolve/resolve-inconsistent-names.stderr b/src/test/ui/resolve/resolve-inconsistent-names.stderr
index 9de191f7d32..773c9f6cd11 100644
--- a/src/test/ui/resolve/resolve-inconsistent-names.stderr
+++ b/src/test/ui/resolve/resolve-inconsistent-names.stderr
@@ -55,7 +55,7 @@ LL |         (A, B) | (ref B, c) | (c, A) => ()
    |             first binding
 
 error[E0408]: variable `CONST1` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:30:23
+  --> $DIR/resolve-inconsistent-names.rs:31:23
    |
 LL |         (CONST1, _) | (_, Const2) => ()
    |          ------       ^^^^^^^^^^^ pattern doesn't bind `CONST1`
@@ -69,7 +69,7 @@ LL |     const CONST1: usize = 10;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ not accessible
 
 error[E0408]: variable `Const2` is not bound in all patterns
-  --> $DIR/resolve-inconsistent-names.rs:30:9
+  --> $DIR/resolve-inconsistent-names.rs:31:9
    |
 LL |         (CONST1, _) | (_, Const2) => ()
    |         ^^^^^^^^^^^       ------ variable not in all patterns
@@ -92,6 +92,11 @@ LL |         (A, B) | (ref B, c) | (c, A) => ()
    |             first introduced with type `E` here
    |
    = note: in the same arm, a binding must have the same type in all alternatives
+help: consider removing `ref`
+   |
+LL -         (A, B) | (ref B, c) | (c, A) => ()
+LL +         (A, B) | (B, c) | (c, A) => ()
+   |
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs
index c6d7166e740..1914e155493 100644
--- a/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs
+++ b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-embedded.rs
@@ -5,7 +5,7 @@
 
 #![warn(pointer_structural_match)]
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive
 // (which doesn't matter here because `<*const T>::eq` won't recur on `T`).
diff --git a/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs
index cc7ea6cde8d..e713b003b00 100644
--- a/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs
+++ b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-direct-unsafe-ptr-param.rs
@@ -5,7 +5,7 @@
 
 #![warn(pointer_structural_match)]
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive
 // (which doesn't matter here because `<*const T>::eq` won't recur on `T`).
diff --git a/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs
index 86db09cc08f..04da14c5419 100644
--- a/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs
+++ b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-embedded.rs
@@ -5,7 +5,7 @@
 
 #![warn(pointer_structural_match)]
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive
 // (which doesn't matter here because `<*const T>::eq` won't recur on `T`).
diff --git a/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs
index 99c574d0780..8313c25e753 100644
--- a/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs
+++ b/src/test/ui/rfc-1445-restrict-constants-in-patterns/allow-hide-behind-indirect-unsafe-ptr-param.rs
@@ -5,7 +5,7 @@
 
 #![warn(pointer_structural_match)]
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive
 // (which doesn't matter here because `<*const T>::eq` won't recur on `T`).
diff --git a/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs
index 4a8a0949379..7623839fdd1 100644
--- a/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs
+++ b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-direct-struct-embedded.rs
@@ -5,7 +5,7 @@
 //
 // See discussion on rust-lang/rust#62307 and rust-lang/rust#62339
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
diff --git a/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs
index fe62774d220..894739ff705 100644
--- a/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs
+++ b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-embedded.rs
@@ -7,7 +7,7 @@
 #![warn(indirect_structural_match)]
 // run-pass
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
diff --git a/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs
index c3a30674ea3..1699dae4624 100644
--- a/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs
+++ b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-doubly-indirect-param.rs
@@ -7,7 +7,7 @@
 #![warn(indirect_structural_match)]
 // run-pass
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
diff --git a/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs
index 4d0e80d5af3..2672bdd9e56 100644
--- a/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs
+++ b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-embedded.rs
@@ -7,7 +7,7 @@
 #![warn(indirect_structural_match)]
 // run-pass
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
diff --git a/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs
index 432f196ec81..3489995ae71 100644
--- a/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs
+++ b/src/test/ui/rfc-1445-restrict-constants-in-patterns/cant-hide-behind-indirect-struct-param.rs
@@ -7,7 +7,7 @@
 #![warn(indirect_structural_match)]
 // run-pass
 
-struct NoDerive(i32);
+struct NoDerive(#[allow(unused_tuple_struct_fields)] i32);
 
 // This impl makes NoDerive irreflexive.
 impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } }
diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
index 689fdcebbfb..0fe50932b4b 100644
--- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
+++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
@@ -32,6 +32,8 @@ fn _if_let_guard() {
         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
         //~^ ERROR `if let` guards are experimental
         //~| ERROR expected expression, found `let` statement
+        //~| ERROR expected expression, found `let` statement
+        //~| ERROR expected expression, found `let` statement
 
         () if let Range { start: _, end: _ } = (true..true) && false => {}
         //~^ ERROR `if let` guards are experimental
diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
index b61041050a8..35db84a6cb7 100644
--- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
+++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
@@ -41,19 +41,31 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |                                          ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:52:16
+  --> $DIR/feature-gate.rs:32:55
+   |
+LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
+   |                                                       ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/feature-gate.rs:32:68
+   |
+LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
+   |                                                                    ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/feature-gate.rs:54:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/feature-gate.rs:54:16
+  --> $DIR/feature-gate.rs:56:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
 
 error: no rules expected the token `let`
-  --> $DIR/feature-gate.rs:62:15
+  --> $DIR/feature-gate.rs:64:15
    |
 LL |     macro_rules! use_expr {
    |     --------------------- when calling this macro
@@ -102,7 +114,7 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:36:12
+  --> $DIR/feature-gate.rs:38:12
    |
 LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,7 +124,7 @@ LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:58:12
+  --> $DIR/feature-gate.rs:60:12
    |
 LL |         () if let 0 = 1 => {}
    |            ^^^^^^^^^^^^
@@ -121,6 +133,6 @@ LL |         () if let 0 = 1 => {}
    = help: add `#![feature(if_let_guard)]` to the crate attributes to enable
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
-error: aborting due to 16 previous errors
+error: aborting due to 18 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
index a89c58785e3..e8f1ff9c3fd 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
@@ -51,6 +51,8 @@ fn _if() {
     //~| ERROR `let` expressions are not supported here
     //~| ERROR `let` expressions are not supported here
     //~| ERROR expected expression, found `let` statement
+    //~| ERROR expected expression, found `let` statement
+    //~| ERROR expected expression, found `let` statement
 }
 
 fn _while() {
@@ -81,6 +83,8 @@ fn _while() {
     //~| ERROR `let` expressions are not supported here
     //~| ERROR `let` expressions are not supported here
     //~| ERROR expected expression, found `let` statement
+    //~| ERROR expected expression, found `let` statement
+    //~| ERROR expected expression, found `let` statement
 }
 
 fn _macros() {
@@ -146,6 +150,7 @@ fn nested_within_if_expr() {
     //~| ERROR expected expression, found `let` statement
     if true || (true && let 0 = 0) {}
     //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
 
     let mut x = true;
     if x = let 0 = 0 {}
@@ -237,6 +242,7 @@ fn nested_within_while_expr() {
     //~| ERROR expected expression, found `let` statement
     while true || (true && let 0 = 0) {}
     //~^ ERROR `let` expressions are not supported here
+    //~| ERROR expected expression, found `let` statement
 
     let mut x = true;
     while x = let 0 = 0 {}
@@ -388,16 +394,19 @@ fn inside_const_generic_arguments() {
     if let A::<{
         true && let 1 = 1
         //~^ ERROR `let` expressions are not supported here
+        //~| ERROR expected expression, found `let` statement
     }>::O = 5 {}
 
     while let A::<{
         true && let 1 = 1
         //~^ ERROR `let` expressions are not supported here
+        //~| ERROR expected expression, found `let` statement
     }>::O = 5 {}
 
     if A::<{
         true && let 1 = 1
         //~^ ERROR `let` expressions are not supported here
+        //~| ERROR expected expression, found `let` statement
     }>::O == 5 {}
 
     // In the cases above we have `ExprKind::Block` to help us out.
@@ -409,7 +418,8 @@ fn inside_const_generic_arguments() {
     if A::<
         true && let 1 = 1
         //~^ ERROR `let` expressions are not supported here
-        //~| ERROR  expressions must be enclosed in braces
+        //~| ERROR expressions must be enclosed in braces
+        //~| ERROR expected expression, found `let` statement
     >::O == 5 {}
 }
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 5e5289f1693..d5d82166a4a 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -41,313 +41,373 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:57:12
+  --> $DIR/disallowed-positions.rs:49:48
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:49:61
+   |
+LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                             ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:59:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:61:14
+  --> $DIR/disallowed-positions.rs:63:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:67:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:69:20
+  --> $DIR/disallowed-positions.rs:71:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:73:12
+  --> $DIR/disallowed-positions.rs:75:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:73:27
+  --> $DIR/disallowed-positions.rs:75:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:79:38
+  --> $DIR/disallowed-positions.rs:81:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:110:9
+  --> $DIR/disallowed-positions.rs:81:51
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                   ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:81:64
+   |
+LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
+   |                                                                ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:114:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:115:9
+  --> $DIR/disallowed-positions.rs:119:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:118:9
+  --> $DIR/disallowed-positions.rs:122:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:122:9
+  --> $DIR/disallowed-positions.rs:126:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:132:9
+  --> $DIR/disallowed-positions.rs:136:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:138:16
+  --> $DIR/disallowed-positions.rs:142:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:141:17
+  --> $DIR/disallowed-positions.rs:145:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:144:25
+  --> $DIR/disallowed-positions.rs:148:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:151:12
+  --> $DIR/disallowed-positions.rs:151:25
+   |
+LL |     if true || (true && let 0 = 0) {}
+   |                         ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:156:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:156:15
+  --> $DIR/disallowed-positions.rs:161:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:160:11
+  --> $DIR/disallowed-positions.rs:165:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:164:9
+  --> $DIR/disallowed-positions.rs:169:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:195:19
+  --> $DIR/disallowed-positions.rs:200:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:201:12
+  --> $DIR/disallowed-positions.rs:206:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:206:12
+  --> $DIR/disallowed-positions.rs:211:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:209:12
+  --> $DIR/disallowed-positions.rs:214:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:213:12
+  --> $DIR/disallowed-positions.rs:218:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:223:12
+  --> $DIR/disallowed-positions.rs:228:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:229:19
+  --> $DIR/disallowed-positions.rs:234:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:232:20
+  --> $DIR/disallowed-positions.rs:237:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:235:28
+  --> $DIR/disallowed-positions.rs:240:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:242:15
+  --> $DIR/disallowed-positions.rs:243:28
+   |
+LL |     while true || (true && let 0 = 0) {}
+   |                            ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:248:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:247:18
+  --> $DIR/disallowed-positions.rs:253:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:251:14
+  --> $DIR/disallowed-positions.rs:257:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:255:12
+  --> $DIR/disallowed-positions.rs:261:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:286:22
+  --> $DIR/disallowed-positions.rs:292:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:302:6
+  --> $DIR/disallowed-positions.rs:308:6
    |
 LL |     &let 0 = 0;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:306:6
+  --> $DIR/disallowed-positions.rs:312:6
    |
 LL |     !let 0 = 0;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:309:6
+  --> $DIR/disallowed-positions.rs:315:6
    |
 LL |     *let 0 = 0;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:313:6
+  --> $DIR/disallowed-positions.rs:319:6
    |
 LL |     -let 0 = 0;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:323:6
+  --> $DIR/disallowed-positions.rs:329:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:329:13
+  --> $DIR/disallowed-positions.rs:335:13
    |
 LL |     true || let 0 = 0;
    |             ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:332:14
+  --> $DIR/disallowed-positions.rs:338:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:335:22
+  --> $DIR/disallowed-positions.rs:341:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:340:9
+  --> $DIR/disallowed-positions.rs:346:9
    |
 LL |     x = let 0 = 0;
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:344:12
+  --> $DIR/disallowed-positions.rs:350:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:347:8
+  --> $DIR/disallowed-positions.rs:353:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:350:6
+  --> $DIR/disallowed-positions.rs:356:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:354:6
+  --> $DIR/disallowed-positions.rs:360:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:359:6
+  --> $DIR/disallowed-positions.rs:365:6
    |
 LL |     (let true = let true = true);
    |      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:359:17
+  --> $DIR/disallowed-positions.rs:365:17
    |
 LL |     (let true = let true = true);
    |                 ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:366:25
+  --> $DIR/disallowed-positions.rs:372:25
    |
 LL |         let x = true && let y = 1;
    |                         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:372:19
+  --> $DIR/disallowed-positions.rs:378:19
    |
 LL |         [1, 2, 3][let _ = ()]
    |                   ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:377:6
+  --> $DIR/disallowed-positions.rs:383:6
    |
 LL |     &let 0 = 0
    |      ^^^
 
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:395:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:401:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:407:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+
+error: expected expression, found `let` statement
+  --> $DIR/disallowed-positions.rs:419:17
+   |
+LL |         true && let 1 = 1
+   |                 ^^^
+
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions.rs:410:9
+  --> $DIR/disallowed-positions.rs:419:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -358,97 +418,97 @@ LL |         { true && let 1 = 1 }
    |         +                   +
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:419:9
+  --> $DIR/disallowed-positions.rs:429:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:424:9
+  --> $DIR/disallowed-positions.rs:434:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:428:9
+  --> $DIR/disallowed-positions.rs:438:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:428:32
+  --> $DIR/disallowed-positions.rs:438:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:437:9
+  --> $DIR/disallowed-positions.rs:447:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:437:31
+  --> $DIR/disallowed-positions.rs:447:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:443:9
+  --> $DIR/disallowed-positions.rs:453:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:443:31
+  --> $DIR/disallowed-positions.rs:453:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:449:9
+  --> $DIR/disallowed-positions.rs:459:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:466:22
+  --> $DIR/disallowed-positions.rs:476:22
    |
 LL |     let x = (true && let y = 1);
    |                      ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:471:20
+  --> $DIR/disallowed-positions.rs:481:20
    |
 LL |         ([1, 2, 3][let _ = ()])
    |                    ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:475:20
+  --> $DIR/disallowed-positions.rs:485:20
    |
 LL |     #[cfg(FALSE)] (let 0 = 1);
    |                    ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:93:16
+  --> $DIR/disallowed-positions.rs:97:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:101:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:101:23
+  --> $DIR/disallowed-positions.rs:105:23
    |
 LL |     use_expr!(true && let 0 = 1);
    |                       ^^^
 
 error: expected expression, found `let` statement
-  --> $DIR/disallowed-positions.rs:105:17
+  --> $DIR/disallowed-positions.rs:109:17
    |
 LL |     noop_expr!((let 0 = 1));
    |                 ^^^
@@ -571,176 +631,176 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:57:12
+  --> $DIR/disallowed-positions.rs:59:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:57:12
+  --> $DIR/disallowed-positions.rs:59:12
    |
 LL |     while (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:61:14
+  --> $DIR/disallowed-positions.rs:63:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:61:14
+  --> $DIR/disallowed-positions.rs:63:14
    |
 LL |     while (((let 0 = 1))) {}
    |              ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:67:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:67:12
    |
 LL |     while (let 0 = 1) && true {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:69:20
+  --> $DIR/disallowed-positions.rs:71:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:69:20
+  --> $DIR/disallowed-positions.rs:71:20
    |
 LL |     while true && (let 0 = 1) {}
    |                    ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:73:12
+  --> $DIR/disallowed-positions.rs:75:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:73:12
+  --> $DIR/disallowed-positions.rs:75:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:73:27
+  --> $DIR/disallowed-positions.rs:75:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:73:27
+  --> $DIR/disallowed-positions.rs:75:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
    |                           ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:79:38
+  --> $DIR/disallowed-positions.rs:81:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:79:38
+  --> $DIR/disallowed-positions.rs:81:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:79:51
+  --> $DIR/disallowed-positions.rs:81:51
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:79:38
+  --> $DIR/disallowed-positions.rs:81:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:79:64
+  --> $DIR/disallowed-positions.rs:81:64
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                                                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:79:38
+  --> $DIR/disallowed-positions.rs:81:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:93:16
+  --> $DIR/disallowed-positions.rs:97:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:93:16
+  --> $DIR/disallowed-positions.rs:97:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:93:16
+  --> $DIR/disallowed-positions.rs:97:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:93:16
+  --> $DIR/disallowed-positions.rs:97:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:101:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:101:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:101:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:97:16
+  --> $DIR/disallowed-positions.rs:101:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:110:9
+  --> $DIR/disallowed-positions.rs:114:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
@@ -748,7 +808,7 @@ LL |     if &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:115:9
+  --> $DIR/disallowed-positions.rs:119:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
@@ -756,7 +816,7 @@ LL |     if !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:118:9
+  --> $DIR/disallowed-positions.rs:122:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
@@ -764,7 +824,7 @@ LL |     if *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:122:9
+  --> $DIR/disallowed-positions.rs:126:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
@@ -772,72 +832,72 @@ LL |     if -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:132:9
+  --> $DIR/disallowed-positions.rs:136:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:132:9
+  --> $DIR/disallowed-positions.rs:136:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:138:16
+  --> $DIR/disallowed-positions.rs:142:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:138:13
+  --> $DIR/disallowed-positions.rs:142:13
    |
 LL |     if true || let 0 = 0 {}
    |             ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:141:17
+  --> $DIR/disallowed-positions.rs:145:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:141:14
+  --> $DIR/disallowed-positions.rs:145:14
    |
 LL |     if (true || let 0 = 0) {}
    |              ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:144:25
+  --> $DIR/disallowed-positions.rs:148:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:144:22
+  --> $DIR/disallowed-positions.rs:148:22
    |
 LL |     if true && (true || let 0 = 0) {}
    |                      ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:147:25
+  --> $DIR/disallowed-positions.rs:151:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:147:17
+  --> $DIR/disallowed-positions.rs:151:17
    |
 LL |     if true || (true && let 0 = 0) {}
    |                 ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:151:12
+  --> $DIR/disallowed-positions.rs:156:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^^^^^^^
@@ -845,46 +905,46 @@ LL |     if x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:156:15
+  --> $DIR/disallowed-positions.rs:161:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:156:15
+  --> $DIR/disallowed-positions.rs:161:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:160:11
+  --> $DIR/disallowed-positions.rs:165:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:160:11
+  --> $DIR/disallowed-positions.rs:165:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:164:9
+  --> $DIR/disallowed-positions.rs:169:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:164:9
+  --> $DIR/disallowed-positions.rs:169:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:170:8
+  --> $DIR/disallowed-positions.rs:175:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -892,7 +952,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:174:8
+  --> $DIR/disallowed-positions.rs:179:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -900,7 +960,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:181:8
+  --> $DIR/disallowed-positions.rs:186:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -908,7 +968,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:189:8
+  --> $DIR/disallowed-positions.rs:194:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -916,7 +976,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:195:19
+  --> $DIR/disallowed-positions.rs:200:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^^^^^^^^^^^^^
@@ -924,7 +984,7 @@ LL |     if let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:201:12
+  --> $DIR/disallowed-positions.rs:206:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
@@ -932,7 +992,7 @@ LL |     while &let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:206:12
+  --> $DIR/disallowed-positions.rs:211:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
@@ -940,7 +1000,7 @@ LL |     while !let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:209:12
+  --> $DIR/disallowed-positions.rs:214:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
@@ -948,7 +1008,7 @@ LL |     while *let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:213:12
+  --> $DIR/disallowed-positions.rs:218:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
@@ -956,72 +1016,72 @@ LL |     while -let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:223:12
+  --> $DIR/disallowed-positions.rs:228:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:223:12
+  --> $DIR/disallowed-positions.rs:228:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:229:19
+  --> $DIR/disallowed-positions.rs:234:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:229:16
+  --> $DIR/disallowed-positions.rs:234:16
    |
 LL |     while true || let 0 = 0 {}
    |                ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:232:20
+  --> $DIR/disallowed-positions.rs:237:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:232:17
+  --> $DIR/disallowed-positions.rs:237:17
    |
 LL |     while (true || let 0 = 0) {}
    |                 ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:235:28
+  --> $DIR/disallowed-positions.rs:240:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:235:25
+  --> $DIR/disallowed-positions.rs:240:25
    |
 LL |     while true && (true || let 0 = 0) {}
    |                         ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:238:28
+  --> $DIR/disallowed-positions.rs:243:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:238:20
+  --> $DIR/disallowed-positions.rs:243:20
    |
 LL |     while true || (true && let 0 = 0) {}
    |                    ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:242:15
+  --> $DIR/disallowed-positions.rs:248:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^^^^^^^
@@ -1029,46 +1089,46 @@ LL |     while x = let 0 = 0 {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:247:18
+  --> $DIR/disallowed-positions.rs:253:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:247:18
+  --> $DIR/disallowed-positions.rs:253:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:251:14
+  --> $DIR/disallowed-positions.rs:257:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:251:14
+  --> $DIR/disallowed-positions.rs:257:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:255:12
+  --> $DIR/disallowed-positions.rs:261:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:255:12
+  --> $DIR/disallowed-positions.rs:261:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:261:11
+  --> $DIR/disallowed-positions.rs:267:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1076,7 +1136,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:265:11
+  --> $DIR/disallowed-positions.rs:271:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1084,7 +1144,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:272:11
+  --> $DIR/disallowed-positions.rs:278:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1092,7 +1152,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:280:11
+  --> $DIR/disallowed-positions.rs:286:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1100,7 +1160,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:286:22
+  --> $DIR/disallowed-positions.rs:292:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^^^^^^^^^^^^^
@@ -1108,7 +1168,7 @@ LL |     while let true = let true = true {}
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:302:6
+  --> $DIR/disallowed-positions.rs:308:6
    |
 LL |     &let 0 = 0;
    |      ^^^^^^^^^
@@ -1116,7 +1176,7 @@ LL |     &let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:306:6
+  --> $DIR/disallowed-positions.rs:312:6
    |
 LL |     !let 0 = 0;
    |      ^^^^^^^^^
@@ -1124,7 +1184,7 @@ LL |     !let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:309:6
+  --> $DIR/disallowed-positions.rs:315:6
    |
 LL |     *let 0 = 0;
    |      ^^^^^^^^^
@@ -1132,7 +1192,7 @@ LL |     *let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:313:6
+  --> $DIR/disallowed-positions.rs:319:6
    |
 LL |     -let 0 = 0;
    |      ^^^^^^^^^
@@ -1140,59 +1200,59 @@ LL |     -let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:323:6
+  --> $DIR/disallowed-positions.rs:329:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:323:6
+  --> $DIR/disallowed-positions.rs:329:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:329:13
+  --> $DIR/disallowed-positions.rs:335:13
    |
 LL |     true || let 0 = 0;
    |             ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:329:10
+  --> $DIR/disallowed-positions.rs:335:10
    |
 LL |     true || let 0 = 0;
    |          ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:332:14
+  --> $DIR/disallowed-positions.rs:338:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:332:11
+  --> $DIR/disallowed-positions.rs:338:11
    |
 LL |     (true || let 0 = 0);
    |           ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:335:22
+  --> $DIR/disallowed-positions.rs:341:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `||` operators are not supported in let chain expressions
-  --> $DIR/disallowed-positions.rs:335:19
+  --> $DIR/disallowed-positions.rs:341:19
    |
 LL |     true && (true || let 0 = 0);
    |                   ^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:340:9
+  --> $DIR/disallowed-positions.rs:346:9
    |
 LL |     x = let 0 = 0;
    |         ^^^^^^^^^
@@ -1200,46 +1260,46 @@ LL |     x = let 0 = 0;
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:344:12
+  --> $DIR/disallowed-positions.rs:350:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:344:12
+  --> $DIR/disallowed-positions.rs:350:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:347:8
+  --> $DIR/disallowed-positions.rs:353:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:347:8
+  --> $DIR/disallowed-positions.rs:353:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:350:6
+  --> $DIR/disallowed-positions.rs:356:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:350:6
+  --> $DIR/disallowed-positions.rs:356:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:354:6
+  --> $DIR/disallowed-positions.rs:360:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1247,20 +1307,20 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:359:6
+  --> $DIR/disallowed-positions.rs:365:6
    |
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:359:6
+  --> $DIR/disallowed-positions.rs:365:6
    |
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:377:6
+  --> $DIR/disallowed-positions.rs:383:6
    |
 LL |     &let 0 = 0
    |      ^^^^^^^^^
@@ -1268,7 +1328,7 @@ LL |     &let 0 = 0
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:389:17
+  --> $DIR/disallowed-positions.rs:395:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -1276,7 +1336,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:394:17
+  --> $DIR/disallowed-positions.rs:401:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -1284,7 +1344,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:399:17
+  --> $DIR/disallowed-positions.rs:407:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -1292,7 +1352,7 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:410:17
+  --> $DIR/disallowed-positions.rs:419:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -1300,124 +1360,124 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if` and `while` expressions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:419:9
+  --> $DIR/disallowed-positions.rs:429:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:419:9
+  --> $DIR/disallowed-positions.rs:429:9
    |
 LL |     if (let Some(a) = opt && true) {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:424:9
+  --> $DIR/disallowed-positions.rs:434:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:424:9
+  --> $DIR/disallowed-positions.rs:434:9
    |
 LL |     if (let Some(a) = opt) && true {
    |         ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:428:9
+  --> $DIR/disallowed-positions.rs:438:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:428:9
+  --> $DIR/disallowed-positions.rs:438:9
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |         ^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:428:32
+  --> $DIR/disallowed-positions.rs:438:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:428:32
+  --> $DIR/disallowed-positions.rs:438:32
    |
 LL |     if (let Some(a) = opt) && (let Some(b) = a) {
    |                                ^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:437:9
+  --> $DIR/disallowed-positions.rs:447:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:437:9
+  --> $DIR/disallowed-positions.rs:447:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:437:31
+  --> $DIR/disallowed-positions.rs:447:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:437:31
+  --> $DIR/disallowed-positions.rs:447:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && b == 1 {
    |                               ^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:443:9
+  --> $DIR/disallowed-positions.rs:453:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:443:9
+  --> $DIR/disallowed-positions.rs:453:9
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:443:31
+  --> $DIR/disallowed-positions.rs:453:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:443:31
+  --> $DIR/disallowed-positions.rs:453:31
    |
 LL |     if (let Some(a) = opt && (let Some(b) = a)) && true {
    |                               ^^^^^^^^^^^^^^^
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:449:9
+  --> $DIR/disallowed-positions.rs:459:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^
    |
    = note: only supported directly in conditions of `if` and `while` expressions
 note: `let`s wrapped in parentheses are not supported in a context with let chains
-  --> $DIR/disallowed-positions.rs:449:9
+  --> $DIR/disallowed-positions.rs:459:9
    |
 LL |     if (let Some(a) = opt && (true)) && true {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:110:8
+  --> $DIR/disallowed-positions.rs:114:8
    |
 LL |     if &let 0 = 0 {}
    |        ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -1429,19 +1489,19 @@ LL +     if let 0 = 0 {}
    |
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:118:8
+  --> $DIR/disallowed-positions.rs:122:8
    |
 LL |     if *let 0 = 0 {}
    |        ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:122:8
+  --> $DIR/disallowed-positions.rs:126:8
    |
 LL |     if -let 0 = 0 {}
    |        ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:132:8
+  --> $DIR/disallowed-positions.rs:136:8
    |
 LL |     if (let 0 = 0)? {}
    |        ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -1449,7 +1509,7 @@ LL |     if (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:132:19
+  --> $DIR/disallowed-positions.rs:136:19
    |
 LL | / fn nested_within_if_expr() {
 LL | |     if &let 0 = 0 {}
@@ -1466,7 +1526,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:151:8
+  --> $DIR/disallowed-positions.rs:156:8
    |
 LL |     if x = let 0 = 0 {}
    |        ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -1477,7 +1537,7 @@ LL |     if x == let 0 = 0 {}
    |          ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:156:8
+  --> $DIR/disallowed-positions.rs:161:8
    |
 LL |     if true..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1486,7 +1546,7 @@ LL |     if true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:160:8
+  --> $DIR/disallowed-positions.rs:165:8
    |
 LL |     if ..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -1495,7 +1555,7 @@ LL |     if ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:164:8
+  --> $DIR/disallowed-positions.rs:169:8
    |
 LL |     if (let 0 = 0).. {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -1504,7 +1564,7 @@ LL |     if (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:170:12
+  --> $DIR/disallowed-positions.rs:175:12
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1515,7 +1575,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:170:8
+  --> $DIR/disallowed-positions.rs:175:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1524,7 +1584,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:174:12
+  --> $DIR/disallowed-positions.rs:179:12
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1535,7 +1595,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:174:8
+  --> $DIR/disallowed-positions.rs:179:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1544,7 +1604,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:181:12
+  --> $DIR/disallowed-positions.rs:186:12
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -1555,20 +1615,20 @@ LL |     if let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:181:41
+  --> $DIR/disallowed-positions.rs:186:41
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |                                         ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:181:41: 181:43]`
+           found closure `[closure@$DIR/disallowed-positions.rs:186:41: 186:43]`
 help: use parentheses to call this closure
    |
 LL |     if let Range { start: F, end } = F..(|| true)() {}
    |                                         +       +++
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:181:8
+  --> $DIR/disallowed-positions.rs:186:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1577,7 +1637,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:189:12
+  --> $DIR/disallowed-positions.rs:194:12
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -1588,7 +1648,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:189:44
+  --> $DIR/disallowed-positions.rs:194:44
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |                                            ^^^^^^^ expected `bool`, found `&&bool`
@@ -1600,7 +1660,7 @@ LL +     if let Range { start: true, end } = t..false {}
    |
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:189:8
+  --> $DIR/disallowed-positions.rs:194:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1609,7 +1669,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:128:20
+  --> $DIR/disallowed-positions.rs:132:20
    |
 LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1617,7 +1677,7 @@ LL |         if let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:201:11
+  --> $DIR/disallowed-positions.rs:206:11
    |
 LL |     while &let 0 = 0 {}
    |           ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -1629,19 +1689,19 @@ LL +     while let 0 = 0 {}
    |
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:209:11
+  --> $DIR/disallowed-positions.rs:214:11
    |
 LL |     while *let 0 = 0 {}
    |           ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:213:11
+  --> $DIR/disallowed-positions.rs:218:11
    |
 LL |     while -let 0 = 0 {}
    |           ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:223:11
+  --> $DIR/disallowed-positions.rs:228:11
    |
 LL |     while (let 0 = 0)? {}
    |           ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -1649,7 +1709,7 @@ LL |     while (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:223:22
+  --> $DIR/disallowed-positions.rs:228:22
    |
 LL | / fn nested_within_while_expr() {
 LL | |     while &let 0 = 0 {}
@@ -1666,7 +1726,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:242:11
+  --> $DIR/disallowed-positions.rs:248:11
    |
 LL |     while x = let 0 = 0 {}
    |           ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -1677,7 +1737,7 @@ LL |     while x == let 0 = 0 {}
    |             ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:247:11
+  --> $DIR/disallowed-positions.rs:253:11
    |
 LL |     while true..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1686,7 +1746,7 @@ LL |     while true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:251:11
+  --> $DIR/disallowed-positions.rs:257:11
    |
 LL |     while ..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -1695,7 +1755,7 @@ LL |     while ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:255:11
+  --> $DIR/disallowed-positions.rs:261:11
    |
 LL |     while (let 0 = 0).. {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -1704,7 +1764,7 @@ LL |     while (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:261:15
+  --> $DIR/disallowed-positions.rs:267:15
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1715,7 +1775,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:261:11
+  --> $DIR/disallowed-positions.rs:267:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1724,7 +1784,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:265:15
+  --> $DIR/disallowed-positions.rs:271:15
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1735,7 +1795,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:265:11
+  --> $DIR/disallowed-positions.rs:271:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1744,7 +1804,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:272:15
+  --> $DIR/disallowed-positions.rs:278:15
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -1755,20 +1815,20 @@ LL |     while let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:272:44
+  --> $DIR/disallowed-positions.rs:278:44
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |                                            ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:272:44: 272:46]`
+           found closure `[closure@$DIR/disallowed-positions.rs:278:44: 278:46]`
 help: use parentheses to call this closure
    |
 LL |     while let Range { start: F, end } = F..(|| true)() {}
    |                                            +       +++
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:272:11
+  --> $DIR/disallowed-positions.rs:278:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1777,7 +1837,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:280:15
+  --> $DIR/disallowed-positions.rs:286:15
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -1788,7 +1848,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:280:47
+  --> $DIR/disallowed-positions.rs:286:47
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |                                               ^^^^^^^ expected `bool`, found `&&bool`
@@ -1800,7 +1860,7 @@ LL +     while let Range { start: true, end } = t..false {}
    |
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:280:11
+  --> $DIR/disallowed-positions.rs:286:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -1809,7 +1869,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:219:23
+  --> $DIR/disallowed-positions.rs:224:23
    |
 LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
@@ -1817,19 +1877,19 @@ LL |         while let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:309:5
+  --> $DIR/disallowed-positions.rs:315:5
    |
 LL |     *let 0 = 0;
    |     ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:313:5
+  --> $DIR/disallowed-positions.rs:319:5
    |
 LL |     -let 0 = 0;
    |     ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:323:5
+  --> $DIR/disallowed-positions.rs:329:5
    |
 LL |     (let 0 = 0)?;
    |     ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -1837,7 +1897,7 @@ LL |     (let 0 = 0)?;
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:323:16
+  --> $DIR/disallowed-positions.rs:329:16
    |
 LL | / fn outside_if_and_while_expr() {
 LL | |     &let 0 = 0;
@@ -1854,7 +1914,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:354:10
+  --> $DIR/disallowed-positions.rs:360:10
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -1865,7 +1925,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:377:5
+  --> $DIR/disallowed-positions.rs:383:5
    |
 LL | fn outside_if_and_while_expr() {
    |                                - help: try adding a return type: `-> &bool`
@@ -1874,14 +1934,14 @@ LL |     &let 0 = 0
    |     ^^^^^^^^^^ expected `()`, found `&bool`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:319:17
+  --> $DIR/disallowed-positions.rs:325:17
    |
 LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
 
-error: aborting due to 208 previous errors
+error: aborting due to 218 previous errors
 
 Some errors have detailed explanations: E0277, E0308, E0600, E0614.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
index 42685cad948..77f425c3e45 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.rs
@@ -7,6 +7,10 @@ extern "C" {
     #[link_ordinal(42)]
     //~^ ERROR cannot use `#[link_name]` with `#[link_ordinal]`
     fn foo();
+    #[link_name="foo"]
+    #[link_ordinal(5)]
+    //~^ ERROR cannot use `#[link_name]` with `#[link_ordinal]`
+    static mut imported_variable: i32;
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
index 5d8545b5062..dfe9d031c77 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-and-name.stderr
@@ -13,5 +13,11 @@ error: cannot use `#[link_name]` with `#[link_ordinal]`
 LL |     #[link_ordinal(42)]
    |     ^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error: cannot use `#[link_name]` with `#[link_ordinal]`
+  --> $DIR/link-ordinal-and-name.rs:11:5
+   |
+LL |     #[link_ordinal(5)]
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
index 135f5909ea1..4687fe47f90 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.rs
@@ -6,6 +6,9 @@ extern "C" {
     #[link_ordinal("JustMonika")]
     //~^ ERROR illegal ordinal format in `link_ordinal`
     fn foo();
+    #[link_ordinal("JustMonika")]
+    //~^ ERROR illegal ordinal format in `link_ordinal`
+    static mut imported_variable: i32;
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
index 8453a3966be..1d0fad6cb49 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-invalid-format.stderr
@@ -15,5 +15,13 @@ LL |     #[link_ordinal("JustMonika")]
    |
    = note: an unsuffixed integer value, e.g., `1`, is expected
 
-error: aborting due to previous error; 1 warning emitted
+error: illegal ordinal format in `link_ordinal`
+  --> $DIR/link-ordinal-invalid-format.rs:9:5
+   |
+LL |     #[link_ordinal("JustMonika")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: an unsuffixed integer value, e.g., `1`, is expected
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
index c391ccd1c82..becf2700aeb 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.rs
@@ -6,6 +6,9 @@ extern "C" {
     #[link_ordinal()]
     //~^ ERROR incorrect number of arguments to `#[link_ordinal]`
     fn foo();
+    #[link_ordinal()]
+    //~^ ERROR incorrect number of arguments to `#[link_ordinal]`
+    static mut imported_variable: i32;
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
index 8e9edfb9d20..5b0ec869d03 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-missing-argument.stderr
@@ -15,5 +15,13 @@ LL |     #[link_ordinal()]
    |
    = note: the attribute requires exactly one argument
 
-error: aborting due to previous error; 1 warning emitted
+error: incorrect number of arguments to `#[link_ordinal]`
+  --> $DIR/link-ordinal-missing-argument.rs:9:5
+   |
+LL |     #[link_ordinal()]
+   |     ^^^^^^^^^^^^^^^^^
+   |
+   = note: the attribute requires exactly one argument
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
index 2a15b1d799f..7b07d09e72a 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
@@ -7,6 +7,9 @@ extern "C" {
     #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes
     #[link_ordinal(2)]
     fn foo();
+    #[link_ordinal(1)] //~ ERROR multiple `link_ordinal` attributes
+    #[link_ordinal(2)]
+    static mut imported_variable: i32;
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
index 4772533ab2f..92a39b3d1b0 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.stderr
@@ -19,5 +19,17 @@ note: attribute also specified here
 LL |     #[link_ordinal(2)]
    |     ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error; 1 warning emitted
+error: multiple `link_ordinal` attributes
+  --> $DIR/link-ordinal-multiple.rs:10:5
+   |
+LL |     #[link_ordinal(1)]
+   |     ^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/link-ordinal-multiple.rs:11:5
+   |
+LL |     #[link_ordinal(2)]
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
new file mode 100644
index 00000000000..5d273d52a92
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.rs
@@ -0,0 +1,25 @@
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete
+
+#[link_ordinal(123)]
+//~^ ERROR attribute should be applied to a foreign function or static
+struct Foo {}
+
+#[link_ordinal(123)]
+//~^ ERROR attribute should be applied to a foreign function or static
+fn test() {}
+
+#[link_ordinal(42)]
+//~^ ERROR attribute should be applied to a foreign function or static
+static mut imported_val: i32 = 123;
+
+#[link(name = "exporter", kind = "raw-dylib")]
+extern {
+    #[link_ordinal(13)]
+    fn imported_function();
+
+    #[link_ordinal(42)]
+    static mut imported_variable: i32;
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
new file mode 100644
index 00000000000..8fa2f16f44d
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-not-foreign-fn.stderr
@@ -0,0 +1,29 @@
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/link-ordinal-not-foreign-fn.rs:1:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: attribute should be applied to a foreign function or static
+  --> $DIR/link-ordinal-not-foreign-fn.rs:4:1
+   |
+LL | #[link_ordinal(123)]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: attribute should be applied to a foreign function or static
+  --> $DIR/link-ordinal-not-foreign-fn.rs:8:1
+   |
+LL | #[link_ordinal(123)]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: attribute should be applied to a foreign function or static
+  --> $DIR/link-ordinal-not-foreign-fn.rs:12:1
+   |
+LL | #[link_ordinal(42)]
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors; 1 warning emitted
+
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
index b6089d27e7a..99d7d9d0b7e 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.rs
@@ -6,6 +6,9 @@ extern "C" {
     #[link_ordinal(72436)]
     //~^ ERROR ordinal value in `link_ordinal` is too large: `72436`
     fn foo();
+    #[link_ordinal(72436)]
+    //~^ ERROR ordinal value in `link_ordinal` is too large: `72436`
+    static mut imported_variable: i32;
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
index bbe985fa10a..36f278bd856 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-large.stderr
@@ -15,5 +15,13 @@ LL |     #[link_ordinal(72436)]
    |
    = note: the value may not exceed `u16::MAX`
 
-error: aborting due to previous error; 1 warning emitted
+error: ordinal value in `link_ordinal` is too large: `72436`
+  --> $DIR/link-ordinal-too-large.rs:9:5
+   |
+LL |     #[link_ordinal(72436)]
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the value may not exceed `u16::MAX`
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
index 93286c616c5..eca4186e593 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.rs
@@ -6,6 +6,9 @@ extern "C" {
     #[link_ordinal(3, 4)]
     //~^ ERROR incorrect number of arguments to `#[link_ordinal]`
     fn foo();
+    #[link_ordinal(3, 4)]
+    //~^ ERROR incorrect number of arguments to `#[link_ordinal]`
+    static mut imported_variable: i32;
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
index 484c85a0f42..745aab24dc7 100644
--- a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-too-many-arguments.stderr
@@ -15,5 +15,13 @@ LL |     #[link_ordinal(3, 4)]
    |
    = note: the attribute requires exactly one argument
 
-error: aborting due to previous error; 1 warning emitted
+error: incorrect number of arguments to `#[link_ordinal]`
+  --> $DIR/link-ordinal-too-many-arguments.rs:9:5
+   |
+LL |     #[link_ordinal(3, 4)]
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the attribute requires exactly one argument
+
+error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
index f50e70939df..04462c0a11b 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
@@ -96,7 +96,7 @@ implements_const_drop! {
 }
 
 fn main() {
-    struct HasDropGlue(Box<u8>);
+    struct HasDropGlue(#[allow(unused_tuple_struct_fields)] Box<u8>);
     struct HasDropImpl;
     impl Drop for HasDropImpl {
         fn drop(&mut self) {
diff --git a/src/test/ui/rfcs/rfc-2151-raw-identifiers/attr.rs b/src/test/ui/rfcs/rfc-2151-raw-identifiers/attr.rs
index 2fe1e05e509..d359067f627 100644
--- a/src/test/ui/rfcs/rfc-2151-raw-identifiers/attr.rs
+++ b/src/test/ui/rfcs/rfc-2151-raw-identifiers/attr.rs
@@ -7,7 +7,7 @@ struct Test {
 }
 
 #[r#derive(r#Debug)]
-struct Test2(u32);
+struct Test2(#[allow(unused_tuple_struct_fields)] u32);
 
 pub fn main() {
     assert_eq!(mem::size_of::<Test>(), 9);
diff --git a/src/test/ui/rustdoc/check-doc-alias-attr-location.rs b/src/test/ui/rustdoc/check-doc-alias-attr-location.rs
index 4738e5116b4..10609e5d8f4 100644
--- a/src/test/ui/rustdoc/check-doc-alias-attr-location.rs
+++ b/src/test/ui/rustdoc/check-doc-alias-attr-location.rs
@@ -21,6 +21,12 @@ impl Foo for Bar {
     type X = i32;
     fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X {
         //~^ ERROR
-        0
+        #[doc(alias = "stmt")] //~ ERROR
+        let x = 0;
+        #[doc(alias = "expr")] //~ ERROR
+        match x {
+            #[doc(alias = "arm")] //~ ERROR
+            _ => 0
+        }
     }
 }
diff --git a/src/test/ui/rustdoc/check-doc-alias-attr-location.stderr b/src/test/ui/rustdoc/check-doc-alias-attr-location.stderr
index 650a82a23a9..23c93a4ed8b 100644
--- a/src/test/ui/rustdoc/check-doc-alias-attr-location.stderr
+++ b/src/test/ui/rustdoc/check-doc-alias-attr-location.stderr
@@ -4,7 +4,7 @@ error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed
 LL |     fn foo(#[doc(alias = "qux")] _x: u32) -> Self::X {
    |            ^^^^^^^^^^^^^^^^^^^^^
 
-error: `#[doc(alias = "...")]` isn't allowed on extern block
+error: `#[doc(alias = "...")]` isn't allowed on foreign module
   --> $DIR/check-doc-alias-attr-location.rs:9:7
    |
 LL | #[doc(alias = "foo")]
@@ -28,5 +28,23 @@ error: `#[doc(alias = "...")]` isn't allowed on type alias in implementation blo
 LL |     #[doc(alias = "assoc")]
    |           ^^^^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: `#[doc(alias = "...")]` isn't allowed on statement
+  --> $DIR/check-doc-alias-attr-location.rs:24:15
+   |
+LL |         #[doc(alias = "stmt")]
+   |               ^^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` isn't allowed on expression
+  --> $DIR/check-doc-alias-attr-location.rs:26:15
+   |
+LL |         #[doc(alias = "expr")]
+   |               ^^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` isn't allowed on match arm
+  --> $DIR/check-doc-alias-attr-location.rs:28:19
+   |
+LL |             #[doc(alias = "arm")]
+   |                   ^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/specialization/issue-43037.rs b/src/test/ui/specialization/issue-43037.rs
new file mode 100644
index 00000000000..c49119f9c09
--- /dev/null
+++ b/src/test/ui/specialization/issue-43037.rs
@@ -0,0 +1,20 @@
+#![feature(specialization)]
+#![allow(incomplete_features)]
+
+trait X {}
+trait Y: X {}
+trait Z {
+    type Assoc: Y;
+}
+struct A<T>(T);
+
+impl<T> Y for T where T: X {}
+impl<T: X> Z for A<T> {
+    type Assoc = T;
+}
+
+// this impl is invalid, but causes an ICE anyway
+impl<T> From<<A<T> as Z>::Assoc> for T {}
+//~^ ERROR type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
+
+fn main() {}
diff --git a/src/test/ui/specialization/issue-43037.stderr b/src/test/ui/specialization/issue-43037.stderr
new file mode 100644
index 00000000000..4249cd89477
--- /dev/null
+++ b/src/test/ui/specialization/issue-43037.stderr
@@ -0,0 +1,12 @@
+error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
+  --> $DIR/issue-43037.rs:17:6
+   |
+LL | impl<T> From<<A<T> as Z>::Assoc> for T {}
+   |      ^ type parameter `T` must be used as the type parameter for some local type
+   |
+   = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
+   = note: only traits defined in the current crate can be implemented for a type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0210`.
diff --git a/src/test/ui/specialization/issue-45814.rs b/src/test/ui/specialization/issue-45814.rs
new file mode 100644
index 00000000000..8ee5d3e2e58
--- /dev/null
+++ b/src/test/ui/specialization/issue-45814.rs
@@ -0,0 +1,12 @@
+//~ ERROR overflow evaluating the requirement `T: Trait<_>`
+
+#![feature(specialization)]
+#![allow(incomplete_features)]
+
+pub trait Trait<T> {}
+
+default impl<T, U> Trait<T> for U {}
+
+impl<T> Trait<<T as Iterator>::Item> for T {}
+
+fn main() {}
diff --git a/src/test/ui/specialization/issue-45814.stderr b/src/test/ui/specialization/issue-45814.stderr
new file mode 100644
index 00000000000..ab6adf477c9
--- /dev/null
+++ b/src/test/ui/specialization/issue-45814.stderr
@@ -0,0 +1,14 @@
+error[E0275]: overflow evaluating the requirement `T: Trait<_>`
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_45814`)
+note: required because of the requirements on the impl of `Trait<_>` for `T`
+  --> $DIR/issue-45814.rs:8:20
+   |
+LL | default impl<T, U> Trait<T> for U {}
+   |                    ^^^^^^^^     ^
+   = note: 128 redundant requirements hidden
+   = note: required because of the requirements on the impl of `Trait<_>` for `T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/specialization/specialization-cross-crate.rs b/src/test/ui/specialization/specialization-cross-crate.rs
index 4171505aa37..d9381d66152 100644
--- a/src/test/ui/specialization/specialization-cross-crate.rs
+++ b/src/test/ui/specialization/specialization-cross-crate.rs
@@ -14,7 +14,7 @@ struct NotClone;
 struct MarkedAndClone;
 impl MyMarker for MarkedAndClone {}
 
-struct MyType<T>(T);
+struct MyType<T>(#[allow(unused_tuple_struct_fields)] T);
 impl<T> Foo for MyType<T> {
     default fn foo(&self) -> &'static str {
         "generic MyType"
diff --git a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs
index 5c2781a9c63..904aeaa088b 100644
--- a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs
+++ b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.rs
@@ -14,7 +14,7 @@ impl<'a> WithAssoc for &'a () {
     type Item = &'a u32;
 }
 
-struct Cloned<I>(I);
+struct Cloned<I>(#[allow(unused_tuple_struct_fields)] I);
 
 impl<'a, I, T: 'a> Iterator for Cloned<I>
     where I: WithAssoc<Item=&'a T>, T: Clone
diff --git a/src/test/ui/stdlib-unit-tests/raw-fat-ptr.rs b/src/test/ui/stdlib-unit-tests/raw-fat-ptr.rs
index 9f50659ed60..6b0b09c9894 100644
--- a/src/test/ui/stdlib-unit-tests/raw-fat-ptr.rs
+++ b/src/test/ui/stdlib-unit-tests/raw-fat-ptr.rs
@@ -39,6 +39,7 @@ impl<T> Foo for T {
     }
 }
 
+#[allow(unused_tuple_struct_fields)]
 struct S<T:?Sized>(u32, T);
 
 fn main() {
diff --git a/src/test/ui/struct-ctor-mangling.rs b/src/test/ui/struct-ctor-mangling.rs
index f242cb8457f..ba6abbf03a5 100644
--- a/src/test/ui/struct-ctor-mangling.rs
+++ b/src/test/ui/struct-ctor-mangling.rs
@@ -4,7 +4,7 @@ fn size_of_val<T>(_: &T) -> usize {
     std::mem::size_of::<T>()
 }
 
-struct Foo(i64);
+struct Foo(#[allow(unused_tuple_struct_fields)] i64);
 
 // Test that the (symbol) mangling of `Foo` (the `struct` type) and that of
 // `typeof Foo` (the function type of the `struct` constructor) don't collide.
diff --git a/src/test/ui/structs-enums/enum-null-pointer-opt.rs b/src/test/ui/structs-enums/enum-null-pointer-opt.rs
index 32fdbf620a9..85fa1eac2e2 100644
--- a/src/test/ui/structs-enums/enum-null-pointer-opt.rs
+++ b/src/test/ui/structs-enums/enum-null-pointer-opt.rs
@@ -10,8 +10,8 @@ use std::sync::Arc;
 trait Trait { fn dummy(&self) { } }
 trait Mirror { type Image; }
 impl<T> Mirror for T { type Image = T; }
-struct ParamTypeStruct<T>(T);
-struct AssocTypeStruct<T>(<T as Mirror>::Image);
+struct ParamTypeStruct<T>(#[allow(unused_tuple_struct_fields)] T);
+struct AssocTypeStruct<T>(#[allow(unused_tuple_struct_fields)] <T as Mirror>::Image);
 #[repr(transparent)]
 union MaybeUninitUnion<T: Copy> {
     _value: T,
@@ -46,7 +46,7 @@ fn main() {
     struct Foo {
         _a: Box<isize>
     }
-    struct Bar(Box<isize>);
+    struct Bar(#[allow(unused_tuple_struct_fields)] Box<isize>);
 
     // Should apply through structs
     assert_eq!(size_of::<Foo>(), size_of::<Option<Foo>>());
diff --git a/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs b/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs
index 53892a4e0ae..a05cf8b93d5 100644
--- a/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs
+++ b/src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs
@@ -6,7 +6,7 @@
  * represented with nullable pointers could be misoptimized in some cases.
  */
 
-enum List<X> { Nil, Cons(X, Box<List<X>>) }
+enum List<X> { Nil, Cons(X, #[allow(unused_tuple_struct_fields)] Box<List<X>>) }
 pub fn main() {
     match List::Cons(10, Box::new(List::Nil)) {
         List::Cons(10, _) => {}
diff --git a/src/test/ui/structs-enums/resource-in-struct.rs b/src/test/ui/structs-enums/resource-in-struct.rs
index 35a4b14bc3f..9613ca62a49 100644
--- a/src/test/ui/structs-enums/resource-in-struct.rs
+++ b/src/test/ui/structs-enums/resource-in-struct.rs
@@ -25,7 +25,7 @@ fn close_res(i: closable) -> close_res {
     }
 }
 
-enum option<T> { none, some(T), }
+enum option<T> { none, some(#[allow(unused_tuple_struct_fields)] T), }
 
 fn sink(_res: option<close_res>) { }
 
diff --git a/src/test/ui/structs-enums/tuple-struct-construct.rs b/src/test/ui/structs-enums/tuple-struct-construct.rs
index 972fc9dc04a..fbf97e6b225 100644
--- a/src/test/ui/structs-enums/tuple-struct-construct.rs
+++ b/src/test/ui/structs-enums/tuple-struct-construct.rs
@@ -1,4 +1,5 @@
 // run-pass
+#[allow(unused_tuple_struct_fields)]
 #[derive(Debug)]
 struct Foo(isize, isize);
 
diff --git a/src/test/ui/structs-enums/uninstantiable-struct.rs b/src/test/ui/structs-enums/uninstantiable-struct.rs
index b1ef525614e..b24effe5a9c 100644
--- a/src/test/ui/structs-enums/uninstantiable-struct.rs
+++ b/src/test/ui/structs-enums/uninstantiable-struct.rs
@@ -1,4 +1,4 @@
 // run-pass
-pub struct Z(&'static Z);
+pub struct Z(#[allow(unused_tuple_struct_fields)] &'static Z);
 
 pub fn main() {}
diff --git a/src/test/ui/suggestions/const-no-type.rs b/src/test/ui/suggestions/const-no-type.rs
index 6f46cfdf024..c6fdcdadbea 100644
--- a/src/test/ui/suggestions/const-no-type.rs
+++ b/src/test/ui/suggestions/const-no-type.rs
@@ -14,38 +14,38 @@ fn main() {}
 const C2 = 42;
 //~^ ERROR missing type for `const` item
 //~| HELP provide a type for the item
-//~| SUGGESTION C2: <type>
+//~| SUGGESTION : <type>
 
 #[cfg(FALSE)]
 static S2 = "abc";
 //~^ ERROR missing type for `static` item
 //~| HELP provide a type for the item
-//~| SUGGESTION S2: <type>
+//~| SUGGESTION : <type>
 
 #[cfg(FALSE)]
 static mut SM2 = "abc";
 //~^ ERROR missing type for `static mut` item
 //~| HELP provide a type for the item
-//~| SUGGESTION SM2: <type>
+//~| SUGGESTION : <type>
 
 // These will, so the diagnostics should be stolen by typeck:
 
 const C = 42;
 //~^ ERROR missing type for `const` item
 //~| HELP provide a type for the constant
-//~| SUGGESTION C: i32
+//~| SUGGESTION : i32
 
 const D = &&42;
 //~^ ERROR missing type for `const` item
 //~| HELP provide a type for the constant
-//~| SUGGESTION D: &&i32
+//~| SUGGESTION : &&i32
 
 static S = Vec::<String>::new();
 //~^ ERROR missing type for `static` item
 //~| HELP provide a type for the static variable
-//~| SUGGESTION S: Vec<String>
+//~| SUGGESTION : Vec<String>
 
 static mut SM = "abc";
 //~^ ERROR missing type for `static mut` item
 //~| HELP provide a type for the static variable
-//~| SUGGESTION &str
+//~| SUGGESTION : &str
diff --git a/src/test/ui/suggestions/const-no-type.stderr b/src/test/ui/suggestions/const-no-type.stderr
index 3b0fd6337f1..bd703992fd4 100644
--- a/src/test/ui/suggestions/const-no-type.stderr
+++ b/src/test/ui/suggestions/const-no-type.stderr
@@ -1,44 +1,44 @@
 error: missing type for `const` item
-  --> $DIR/const-no-type.rs:33:7
+  --> $DIR/const-no-type.rs:33:8
    |
 LL | const C = 42;
-   |       ^ help: provide a type for the constant: `C: i32`
+   |        ^ help: provide a type for the constant: `: i32`
 
 error: missing type for `const` item
-  --> $DIR/const-no-type.rs:38:7
+  --> $DIR/const-no-type.rs:38:8
    |
 LL | const D = &&42;
-   |       ^ help: provide a type for the constant: `D: &&i32`
+   |        ^ help: provide a type for the constant: `: &&i32`
 
 error: missing type for `static` item
-  --> $DIR/const-no-type.rs:43:8
+  --> $DIR/const-no-type.rs:43:9
    |
 LL | static S = Vec::<String>::new();
-   |        ^ help: provide a type for the static variable: `S: Vec<String>`
+   |         ^ help: provide a type for the static variable: `: Vec<String>`
 
 error: missing type for `static mut` item
-  --> $DIR/const-no-type.rs:48:12
+  --> $DIR/const-no-type.rs:48:14
    |
 LL | static mut SM = "abc";
-   |            ^^ help: provide a type for the static variable: `SM: &str`
+   |              ^ help: provide a type for the static variable: `: &str`
 
 error: missing type for `const` item
-  --> $DIR/const-no-type.rs:14:7
+  --> $DIR/const-no-type.rs:14:9
    |
 LL | const C2 = 42;
-   |       ^^ help: provide a type for the item: `C2: <type>`
+   |         ^ help: provide a type for the item: `: <type>`
 
 error: missing type for `static` item
-  --> $DIR/const-no-type.rs:20:8
+  --> $DIR/const-no-type.rs:20:10
    |
 LL | static S2 = "abc";
-   |        ^^ help: provide a type for the item: `S2: <type>`
+   |          ^ help: provide a type for the item: `: <type>`
 
 error: missing type for `static mut` item
-  --> $DIR/const-no-type.rs:26:12
+  --> $DIR/const-no-type.rs:26:15
    |
 LL | static mut SM2 = "abc";
-   |            ^^^ help: provide a type for the item: `SM2: <type>`
+   |               ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr
index ca09c3d5ff1..e5443290f9e 100644
--- a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr
+++ b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr
@@ -1,4 +1,4 @@
-error[E0507]: cannot move out of `s.0` which is behind a shared reference
+error[E0507]: cannot move out of `s` which is behind a shared reference
   --> $DIR/simple.rs:38:17
    |
 LL |     let X(_t) = *s;
@@ -7,7 +7,7 @@ LL |     let X(_t) = *s;
    |           data moved here
    |           move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:42:30
    |
 LL |     if let Either::One(_t) = *r { }
@@ -16,7 +16,7 @@ LL |     if let Either::One(_t) = *r { }
    |                        data moved here
    |                        move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:46:33
    |
 LL |     while let Either::One(_t) = *r { }
@@ -25,7 +25,7 @@ LL |     while let Either::One(_t) = *r { }
    |                           data moved here
    |                           move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `Two` which is behind a shared reference
   --> $DIR/simple.rs:50:11
    |
 LL |     match *r {
@@ -37,7 +37,7 @@ LL |         Either::One(_t)
    |                     data moved here
    |                     move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:57:11
    |
 LL |     match *r {
@@ -49,7 +49,7 @@ LL |         Either::One(_t) => (),
    |                     data moved here
    |                     move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `sm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `sm` which is behind a mutable reference
   --> $DIR/simple.rs:66:17
    |
 LL |     let X(_t) = *sm;
@@ -58,7 +58,7 @@ LL |     let X(_t) = *sm;
    |           data moved here
    |           move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:70:30
    |
 LL |     if let Either::One(_t) = *rm { }
@@ -67,7 +67,7 @@ LL |     if let Either::One(_t) = *rm { }
    |                        data moved here
    |                        move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:74:33
    |
 LL |     while let Either::One(_t) = *rm { }
@@ -76,7 +76,7 @@ LL |     while let Either::One(_t) = *rm { }
    |                           data moved here
    |                           move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `Two` which is behind a mutable reference
   --> $DIR/simple.rs:78:11
    |
 LL |     match *rm {
@@ -88,7 +88,7 @@ LL |         Either::One(_t)
    |                     data moved here
    |                     move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:85:11
    |
 LL |     match *rm {
@@ -100,7 +100,7 @@ LL |         Either::One(_t) => (),
    |                     data moved here
    |                     move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:93:11
    |
 LL |     match *rm {
@@ -226,7 +226,7 @@ LL |         Either::One(_t) => (),
    |                     data moved here
    |                     move occurs because `_t` has type `X`, which does not implement the `Copy` trait
 
-error[E0507]: cannot move out of `s.0` which is behind a shared reference
+error[E0507]: cannot move out of `s` which is behind a shared reference
   --> $DIR/simple.rs:168:18
    |
 LL |     let &X(_t) = s;
@@ -236,7 +236,7 @@ LL |     let &X(_t) = s;
    |         |  move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
    |         help: consider removing the `&`: `X(_t)`
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:172:31
    |
 LL |     if let &Either::One(_t) = r { }
@@ -246,7 +246,7 @@ LL |     if let &Either::One(_t) = r { }
    |            |            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |            help: consider removing the `&`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:176:34
    |
 LL |     while let &Either::One(_t) = r { }
@@ -256,7 +256,7 @@ LL |     while let &Either::One(_t) = r { }
    |               |            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |               help: consider removing the `&`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `Two` which is behind a shared reference
   --> $DIR/simple.rs:180:11
    |
 LL |     match r {
@@ -276,7 +276,7 @@ LL +
 LL ~         | &Either::Two(_t) => (),
    |
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:188:11
    |
 LL |     match r {
@@ -289,7 +289,7 @@ LL |         &Either::One(_t) => (),
    |         |            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |         help: consider removing the `&`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `r.0` which is behind a shared reference
+error[E0507]: cannot move out of `r` as enum variant `One` which is behind a shared reference
   --> $DIR/simple.rs:195:11
    |
 LL |     match r {
@@ -302,7 +302,7 @@ LL |         &Either::One(_t) => (),
    |         |            move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |         help: consider removing the `&`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `sm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `sm` which is behind a mutable reference
   --> $DIR/simple.rs:207:22
    |
 LL |     let &mut X(_t) = sm;
@@ -312,7 +312,7 @@ LL |     let &mut X(_t) = sm;
    |         |      move occurs because `_t` has type `Y`, which does not implement the `Copy` trait
    |         help: consider removing the `&mut`: `X(_t)`
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:211:35
    |
 LL |     if let &mut Either::One(_t) = rm { }
@@ -322,7 +322,7 @@ LL |     if let &mut Either::One(_t) = rm { }
    |            |                move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |            help: consider removing the `&mut`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:215:38
    |
 LL |     while let &mut Either::One(_t) = rm { }
@@ -332,7 +332,7 @@ LL |     while let &mut Either::One(_t) = rm { }
    |               |                move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |               help: consider removing the `&mut`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `Two` which is behind a mutable reference
   --> $DIR/simple.rs:219:11
    |
 LL |     match rm {
@@ -354,7 +354,7 @@ help: consider removing the `&mut`
 LL |         Either::Two(_t) => (),
    |         ~~~~~~~~~~~~~~~
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:228:11
    |
 LL |     match rm {
@@ -367,7 +367,7 @@ LL |         &mut Either::One(_t) => (),
    |         |                move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |         help: consider removing the `&mut`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:235:11
    |
 LL |     match rm {
@@ -380,7 +380,7 @@ LL |         &mut Either::One(_t) => (),
    |         |                move occurs because `_t` has type `X`, which does not implement the `Copy` trait
    |         help: consider removing the `&mut`: `Either::One(_t)`
 
-error[E0507]: cannot move out of `rm.0` which is behind a mutable reference
+error[E0507]: cannot move out of `rm` as enum variant `One` which is behind a mutable reference
   --> $DIR/simple.rs:242:11
    |
 LL |     match rm {
diff --git a/src/test/ui/suggestions/unnamable-types.stderr b/src/test/ui/suggestions/unnamable-types.stderr
index de64269d1f1..ede3ebfa739 100644
--- a/src/test/ui/suggestions/unnamable-types.stderr
+++ b/src/test/ui/suggestions/unnamable-types.stderr
@@ -1,8 +1,8 @@
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:6:7
+  --> $DIR/unnamable-types.rs:6:8
    |
 LL | const A = 5;
-   |       ^ help: provide a type for the constant: `A: i32`
+   |        ^ help: provide a type for the constant: `: i32`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/unnamable-types.rs:10:11
@@ -26,10 +26,10 @@ LL | const C: _ = || 42;
    |              ^^^^^
 
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:23:7
+  --> $DIR/unnamable-types.rs:23:8
    |
 LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
-   |       ^
+   |        ^
    |
 note: however, the inferred type `S<[closure@$DIR/unnamable-types.rs:23:31: 23:45]>` cannot be named
   --> $DIR/unnamable-types.rs:23:11
@@ -38,22 +38,22 @@ LL | const D = S { t: { let i = 0; move || -> i32 { i } } };
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:29:7
+  --> $DIR/unnamable-types.rs:29:8
    |
 LL | const E = foo;
-   |       ^ help: provide a type for the constant: `E: fn() -> i32`
+   |        ^ help: provide a type for the constant: `: fn() -> i32`
 
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:32:7
+  --> $DIR/unnamable-types.rs:32:8
    |
 LL | const F = S { t: foo };
-   |       ^ help: provide a type for the constant: `F: S<fn() -> i32>`
+   |        ^ help: provide a type for the constant: `: S<fn() -> i32>`
 
 error: missing type for `const` item
-  --> $DIR/unnamable-types.rs:37:7
+  --> $DIR/unnamable-types.rs:37:8
    |
 LL | const G = || -> i32 { yield 0; return 1; };
-   |       ^
+   |        ^
    |
 note: however, the inferred type `[generator@$DIR/unnamable-types.rs:37:11: 37:20]` cannot be named
   --> $DIR/unnamable-types.rs:37:11
diff --git a/src/test/ui/trailing-comma.rs b/src/test/ui/trailing-comma.rs
index 97006ae50a0..90adba99e54 100644
--- a/src/test/ui/trailing-comma.rs
+++ b/src/test/ui/trailing-comma.rs
@@ -3,7 +3,7 @@
 
 fn f<T,>(_: T,) {}
 
-struct Foo<T,>(T);
+struct Foo<T,>(#[allow(unused_tuple_struct_fields)] T);
 
 struct Bar;
 
@@ -14,7 +14,7 @@ impl Bar {
 }
 
 enum Baz {
-    Qux(isize,),
+    Qux(#[allow(unused_tuple_struct_fields)] isize,),
 }
 
 #[allow(unused,)]
diff --git a/src/test/ui/traits/augmented-assignments-trait.rs b/src/test/ui/traits/augmented-assignments-trait.rs
index 8c418daffdf..747a5393f12 100644
--- a/src/test/ui/traits/augmented-assignments-trait.rs
+++ b/src/test/ui/traits/augmented-assignments-trait.rs
@@ -1,7 +1,7 @@
 // run-pass
 use std::ops::AddAssign;
 
-struct Int(i32);
+struct Int(#[allow(unused_tuple_struct_fields)] i32);
 
 impl AddAssign for Int {
     fn add_assign(&mut self, _: Int) {
diff --git a/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr b/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr
index 86dbd0aac03..f5d6d72afc2 100644
--- a/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr
+++ b/src/test/ui/traits/issue-91949-hangs-on-recursion.stderr
@@ -4,11 +4,10 @@ warning: function cannot return without recursing
 LL | / fn recurse<T>(elements: T) -> Vec<char>
 LL | | where
 LL | |     T: Iterator<Item = ()>,
-LL | | {
-LL | |     recurse(IteratorOfWrapped(elements).map(|t| t.0))
-   | |     ------------------------------------------------- recursive call site
-LL | | }
-   | |_^ cannot return without recursing
+   | |___________________________^ cannot return without recursing
+LL |   {
+LL |       recurse(IteratorOfWrapped(elements).map(|t| t.0))
+   |       ------------------------------------------------- recursive call site
    |
    = note: `#[warn(unconditional_recursion)]` on by default
    = help: a `loop` may express intention better if this is on purpose
diff --git a/src/test/ui/traits/negative-impls/negated-auto-traits-rpass.rs b/src/test/ui/traits/negative-impls/negated-auto-traits-rpass.rs
index 010dbf24664..a1042f8310a 100644
--- a/src/test/ui/traits/negative-impls/negated-auto-traits-rpass.rs
+++ b/src/test/ui/traits/negative-impls/negated-auto-traits-rpass.rs
@@ -7,7 +7,7 @@ use std::marker::Send;
 pub struct WaitToken;
 impl !Send for WaitToken {}
 
-pub struct Test<T>(T);
+pub struct Test<T>(#[allow(unused_tuple_struct_fields)] T);
 unsafe impl<T: 'static> Send for Test<T> {}
 
 pub fn spawn<F>(_: F) -> () where F: FnOnce(), F: Send + 'static {}
diff --git a/src/test/ui/traits/object/exclusion.rs b/src/test/ui/traits/object/exclusion.rs
index 0b8b0e2f5ef..766dceeaffe 100644
--- a/src/test/ui/traits/object/exclusion.rs
+++ b/src/test/ui/traits/object/exclusion.rs
@@ -8,7 +8,7 @@ trait Future: 'static {
     }
 }
 
-struct Map<A>(A);
+struct Map<A>(#[allow(unused_tuple_struct_fields)] A);
 impl<A: Future> Future for Map<A> {}
 
 pub struct Promise;
diff --git a/src/test/ui/traits/object/generics.rs b/src/test/ui/traits/object/generics.rs
index e5a96af3810..5a4a6aecc6b 100644
--- a/src/test/ui/traits/object/generics.rs
+++ b/src/test/ui/traits/object/generics.rs
@@ -25,7 +25,7 @@ impl<A1, A2, A3> Impl<A1, A2, A3> {
 
 // test for #8601
 
-enum Type<T> { Constant(T) }
+enum Type<T> { Constant(#[allow(unused_tuple_struct_fields)] T) }
 
 trait Trait<K,V> {
     fn method(&self, _: Type<(K,V)>) -> isize;
diff --git a/src/test/ui/traits/pointee-deduction.rs b/src/test/ui/traits/pointee-deduction.rs
index f888246967d..c333b0129c8 100644
--- a/src/test/ui/traits/pointee-deduction.rs
+++ b/src/test/ui/traits/pointee-deduction.rs
@@ -13,8 +13,8 @@ impl Foo for () {
     type Bar = ();
 }
 
-struct Wrapper1<T: Foo>(<T as Foo>::Bar);
-struct Wrapper2<T: Foo>(<Wrapper1<T> as Pointee>::Metadata);
+struct Wrapper1<T: Foo>(#[allow(unused_tuple_struct_fields)] <T as Foo>::Bar);
+struct Wrapper2<T: Foo>(#[allow(unused_tuple_struct_fields)] <Wrapper1<T> as Pointee>::Metadata);
 
 fn main() {
     let _: Wrapper2<()> = Wrapper2(());
diff --git a/src/test/ui/traits/principal-less-objects.rs b/src/test/ui/traits/principal-less-objects.rs
index 82c76eb693a..62bad0d7d77 100644
--- a/src/test/ui/traits/principal-less-objects.rs
+++ b/src/test/ui/traits/principal-less-objects.rs
@@ -7,7 +7,7 @@ use std::mem;
 // Array is to make sure the size is not exactly pointer-size, so
 // we can be sure we are measuring the right size in the
 // `size_of_val` test.
-struct SetOnDrop<'a>(&'a AtomicUsize, [u8; 64]);
+struct SetOnDrop<'a>(&'a AtomicUsize, #[allow(unused_tuple_struct_fields)] [u8; 64]);
 impl<'a> Drop for SetOnDrop<'a> {
     fn drop(&mut self) {
         self.0.store(self.0.load(Ordering::Relaxed) + 1, Ordering::Relaxed);
diff --git a/src/test/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr b/src/test/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr
index ac005725ab4..15faab16abe 100644
--- a/src/test/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr
+++ b/src/test/ui/traits/trait-upcasting/cyclic-trait-resolution.stderr
@@ -14,7 +14,7 @@ note: cycle used when collecting item types in top-level module
   --> $DIR/cyclic-trait-resolution.rs:1:1
    |
 LL | trait A: B + A {}
-   | ^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/transmutability/abstraction/abstracted_assume.rs b/src/test/ui/transmutability/abstraction/abstracted_assume.rs
new file mode 100644
index 00000000000..2abbbf3c158
--- /dev/null
+++ b/src/test/ui/transmutability/abstraction/abstracted_assume.rs
@@ -0,0 +1,73 @@
+// check-pass
+//! The implementation should behave correctly when the `ASSUME` parameters are
+//! provided indirectly through an abstraction.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<
+        Src,
+        Dst,
+        Context,
+        const ASSUME_ALIGNMENT: bool,
+        const ASSUME_LIFETIMES: bool,
+        const ASSUME_VALIDITY: bool,
+        const ASSUME_VISIBILITY: bool,
+    >()
+    where
+        Dst: BikeshedIntrinsicFrom<
+            Src,
+            Context,
+            ASSUME_ALIGNMENT,
+            ASSUME_LIFETIMES,
+            ASSUME_VALIDITY,
+            ASSUME_VISIBILITY,
+        >,
+    {}
+}
+
+fn direct() {
+    struct Context;
+    #[repr(C)] struct Src;
+    #[repr(C)] struct Dst;
+
+    assert::is_transmutable::<Src, Dst, Context, false, false, false, false>();
+}
+
+fn via_const() {
+    struct Context;
+    #[repr(C)] struct Src;
+    #[repr(C)] struct Dst;
+
+    const FALSE: bool = false;
+
+    assert::is_transmutable::<Src, Dst, Context, FALSE, FALSE, FALSE, FALSE>();
+}
+
+fn via_associated_const() {
+    struct Context;
+    #[repr(C)] struct Src;
+    #[repr(C)] struct Dst;
+
+    trait Trait {
+        const FALSE: bool = true;
+    }
+
+    struct Ty;
+
+    impl Trait for Ty {}
+
+    assert::is_transmutable::<
+        Src,
+        Dst,
+        Context,
+        {Ty::FALSE},
+        {Ty::FALSE},
+        {Ty::FALSE},
+        {Ty::FALSE}
+    >();
+}
diff --git a/src/test/ui/transmutability/abstraction/const_generic_fn.rs b/src/test/ui/transmutability/abstraction/const_generic_fn.rs
new file mode 100644
index 00000000000..94c38bb28f7
--- /dev/null
+++ b/src/test/ui/transmutability/abstraction/const_generic_fn.rs
@@ -0,0 +1,41 @@
+// check-pass
+//! An array must have the correct length.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn array_like<T, E, const N: usize>()
+    where
+        T: BikeshedIntrinsicFrom<[E; N], Context, false, false, false, true>,
+        [E; N]: BikeshedIntrinsicFrom<T, Context, false, false, false, true>
+    {}
+}
+
+fn len_0() {
+    type Array = [u8; 0];
+    #[repr(C)] struct Struct();
+    assert::array_like::<Struct, u8, 0>();
+}
+
+fn len_1() {
+    type Array = [u8; 1];
+    #[repr(C)] struct Struct(u8);
+    assert::array_like::<Struct, u8, 1>();
+}
+
+fn len_2() {
+    type Array = [u8; 2];
+    #[repr(C)] struct Struct(u8, u8);
+    assert::array_like::<Struct, u8, 2>();
+}
+
+fn len_3() {
+    type Array = [u8; 3];
+    #[repr(C)] struct Struct(u8, u8, u8);
+    assert::array_like::<Struct, u8, 3>();
+}
diff --git a/src/test/ui/transmutability/arrays/should_have_correct_length.rs b/src/test/ui/transmutability/arrays/should_have_correct_length.rs
new file mode 100644
index 00000000000..bfe6d830a1b
--- /dev/null
+++ b/src/test/ui/transmutability/arrays/should_have_correct_length.rs
@@ -0,0 +1,44 @@
+// check-pass
+//! An array must have the correct length.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_have_len_0() {
+    type Array = [u8; 0];
+    #[repr(C)] struct Struct();
+    assert::is_maybe_transmutable::<Array, Struct>();
+    assert::is_maybe_transmutable::<Struct, Array>();
+}
+
+fn should_have_len_1() {
+    type Array = [u8; 1];
+    #[repr(C)] struct Struct(u8);
+    assert::is_maybe_transmutable::<Array, Struct>();
+    assert::is_maybe_transmutable::<Struct, Array>();
+}
+
+fn should_have_len_2() {
+    type Array = [u8; 2];
+    #[repr(C)] struct Struct(u8, u8);
+    assert::is_maybe_transmutable::<Array, Struct>();
+    assert::is_maybe_transmutable::<Struct, Array>();
+}
+
+fn should_have_len_3() {
+    type Array = [u8; 3];
+    #[repr(C)] struct Struct(u8, u8, u8);
+    assert::is_maybe_transmutable::<Array, Struct>();
+    assert::is_maybe_transmutable::<Struct, Array>();
+}
diff --git a/src/test/ui/transmutability/arrays/should_inherit_alignment.rs b/src/test/ui/transmutability/arrays/should_inherit_alignment.rs
new file mode 100644
index 00000000000..fcb1765ea6b
--- /dev/null
+++ b/src/test/ui/transmutability/arrays/should_inherit_alignment.rs
@@ -0,0 +1,55 @@
+// check-pass
+//! An array must inherit the alignment of its inner type.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+#[repr(C)]
+union Uninit {
+    a: (),
+    b: OxFF,
+}
+
+#[repr(C, align(2))] struct align_2(Ox00);
+
+fn len_0() {
+    #[repr(C)] struct ImplicitlyPadded([align_2; 0], Ox01);
+    #[repr(C)] struct ExplicitlyPadded(Ox01, Uninit);
+
+    #[repr(C)] struct Struct();
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
+
+fn len_1() {
+    #[repr(C)] struct ImplicitlyPadded([align_2; 1], Ox01);
+    #[repr(C)] struct ExplicitlyPadded(Ox00, Uninit, Ox01, Uninit);
+
+    #[repr(C)] struct Struct();
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
+
+fn len_2() {
+    #[repr(C)] struct ImplicitlyPadded([align_2; 2], Ox01);
+    #[repr(C)] struct ExplicitlyPadded(Ox00, Uninit, Ox00, Uninit, Ox01, Uninit);
+
+    #[repr(C)] struct Struct();
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
diff --git a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs
new file mode 100644
index 00000000000..8e69527c186
--- /dev/null
+++ b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs
@@ -0,0 +1,61 @@
+//! An array must have a well-defined layout to participate in a transmutation.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_reject_repr_rust()
+{
+    fn unit() {
+        type repr_rust = [String; 0];
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn singleton() {
+        type repr_rust = [String; 1];
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn duplex() {
+        type repr_rust = [String; 2];
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn should_accept_repr_C()
+{
+    fn unit() {
+        #[repr(C)] struct repr_c(u8, u16, u8);
+        type array = [repr_c; 0];
+        assert::is_maybe_transmutable::<array, ()>();
+        assert::is_maybe_transmutable::<i128, array>();
+    }
+
+    fn singleton() {
+        #[repr(C)] struct repr_c(u8, u16, u8);
+        type array = [repr_c; 1];
+        assert::is_maybe_transmutable::<array, repr_c>();
+        assert::is_maybe_transmutable::<repr_c, array>();
+    }
+
+    fn duplex() {
+        #[repr(C)] struct repr_c(u8, u16, u8);
+        #[repr(C)] struct duplex(repr_c, repr_c);
+        type array = [repr_c; 2];
+        assert::is_maybe_transmutable::<array, duplex>();
+        assert::is_maybe_transmutable::<duplex, array>();
+    }
+}
diff --git a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr
new file mode 100644
index 00000000000..eae0c947d42
--- /dev/null
+++ b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr
@@ -0,0 +1,99 @@
+error[E0277]: `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:21:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:22:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 0]`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:27:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:28:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 1]`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:33:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:34:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 2]`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs
new file mode 100644
index 00000000000..18e02b0d2b9
--- /dev/null
+++ b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs
@@ -0,0 +1,149 @@
+//! An enum with a primitive repr should have exactly the size of that primitive.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[repr(C)]
+struct Zst;
+
+#[derive(Clone, Copy)]
+#[repr(i8)] enum V0i8 { V }
+#[repr(u8)] enum V0u8 { V }
+#[repr(i16)] enum V0i16 { V }
+#[repr(u16)] enum V0u16 { V }
+#[repr(i32)] enum V0i32 { V }
+#[repr(u32)] enum V0u32 { V }
+#[repr(i64)] enum V0i64 { V }
+#[repr(u64)] enum V0u64 { V }
+#[repr(isize)] enum V0isize { V }
+#[repr(usize)] enum V0usize { V }
+
+fn n8() {
+    struct Context;
+
+    type Smaller = Zst;
+    type Analog = u8;
+    type Larger = u16;
+
+    fn i_should_have_correct_length() {
+        type Current = V0i8;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn u_should_have_correct_length() {
+        type Current = V0u8;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn n16() {
+    struct Context;
+
+    type Smaller = u8;
+    type Analog = u16;
+    type Larger = u32;
+
+    fn i_should_have_correct_length() {
+        type Current = V0i16;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn u_should_have_correct_length() {
+        type Current = V0u16;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn n32() {
+    struct Context;
+
+    type Smaller = u16;
+    type Analog = u32;
+    type Larger = u64;
+
+    fn i_should_have_correct_length() {
+        type Current = V0i32;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn u_should_have_correct_length() {
+        type Current = V0u32;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn n64() {
+    struct Context;
+
+    type Smaller = u32;
+    type Analog = u64;
+    type Larger = u128;
+
+    fn i_should_have_correct_length() {
+        type Current = V0i64;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn u_should_have_correct_length() {
+        type Current = V0u64;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn nsize() {
+    struct Context;
+
+    type Smaller = u8;
+    type Analog = usize;
+    type Larger = [usize; 2];
+
+    fn i_should_have_correct_length() {
+        type Current = V0isize;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn u_should_have_correct_length() {
+        type Current = V0usize;
+
+        assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
+        assert::is_transmutable::<Current, Analog, Context>();
+        assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
+    }
+}
diff --git a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr
new file mode 100644
index 00000000000..fa2e3b89b07
--- /dev/null
+++ b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr
@@ -0,0 +1,323 @@
+error[E0277]: `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:41:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Zst, n8::Context, true, true, true, true>` is not implemented for `V0i8`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:43:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0i8, n8::Context, true, true, true, true>` is not implemented for `u16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:49:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Zst, n8::Context, true, true, true, true>` is not implemented for `V0u8`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:51:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0u8, n8::Context, true, true, true, true>` is not implemented for `u16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:65:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, n16::Context, true, true, true, true>` is not implemented for `V0i16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:67:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0i16, n16::Context, true, true, true, true>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:73:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, n16::Context, true, true, true, true>` is not implemented for `V0u16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:75:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0u16, n16::Context, true, true, true, true>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:89:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, n32::Context, true, true, true, true>` is not implemented for `V0i32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:91:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0i32, n32::Context, true, true, true, true>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:97:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, n32::Context, true, true, true, true>` is not implemented for `V0u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:99:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0u32, n32::Context, true, true, true, true>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:113:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, n64::Context, true, true, true, true>` is not implemented for `V0i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:115:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0i64, n64::Context, true, true, true, true>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:121:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, n64::Context, true, true, true, true>` is not implemented for `V0u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:123:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0u64, n64::Context, true, true, true, true>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:137:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, nsize::Context, true, true, true, true>` is not implemented for `V0isize`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:139:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0isize, nsize::Context, true, true, true, true>` is not implemented for `[usize; 2]`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:145:44
+   |
+LL |         assert::is_transmutable::<Smaller, Current, Context>();
+   |                                            ^^^^^^^ `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, nsize::Context, true, true, true, true>` is not implemented for `V0usize`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:147:44
+   |
+LL |         assert::is_transmutable::<Current, Larger, Context>();
+   |                                            ^^^^^^ `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<V0usize, nsize::Context, true, true, true, true>` is not implemented for `[usize; 2]`
+note: required by a bound in `is_transmutable`
+  --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 20 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs
new file mode 100644
index 00000000000..978a12648f0
--- /dev/null
+++ b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs
@@ -0,0 +1,117 @@
+//! An enum must have a well-defined layout to participate in a transmutation.
+
+#![crate_type = "lib"]
+#![feature(repr128)]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_reject_repr_rust() {
+    fn void() {
+        enum repr_rust {}
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn singleton() {
+        enum repr_rust { V }
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn duplex() {
+        enum repr_rust { A, B }
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn should_accept_primitive_reprs()
+{
+    fn should_accept_repr_i8() {
+        #[repr(i8)] enum repr_i8 { V }
+        assert::is_maybe_transmutable::<repr_i8, ()>();
+        assert::is_maybe_transmutable::<i8, repr_i8>();
+    }
+
+    fn should_accept_repr_u8() {
+        #[repr(u8)] enum repr_u8 { V }
+        assert::is_maybe_transmutable::<repr_u8, ()>();
+        assert::is_maybe_transmutable::<u8, repr_u8>();
+    }
+
+    fn should_accept_repr_i16() {
+        #[repr(i16)] enum repr_i16 { V }
+        assert::is_maybe_transmutable::<repr_i16, ()>();
+        assert::is_maybe_transmutable::<i16, repr_i16>();
+    }
+
+    fn should_accept_repr_u16() {
+        #[repr(u16)] enum repr_u16 { V }
+        assert::is_maybe_transmutable::<repr_u16, ()>();
+        assert::is_maybe_transmutable::<u16, repr_u16>();
+    }
+
+    fn should_accept_repr_i32() {
+        #[repr(i32)] enum repr_i32 { V }
+        assert::is_maybe_transmutable::<repr_i32, ()>();
+        assert::is_maybe_transmutable::<i32, repr_i32>();
+    }
+
+    fn should_accept_repr_u32() {
+        #[repr(u32)] enum repr_u32 { V }
+        assert::is_maybe_transmutable::<repr_u32, ()>();
+        assert::is_maybe_transmutable::<u32, repr_u32>();
+    }
+
+    fn should_accept_repr_i64() {
+        #[repr(i64)] enum repr_i64 { V }
+        assert::is_maybe_transmutable::<repr_i64, ()>();
+        assert::is_maybe_transmutable::<i64, repr_i64>();
+    }
+
+    fn should_accept_repr_u64() {
+        #[repr(u64)] enum repr_u64 { V }
+        assert::is_maybe_transmutable::<repr_u64, ()>();
+        assert::is_maybe_transmutable::<u64, repr_u64>();
+    }
+
+    fn should_accept_repr_i128() {
+        #[repr(i128)] enum repr_i128 { V }
+        assert::is_maybe_transmutable::<repr_i128, ()>();
+        assert::is_maybe_transmutable::<i128, repr_i128>();
+    }
+
+    fn should_accept_repr_u128() {
+        #[repr(u128)] enum repr_u128 { V }
+        assert::is_maybe_transmutable::<repr_u128, ()>();
+        assert::is_maybe_transmutable::<u128, repr_u128>();
+    }
+
+    fn should_accept_repr_isize() {
+        #[repr(isize)] enum repr_isize { V }
+        assert::is_maybe_transmutable::<repr_isize, ()>();
+        assert::is_maybe_transmutable::<isize, repr_isize>();
+    }
+
+    fn should_accept_repr_usize() {
+        #[repr(usize)] enum repr_usize { V }
+        assert::is_maybe_transmutable::<repr_usize, ()>();
+        assert::is_maybe_transmutable::<usize, repr_usize>();
+    }
+}
+
+fn should_accept_repr_C() {
+    #[repr(C)] enum repr_c { V }
+    assert::is_maybe_transmutable::<repr_c, ()>();
+    assert::is_maybe_transmutable::<i128, repr_c>();
+}
diff --git a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr
new file mode 100644
index 00000000000..3273e87c89f
--- /dev/null
+++ b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr
@@ -0,0 +1,99 @@
+error[E0277]: `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:21:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<void::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:22:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `void::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:27:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<singleton::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:28:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `singleton::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:33:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<duplex::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:34:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `duplex::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:14:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/enums/should_order_correctly.rs b/src/test/ui/transmutability/enums/should_order_correctly.rs
new file mode 100644
index 00000000000..6558d2658ee
--- /dev/null
+++ b/src/test/ui/transmutability/enums/should_order_correctly.rs
@@ -0,0 +1,32 @@
+// check-pass
+//! The payloads of an enum variant should be ordered after its tag.
+
+#![crate_type = "lib"]
+#![feature(arbitrary_enum_discriminant)]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[repr(u8)] enum V0 { V = 0 }
+#[repr(u8)] enum V1 { V = 1 }
+#[repr(u8)] enum V2 { V = 2 }
+
+#[repr(u8)] enum E01 { V0(V1) = 0u8 }
+#[repr(u8)] enum E012 { V0(V1, V2) = 0u8 }
+
+fn should_order_tag_and_fields_correctly() {
+    // An implementation that (incorrectly) arranges E01 as [0x01, 0x00] will,
+    // in principle, reject this transmutation.
+    assert::is_transmutable::<E01, V0>();
+    // Again, but with one more field.
+    assert::is_transmutable::<E012, E01>();
+}
diff --git a/src/test/ui/transmutability/enums/should_pad_variants.rs b/src/test/ui/transmutability/enums/should_pad_variants.rs
new file mode 100644
index 00000000000..466b6c8a15b
--- /dev/null
+++ b/src/test/ui/transmutability/enums/should_pad_variants.rs
@@ -0,0 +1,40 @@
+//! The variants of an enum must be padded with uninit bytes such that they have
+//! the same length (in bytes).
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)] struct Zst;
+
+#[derive(Clone, Copy)]
+#[repr(u8)] enum V0 { V = 0 }
+
+#[derive(Clone, Copy)]
+#[repr(u8)] enum V2 { V = 2 }
+
+#[repr(C, u8)]
+enum Lopsided {
+    Smol(Zst),
+    Lorg(V0),
+}
+
+#[repr(C)] struct Src(V0, Zst, V2);
+#[repr(C)] struct Dst(Lopsided, V2);
+
+fn should_pad_variants() {
+    struct Context;
+    // If the implementation (incorrectly) fails to pad `Lopsided::Smol` with
+    // an uninitialized byte, this transmutation might be (wrongly) accepted:
+    assert::is_transmutable::<Src, Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/enums/should_pad_variants.stderr b/src/test/ui/transmutability/enums/should_pad_variants.stderr
new file mode 100644
index 00000000000..429f7211d17
--- /dev/null
+++ b/src/test/ui/transmutability/enums/should_pad_variants.stderr
@@ -0,0 +1,19 @@
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
+  --> $DIR/should_pad_variants.rs:39:36
+   |
+LL |     assert::is_transmutable::<Src, Dst, Context>();
+   |                                    ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, should_pad_variants::Context, true, true, true, true>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_pad_variants.rs:13:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.rs b/src/test/ui/transmutability/enums/should_respect_endianness.rs
new file mode 100644
index 00000000000..67a3c4e94ba
--- /dev/null
+++ b/src/test/ui/transmutability/enums/should_respect_endianness.rs
@@ -0,0 +1,33 @@
+//! The target endianness should be a consideration in computing the layout of
+//! an enum with a multi-byte tag.
+
+#![crate_type = "lib"]
+#![feature(arbitrary_enum_discriminant)]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[repr(u16)] enum Src { V = 0xCAFE }
+
+#[repr(u8)] enum OxCA { V = 0xCA }
+#[repr(u8)] enum OxFE { V = 0xFE }
+
+#[cfg(target_endian = "big")] #[repr(C)] struct Expected(OxCA, OxFE);
+#[cfg(target_endian = "big")] #[repr(C)] struct Unexpected(OxFE, OxCA);
+
+#[cfg(target_endian = "little")] #[repr(C)] struct Expected(OxFE, OxCA);
+#[cfg(target_endian = "little")] #[repr(C)] struct Unexpected(OxCA, OxFE);
+
+fn should_respect_endianness() {
+    assert::is_transmutable::<Src, Expected>();
+    assert::is_transmutable::<Src, Unexpected>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.stderr b/src/test/ui/transmutability/enums/should_respect_endianness.stderr
new file mode 100644
index 00000000000..78023cb378a
--- /dev/null
+++ b/src/test/ui/transmutability/enums/should_respect_endianness.stderr
@@ -0,0 +1,19 @@
+error[E0277]: `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`.
+  --> $DIR/should_respect_endianness.rs:32:36
+   |
+LL |     assert::is_transmutable::<Src, Unexpected>();
+   |                                    ^^^^^^^^^^ `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, assert::Context, true, true, true, true>` is not implemented for `Unexpected`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_respect_endianness.rs:15:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs
new file mode 100644
index 00000000000..30c381745d0
--- /dev/null
+++ b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs
@@ -0,0 +1,9 @@
+// The trait must not be available if its feature flag is absent.
+
+#![crate_type = "lib"]
+
+use std::mem::BikeshedIntrinsicFrom;
+//~^ ERROR use of unstable library feature 'transmutability' [E0658]
+
+use std::mem::Assume;
+//~^ ERROR use of unstable library feature 'transmutability' [E0658]
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr
new file mode 100644
index 00000000000..ba8093f8614
--- /dev/null
+++ b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr
@@ -0,0 +1,21 @@
+error[E0658]: use of unstable library feature 'transmutability'
+  --> $DIR/feature-missing.rs:5:5
+   |
+LL | use std::mem::BikeshedIntrinsicFrom;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #99571 <https://github.com/rust-lang/rust/issues/99571> for more information
+   = help: add `#![feature(transmutability)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'transmutability'
+  --> $DIR/feature-missing.rs:8:5
+   |
+LL | use std::mem::Assume;
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #99571 <https://github.com/rust-lang/rust/issues/99571> for more information
+   = help: add `#![feature(transmutability)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs
new file mode 100644
index 00000000000..e13462d390b
--- /dev/null
+++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs
@@ -0,0 +1,21 @@
+// An unknown destination type should be gracefully handled.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+    {}
+}
+
+fn should_gracefully_handle_unknown_dst() {
+    struct Context;
+    struct Src;
+    assert::is_transmutable::<Src, Dst, Context>(); //~ cannot find type
+}
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr
new file mode 100644
index 00000000000..85087282d3a
--- /dev/null
+++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr
@@ -0,0 +1,12 @@
+error[E0412]: cannot find type `Dst` in this scope
+  --> $DIR/unknown_dst.rs:20:36
+   |
+LL | fn should_gracefully_handle_unknown_dst() {
+   |                                        - help: you might be missing a type parameter: `<Dst>`
+...
+LL |     assert::is_transmutable::<Src, Dst, Context>();
+   |                                    ^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs
new file mode 100644
index 00000000000..dc51e2a8f4d
--- /dev/null
+++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs
@@ -0,0 +1,21 @@
+// An unknown source type should be gracefully handled.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+    {}
+}
+
+fn should_gracefully_handle_unknown_src() {
+    struct Context;
+    #[repr(C)] struct Dst;
+    assert::is_transmutable::<Src, Dst, Context>(); //~ cannot find type
+}
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr
new file mode 100644
index 00000000000..9bedbe87c3f
--- /dev/null
+++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr
@@ -0,0 +1,12 @@
+error[E0412]: cannot find type `Src` in this scope
+  --> $DIR/unknown_src.rs:20:31
+   |
+LL | fn should_gracefully_handle_unknown_src() {
+   |                                        - help: you might be missing a type parameter: `<Src>`
+...
+LL |     assert::is_transmutable::<Src, Dst, Context>();
+   |                               ^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs
new file mode 100644
index 00000000000..86fc8bd6b28
--- /dev/null
+++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs
@@ -0,0 +1,22 @@
+// An unknown destination type should be gracefully handled.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+    {}
+}
+
+fn should_gracefully_handle_unknown_dst_field() {
+    struct Context;
+    #[repr(C)] struct Src;
+    #[repr(C)] struct Dst(Missing); //~ cannot find type
+    assert::is_transmutable::<Src, Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr
new file mode 100644
index 00000000000..475e6f429f3
--- /dev/null
+++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `Missing` in this scope
+  --> $DIR/unknown_src_field.rs:20:27
+   |
+LL |     #[repr(C)] struct Dst(Missing);
+   |                           ^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs
new file mode 100644
index 00000000000..bd36748e790
--- /dev/null
+++ b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs
@@ -0,0 +1,40 @@
+//! The implementation must behave well if const values of wrong types are
+//! provided.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<
+        Src,
+        Dst,
+        Context,
+        const ASSUME_ALIGNMENT: bool,
+        const ASSUME_LIFETIMES: bool,
+        const ASSUME_VALIDITY: bool,
+        const ASSUME_VISIBILITY: bool,
+    >()
+    where
+        Dst: BikeshedIntrinsicFrom<
+            Src,
+            Context,
+            ASSUME_ALIGNMENT,
+            ASSUME_LIFETIMES,
+            ASSUME_VALIDITY,
+            ASSUME_VISIBILITY,
+        >,
+    {}
+}
+
+fn test() {
+    struct Context;
+    #[repr(C)] struct Src;
+    #[repr(C)] struct Dst;
+    assert::is_transmutable::<Src, Dst, Context, {0u8}, false, false, false>(); //~ ERROR mismatched types
+    assert::is_transmutable::<Src, Dst, Context, false, {0u8}, false, false>(); //~ ERROR mismatched types
+    assert::is_transmutable::<Src, Dst, Context, false, false, {0u8}, false>(); //~ ERROR mismatched types
+    assert::is_transmutable::<Src, Dst, Context, false, false, false, {0u8}>(); //~ ERROR mismatched types
+}
diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr
new file mode 100644
index 00000000000..e1464e02352
--- /dev/null
+++ b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr
@@ -0,0 +1,27 @@
+error[E0308]: mismatched types
+  --> $DIR/wrong-type-assume.rs:36:51
+   |
+LL |     assert::is_transmutable::<Src, Dst, Context, {0u8}, false, false, false>();
+   |                                                   ^^^ expected `bool`, found `u8`
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-type-assume.rs:37:58
+   |
+LL |     assert::is_transmutable::<Src, Dst, Context, false, {0u8}, false, false>();
+   |                                                          ^^^ expected `bool`, found `u8`
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-type-assume.rs:38:65
+   |
+LL |     assert::is_transmutable::<Src, Dst, Context, false, false, {0u8}, false>();
+   |                                                                 ^^^ expected `bool`, found `u8`
+
+error[E0308]: mismatched types
+  --> $DIR/wrong-type-assume.rs:39:72
+   |
+LL |     assert::is_transmutable::<Src, Dst, Context, false, false, false, {0u8}>();
+   |                                                                        ^^^ expected `bool`, found `u8`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/transmutability/primitives/bool.rs b/src/test/ui/transmutability/primitives/bool.rs
new file mode 100644
index 00000000000..4f79bc25337
--- /dev/null
+++ b/src/test/ui/transmutability/primitives/bool.rs
@@ -0,0 +1,25 @@
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+#![allow(incomplete_features)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+    {}
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+    {}
+}
+
+fn contrast_with_u8() {
+    assert::is_transmutable::<u8, bool>(); //~ ERROR cannot be safely transmuted
+    assert::is_maybe_transmutable::<u8, bool>();
+    assert::is_transmutable::<bool, u8>();
+}
diff --git a/src/test/ui/transmutability/primitives/bool.stderr b/src/test/ui/transmutability/primitives/bool.stderr
new file mode 100644
index 00000000000..dc740251c87
--- /dev/null
+++ b/src/test/ui/transmutability/primitives/bool.stderr
@@ -0,0 +1,19 @@
+error[E0277]: `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`.
+  --> $DIR/bool.rs:22:35
+   |
+LL |     assert::is_transmutable::<u8, bool>();
+   |                                   ^^^^ `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, true>` is not implemented for `bool`
+note: required by a bound in `is_transmutable`
+  --> $DIR/bool.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/primitives/numbers.rs b/src/test/ui/transmutability/primitives/numbers.rs
new file mode 100644
index 00000000000..a5f79065d8a
--- /dev/null
+++ b/src/test/ui/transmutability/primitives/numbers.rs
@@ -0,0 +1,128 @@
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+#![allow(incomplete_features)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+    {}
+}
+
+fn should_accept_identity() {
+    assert::is_transmutable::<   i8,    i8>();
+    assert::is_transmutable::<   u8,    u8>();
+    assert::is_transmutable::<  i16,   i16>();
+    assert::is_transmutable::<  u16,   u16>();
+    assert::is_transmutable::<  i32,   i32>();
+    assert::is_transmutable::<  f32,   f32>();
+    assert::is_transmutable::<  u32,   u32>();
+    assert::is_transmutable::<  i64,   i64>();
+    assert::is_transmutable::<  f64,   f64>();
+    assert::is_transmutable::<  u64,   u64>();
+    assert::is_transmutable::< i128,  i128>();
+    assert::is_transmutable::< u128,  u128>();
+    assert::is_transmutable::<isize, isize>();
+    assert::is_transmutable::<usize, usize>();
+}
+
+fn should_be_bitransmutable() {
+    assert::is_transmutable::<   i8,    u8>();
+    assert::is_transmutable::<   u8,    i8>();
+
+    assert::is_transmutable::<  i16,   u16>();
+    assert::is_transmutable::<  u16,   i16>();
+
+    assert::is_transmutable::<  i32,   f32>();
+    assert::is_transmutable::<  i32,   u32>();
+    assert::is_transmutable::<  f32,   i32>();
+    assert::is_transmutable::<  f32,   u32>();
+    assert::is_transmutable::<  u32,   i32>();
+    assert::is_transmutable::<  u32,   f32>();
+
+    assert::is_transmutable::<  u64,   i64>();
+    assert::is_transmutable::<  u64,   f64>();
+    assert::is_transmutable::<  i64,   u64>();
+    assert::is_transmutable::<  i64,   f64>();
+    assert::is_transmutable::<  f64,   u64>();
+    assert::is_transmutable::<  f64,   i64>();
+
+    assert::is_transmutable::< u128,  i128>();
+    assert::is_transmutable::< i128,  u128>();
+
+    assert::is_transmutable::<isize, usize>();
+    assert::is_transmutable::<usize, isize>();
+}
+
+fn should_reject_extension() {
+    assert::is_transmutable::<   i8,   i16>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   u16>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   i32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   f32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   u32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   i8,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<   u8,   i16>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   u16>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   i32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   f32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   u32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<   u8,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  i16,   i32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,   f32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,   u32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i16,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  u16,   i32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,   f32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,   u32>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u16,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  i32,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i32,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i32,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i32,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i32,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  f32,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  f32,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  f32,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  f32,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  f32,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  u32,   u64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u32,   i64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u32,   f64>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u32,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u32,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  u64,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  u64,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  i64,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  i64,  i128>(); //~ ERROR cannot be safely transmuted
+
+    assert::is_transmutable::<  f64,  u128>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<  f64,  i128>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/primitives/numbers.stderr b/src/test/ui/transmutability/primitives/numbers.stderr
new file mode 100644
index 00000000000..9b802a444e8
--- /dev/null
+++ b/src/test/ui/transmutability/primitives/numbers.stderr
@@ -0,0 +1,915 @@
+error[E0277]: `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:62:40
+   |
+LL |     assert::is_transmutable::<   i8,   i16>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:63:40
+   |
+LL |     assert::is_transmutable::<   i8,   u16>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:64:40
+   |
+LL |     assert::is_transmutable::<   i8,   i32>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:65:40
+   |
+LL |     assert::is_transmutable::<   i8,   f32>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `f32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:66:40
+   |
+LL |     assert::is_transmutable::<   i8,   u32>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:67:40
+   |
+LL |     assert::is_transmutable::<   i8,   u64>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:68:40
+   |
+LL |     assert::is_transmutable::<   i8,   i64>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:69:40
+   |
+LL |     assert::is_transmutable::<   i8,   f64>();
+   |                                        ^^^ `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:70:39
+   |
+LL |     assert::is_transmutable::<   i8,  u128>();
+   |                                       ^^^^ `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:71:39
+   |
+LL |     assert::is_transmutable::<   i8,  i128>();
+   |                                       ^^^^ `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:73:40
+   |
+LL |     assert::is_transmutable::<   u8,   i16>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:74:40
+   |
+LL |     assert::is_transmutable::<   u8,   u16>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u16`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:75:40
+   |
+LL |     assert::is_transmutable::<   u8,   i32>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:76:40
+   |
+LL |     assert::is_transmutable::<   u8,   f32>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `f32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:77:40
+   |
+LL |     assert::is_transmutable::<   u8,   u32>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:78:40
+   |
+LL |     assert::is_transmutable::<   u8,   u64>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:79:40
+   |
+LL |     assert::is_transmutable::<   u8,   i64>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:80:40
+   |
+LL |     assert::is_transmutable::<   u8,   f64>();
+   |                                        ^^^ `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:81:39
+   |
+LL |     assert::is_transmutable::<   u8,  u128>();
+   |                                       ^^^^ `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:82:39
+   |
+LL |     assert::is_transmutable::<   u8,  i128>();
+   |                                       ^^^^ `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:84:40
+   |
+LL |     assert::is_transmutable::<  i16,   i32>();
+   |                                        ^^^ `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:85:40
+   |
+LL |     assert::is_transmutable::<  i16,   f32>();
+   |                                        ^^^ `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `f32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:86:40
+   |
+LL |     assert::is_transmutable::<  i16,   u32>();
+   |                                        ^^^ `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:87:40
+   |
+LL |     assert::is_transmutable::<  i16,   u64>();
+   |                                        ^^^ `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:88:40
+   |
+LL |     assert::is_transmutable::<  i16,   i64>();
+   |                                        ^^^ `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:89:40
+   |
+LL |     assert::is_transmutable::<  i16,   f64>();
+   |                                        ^^^ `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:90:39
+   |
+LL |     assert::is_transmutable::<  i16,  u128>();
+   |                                       ^^^^ `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:91:39
+   |
+LL |     assert::is_transmutable::<  i16,  i128>();
+   |                                       ^^^^ `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:93:40
+   |
+LL |     assert::is_transmutable::<  u16,   i32>();
+   |                                        ^^^ `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:94:40
+   |
+LL |     assert::is_transmutable::<  u16,   f32>();
+   |                                        ^^^ `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `f32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:95:40
+   |
+LL |     assert::is_transmutable::<  u16,   u32>();
+   |                                        ^^^ `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u32`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:96:40
+   |
+LL |     assert::is_transmutable::<  u16,   u64>();
+   |                                        ^^^ `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:97:40
+   |
+LL |     assert::is_transmutable::<  u16,   i64>();
+   |                                        ^^^ `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:98:40
+   |
+LL |     assert::is_transmutable::<  u16,   f64>();
+   |                                        ^^^ `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:99:39
+   |
+LL |     assert::is_transmutable::<  u16,  u128>();
+   |                                       ^^^^ `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:100:39
+   |
+LL |     assert::is_transmutable::<  u16,  i128>();
+   |                                       ^^^^ `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:102:40
+   |
+LL |     assert::is_transmutable::<  i32,   u64>();
+   |                                        ^^^ `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:103:40
+   |
+LL |     assert::is_transmutable::<  i32,   i64>();
+   |                                        ^^^ `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:104:40
+   |
+LL |     assert::is_transmutable::<  i32,   f64>();
+   |                                        ^^^ `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:105:39
+   |
+LL |     assert::is_transmutable::<  i32,  u128>();
+   |                                       ^^^^ `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:106:39
+   |
+LL |     assert::is_transmutable::<  i32,  i128>();
+   |                                       ^^^^ `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:108:40
+   |
+LL |     assert::is_transmutable::<  f32,   u64>();
+   |                                        ^^^ `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:109:40
+   |
+LL |     assert::is_transmutable::<  f32,   i64>();
+   |                                        ^^^ `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:110:40
+   |
+LL |     assert::is_transmutable::<  f32,   f64>();
+   |                                        ^^^ `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:111:39
+   |
+LL |     assert::is_transmutable::<  f32,  u128>();
+   |                                       ^^^^ `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:112:39
+   |
+LL |     assert::is_transmutable::<  f32,  i128>();
+   |                                       ^^^^ `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:114:40
+   |
+LL |     assert::is_transmutable::<  u32,   u64>();
+   |                                        ^^^ `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `u64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:115:40
+   |
+LL |     assert::is_transmutable::<  u32,   i64>();
+   |                                        ^^^ `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `i64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:116:40
+   |
+LL |     assert::is_transmutable::<  u32,   f64>();
+   |                                        ^^^ `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `f64`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:117:39
+   |
+LL |     assert::is_transmutable::<  u32,  u128>();
+   |                                       ^^^^ `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:118:39
+   |
+LL |     assert::is_transmutable::<  u32,  i128>();
+   |                                       ^^^^ `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:120:39
+   |
+LL |     assert::is_transmutable::<  u64,  u128>();
+   |                                       ^^^^ `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u64, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:121:39
+   |
+LL |     assert::is_transmutable::<  u64,  i128>();
+   |                                       ^^^^ `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u64, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:123:39
+   |
+LL |     assert::is_transmutable::<  i64,  u128>();
+   |                                       ^^^^ `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i64, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:124:39
+   |
+LL |     assert::is_transmutable::<  i64,  i128>();
+   |                                       ^^^^ `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<i64, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:126:39
+   |
+LL |     assert::is_transmutable::<  f64,  u128>();
+   |                                       ^^^^ `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f64, assert::Context, false, false, false, false>` is not implemented for `u128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+  --> $DIR/numbers.rs:127:39
+   |
+LL |     assert::is_transmutable::<  f64,  i128>();
+   |                                       ^^^^ `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<f64, assert::Context, false, false, false, false>` is not implemented for `i128`
+note: required by a bound in `is_transmutable`
+  --> $DIR/numbers.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 57 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/primitives/unit.rs b/src/test/ui/transmutability/primitives/unit.rs
new file mode 100644
index 00000000000..86d4740300d
--- /dev/null
+++ b/src/test/ui/transmutability/primitives/unit.rs
@@ -0,0 +1,24 @@
+//! The unit type, `()`, should be one byte.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[repr(C)]
+struct Zst;
+
+fn should_have_correct_size() {
+    struct Context;
+    assert::is_transmutable::<(), Zst, Context>();
+    assert::is_transmutable::<Zst, (), Context>();
+    assert::is_transmutable::<(), u8, Context>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/primitives/unit.stderr b/src/test/ui/transmutability/primitives/unit.stderr
new file mode 100644
index 00000000000..cf27c0d17b3
--- /dev/null
+++ b/src/test/ui/transmutability/primitives/unit.stderr
@@ -0,0 +1,19 @@
+error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`.
+  --> $DIR/unit.rs:23:35
+   |
+LL |     assert::is_transmutable::<(), u8, Context>();
+   |                                   ^^ `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not implemented for `u8`
+note: required by a bound in `is_transmutable`
+  --> $DIR/unit.rs:12:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/references.rs b/src/test/ui/transmutability/references.rs
new file mode 100644
index 00000000000..c6fd4c43e95
--- /dev/null
+++ b/src/test/ui/transmutability/references.rs
@@ -0,0 +1,20 @@
+//! Transmutations involving references are not yet supported.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn not_yet_implemented() {
+    #[repr(C)] struct Unit;
+    assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/references.stderr b/src/test/ui/transmutability/references.stderr
new file mode 100644
index 00000000000..b1359ea5865
--- /dev/null
+++ b/src/test/ui/transmutability/references.stderr
@@ -0,0 +1,19 @@
+error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`.
+  --> $DIR/references.rs:19:37
+   |
+LL |     assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
+   |                                     ^^^^^^^^^^^^^ `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not implemented for `&'static Unit`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/references.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/structs/repr/should_handle_align.rs b/src/test/ui/transmutability/structs/repr/should_handle_align.rs
new file mode 100644
index 00000000000..71720165ab0
--- /dev/null
+++ b/src/test/ui/transmutability/structs/repr/should_handle_align.rs
@@ -0,0 +1,36 @@
+// check-pass
+//! The presence of an `align(X)` annotation must be accounted for.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_pad_explicitly_aligned_field() {
+    #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
+
+    #[repr(C)]
+    pub union Uninit {
+        a: (),
+        b: V0u8,
+    }
+
+    #[repr(C, align(2))] struct align_2(V0u8);
+
+    #[repr(C)] struct ImplicitlyPadded(align_2, V0u8);
+    #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8);
+
+    // An implementation that (incorrectly) does not place a padding byte after
+    // `align_2` will, incorrectly, reject the following transmutations.
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
diff --git a/src/test/ui/transmutability/structs/repr/should_handle_packed.rs b/src/test/ui/transmutability/structs/repr/should_handle_packed.rs
new file mode 100644
index 00000000000..ae8acf50418
--- /dev/null
+++ b/src/test/ui/transmutability/structs/repr/should_handle_packed.rs
@@ -0,0 +1,35 @@
+// check-pass
+//! The presence of an `align(X)` annotation must be accounted for.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_pad_explicitly_packed_field() {
+    #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
+    #[derive(Clone, Copy)] #[repr(u32)] enum V0u32 { V = 0 }
+
+    #[repr(C)]
+    pub union Uninit {
+        a: (),
+        b: V0u8,
+    }
+
+    #[repr(C, packed(2))] struct ImplicitlyPadded(V0u8, V0u32);
+    #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8, V0u8, V0u8, V0u8);
+
+    // An implementation that (incorrectly) does not place a padding byte after
+    // `align_2` will, incorrectly, reject the following transmutations.
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
diff --git a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs
new file mode 100644
index 00000000000..556be989dbc
--- /dev/null
+++ b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs
@@ -0,0 +1,76 @@
+//! A struct must have a well-defined layout to participate in a transmutation.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_reject_repr_rust()
+{
+    fn unit() {
+        struct repr_rust;
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn tuple() {
+        struct repr_rust();
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn braces() {
+        struct repr_rust{}
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn aligned() {
+        #[repr(align(1))] struct repr_rust{}
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn packed() {
+        #[repr(packed)] struct repr_rust{}
+        assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+    }
+
+    fn nested() {
+        struct repr_rust;
+        #[repr(C)] struct repr_c(repr_rust);
+        assert::is_maybe_transmutable::<repr_c, ()>(); //~ ERROR cannot be safely transmuted
+        assert::is_maybe_transmutable::<u128, repr_c>(); //~ ERROR cannot be safely transmuted
+    }
+}
+
+fn should_accept_repr_C()
+{
+    fn unit() {
+        #[repr(C)] struct repr_c;
+        assert::is_maybe_transmutable::<repr_c, ()>();
+        assert::is_maybe_transmutable::<i128, repr_c>();
+    }
+
+    fn tuple() {
+        #[repr(C)] struct repr_c();
+        assert::is_maybe_transmutable::<repr_c, ()>();
+        assert::is_maybe_transmutable::<i128, repr_c>();
+    }
+
+    fn braces() {
+        #[repr(C)] struct repr_c{}
+        assert::is_maybe_transmutable::<repr_c, ()>();
+        assert::is_maybe_transmutable::<i128, repr_c>();
+    }
+}
diff --git a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr
new file mode 100644
index 00000000000..07355f7c2ad
--- /dev/null
+++ b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr
@@ -0,0 +1,195 @@
+error[E0277]: `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:21:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::unit::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:22:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::unit::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:27:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::tuple::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:28:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::tuple::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:33:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::braces::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:34:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::braces::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:39:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<aligned::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:40:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `aligned::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:45:52
+   |
+LL |         assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                    ^^ `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<packed::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:46:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                               ^^^^^^^^^ `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `packed::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:52:49
+   |
+LL |         assert::is_maybe_transmutable::<repr_c, ()>();
+   |                                                 ^^ `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<nested::repr_c, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:53:47
+   |
+LL |         assert::is_maybe_transmutable::<u128, repr_c>();
+   |                                               ^^^^^^ `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `nested::repr_c`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/structs/should_order_fields_correctly.rs b/src/test/ui/transmutability/structs/should_order_fields_correctly.rs
new file mode 100644
index 00000000000..db49b914fe0
--- /dev/null
+++ b/src/test/ui/transmutability/structs/should_order_fields_correctly.rs
@@ -0,0 +1,31 @@
+// check-pass
+//! The fields of a struct should be laid out in lexical order.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[repr(u8)] enum V0 { V = 0 }
+#[repr(u8)] enum V1 { V = 1 }
+#[repr(u8)] enum V2 { V = 2 }
+
+#[repr(C)] struct S01(V0, V1);
+#[repr(C)] struct S012(V0, V1, V2);
+
+fn should_order_tag_and_fields_correctly() {
+    // An implementation that (incorrectly) arranges S01 as [0x01, 0x00] will,
+    // in principle, reject this transmutation.
+    assert::is_transmutable::<S01, V0>();
+    // Again, but with one more field.
+    assert::is_transmutable::<S012, S01>();
+}
diff --git a/src/test/ui/transmutability/unions/boolish.rs b/src/test/ui/transmutability/unions/boolish.rs
new file mode 100644
index 00000000000..975118b99b7
--- /dev/null
+++ b/src/test/ui/transmutability/unions/boolish.rs
@@ -0,0 +1,31 @@
+// check-pass
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![feature(marker_trait_attr)]
+#![allow(dead_code)]
+#![allow(incomplete_features)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+    {}
+}
+
+fn should_match_bool() {
+    #[derive(Copy, Clone)] #[repr(u8)] pub enum False { V = 0 }
+    #[derive(Copy, Clone)] #[repr(u8)] pub enum True { V = 1 }
+
+    #[repr(C)]
+    pub union Bool {
+        pub f: False,
+        pub t: True,
+    }
+
+    assert::is_transmutable::<Bool, bool>();
+    assert::is_transmutable::<bool, Bool>();
+}
diff --git a/src/test/ui/transmutability/unions/repr/should_handle_align.rs b/src/test/ui/transmutability/unions/repr/should_handle_align.rs
new file mode 100644
index 00000000000..e215799a232
--- /dev/null
+++ b/src/test/ui/transmutability/unions/repr/should_handle_align.rs
@@ -0,0 +1,40 @@
+// check-pass
+//! The presence of an `align(X)` annotation must be accounted for.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_pad_explicitly_aligned_field() {
+    #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
+    #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 }
+
+    #[repr(C)]
+    pub union Uninit {
+        a: (),
+        b: V1u8,
+    }
+
+    #[repr(C, align(2))]
+    pub union align_2 {
+        a: V0u8,
+    }
+
+    #[repr(C)] struct ImplicitlyPadded(align_2, V0u8);
+    #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8);
+
+    // An implementation that (incorrectly) does not place a padding byte after
+    // `align_2` will, incorrectly, reject the following transmutations.
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
diff --git a/src/test/ui/transmutability/unions/repr/should_handle_packed.rs b/src/test/ui/transmutability/unions/repr/should_handle_packed.rs
new file mode 100644
index 00000000000..34a53c7a80c
--- /dev/null
+++ b/src/test/ui/transmutability/unions/repr/should_handle_packed.rs
@@ -0,0 +1,41 @@
+// check-pass
+//! The presence of an `align(X)` annotation must be accounted for.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_pad_explicitly_packed_field() {
+    #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
+    #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 }
+    #[derive(Clone, Copy)] #[repr(u8)] enum V2u8 { V = 2 }
+    #[derive(Clone, Copy)] #[repr(u32)] enum V3u32 { V = 3 }
+
+    #[repr(C)]
+    pub union Uninit {
+        a: (),
+        b: V1u8,
+    }
+
+    #[repr(C, packed(2))]
+    pub union Packed {
+        a: [V3u32; 0],
+        b: V0u8,
+    }
+
+    #[repr(C)] struct ImplicitlyPadded(Packed, V2u8);
+    #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V2u8);
+
+    assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
+    assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
+}
diff --git a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs
new file mode 100644
index 00000000000..cec8e389f44
--- /dev/null
+++ b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs
@@ -0,0 +1,37 @@
+//! A struct must have a well-defined layout to participate in a transmutation.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+fn should_reject_repr_rust()
+{
+    union repr_rust {
+        a: u8
+    }
+
+    assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
+    assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
+}
+
+fn should_accept_repr_C()
+{
+    #[repr(C)]
+    union repr_c {
+        a: u8
+    }
+
+    struct repr_rust;
+    assert::is_maybe_transmutable::<repr_c, ()>();
+    assert::is_maybe_transmutable::<u128, repr_c>();
+}
diff --git a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr
new file mode 100644
index 00000000000..2ed01b159ab
--- /dev/null
+++ b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr
@@ -0,0 +1,35 @@
+error[E0277]: `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:23:48
+   |
+LL |     assert::is_maybe_transmutable::<repr_rust, ()>();
+   |                                                ^^ `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`.
+  --> $DIR/should_require_well_defined_layout.rs:24:43
+   |
+LL |     assert::is_maybe_transmutable::<u128, repr_rust>();
+   |                                           ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::repr_rust`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_require_well_defined_layout.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/unions/should_pad_variants.rs b/src/test/ui/transmutability/unions/should_pad_variants.rs
new file mode 100644
index 00000000000..c4757900f9c
--- /dev/null
+++ b/src/test/ui/transmutability/unions/should_pad_variants.rs
@@ -0,0 +1,40 @@
+//! The variants of a union must be padded with uninit bytes such that they have
+//! the same length (in bytes).
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+    {}
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)] struct Zst;
+
+#[derive(Clone, Copy)]
+#[repr(u8)] enum V0 { V = 0 }
+
+#[derive(Clone, Copy)]
+#[repr(u8)] enum V2 { V = 2 }
+
+#[repr(C)]
+union Lopsided {
+    smol: Zst,
+    lorg: V0,
+}
+
+#[repr(C)] struct Src(V0, Zst, V2);
+#[repr(C)] struct Dst(V0, Lopsided, V2);
+
+fn should_pad_variants() {
+    struct Context;
+    // If the implementation (incorrectly) fails to pad `Lopsided::smol` with
+    // an uninitialized byte, this transmutation might be (wrongly) accepted:
+    assert::is_transmutable::<Src, Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/unions/should_pad_variants.stderr b/src/test/ui/transmutability/unions/should_pad_variants.stderr
new file mode 100644
index 00000000000..429f7211d17
--- /dev/null
+++ b/src/test/ui/transmutability/unions/should_pad_variants.stderr
@@ -0,0 +1,19 @@
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
+  --> $DIR/should_pad_variants.rs:39:36
+   |
+LL |     assert::is_transmutable::<Src, Dst, Context>();
+   |                                    ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, should_pad_variants::Context, true, true, true, true>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_pad_variants.rs:13:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs b/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs
new file mode 100644
index 00000000000..2493d71554a
--- /dev/null
+++ b/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs
@@ -0,0 +1,39 @@
+// check-pass
+//! If validity is assumed, there need only be one matching bit-pattern between
+//! the source and destination types.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+        // validity IS assumed --------------------------------^^^^
+    {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox7F { V = 0x7F }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+fn test() {
+    #[repr(C)]
+    union A {
+        a: Ox00,
+        b: Ox7F,
+    }
+
+    #[repr(C)]
+    union B {
+        a: Ox7F,
+        b: OxFF,
+    }
+
+    assert::is_maybe_transmutable::<A, B>();
+    assert::is_maybe_transmutable::<B, A>();
+}
diff --git a/src/test/ui/transmutability/unions/should_reject_contraction.rs b/src/test/ui/transmutability/unions/should_reject_contraction.rs
new file mode 100644
index 00000000000..e8138d0e046
--- /dev/null
+++ b/src/test/ui/transmutability/unions/should_reject_contraction.rs
@@ -0,0 +1,36 @@
+//! Validity may not be contracted, unless validity is assumed.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+    {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+fn test() {
+    #[repr(C)]
+    union Subset {
+        a: Ox00,
+        b: OxFF,
+    }
+
+    #[repr(C)]
+    union Superset {
+        a: Ox00,
+        b: OxFF,
+        c: Ox01,
+    }
+
+    assert::is_transmutable::<Superset, Subset>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/unions/should_reject_contraction.stderr b/src/test/ui/transmutability/unions/should_reject_contraction.stderr
new file mode 100644
index 00000000000..99f58900817
--- /dev/null
+++ b/src/test/ui/transmutability/unions/should_reject_contraction.stderr
@@ -0,0 +1,19 @@
+error[E0277]: `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`.
+  --> $DIR/should_reject_contraction.rs:35:41
+   |
+LL |     assert::is_transmutable::<Superset, Subset>();
+   |                                         ^^^^^^ `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Superset, assert::Context, false, false, false, true>` is not implemented for `Subset`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_contraction.rs:13:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/unions/should_reject_disjoint.rs b/src/test/ui/transmutability/unions/should_reject_disjoint.rs
new file mode 100644
index 00000000000..16160e29a54
--- /dev/null
+++ b/src/test/ui/transmutability/unions/should_reject_disjoint.rs
@@ -0,0 +1,36 @@
+//! Validity must be satisfiable, even if validity is assumed.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_maybe_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+        // validity IS assumed --------------------------------^^^^
+    {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+fn test() {
+    #[repr(C)]
+    union A {
+        a: Ox00,
+        b: OxFF,
+    }
+
+    #[repr(C)]
+    union B {
+        c: Ox01,
+    }
+
+    assert::is_maybe_transmutable::<A, B>(); //~ ERROR cannot be safely transmuted
+    assert::is_maybe_transmutable::<B, A>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/unions/should_reject_disjoint.stderr b/src/test/ui/transmutability/unions/should_reject_disjoint.stderr
new file mode 100644
index 00000000000..5714e2bf320
--- /dev/null
+++ b/src/test/ui/transmutability/unions/should_reject_disjoint.stderr
@@ -0,0 +1,35 @@
+error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
+  --> $DIR/should_reject_disjoint.rs:34:40
+   |
+LL |     assert::is_maybe_transmutable::<A, B>();
+   |                                        ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<A, assert::Context, false, false, true, true>` is not implemented for `B`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_reject_disjoint.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+  --> $DIR/should_reject_disjoint.rs:35:40
+   |
+LL |     assert::is_maybe_transmutable::<B, A>();
+   |                                        ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<B, assert::Context, false, false, true, true>` is not implemented for `A`
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/should_reject_disjoint.rs:13:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/unions/should_reject_intersecting.rs b/src/test/ui/transmutability/unions/should_reject_intersecting.rs
new file mode 100644
index 00000000000..58e399fb962
--- /dev/null
+++ b/src/test/ui/transmutability/unions/should_reject_intersecting.rs
@@ -0,0 +1,38 @@
+//! ALL valid bit patterns of the source must be valid bit patterns of the
+//! destination type, unless validity is assumed.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code, incomplete_features, non_camel_case_types)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+    pub struct Context;
+
+    pub fn is_transmutable<Src, Dst>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+        // validity is NOT assumed ----------------------------^^^^^
+    {}
+}
+
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
+#[derive(Clone, Copy)] #[repr(u8)] enum Ox7F { V = 0x7F }
+#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
+
+fn test() {
+    #[repr(C)]
+    union A {
+        a: Ox00,
+        b: Ox7F,
+    }
+
+    #[repr(C)]
+    union B {
+        a: Ox7F,
+        b: OxFF,
+    }
+
+    assert::is_transmutable::<A, B>(); //~ ERROR cannot be safely transmuted
+    assert::is_transmutable::<B, A>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/unions/should_reject_intersecting.stderr b/src/test/ui/transmutability/unions/should_reject_intersecting.stderr
new file mode 100644
index 00000000000..92689a5f828
--- /dev/null
+++ b/src/test/ui/transmutability/unions/should_reject_intersecting.stderr
@@ -0,0 +1,35 @@
+error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
+  --> $DIR/should_reject_intersecting.rs:36:34
+   |
+LL |     assert::is_transmutable::<A, B>();
+   |                                  ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<A, assert::Context, false, false, false, true>` is not implemented for `B`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_intersecting.rs:14:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+  --> $DIR/should_reject_intersecting.rs:37:34
+   |
+LL |     assert::is_transmutable::<B, A>();
+   |                                  ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<B, assert::Context, false, false, false, true>` is not implemented for `A`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_intersecting.rs:14:14
+   |
+LL |     pub fn is_transmutable<Src, Dst>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs
new file mode 100644
index 00000000000..5a8c810494c
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs
@@ -0,0 +1,38 @@
+// check-pass
+//! If visibility is assumed, a transmutation should be accepted even if the
+//! destination type contains a private field.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+        // visibility IS assumed -------------------------------------^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(self) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(self) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(self) field: Zst, // <- private field
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs
new file mode 100644
index 00000000000..77ab4fa6bff
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs
@@ -0,0 +1,39 @@
+// check-pass
+//! If visibility is assumed, a transmutation should be accepted even if the
+//! destination type contains a private variant.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+        // visibility IS assumed -------------------------------------^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(self) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(self) field: Zst,
+    }
+}
+
+mod dst {
+    #[derive(Copy, Clone)]
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) union Dst {
+        pub(self) field: Zst, // <- private variant
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs
new file mode 100644
index 00000000000..2421b24cbf0
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs
@@ -0,0 +1,46 @@
+// check-pass
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+//!
+//! This test exercises a tricky-to-implement instance of this principle: the
+//! "pub-in-priv trick". In the below example, the type `dst::private::Zst` is
+//! unreachable from `Context`.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+        // visibility IS assumed -------------------------------------^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    mod private {
+        #[repr(C)] pub struct Zst; // <- unreachable type
+    }
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: private::Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs
new file mode 100644
index 00000000000..80b454fda56
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs
@@ -0,0 +1,39 @@
+//! If visibility is assumed, a transmutation should be accepted even if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+        // visibility IS assumed -------------------------------------^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(self) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(self) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(self) struct Zst; // <- unreachable type
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: Zst, //~ ERROR private type
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr
new file mode 100644
index 00000000000..be83b7ce33f
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr
@@ -0,0 +1,12 @@
+error[E0446]: private type `dst::Zst` in public interface
+  --> $DIR/should_accept_if_dst_has_unreachable_field.rs:32:9
+   |
+LL |     #[repr(C)] pub(self) struct Zst; // <- unreachable type
+   |                -------------------- `dst::Zst` declared as private
+...
+LL |         pub(in super) field: Zst,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0446`.
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs
new file mode 100644
index 00000000000..7c53c91e4ed
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs
@@ -0,0 +1,40 @@
+//! If visibility is assumed, a transmutation should be accepted even if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
+        // visibility IS assumed -------------------------------------^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(self) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(self) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    // unreachable type
+    #[repr(C)] pub(self) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR `Dst` is private
+}
diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr
new file mode 100644
index 00000000000..827df05decb
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr
@@ -0,0 +1,15 @@
+error[E0603]: struct `Dst` is private
+  --> $DIR/should_accept_if_dst_has_unreachable_ty.rs:39:46
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                              ^^^ private struct
+   |
+note: the struct `Dst` is defined here
+  --> $DIR/should_accept_if_dst_has_unreachable_ty.rs:32:16
+   |
+LL |     #[repr(C)] pub(self) struct Dst {
+   |                ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs
new file mode 100644
index 00000000000..c3f298f0163
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs
@@ -0,0 +1,38 @@
+// check-pass
+//! The presence of a private field in the source type does not affect
+//! transmutability.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(self) field: Zst, // <- private field
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs
new file mode 100644
index 00000000000..73f6aece51e
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs
@@ -0,0 +1,39 @@
+// check-pass
+//! The presence of a private variant in the source type does not affect
+//! transmutability.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[derive(Copy, Clone)]
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) union Src {
+        pub(self) field: Zst, // <- private variant
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs
new file mode 100644
index 00000000000..6d602601e96
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs
@@ -0,0 +1,38 @@
+//! The presence of an unreachable field in the source type (e.g., a public
+//! field with a private type does not affect transmutability. (This rule is
+//! distinct from type privacy, which still may forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(self) struct Zst; // <- unreachable type
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst, //~ ERROR private type
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr
new file mode 100644
index 00000000000..3f7d08d0ae2
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr
@@ -0,0 +1,12 @@
+error[E0446]: private type `src::Zst` in public interface
+  --> $DIR/should_accept_if_src_has_unreachable_field.rs:23:9
+   |
+LL |     #[repr(C)] pub(self) struct Zst; // <- unreachable type
+   |                -------------------- `src::Zst` declared as private
+...
+LL |         pub(in super) field: Zst,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0446`.
diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs
new file mode 100644
index 00000000000..1943fb8716a
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs
@@ -0,0 +1,39 @@
+//! The presence of an unreachable source type (i.e., the source type is
+//! private) does not affect transmutability. (This rule is distinct from type
+//! privacy, which still may forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    // unreachable type
+    #[repr(C)] pub(self) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR `Src` is private
+}
diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr
new file mode 100644
index 00000000000..e961984e189
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr
@@ -0,0 +1,15 @@
+error[E0603]: struct `Src` is private
+  --> $DIR/should_accept_if_src_has_unreachable_ty.rs:38:36
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                    ^^^ private struct
+   |
+note: the struct `Src` is defined here
+  --> $DIR/should_accept_if_src_has_unreachable_ty.rs:23:16
+   |
+LL |     #[repr(C)] pub(self) struct Src {
+   |                ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs
new file mode 100644
index 00000000000..fcf3f3a5278
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs
@@ -0,0 +1,37 @@
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains a private field.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(self) field: Zst, // <- private field
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr
new file mode 100644
index 00000000000..85124019e7f
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr
@@ -0,0 +1,19 @@
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+  --> $DIR/should_reject_if_dst_has_private_field.rs:36:41
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                         ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_if_dst_has_private_field.rs:13:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs
new file mode 100644
index 00000000000..566b5646712
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs
@@ -0,0 +1,38 @@
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains a private variant.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    #[derive(Copy, Clone)]
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) union Dst {
+        pub(self) field: Zst, // <- private variant
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr
new file mode 100644
index 00000000000..0be564d93e2
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr
@@ -0,0 +1,19 @@
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+  --> $DIR/should_reject_if_dst_has_private_variant.rs:37:41
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                         ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_if_dst_has_private_variant.rs:13:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs
new file mode 100644
index 00000000000..35fff5966c8
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs
@@ -0,0 +1,52 @@
+// check-pass
+//! NOTE: This test documents a known-bug in the implementation of the
+//! transmutability trait. Once fixed, the above "check-pass" header should be
+//! removed, and an "ERROR cannot be safely transmuted" annotation should be added at the end
+//! of the line starting with `assert::is_transmutable`.
+//!
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+//!
+//! This test exercises a tricky-to-implement instance of this principle: the
+//! "pub-in-priv trick". In the below example, the type `dst::private::Zst` is
+//! unreachable from `Context`. Consequently, the transmute from `Src` to `Dst`
+//! SHOULD be rejected.
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    mod private {
+        #[repr(C)] pub struct Zst; // <- unreachable type
+    }
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: private::Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+}
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs
new file mode 100644
index 00000000000..42799d803b0
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs
@@ -0,0 +1,39 @@
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(self) struct Zst; // <- unreachable type
+
+    #[repr(C)] pub(in super) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr
new file mode 100644
index 00000000000..95c68d45201
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr
@@ -0,0 +1,19 @@
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+  --> $DIR/should_reject_if_dst_has_unreachable_field.rs:38:41
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                         ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_if_dst_has_unreachable_field.rs:15:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs
new file mode 100644
index 00000000000..e13b32b30d9
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs
@@ -0,0 +1,42 @@
+//! Unless visibility is assumed, a transmutation should be rejected if the
+//! destination type contains an unreachable field (e.g., a public field with a
+//! private type). (This rule is distinct from type privacy, which still may
+//! forbid naming such types.)
+
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+    use std::mem::BikeshedIntrinsicFrom;
+
+    pub fn is_transmutable<Src, Dst, Context>()
+    where
+        Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+        // visibility is NOT assumed ---------------------------------^^^^^
+    {}
+}
+
+mod src {
+    #[repr(C)] pub(in super) struct Zst;
+
+    #[repr(C)] pub(in super) struct Src {
+        pub(in super) field: Zst,
+    }
+}
+
+mod dst {
+    #[repr(C)] pub(in super) struct Zst;
+
+    // unreachable type
+    #[repr(C)] pub(self) struct Dst {
+        pub(in super) field: Zst,
+    }
+}
+
+fn test() {
+    struct Context;
+    assert::is_transmutable::<src::Src, dst::Dst, Context>();
+    //~^ ERROR `Dst` is private
+    //~| ERROR cannot be safely transmuted
+}
diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr
new file mode 100644
index 00000000000..3391839e39e
--- /dev/null
+++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr
@@ -0,0 +1,32 @@
+error[E0603]: struct `Dst` is private
+  --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:46
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                              ^^^ private struct
+   |
+note: the struct `Dst` is defined here
+  --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:32:16
+   |
+LL |     #[repr(C)] pub(self) struct Dst {
+   |                ^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+  --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:41
+   |
+LL |     assert::is_transmutable::<src::Src, dst::Dst, Context>();
+   |                                         ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
+   |
+   = help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
+note: required by a bound in `is_transmutable`
+  --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:15:14
+   |
+LL |     pub fn is_transmutable<Src, Dst, Context>()
+   |            --------------- required by a bound in this
+LL |     where
+LL |         Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0603.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs
index 19fcc78721a..0aa644db052 100644
--- a/src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs
+++ b/src/test/ui/type-alias-enum-variants/enum-variant-generic-args-pass.rs
@@ -9,7 +9,7 @@
 
 #![allow(irrefutable_let_patterns)]
 
-enum Enum<T> { TSVariant(T), SVariant { _v: T }, UVariant }
+enum Enum<T> { TSVariant(#[allow(unused_tuple_struct_fields)] T), SVariant { _v: T }, UVariant }
 type Alias<T> = Enum<T>;
 type AliasFixed = Enum<()>;
 
diff --git a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr
index 277f4e84240..4775e68820b 100644
--- a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr
+++ b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr
@@ -2,18 +2,18 @@ error[E0391]: cycle detected when simplifying constant for the type system `Alph
   --> $DIR/self-in-enum-definition.rs:5:10
    |
 LL |     V3 = Self::V1 {} as u8 + 2,
-   |          ^^^^^^^^
+   |          ^^^^^^^^^^^^^^^^^^^^^
    |
 note: ...which requires simplifying constant for the type system `Alpha::V3::{constant#0}`...
   --> $DIR/self-in-enum-definition.rs:5:10
    |
 LL |     V3 = Self::V1 {} as u8 + 2,
-   |          ^^^^^^^^
+   |          ^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires const-evaluating + checking `Alpha::V3::{constant#0}`...
   --> $DIR/self-in-enum-definition.rs:5:10
    |
 LL |     V3 = Self::V1 {} as u8 + 2,
-   |          ^^^^^^^^
+   |          ^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires computing layout of `Alpha`...
    = note: ...which again requires simplifying constant for the type system `Alpha::V3::{constant#0}`, completing the cycle
 note: cycle used when collecting item types in top-level module
diff --git a/src/test/ui/type-alias-impl-trait/issue-74280.stderr b/src/test/ui/type-alias-impl-trait/issue-74280.stderr
index 5ed29e0ac94..66886db6eb9 100644
--- a/src/test/ui/type-alias-impl-trait/issue-74280.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-74280.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/issue-74280.rs:9:5
    |
 LL | fn test() -> Test {
-   |              ---- expected `_` because of return type
+   |              ---- expected `()` because of return type
 LL |     let y = || -> Test { () };
 LL |     7
    |     ^ expected `()`, found integer
diff --git a/src/test/ui/type/missing-let-in-binding.fixed b/src/test/ui/type/missing-let-in-binding.fixed
new file mode 100644
index 00000000000..d1787688950
--- /dev/null
+++ b/src/test/ui/type/missing-let-in-binding.fixed
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+    let mut _foo: i32 = 1;
+    let _foo: i32 = 4; //~ ERROR type ascription is experimental
+}
diff --git a/src/test/ui/type/missing-let-in-binding.rs b/src/test/ui/type/missing-let-in-binding.rs
new file mode 100644
index 00000000000..ca42f2e6eac
--- /dev/null
+++ b/src/test/ui/type/missing-let-in-binding.rs
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+    let mut _foo: i32 = 1;
+    _foo: i32 = 4; //~ ERROR type ascription is experimental
+}
diff --git a/src/test/ui/type/missing-let-in-binding.stderr b/src/test/ui/type/missing-let-in-binding.stderr
new file mode 100644
index 00000000000..12759c5096e
--- /dev/null
+++ b/src/test/ui/type/missing-let-in-binding.stderr
@@ -0,0 +1,16 @@
+error[E0658]: type ascription is experimental
+  --> $DIR/missing-let-in-binding.rs:4:5
+   |
+LL |     _foo: i32 = 4;
+   |     ^^^^^^^^^
+   |
+   = note: see issue #23416 <https://github.com/rust-lang/rust/issues/23416> for more information
+   = help: add `#![feature(type_ascription)]` to the crate attributes to enable
+help: you might have meant to introduce a new binding
+   |
+LL |     let _foo: i32 = 4;
+   |     +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/typeck/issue-100164.fixed b/src/test/ui/typeck/issue-100164.fixed
new file mode 100644
index 00000000000..a5f68beb1d5
--- /dev/null
+++ b/src/test/ui/typeck/issue-100164.fixed
@@ -0,0 +1,9 @@
+// run-rustfix
+
+const _A: i32 = 123;
+//~^ ERROR: missing type for `const` item
+
+fn main() {
+    const _B: i32 = 123;
+    //~^ ERROR: missing type for `const` item
+}
diff --git a/src/test/ui/typeck/issue-100164.rs b/src/test/ui/typeck/issue-100164.rs
new file mode 100644
index 00000000000..7efb9ac6240
--- /dev/null
+++ b/src/test/ui/typeck/issue-100164.rs
@@ -0,0 +1,9 @@
+// run-rustfix
+
+const _A: = 123;
+//~^ ERROR: missing type for `const` item
+
+fn main() {
+    const _B: = 123;
+    //~^ ERROR: missing type for `const` item
+}
diff --git a/src/test/ui/typeck/issue-100164.stderr b/src/test/ui/typeck/issue-100164.stderr
new file mode 100644
index 00000000000..06a132d6514
--- /dev/null
+++ b/src/test/ui/typeck/issue-100164.stderr
@@ -0,0 +1,14 @@
+error: missing type for `const` item
+  --> $DIR/issue-100164.rs:3:10
+   |
+LL | const _A: = 123;
+   |          ^ help: provide a type for the constant: `i32`
+
+error: missing type for `const` item
+  --> $DIR/issue-100164.rs:7:14
+   |
+LL |     const _B: = 123;
+   |              ^ help: provide a type for the constant: `i32`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/typeck/issue-79040.stderr b/src/test/ui/typeck/issue-79040.stderr
index aec2e1ec9e4..c820d1e08c4 100644
--- a/src/test/ui/typeck/issue-79040.stderr
+++ b/src/test/ui/typeck/issue-79040.stderr
@@ -7,10 +7,10 @@ LL |     const FOO = "hello" + 1;
    |                 &str
 
 error: missing type for `const` item
-  --> $DIR/issue-79040.rs:2:11
+  --> $DIR/issue-79040.rs:2:14
    |
 LL |     const FOO = "hello" + 1;
-   |           ^^^ help: provide a type for the item: `FOO: <type>`
+   |              ^ help: provide a type for the item: `: <type>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/typeck/issue-98982.rs b/src/test/ui/typeck/issue-98982.rs
new file mode 100644
index 00000000000..2553824bbfe
--- /dev/null
+++ b/src/test/ui/typeck/issue-98982.rs
@@ -0,0 +1,9 @@
+fn foo() -> i32 {
+    for i in 0..0 {
+    //~^ ERROR: mismatched types [E0308]
+        return i;
+    }
+    //~| help: return a value for the case when the loop has zero elements to iterate on, or consider changing the return type to account for that possibility
+}
+
+fn main() {}
diff --git a/src/test/ui/typeck/issue-98982.stderr b/src/test/ui/typeck/issue-98982.stderr
new file mode 100644
index 00000000000..3c9806ac965
--- /dev/null
+++ b/src/test/ui/typeck/issue-98982.stderr
@@ -0,0 +1,24 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-98982.rs:2:5
+   |
+LL |   fn foo() -> i32 {
+   |               --- expected `i32` because of return type
+LL | /     for i in 0..0 {
+LL | |
+LL | |         return i;
+LL | |     }
+   | |_____^ expected `i32`, found `()`
+   |
+note: the function expects a value to always be returned, but loops might run zero times
+  --> $DIR/issue-98982.rs:2:5
+   |
+LL |     for i in 0..0 {
+   |     ^^^^^^^^^^^^^ this might have zero elements to iterate on
+LL |
+LL |         return i;
+   |         -------- if the loop doesn't execute, this value would never get returned
+   = help: return a value for the case when the loop has zero elements to iterate on, or consider changing the return type to account for that possibility
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr
index 3ea317dfb1a..c57f71b8057 100644
--- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr
+++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr
@@ -189,10 +189,10 @@ LL ~     b: (T, T),
    |
 
 error: missing type for `static` item
-  --> $DIR/typeck_type_placeholder_item.rs:73:12
+  --> $DIR/typeck_type_placeholder_item.rs:73:13
    |
 LL |     static A = 42;
-   |            ^ help: provide a type for the static variable: `A: i32`
+   |             ^ help: provide a type for the static variable: `: i32`
 
 error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:75:15
diff --git a/src/test/ui/unboxed-closures/type-id-higher-rank.rs b/src/test/ui/unboxed-closures/type-id-higher-rank.rs
index 355d1109941..1f8aec205fb 100644
--- a/src/test/ui/unboxed-closures/type-id-higher-rank.rs
+++ b/src/test/ui/unboxed-closures/type-id-higher-rank.rs
@@ -4,7 +4,7 @@
 
 use std::any::{Any, TypeId};
 
-struct Struct<'a>(&'a ());
+struct Struct<'a>(#[allow(unused_tuple_struct_fields)] &'a ());
 trait Trait<'a> {}
 
 fn main() {
diff --git a/src/test/ui/unsized-locals/unsized-exprs-rpass.rs b/src/test/ui/unsized-locals/unsized-exprs-rpass.rs
index 8fcb6d93d39..175b02fcb81 100644
--- a/src/test/ui/unsized-locals/unsized-exprs-rpass.rs
+++ b/src/test/ui/unsized-locals/unsized-exprs-rpass.rs
@@ -2,7 +2,7 @@
 #![allow(incomplete_features, unused_braces, unused_parens)]
 #![feature(unsized_tuple_coercion, unsized_locals, unsized_fn_params)]
 
-struct A<X: ?Sized>(X);
+struct A<X: ?Sized>(#[allow(unused_tuple_struct_fields)] X);
 
 fn udrop<T: ?Sized>(_x: T) {}
 fn foo() -> Box<[u8]> {
diff --git a/src/test/ui/unsized/unchanged-param.rs b/src/test/ui/unsized/unchanged-param.rs
index 93c7af68ac3..6bdc89310eb 100644
--- a/src/test/ui/unsized/unchanged-param.rs
+++ b/src/test/ui/unsized/unchanged-param.rs
@@ -1,8 +1,8 @@
 // run-pass
 // Test that we allow unsizing even if there is an unchanged param in the
 // field getting unsized.
-struct A<T, U: ?Sized + 'static>(T, B<T, U>);
-struct B<T, U: ?Sized>(T, U);
+struct A<T, U: ?Sized + 'static>(#[allow(unused_tuple_struct_fields)] T, B<T, U>);
+struct B<T, U: ?Sized>(#[allow(unused_tuple_struct_fields)] T, U);
 
 fn main() {
     let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1]));
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 85b500ccad8cd0b63995fd94a03ddd4b83f7905
+Subproject 4fd148c47e733770c537efac5220744945d572e
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
index b6affdee523..4caab623090 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
@@ -19,6 +19,9 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// An assertion failure cannot output an useful message of the error.
     ///
+    /// ### Known problems
+    /// The suggested replacement decreases the readability of code and log output.
+    ///
     /// ### Example
     /// ```rust,ignore
     /// # let r = Ok::<_, ()>(());
@@ -28,7 +31,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.64.0"]
     pub ASSERTIONS_ON_RESULT_STATES,
-    style,
+    restriction,
     "`assert!(r.is_ok())`/`assert!(r.is_err())` gives worse error message than directly calling `r.unwrap()`/`r.unwrap_err()`"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 80c84014bfd..4f9ff97f1fd 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -220,9 +220,11 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure_ty: Ty<'tcx>, call_ty: Ty<'tc
 }
 
 fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: DefId) -> String {
-    match cx.tcx.associated_item(method_def_id).container {
-        ty::TraitContainer(def_id) => cx.tcx.def_path_str(def_id),
-        ty::ImplContainer(def_id) => {
+    let assoc_item = cx.tcx.associated_item(method_def_id);
+    let def_id = assoc_item.container_id(cx.tcx);
+    match assoc_item.container {
+        ty::TraitContainer => cx.tcx.def_path_str(def_id),
+        ty::ImplContainer => {
             let ty = cx.tcx.type_of(def_id);
             match ty.kind() {
                 ty::Adt(adt, _) => cx.tcx.def_path_str(adt.did()),
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 5c46d6c7df7..ef7d75aa8ed 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -9,7 +9,7 @@ use rustc_middle::ty::{EarlyBinder, Opaque, PredicateKind::Trait};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Span};
 use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt;
-use rustc_trait_selection::traits::{self, FulfillmentError, TraitEngine};
+use rustc_trait_selection::traits::{self, FulfillmentError};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -80,9 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
                 let span = decl.output.span();
                 let send_errors = cx.tcx.infer_ctxt().enter(|infcx| {
                     let cause = traits::ObligationCause::misc(span, hir_id);
-                    let mut fulfillment_cx = traits::FulfillmentContext::new();
-                    fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause);
-                    fulfillment_cx.select_all_or_error(&infcx)
+                    traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait)
                 });
                 if !send_errors.is_empty() {
                     span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
index 5be1c417bf8..0ba9b7ae7e5 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
@@ -6,7 +6,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(almost_complete_letter_range::ALMOST_COMPLETE_LETTER_RANGE),
     LintId::of(approx_const::APPROX_CONSTANT),
     LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
-    LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
     LintId::of(async_yields_async::ASYNC_YIELDS_ASYNC),
     LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
     LintId::of(attrs::DEPRECATED_CFG_ATTR),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
index 495abd8387e..a7339ef2721 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
@@ -7,6 +7,7 @@ store.register_group(true, "clippy::restriction", Some("clippy_restriction"), ve
     LintId::of(as_underscore::AS_UNDERSCORE),
     LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
     LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
+    LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
     LintId::of(attrs::ALLOW_ATTRIBUTES_WITHOUT_REASON),
     LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
     LintId::of(create_dir::CREATE_DIR),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_style.rs b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
index e029a5235e7..e95bab1d045 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
@@ -4,7 +4,6 @@
 
 store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
-    LintId::of(assertions_on_result_states::ASSERTIONS_ON_RESULT_STATES),
     LintId::of(blacklisted_name::BLACKLISTED_NAME),
     LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index b638f271602..e9e13aece18 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -1112,7 +1112,7 @@ fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool {
     let mut pos = 0usize;
     let mut iter = tokenize(&snip).map(|t| {
         let start = pos;
-        pos += t.len;
+        pos += t.len as usize;
         (t.kind, start..pos)
     });
 
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index a20377f320b..88ba002927a 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -10,7 +10,7 @@ use clippy_utils::diagnostics::span_lint;
 use rustc_ast::ast;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::{self, DefIdTree};
+use rustc_middle::ty::DefIdTree;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::source_map::Span;
@@ -153,13 +153,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
         // If the method is an impl for a trait, don't doc.
-        match cx.tcx.associated_item(impl_item.def_id).container {
-            ty::TraitContainer(_) => return,
-            ty::ImplContainer(cid) => {
-                if cx.tcx.impl_trait_ref(cid).is_some() {
-                    return;
-                }
-            },
+        if let Some(cid) = cx.tcx.associated_item(impl_item.def_id).impl_container(cx.tcx) {
+            if cx.tcx.impl_trait_ref(cid).is_some() {
+                return;
+            }
+        } else {
+            return;
         }
 
         let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 0d953299189..07bc2ca5d3c 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -105,7 +105,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
                     match tit_.kind {
                         hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {},
                         hir::TraitItemKind::Fn(..) => {
-                            if tit.defaultness.has_value() {
+                            if cx.tcx.impl_defaultness(tit.id.def_id).has_value() {
                                 // trait method with default body needs inline in case
                                 // an impl is not provided
                                 let desc = "a default trait method";
@@ -151,9 +151,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
             hir::ImplItemKind::Const(..) | hir::ImplItemKind::TyAlias(_) => return,
         };
 
-        let trait_def_id = match cx.tcx.associated_item(impl_item.def_id).container {
-            TraitContainer(cid) => Some(cid),
-            ImplContainer(cid) => cx.tcx.impl_trait_ref(cid).map(|t| t.def_id),
+        let assoc_item = cx.tcx.associated_item(impl_item.def_id);
+        let container_id = assoc_item.container_id(cx.tcx);
+        let trait_def_id = match assoc_item.container {
+            TraitContainer => Some(container_id),
+            ImplContainer => cx.tcx.impl_trait_ref(container_id).map(|t| t.def_id),
         };
 
         if let Some(trait_def_id) = trait_def_id {
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 04f16fd2161..d2e675a783e 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -345,7 +345,7 @@ fn text_has_safety_comment(src: &str, line_starts: &[BytePos], offset: usize) ->
         if line.starts_with("/*") {
             let src = src[line_start..line_starts.last().unwrap().to_usize() - offset].trim_start();
             let mut tokens = tokenize(src);
-            return src[..tokens.next().unwrap().len]
+            return src[..tokens.next().unwrap().len as usize]
                 .to_ascii_uppercase()
                 .contains("SAFETY:")
                 && tokens.all(|t| t.kind == TokenKind::Whitespace);
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 3a99d1b417f..32718200c0b 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -441,7 +441,7 @@ impl SimpleFormatArgs {
         };
 
         match arg.position {
-            ArgumentIs(n, _) | ArgumentImplicitlyIs(n) => {
+            ArgumentIs(n) | ArgumentImplicitlyIs(n) => {
                 if self.unnamed.len() <= n {
                     // Use a dummy span to mark all unseen arguments.
                     self.unnamed.resize_with(n, || vec![DUMMY_SP]);
@@ -462,7 +462,7 @@ impl SimpleFormatArgs {
                     }
                 }
             },
-            ArgumentNamed(n, _) => {
+            ArgumentNamed(n) => {
                 let n = Symbol::intern(n);
                 if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) {
                     match x.1.as_slice() {
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index eaf260ddfb8..1834e2a2de8 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -141,7 +141,7 @@ impl HirEqInterExpr<'_, '_, '_> {
                 let mut left_pos = 0;
                 let left = tokenize(&left)
                     .map(|t| {
-                        let end = left_pos + t.len;
+                        let end = left_pos + t.len as usize;
                         let s = &left[left_pos..end];
                         left_pos = end;
                         (t, s)
@@ -156,7 +156,7 @@ impl HirEqInterExpr<'_, '_, '_> {
                 let mut right_pos = 0;
                 let right = tokenize(&right)
                     .map(|t| {
-                        let end = right_pos + t.len;
+                        let end = right_pos + t.len as usize;
                         let s = &right[right_pos..end];
                         right_pos = end;
                         (t, s)
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs
index 2289f7875f0..f13733af3d0 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs
@@ -2,6 +2,7 @@
 // As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure.
 
 #![allow(clippy::declare_interior_mutable_const)]
+#![allow(unused_tuple_struct_fields)]
 
 use std::sync::atomic::AtomicUsize;
 
diff --git a/src/tools/clippy/tests/ui/format.fixed b/src/tools/clippy/tests/ui/format.fixed
index f4db2d20c71..6b754f3bd71 100644
--- a/src/tools/clippy/tests/ui/format.fixed
+++ b/src/tools/clippy/tests/ui/format.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![allow(
+    unused_tuple_struct_fields,
     clippy::print_literal,
     clippy::redundant_clone,
     clippy::to_string_in_format_args,
diff --git a/src/tools/clippy/tests/ui/format.rs b/src/tools/clippy/tests/ui/format.rs
index bf687cb1e96..ca9826b356e 100644
--- a/src/tools/clippy/tests/ui/format.rs
+++ b/src/tools/clippy/tests/ui/format.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![allow(
+    unused_tuple_struct_fields,
     clippy::print_literal,
     clippy::redundant_clone,
     clippy::to_string_in_format_args,
diff --git a/src/tools/clippy/tests/ui/format.stderr b/src/tools/clippy/tests/ui/format.stderr
index a0f8e7d1937..6c35caeb034 100644
--- a/src/tools/clippy/tests/ui/format.stderr
+++ b/src/tools/clippy/tests/ui/format.stderr
@@ -1,5 +1,5 @@
 error: useless use of `format!`
-  --> $DIR/format.rs:18:5
+  --> $DIR/format.rs:19:5
    |
 LL |     format!("foo");
    |     ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
@@ -7,19 +7,19 @@ LL |     format!("foo");
    = note: `-D clippy::useless-format` implied by `-D warnings`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:19:5
+  --> $DIR/format.rs:20:5
    |
 LL |     format!("{{}}");
    |     ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:20:5
+  --> $DIR/format.rs:21:5
    |
 LL |     format!("{{}} abc {{}}");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:21:5
+  --> $DIR/format.rs:22:5
    |
 LL | /     format!(
 LL | |         r##"foo {{}}
@@ -34,91 +34,91 @@ LL ~ " bar"##.to_string();
    |
 
 error: useless use of `format!`
-  --> $DIR/format.rs:26:13
+  --> $DIR/format.rs:27:13
    |
 LL |     let _ = format!("");
    |             ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:28:5
+  --> $DIR/format.rs:29:5
    |
 LL |     format!("{}", "foo");
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:32:5
+  --> $DIR/format.rs:33:5
    |
 LL |     format!("{:+}", "foo"); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:33:5
+  --> $DIR/format.rs:34:5
    |
 LL |     format!("{:<}", "foo"); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:38:5
+  --> $DIR/format.rs:39:5
    |
 LL |     format!("{}", arg);
    |     ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:42:5
+  --> $DIR/format.rs:43:5
    |
 LL |     format!("{:+}", arg); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:43:5
+  --> $DIR/format.rs:44:5
    |
 LL |     format!("{:<}", arg); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:70:5
+  --> $DIR/format.rs:71:5
    |
 LL |     format!("{}", 42.to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:72:5
+  --> $DIR/format.rs:73:5
    |
 LL |     format!("{}", x.display().to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:76:18
+  --> $DIR/format.rs:77:18
    |
 LL |     let _ = Some(format!("{}", a + "bar"));
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:80:22
+  --> $DIR/format.rs:81:22
    |
 LL |     let _s: String = format!("{}", &*v.join("/n"));
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:86:13
+  --> $DIR/format.rs:87:13
    |
 LL |     let _ = format!("{x}");
    |             ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:88:13
+  --> $DIR/format.rs:89:13
    |
 LL |     let _ = format!("{y}", y = x);
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:92:13
+  --> $DIR/format.rs:93:13
    |
 LL |     let _ = format!("{abc}");
    |             ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:94:13
+  --> $DIR/format.rs:95:13
    |
 LL |     let _ = format!("{xx}");
    |             ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()`
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
index 403c3b3e443..48f8093311c 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
@@ -1,7 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::from_iter_instead_of_collect)]
-#![allow(unused_imports)]
+#![allow(unused_imports, unused_tuple_struct_fields)]
 
 use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
 
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
index fefc7b01a65..ebe0ad278be 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
@@ -1,7 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::from_iter_instead_of_collect)]
-#![allow(unused_imports)]
+#![allow(unused_imports, unused_tuple_struct_fields)]
 
 use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
 
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed
index 9556f6f82cc..04a74a009e0 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.fixed
+++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 #![feature(never_type)]
-#![allow(unused_mut, clippy::redundant_allocation)]
+#![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)]
 #![warn(clippy::must_use_candidate)]
 use std::rc::Rc;
 use std::sync::atomic::{AtomicBool, Ordering};
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs
index 37324220171..f04122f4eea 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.rs
+++ b/src/tools/clippy/tests/ui/must_use_candidates.rs
@@ -1,6 +1,6 @@
 // run-rustfix
 #![feature(never_type)]
-#![allow(unused_mut, clippy::redundant_allocation)]
+#![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)]
 #![warn(clippy::must_use_candidate)]
 use std::rc::Rc;
 use std::sync::atomic::{AtomicBool, Ordering};
diff --git a/src/tools/clippy/tests/ui/numbered_fields.fixed b/src/tools/clippy/tests/ui/numbered_fields.fixed
index 3710b3e9c81..68c987eb4c6 100644
--- a/src/tools/clippy/tests/ui/numbered_fields.fixed
+++ b/src/tools/clippy/tests/ui/numbered_fields.fixed
@@ -1,5 +1,6 @@
 //run-rustfix
 #![warn(clippy::init_numbered_fields)]
+#![allow(unused_tuple_struct_fields)]
 
 #[derive(Default)]
 struct TupleStruct(u32, u32, u8);
diff --git a/src/tools/clippy/tests/ui/numbered_fields.rs b/src/tools/clippy/tests/ui/numbered_fields.rs
index 2af84bc0642..2ef4fb4de53 100644
--- a/src/tools/clippy/tests/ui/numbered_fields.rs
+++ b/src/tools/clippy/tests/ui/numbered_fields.rs
@@ -1,5 +1,6 @@
 //run-rustfix
 #![warn(clippy::init_numbered_fields)]
+#![allow(unused_tuple_struct_fields)]
 
 #[derive(Default)]
 struct TupleStruct(u32, u32, u8);
diff --git a/src/tools/clippy/tests/ui/numbered_fields.stderr b/src/tools/clippy/tests/ui/numbered_fields.stderr
index 01691c8b141..60c0d789806 100644
--- a/src/tools/clippy/tests/ui/numbered_fields.stderr
+++ b/src/tools/clippy/tests/ui/numbered_fields.stderr
@@ -1,5 +1,5 @@
 error: used a field initializer for a tuple struct
-  --> $DIR/numbered_fields.rs:18:13
+  --> $DIR/numbered_fields.rs:19:13
    |
 LL |       let _ = TupleStruct {
    |  _____________^
@@ -12,7 +12,7 @@ LL | |     };
    = note: `-D clippy::init-numbered-fields` implied by `-D warnings`
 
 error: used a field initializer for a tuple struct
-  --> $DIR/numbered_fields.rs:25:13
+  --> $DIR/numbered_fields.rs:26:13
    |
 LL |       let _ = TupleStruct {
    |  _____________^
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index e12e13a57f1..b6d5e106f05 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 #![warn(clippy::option_if_let_else)]
 #![allow(
+    unused_tuple_struct_fields,
     clippy::redundant_closure,
     clippy::ref_option_ref,
     clippy::equatable_if_let,
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index b5206fc26a9..35bae159343 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 #![warn(clippy::option_if_let_else)]
 #![allow(
+    unused_tuple_struct_fields,
     clippy::redundant_closure,
     clippy::ref_option_ref,
     clippy::equatable_if_let,
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index 40aef977b98..daba606004e 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -1,5 +1,5 @@
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:11:5
+  --> $DIR/option_if_let_else.rs:12:5
    |
 LL | /     if let Some(x) = string {
 LL | |         (true, x)
@@ -11,19 +11,19 @@ LL | |     }
    = note: `-D clippy::option-if-let-else` implied by `-D warnings`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:29:13
+  --> $DIR/option_if_let_else.rs:30:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:30:13
+  --> $DIR/option_if_let_else.rs:31:13
    |
 LL |     let _ = if let Some(s) = &num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:31:13
+  --> $DIR/option_if_let_else.rs:32:13
    |
 LL |       let _ = if let Some(s) = &mut num {
    |  _____________^
@@ -43,13 +43,13 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:37:13
+  --> $DIR/option_if_let_else.rs:38:13
    |
 LL |     let _ = if let Some(ref s) = num { s } else { &0 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:38:13
+  --> $DIR/option_if_let_else.rs:39:13
    |
 LL |       let _ = if let Some(mut s) = num {
    |  _____________^
@@ -69,7 +69,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:44:13
+  --> $DIR/option_if_let_else.rs:45:13
    |
 LL |       let _ = if let Some(ref mut s) = num {
    |  _____________^
@@ -89,7 +89,7 @@ LL ~     });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:53:5
+  --> $DIR/option_if_let_else.rs:54:5
    |
 LL | /     if let Some(x) = arg {
 LL | |         let y = x * x;
@@ -108,7 +108,7 @@ LL +     })
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:66:13
+  --> $DIR/option_if_let_else.rs:67:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -120,7 +120,7 @@ LL | |     };
    | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:75:13
+  --> $DIR/option_if_let_else.rs:76:13
    |
 LL |       let _ = if let Some(x) = arg {
    |  _____________^
@@ -143,7 +143,7 @@ LL ~     }, |x| x * x * x * x);
    |
 
 error: use Option::map_or_else instead of an if let/else
-  --> $DIR/option_if_let_else.rs:108:13
+  --> $DIR/option_if_let_else.rs:109:13
    |
 LL | /             if let Some(idx) = s.find('.') {
 LL | |                 vec![s[..idx].to_string(), s[idx..].to_string()]
@@ -153,13 +153,13 @@ LL | |             }
    | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:132:13
+  --> $DIR/option_if_let_else.rs:133:13
    |
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:141:13
+  --> $DIR/option_if_let_else.rs:142:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
@@ -181,13 +181,13 @@ LL ~         });
    |
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:169:13
+  --> $DIR/option_if_let_else.rs:170:13
    |
 LL |     let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:173:13
+  --> $DIR/option_if_let_else.rs:174:13
    |
 LL |       let _ = if let Some(x) = Some(0) {
    |  _____________^
diff --git a/src/tools/clippy/tests/ui/unreadable_literal.fixed b/src/tools/clippy/tests/ui/unreadable_literal.fixed
index e726b652ef1..a67363b09ea 100644
--- a/src/tools/clippy/tests/ui/unreadable_literal.fixed
+++ b/src/tools/clippy/tests/ui/unreadable_literal.fixed
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::unreadable_literal)]
+#![allow(unused_tuple_struct_fields)]
 
 struct Foo(u64);
 
diff --git a/src/tools/clippy/tests/ui/unreadable_literal.rs b/src/tools/clippy/tests/ui/unreadable_literal.rs
index 5bbb2fc9dc1..82f04e7ced5 100644
--- a/src/tools/clippy/tests/ui/unreadable_literal.rs
+++ b/src/tools/clippy/tests/ui/unreadable_literal.rs
@@ -1,6 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::unreadable_literal)]
+#![allow(unused_tuple_struct_fields)]
 
 struct Foo(u64);
 
diff --git a/src/tools/clippy/tests/ui/unreadable_literal.stderr b/src/tools/clippy/tests/ui/unreadable_literal.stderr
index ee5466fd517..b51130c6a6a 100644
--- a/src/tools/clippy/tests/ui/unreadable_literal.stderr
+++ b/src/tools/clippy/tests/ui/unreadable_literal.stderr
@@ -1,5 +1,5 @@
 error: digits of hex or binary literal not grouped by four
-  --> $DIR/unreadable_literal.rs:25:9
+  --> $DIR/unreadable_literal.rs:26:9
    |
 LL |         0x1_234_567,
    |         ^^^^^^^^^^^ help: consider: `0x0123_4567`
@@ -7,7 +7,7 @@ LL |         0x1_234_567,
    = note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:33:17
+  --> $DIR/unreadable_literal.rs:34:17
    |
 LL |     let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
    |                 ^^^^^^^^^^^^ help: consider: `0b11_0110_i64`
@@ -15,55 +15,55 @@ LL |     let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
    = note: `-D clippy::unreadable-literal` implied by `-D warnings`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:33:31
+  --> $DIR/unreadable_literal.rs:34:31
    |
 LL |     let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
    |                               ^^^^^^^^^^^^^^^^ help: consider: `0x1234_5678_usize`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:33:49
+  --> $DIR/unreadable_literal.rs:34:49
    |
 LL |     let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
    |                                                 ^^^^^^^^^^ help: consider: `123_456_f32`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:33:61
+  --> $DIR/unreadable_literal.rs:34:61
    |
 LL |     let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32);
    |                                                             ^^^^^^^^^^^^ help: consider: `1.234_567_f32`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:35:20
+  --> $DIR/unreadable_literal.rs:36:20
    |
 LL |     let _bad_sci = 1.123456e1;
    |                    ^^^^^^^^^^ help: consider: `1.123_456e1`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:37:18
+  --> $DIR/unreadable_literal.rs:38:18
    |
 LL |     let _fail1 = 0xabcdef;
    |                  ^^^^^^^^ help: consider: `0x00ab_cdef`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:38:23
+  --> $DIR/unreadable_literal.rs:39:23
    |
 LL |     let _fail2: u32 = 0xBAFEBAFE;
    |                       ^^^^^^^^^^ help: consider: `0xBAFE_BAFE`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:39:18
+  --> $DIR/unreadable_literal.rs:40:18
    |
 LL |     let _fail3 = 0xabcdeff;
    |                  ^^^^^^^^^ help: consider: `0x0abc_deff`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:40:24
+  --> $DIR/unreadable_literal.rs:41:24
    |
 LL |     let _fail4: i128 = 0xabcabcabcabcabcabc;
    |                        ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc`
 
 error: long literal lacking separators
-  --> $DIR/unreadable_literal.rs:41:18
+  --> $DIR/unreadable_literal.rs:42:18
    |
 LL |     let _fail5 = 1.100300400;
    |                  ^^^^^^^^^^^ help: consider: `1.100_300_400`
diff --git a/src/tools/html-checker/Cargo.toml b/src/tools/html-checker/Cargo.toml
index 34d3954db28..72d61d9bd26 100644
--- a/src/tools/html-checker/Cargo.toml
+++ b/src/tools/html-checker/Cargo.toml
@@ -9,3 +9,4 @@ path = "main.rs"
 
 [dependencies]
 walkdir = "2"
+rayon = "1.5"
diff --git a/src/tools/html-checker/main.rs b/src/tools/html-checker/main.rs
index f52fbdfe2d7..9b4d2c52598 100644
--- a/src/tools/html-checker/main.rs
+++ b/src/tools/html-checker/main.rs
@@ -1,3 +1,4 @@
+use rayon::iter::{ParallelBridge, ParallelIterator};
 use std::env;
 use std::path::Path;
 use std::process::{Command, Output};
@@ -56,27 +57,30 @@ const DOCS_TO_CHECK: &[&str] =
 
 // Returns the number of files read and the number of errors.
 fn find_all_html_files(dir: &Path) -> (usize, usize) {
-    let mut files_read = 0;
-    let mut errors = 0;
-
-    for entry in walkdir::WalkDir::new(dir).into_iter().filter_entry(|e| {
-        e.depth() != 1
-            || e.file_name()
-                .to_str()
-                .map(|s| DOCS_TO_CHECK.into_iter().any(|d| *d == s))
-                .unwrap_or(false)
-    }) {
-        let entry = entry.expect("failed to read file");
-        if !entry.file_type().is_file() {
-            continue;
-        }
-        let entry = entry.path();
-        if entry.extension().and_then(|s| s.to_str()) == Some("html") {
-            errors += check_html_file(&entry);
-            files_read += 1;
-        }
-    }
-    (files_read, errors)
+    walkdir::WalkDir::new(dir)
+        .into_iter()
+        .filter_entry(|e| {
+            e.depth() != 1
+                || e.file_name()
+                    .to_str()
+                    .map(|s| DOCS_TO_CHECK.into_iter().any(|d| *d == s))
+                    .unwrap_or(false)
+        })
+        .par_bridge()
+        .map(|entry| {
+            let entry = entry.expect("failed to read file");
+            if !entry.file_type().is_file() {
+                return (0, 0);
+            }
+            let entry = entry.path();
+            // (Number of files processed, number of errors)
+            if entry.extension().and_then(|s| s.to_str()) == Some("html") {
+                (1, check_html_file(&entry))
+            } else {
+                (0, 0)
+            }
+        })
+        .reduce(|| (0, 0), |a, b| (a.0 + b.0, a.1 + b.1))
 }
 
 /// Default `tidy` command for macOS is too old that it does not have `mute-id` and `mute` options.
diff --git a/src/tools/rls b/src/tools/rls
-Subproject fcf1f94c9ab2acc18cfd4368a4aeb38e77da964
+Subproject 4d8b0a19986a4daab37287a5b5fe2da0775d187
diff --git a/src/tools/rust-analyzer/.github/workflows/publish.yml b/src/tools/rust-analyzer/.github/workflows/publish.yml
index 927996c1bef..a4497f49e3c 100644
--- a/src/tools/rust-analyzer/.github/workflows/publish.yml
+++ b/src/tools/rust-analyzer/.github/workflows/publish.yml
@@ -34,8 +34,21 @@ jobs:
           git config --global user.email "runner@gha.local"
           git config --global user.name "Github Action"
           rm Cargo.lock
+          # Fix names for crates that were published before switch to kebab-case.
+          cargo workspaces rename --from base-db base_db
+          cargo workspaces rename --from hir-def hir_def
+          cargo workspaces rename --from hir-expand hir_expand
+          cargo workspaces rename --from hir-ty hir_ty
+          cargo workspaces rename --from ide-assists ide_assists
+          cargo workspaces rename --from ide-completion ide_completion
+          cargo workspaces rename --from ide-db ide_db
+          cargo workspaces rename --from ide-diagnostics ide_diagnostics
+          cargo workspaces rename --from ide-ssr ide_ssr
+          cargo workspaces rename --from proc-macro-api proc_macro_api
+          cargo workspaces rename --from proc-macro-srv proc_macro_srv
+          cargo workspaces rename --from project-model project_model
+          cargo workspaces rename --from test-utils test_utils
+          cargo workspaces rename --from text-edit text_edit
           cargo workspaces rename ra_ap_%n
           find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} +
-          # Fix names for crates that were published before switch to kebab-case.
-          find crates -name 'Cargo.toml' -exec sed -i "s/ra_ap_base-db/ra_ap_base_db/g; s/ra_ap_hir-def/ra_ap_hir_def/g; s/ra_ap_hir-expand/ra_ap_hir_expand/g; s/ra_ap_hir-ty/ra_ap_hir_ty/g; s/ra_ap_ide-assists/ra_ap_ide_assists/g; s/ra_ap_ide-completion/ra_ap_ide_completion/g; s/ra_ap_ide-db/ra_ap_ide_db/g; s/ra_ap_ide-diagnostics/ra_ap_ide_diagnostics/g; s/ra_ap_ide-ssr/ra_ap_ide_ssr/g; s/ra_ap_proc-macro-api/ra_ap_proc_macro_api/g; s/ra_ap_proc-macro-srv/ra_ap_proc_macro_srv/g; s/ra_ap_project-model/ra_ap_project_model/g; s/ra_ap_test-utils/ra_ap_test_utils/g; s/ra_ap_text-edit/ra_ap_text_edit/g" {} +
           cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$PATCH
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index 8a6b6f3effd..2b39c6f8da8 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -124,13 +124,24 @@ impl RawAttrs {
 
     pub(crate) fn merge(&self, other: Self) -> Self {
         // FIXME: This needs to fixup `AttrId`s
-        match (&self.entries, &other.entries) {
+        match (&self.entries, other.entries) {
             (None, None) => Self::EMPTY,
-            (Some(entries), None) | (None, Some(entries)) => {
-                Self { entries: Some(entries.clone()) }
-            }
+            (None, entries @ Some(_)) => Self { entries },
+            (Some(entries), None) => Self { entries: Some(entries.clone()) },
             (Some(a), Some(b)) => {
-                Self { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
+                let last_ast_index = a.last().map_or(0, |it| it.id.ast_index + 1);
+                Self {
+                    entries: Some(
+                        a.iter()
+                            .cloned()
+                            .chain(b.iter().map(|it| {
+                                let mut it = it.clone();
+                                it.id.ast_index += last_ast_index;
+                                it
+                            }))
+                            .collect(),
+                    ),
+                }
             }
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index 579f803ea19..a11a92204c1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -5,6 +5,7 @@ use std::collections::hash_map::Entry;
 
 use base_db::CrateId;
 use hir_expand::{name::Name, AstId, MacroCallId};
+use itertools::Itertools;
 use once_cell::sync::Lazy;
 use profile::Count;
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -97,15 +98,14 @@ pub(crate) enum BuiltinShadowMode {
 impl ItemScope {
     pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
         // FIXME: shadowing
-        let keys: FxHashSet<_> = self
-            .types
+        self.types
             .keys()
             .chain(self.values.keys())
             .chain(self.macros.keys())
             .chain(self.unresolved.iter())
-            .collect();
-
-        keys.into_iter().map(move |name| (name, self.get(name)))
+            .sorted()
+            .unique()
+            .map(move |name| (name, self.get(name)))
     }
 
     pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index f394c541719..8a6bb929c3d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -1055,7 +1055,7 @@ impl DefCollector<'_> {
         };
         let mut res = ReachedFixedPoint::Yes;
         macros.retain(|directive| {
-            let resolver2 = |path| {
+            let resolver = |path| {
                 let resolved_res = self.def_map.resolve_path_fp_with_macro(
                     self.db,
                     ResolveMode::Other,
@@ -1068,7 +1068,7 @@ impl DefCollector<'_> {
                     .take_macros()
                     .map(|it| (it, macro_id_to_def_id(self.db, it)))
             };
-            let resolver = |path| resolver2(path).map(|(_, it)| it);
+            let resolver_def_id = |path| resolver(path).map(|(_, it)| it);
 
             match &directive.kind {
                 MacroDirectiveKind::FnLike { ast_id, expand_to } => {
@@ -1077,7 +1077,7 @@ impl DefCollector<'_> {
                         ast_id,
                         *expand_to,
                         self.def_map.krate,
-                        &resolver,
+                        &resolver_def_id,
                         &mut |_err| (),
                     );
                     if let Ok(Ok(call_id)) = call_id {
@@ -1093,7 +1093,7 @@ impl DefCollector<'_> {
                         *derive_attr,
                         *derive_pos as u32,
                         self.def_map.krate,
-                        &resolver2,
+                        &resolver,
                     );
 
                     if let Ok((macro_id, def_id, call_id)) = id {
@@ -1158,7 +1158,7 @@ impl DefCollector<'_> {
                         }
                     }
 
-                    let def = match resolver(path.clone()) {
+                    let def = match resolver_def_id(path.clone()) {
                         Some(def) if def.is_attribute() => def,
                         _ => return true,
                     };
@@ -1292,7 +1292,8 @@ impl DefCollector<'_> {
             true
         });
         // Attribute resolution can add unresolved macro invocations, so concatenate the lists.
-        self.unresolved_macros.extend(macros);
+        macros.extend(mem::take(&mut self.unresolved_macros));
+        self.unresolved_macros = macros;
 
         for (module_id, depth, container, macro_call_id) in resolved {
             self.collect_macro_expansion(module_id, macro_call_id, depth, container);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index b0885ab003f..a9c124b42dc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -34,6 +34,7 @@ pub trait TyExt {
     fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
 
     fn strip_references(&self) -> &Ty;
+    fn strip_reference(&self) -> &Ty;
 
     /// If this is a `dyn Trait`, returns that trait.
     fn dyn_trait(&self) -> Option<TraitId>;
@@ -182,6 +183,10 @@ impl TyExt for Ty {
         t
     }
 
+    fn strip_reference(&self) -> &Ty {
+        self.as_reference().map_or(self, |(ty, _, _)| ty)
+    }
+
     fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
         match self.kind(Interner) {
             TyKind::OpaqueType(opaque_ty_id, subst) => {
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index d4925455d7b..8f984210e11 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -2769,6 +2769,10 @@ impl Type {
         self.derived(self.ty.strip_references().clone())
     }
 
+    pub fn strip_reference(&self) -> Type {
+        self.derived(self.ty.strip_reference().clone())
+    }
+
     pub fn is_unknown(&self) -> bool {
         self.ty.is_unknown()
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index fc8f23f19ab..c84318b2fb8 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -324,6 +324,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.resolve_type(ty)
     }
 
+    pub fn resolve_trait(&self, trait_: &ast::Path) -> Option<Trait> {
+        self.imp.resolve_trait(trait_)
+    }
+
     // FIXME: Figure out a nice interface to inspect adjustments
     pub fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
         self.imp.is_implicit_reborrow(expr)
@@ -924,7 +928,12 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn original_ast_node<N: AstNode>(&self, node: N) -> Option<N> {
-        self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(|it| it.value)
+        self.wrap_node_infile(node).original_ast_node(self.db.upcast()).map(
+            |InFile { file_id, value }| {
+                self.cache(find_root(value.syntax()), file_id);
+                value
+            },
+        )
     }
 
     fn diagnostics_display_range(&self, src: InFile<SyntaxNodePtr>) -> FileRange {
@@ -1009,6 +1018,20 @@ impl<'db> SemanticsImpl<'db> {
         Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
     }
 
+    fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
+        let analyze = self.analyze(path.syntax())?;
+        let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id);
+        let ctx = body::LowerCtx::with_hygiene(self.db.upcast(), &hygiene);
+        let hir_path = Path::from_src(path.clone(), &ctx)?;
+        match analyze
+            .resolver
+            .resolve_path_in_type_ns_fully(self.db.upcast(), hir_path.mod_path())?
+        {
+            TypeNs::TraitId(id) => Some(Trait { id }),
+            _ => None,
+        }
+    }
+
     fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
         self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr)
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
index 943c1d90e63..87f5018fb69 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_glob_import.rs
@@ -36,7 +36,7 @@ use crate::{
 //     pub struct Baz;
 // }
 //
-// use foo::{Baz, Bar};
+// use foo::{Bar, Baz};
 //
 // fn qux(bar: Bar, baz: Baz) {}
 // ```
@@ -281,7 +281,7 @@ mod foo {
     pub fn f() {}
 }
 
-use foo::{Baz, Bar, f};
+use foo::{Bar, Baz, f};
 
 fn qux(bar: Bar, baz: Baz) {
     f();
@@ -351,7 +351,7 @@ mod foo {
     pub fn f() {}
 }
 
-use foo::{Baz, Bar, f};
+use foo::{Bar, Baz, f};
 
 fn qux(bar: Bar, baz: Baz) {
     f();
@@ -440,7 +440,7 @@ mod foo {
     }
 }
 
-use foo::{bar::{Baz, Bar, f}, baz::*};
+use foo::{bar::{Bar, Baz, f}, baz::*};
 
 fn qux(bar: Bar, baz: Baz) {
     f();
@@ -561,7 +561,7 @@ mod foo {
 
 use foo::{
     bar::{*, f},
-    baz::{g, qux::{q, h}}
+    baz::{g, qux::{h, q}}
 };
 
 fn qux(bar: Bar, baz: Baz) {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
index 658a1aadf53..80d3b925593 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
@@ -7,7 +7,7 @@ use ide_db::{
     imports::insert_use::remove_path_if_in_use_stmt,
     path_transform::PathTransform,
     search::{FileReference, SearchScope},
-    syntax_helpers::node_ext::expr_as_name_ref,
+    syntax_helpers::{insert_whitespace_into_node::insert_ws_into, node_ext::expr_as_name_ref},
     RootDatabase,
 };
 use itertools::{izip, Itertools};
@@ -301,7 +301,16 @@ fn inline(
     params: &[(ast::Pat, Option<ast::Type>, hir::Param)],
     CallInfo { node, arguments, generic_arg_list }: &CallInfo,
 ) -> ast::Expr {
-    let body = fn_body.clone_for_update();
+    let body = if sema.hir_file_for(fn_body.syntax()).is_macro() {
+        cov_mark::hit!(inline_call_defined_in_macro);
+        if let Some(body) = ast::BlockExpr::cast(insert_ws_into(fn_body.syntax().clone())) {
+            body
+        } else {
+            fn_body.clone_for_update()
+        }
+    } else {
+        fn_body.clone_for_update()
+    };
     let usages_for_locals = |local| {
         Definition::Local(local)
             .usages(sema)
@@ -1147,4 +1156,39 @@ fn bar() -> u32 {
 "#,
         )
     }
+
+    #[test]
+    fn inline_call_defined_in_macro() {
+        cov_mark::check!(inline_call_defined_in_macro);
+        check_assist(
+            inline_call,
+            r#"
+macro_rules! define_foo {
+    () => { fn foo() -> u32 {
+        let x = 0;
+        x
+    } };
+}
+define_foo!();
+fn bar() -> u32 {
+    foo$0()
+}
+"#,
+            r#"
+macro_rules! define_foo {
+    () => { fn foo() -> u32 {
+        let x = 0;
+        x
+    } };
+}
+define_foo!();
+fn bar() -> u32 {
+    {
+      let x = 0;
+      x
+    }
+}
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index e8d48607be0..6eaab48a32b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -535,7 +535,7 @@ mod foo {
     pub struct Baz;
 }
 
-use foo::{Baz, Bar};
+use foo::{Bar, Baz};
 
 fn qux(bar: Bar, baz: Baz) {}
 "#####,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
index 149afcac9d4..72579e6026a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -400,7 +400,7 @@ impl Completions {
     ) {
         if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
             cov_mark::hit!(enum_variant_pattern_path);
-            self.add_variant_pat(ctx, pat_ctx, variant, local_name);
+            self.add_variant_pat(ctx, pat_ctx, Some(path_ctx), variant, local_name);
             return;
         }
 
@@ -484,12 +484,14 @@ impl Completions {
         &mut self,
         ctx: &CompletionContext<'_>,
         pattern_ctx: &PatternContext,
+        path_ctx: Option<&PathCompletionCtx>,
         variant: hir::Variant,
         local_name: Option<hir::Name>,
     ) {
         self.add_opt(render_variant_pat(
             RenderContext::new(ctx),
             pattern_ctx,
+            path_ctx,
             variant,
             local_name.clone(),
             None,
@@ -504,7 +506,14 @@ impl Completions {
         path: hir::ModPath,
     ) {
         let path = Some(&path);
-        self.add_opt(render_variant_pat(RenderContext::new(ctx), pattern_ctx, variant, None, path));
+        self.add_opt(render_variant_pat(
+            RenderContext::new(ctx),
+            pattern_ctx,
+            None,
+            variant,
+            None,
+            path,
+        ));
     }
 
     pub(crate) fn add_struct_pat(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
index 1d8a8c5f20d..d9fe94cb44e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
@@ -115,7 +115,7 @@ pub(crate) fn complete_attribute_path(
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::With { .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
     }
 
     let attributes = annotated_item_kind.and_then(|kind| {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
index 14538fef607..793c22630bf 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/derive.rs
@@ -97,7 +97,7 @@ pub(crate) fn complete_derive_path(
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::With { .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index bdf6e64f096..5d0ddaaf2a2 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
@@ -11,7 +11,14 @@ pub(crate) fn complete_expr_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
     path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
-    &ExprCtx {
+    expr_ctx: &ExprCtx,
+) {
+    let _p = profile::span("complete_expr_path");
+    if !ctx.qualifier_ctx.none() {
+        return;
+    }
+
+    let &ExprCtx {
         in_block_expr,
         in_loop_body,
         after_if_expr,
@@ -23,12 +30,7 @@ pub(crate) fn complete_expr_path(
         ref impl_,
         in_match_guard,
         ..
-    }: &ExprCtx,
-) {
-    let _p = profile::span("complete_expr_path");
-    if !ctx.qualifier_ctx.none() {
-        return;
-    }
+    } = expr_ctx;
 
     let wants_mut_token =
         ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false);
@@ -46,11 +48,32 @@ pub(crate) fn complete_expr_path(
     };
 
     match qualified {
-        Qualified::Infer => ctx
+        Qualified::TypeAnchor { ty: None, trait_: None } => ctx
             .traits_in_scope()
             .iter()
             .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
             .for_each(|item| add_assoc_item(acc, item)),
+        Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
+            trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
+        }
+        Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
+            if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+                cov_mark::hit!(completes_variant_through_alias);
+                acc.add_enum_variants(ctx, path_ctx, e);
+            }
+
+            ctx.iterate_path_candidates(&ty, |item| {
+                add_assoc_item(acc, item);
+            });
+
+            // Iterate assoc types separately
+            ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+                if let hir::AssocItem::TypeAlias(ty) = item {
+                    acc.add_type_alias(ctx, ty)
+                }
+                None::<()>
+            });
+        }
         Qualified::With { resolution: None, .. } => {}
         Qualified::With { resolution: Some(resolution), .. } => {
             // Add associated types on type parameters and `Self`.
@@ -179,10 +202,21 @@ pub(crate) fn complete_expr_path(
                     }
                 }
             }
-            ctx.process_all_names(&mut |name, def| {
-                if scope_def_applicable(def) {
-                    acc.add_path_resolution(ctx, path_ctx, name, def);
+            ctx.process_all_names(&mut |name, def| match def {
+                ScopeDef::ModuleDef(hir::ModuleDef::Trait(t)) => {
+                    let assocs = t.items_with_supertraits(ctx.db);
+                    match &*assocs {
+                        // traits with no assoc items are unusable as expressions since
+                        // there is no associated item path that can be constructed with them
+                        [] => (),
+                        // FIXME: Render the assoc item with the trait qualified
+                        &[_item] => acc.add_path_resolution(ctx, path_ctx, name, def),
+                        // FIXME: Append `::` to the thing here, since a trait on its own won't work
+                        [..] => acc.add_path_resolution(ctx, path_ctx, name, def),
+                    }
                 }
+                _ if scope_def_applicable(def) => acc.add_path_resolution(ctx, path_ctx, name, def),
+                _ => (),
             });
 
             if is_func_update.is_none() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
index 4e4c9fba6cc..60d05ae46b9 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
@@ -66,7 +66,7 @@ pub(crate) fn complete_item_list(
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::No | Qualified::With { .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::No | Qualified::With { .. } => {}
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
index 17dfe432b35..71d2d9d434b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/pattern.rs
@@ -74,7 +74,7 @@ pub(crate) fn complete_pattern(
                 hir::ModuleDef::Variant(variant)
                     if refutable || single_variant_enum(variant.parent_enum(ctx.db)) =>
                 {
-                    acc.add_variant_pat(ctx, pattern_ctx, variant, Some(name.clone()));
+                    acc.add_variant_pat(ctx, pattern_ctx, None, variant, Some(name.clone()));
                     true
                 }
                 hir::ModuleDef::Adt(hir::Adt::Enum(e)) => refutable || single_variant_enum(e),
@@ -180,6 +180,6 @@ pub(crate) fn complete_pattern_path(
 
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::With { .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
index 87a998dfcce..8f9db2f94c2 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/type.rs
@@ -49,11 +49,27 @@ pub(crate) fn complete_type_path(
     };
 
     match qualified {
-        Qualified::Infer => ctx
+        Qualified::TypeAnchor { ty: None, trait_: None } => ctx
             .traits_in_scope()
             .iter()
             .flat_map(|&it| hir::Trait::from(it).items(ctx.sema.db))
             .for_each(|item| add_assoc_item(acc, item)),
+        Qualified::TypeAnchor { trait_: Some(trait_), .. } => {
+            trait_.items(ctx.sema.db).into_iter().for_each(|item| add_assoc_item(acc, item))
+        }
+        Qualified::TypeAnchor { ty: Some(ty), trait_: None } => {
+            ctx.iterate_path_candidates(&ty, |item| {
+                add_assoc_item(acc, item);
+            });
+
+            // Iterate assoc types separately
+            ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
+                if let hir::AssocItem::TypeAlias(ty) = item {
+                    acc.add_type_alias(ctx, ty)
+                }
+                None::<()>
+            });
+        }
         Qualified::With { resolution: None, .. } => {}
         Qualified::With { resolution: Some(resolution), .. } => {
             // Add associated types on type parameters and `Self`.
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
index bb2ecc9fdde..2555c34aa74 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
@@ -115,6 +115,6 @@ pub(crate) fn complete_use_path(
             });
             acc.add_nameref_keywords_with_colon(ctx);
         }
-        Qualified::Infer | Qualified::With { resolution: None, .. } => {}
+        Qualified::TypeAnchor { .. } | Qualified::With { resolution: None, .. } => {}
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
index ca8303906a8..5e6cf4bf9a5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/vis.rs
@@ -29,7 +29,7 @@ pub(crate) fn complete_vis_path(
 
             acc.add_super_keyword(ctx, *super_chain_len);
         }
-        Qualified::Absolute | Qualified::Infer | Qualified::With { .. } => {}
+        Qualified::Absolute | Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
         Qualified::No => {
             if !has_in_token {
                 cov_mark::hit!(kw_completion_in);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 93b6ad5d145..e35f79d2b69 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -193,7 +193,10 @@ pub(super) enum Qualified {
         super_chain_len: Option<usize>,
     },
     /// <_>::
-    Infer,
+    TypeAnchor {
+        ty: Option<hir::Type>,
+        trait_: Option<hir::Trait>,
+    },
     /// Whether the path is an absolute path
     Absolute,
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index c71ffa0ed86..22ec7cead49 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -162,11 +162,52 @@ impl<'a> CompletionContext<'a> {
     }
 
     /// Calculate the expected type and name of the cursor position.
-    fn expected_type_and_name(&self) -> (Option<Type>, Option<NameOrNameRef>) {
+    fn expected_type_and_name(
+        &self,
+        name_like: &ast::NameLike,
+    ) -> (Option<Type>, Option<NameOrNameRef>) {
         let mut node = match self.token.parent() {
             Some(it) => it,
             None => return (None, None),
         };
+
+        let strip_refs = |mut ty: Type| match name_like {
+            ast::NameLike::NameRef(n) => {
+                let p = match n.syntax().parent() {
+                    Some(it) => it,
+                    None => return ty,
+                };
+                let top_syn = match_ast! {
+                    match p {
+                        ast::FieldExpr(e) => e
+                            .syntax()
+                            .ancestors()
+                            .map_while(ast::FieldExpr::cast)
+                            .last()
+                            .map(|it| it.syntax().clone()),
+                        ast::PathSegment(e) => e
+                            .syntax()
+                            .ancestors()
+                            .skip(1)
+                            .take_while(|it| ast::Path::can_cast(it.kind()) || ast::PathExpr::can_cast(it.kind()))
+                            .find_map(ast::PathExpr::cast)
+                            .map(|it| it.syntax().clone()),
+                        _ => None
+                    }
+                };
+                let top_syn = match top_syn {
+                    Some(it) => it,
+                    None => return ty,
+                };
+                for _ in top_syn.ancestors().skip(1).map_while(ast::RefExpr::cast) {
+                    cov_mark::hit!(expected_type_fn_param_ref);
+                    ty = ty.strip_reference();
+                }
+                ty
+            }
+            _ => ty,
+        };
+
         loop {
             break match_ast! {
                 match node {
@@ -199,13 +240,9 @@ impl<'a> CompletionContext<'a> {
                             self.token.clone(),
                         ).map(|ap| {
                             let name = ap.ident().map(NameOrNameRef::Name);
-                            let ty = if has_ref(&self.token) {
-                                cov_mark::hit!(expected_type_fn_param_ref);
-                                ap.ty.remove_ref()
-                            } else {
-                                Some(ap.ty)
-                            };
-                            (ty, name)
+
+                            let ty = strip_refs(ap.ty);
+                            (Some(ty), name)
                         })
                         .unwrap_or((None, None))
                     },
@@ -330,8 +367,6 @@ impl<'a> CompletionContext<'a> {
             return None;
         }
 
-        (self.expected_type, self.expected_name) = self.expected_type_and_name();
-
         // Overwrite the path kind for derives
         if let Some((original_file, file_with_fake_ident, offset, origin_attr)) = derive_ctx {
             if let Some(ast::NameLike::NameRef(name_ref)) =
@@ -389,6 +424,7 @@ impl<'a> CompletionContext<'a> {
                 return Some(analysis);
             }
         };
+        (self.expected_type, self.expected_name) = self.expected_type_and_name(&name_like);
         let analysis = match name_like {
             ast::NameLike::Lifetime(lifetime) => CompletionAnalysis::Lifetime(
                 Self::classify_lifetime(&self.sema, original_file, lifetime)?,
@@ -556,7 +592,7 @@ impl<'a> CompletionContext<'a> {
             has_call_parens: false,
             has_macro_bang: false,
             qualified: Qualified::No,
-            parent: path.parent_path(),
+            parent: None,
             path: path.clone(),
             kind: PathKind::Item { kind: ItemListKind::SourceFile },
             has_type_args: false,
@@ -791,92 +827,125 @@ impl<'a> CompletionContext<'a> {
             PathKind::Type { location: location.unwrap_or(TypeLocation::Other) }
         };
 
+        let mut kind_macro_call = |it: ast::MacroCall| {
+            path_ctx.has_macro_bang = it.excl_token().is_some();
+            let parent = it.syntax().parent()?;
+            // Any path in an item list will be treated as a macro call by the parser
+            let kind = match_ast! {
+                match parent {
+                    ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
+                    ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
+                    ast::MacroType(ty) => make_path_kind_type(ty.into()),
+                    ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
+                    ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
+                        Some(it) => match_ast! {
+                            match it {
+                                ast::Trait(_) => ItemListKind::Trait,
+                                ast::Impl(it) => if it.trait_().is_some() {
+                                    ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
+                                } else {
+                                    ItemListKind::Impl
+                                },
+                                _ => return None
+                            }
+                        },
+                        None => return None,
+                    } },
+                    ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
+                    ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
+                    _ => return None,
+                }
+            };
+            Some(kind)
+        };
+        let make_path_kind_attr = |meta: ast::Meta| {
+            let attr = meta.parent_attr()?;
+            let kind = attr.kind();
+            let attached = attr.syntax().parent()?;
+            let is_trailing_outer_attr = kind != AttrKind::Inner
+                && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next)
+                    .is_none();
+            let annotated_item_kind =
+                if is_trailing_outer_attr { None } else { Some(attached.kind()) };
+            Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } })
+        };
+
         // Infer the path kind
         let parent = path.syntax().parent()?;
         let kind = match_ast! {
-                match parent {
-                    ast::PathType(it) => make_path_kind_type(it.into()),
-                    ast::PathExpr(it) => {
-                        if let Some(p) = it.syntax().parent() {
-                            if ast::ExprStmt::can_cast(p.kind()) {
-                                if let Some(kind) = inbetween_body_and_decl_check(p) {
-                                    return Some(make_res(NameRefKind::Keyword(kind)));
-                                }
+            match parent {
+                ast::PathType(it) => make_path_kind_type(it.into()),
+                ast::PathExpr(it) => {
+                    if let Some(p) = it.syntax().parent() {
+                        if ast::ExprStmt::can_cast(p.kind()) {
+                            if let Some(kind) = inbetween_body_and_decl_check(p) {
+                                return Some(make_res(NameRefKind::Keyword(kind)));
                             }
                         }
+                    }
 
-                        path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
+                    path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
 
-                        make_path_kind_expr(it.into())
-                    },
-                    ast::TupleStructPat(it) => {
-                        path_ctx.has_call_parens = true;
-                        PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                    },
-                    ast::RecordPat(it) => {
-                        path_ctx.has_call_parens = true;
-                        PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                    },
-                    ast::PathPat(it) => {
-                        PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
-                    },
-                    ast::MacroCall(it) => {
-                        // A macro call in this position is usually a result of parsing recovery, so check that
-                        if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
-                            return Some(make_res(NameRefKind::Keyword(kind)));
-                        }
+                    make_path_kind_expr(it.into())
+                },
+                ast::TupleStructPat(it) => {
+                    path_ctx.has_call_parens = true;
+                    PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                },
+                ast::RecordPat(it) => {
+                    path_ctx.has_call_parens = true;
+                    PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                },
+                ast::PathPat(it) => {
+                    PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
+                },
+                ast::MacroCall(it) => {
+                    // A macro call in this position is usually a result of parsing recovery, so check that
+                    if let Some(kind) = inbetween_body_and_decl_check(it.syntax().clone()) {
+                        return Some(make_res(NameRefKind::Keyword(kind)));
+                    }
 
-                        path_ctx.has_macro_bang = it.excl_token().is_some();
-                        let parent = it.syntax().parent()?;
-                        // Any path in an item list will be treated as a macro call by the parser
-                        match_ast! {
-                            match parent {
-                                ast::MacroExpr(expr) => make_path_kind_expr(expr.into()),
-                                ast::MacroPat(it) => PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())},
-                                ast::MacroType(ty) => make_path_kind_type(ty.into()),
-                                ast::ItemList(_) => PathKind::Item { kind: ItemListKind::Module },
-                                ast::AssocItemList(_) => PathKind::Item { kind: match parent.parent() {
-                                    Some(it) => match_ast! {
-                                        match it {
-                                            ast::Trait(_) => ItemListKind::Trait,
-                                            ast::Impl(it) => if it.trait_().is_some() {
-                                                ItemListKind::TraitImpl(find_node_in_file_compensated(sema, original_file, &it))
-                                            } else {
-                                                ItemListKind::Impl
-                                            },
-                                            _ => return None
-                                        }
-                                    },
-                                    None => return None,
-                                } },
-                                ast::ExternItemList(_) => PathKind::Item { kind: ItemListKind::ExternBlock },
-                                ast::SourceFile(_) => PathKind::Item { kind: ItemListKind::SourceFile },
-                                _ => return None,
-                            }
-                        }
-                    },
-                    ast::Meta(meta) => {
-                        let attr = meta.parent_attr()?;
-                        let kind = attr.kind();
-                        let attached = attr.syntax().parent()?;
-                        let is_trailing_outer_attr = kind != AttrKind::Inner
-                            && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none();
-                        let annotated_item_kind = if is_trailing_outer_attr {
-                            None
-                        } else {
-                            Some(attached.kind())
-                        };
-                        PathKind::Attr {
-                            attr_ctx: AttrCtx {
-                                kind,
-                                annotated_item_kind,
-                            }
+                    kind_macro_call(it)?
+                },
+                ast::Meta(meta) => make_path_kind_attr(meta)?,
+                ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
+                ast::UseTree(_) => PathKind::Use,
+                // completing inside a qualifier
+                ast::Path(parent) => {
+                    path_ctx.parent = Some(parent.clone());
+                    let parent = iter::successors(Some(parent), |it| it.parent_path()).last()?.syntax().parent()?;
+                    match_ast! {
+                        match parent {
+                            ast::PathType(it) => make_path_kind_type(it.into()),
+                            ast::PathExpr(it) => {
+                                path_ctx.has_call_parens = it.syntax().parent().map_or(false, |it| ast::CallExpr::can_cast(it.kind()));
+
+                                make_path_kind_expr(it.into())
+                            },
+                            ast::TupleStructPat(it) => {
+                                path_ctx.has_call_parens = true;
+                                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                            },
+                            ast::RecordPat(it) => {
+                                path_ctx.has_call_parens = true;
+                                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into()) }
+                            },
+                            ast::PathPat(it) => {
+                                PathKind::Pat { pat_ctx: pattern_context_for(sema, original_file, it.into())}
+                            },
+                            ast::MacroCall(it) => {
+                                kind_macro_call(it)?
+                            },
+                            ast::Meta(meta) => make_path_kind_attr(meta)?,
+                            ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
+                            ast::UseTree(_) => PathKind::Use,
+                            ast::RecordExpr(it) => make_path_kind_expr(it.into()),
+                            _ => return None,
                         }
-                    },
-                    ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
-                    ast::UseTree(_) => PathKind::Use,
-                    _ => return None,
-
+                    }
+                },
+                ast::RecordExpr(it) => make_path_kind_expr(it.into()),
+                _ => return None,
             }
         };
 
@@ -884,49 +953,53 @@ impl<'a> CompletionContext<'a> {
         path_ctx.has_type_args = segment.generic_arg_list().is_some();
 
         // calculate the qualifier context
-        if let Some((path, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
+        if let Some((qualifier, use_tree_parent)) = path_or_use_tree_qualifier(&path) {
             path_ctx.use_tree_parent = use_tree_parent;
             if !use_tree_parent && segment.coloncolon_token().is_some() {
                 path_ctx.qualified = Qualified::Absolute;
             } else {
-                let path = path
+                let qualifier = qualifier
                     .segment()
                     .and_then(|it| find_node_in_file(original_file, &it))
                     .map(|it| it.parent_path());
-                if let Some(path) = path {
-                    // `<_>::$0`
-                    let is_infer_qualifier = path.qualifier().is_none()
-                        && matches!(
-                            path.segment().and_then(|it| it.kind()),
-                            Some(ast::PathSegmentKind::Type {
-                                type_ref: Some(ast::Type::InferType(_)),
-                                trait_ref: None,
-                            })
-                        );
+                if let Some(qualifier) = qualifier {
+                    let type_anchor = match qualifier.segment().and_then(|it| it.kind()) {
+                        Some(ast::PathSegmentKind::Type {
+                            type_ref: Some(type_ref),
+                            trait_ref,
+                        }) if qualifier.qualifier().is_none() => Some((type_ref, trait_ref)),
+                        _ => None,
+                    };
 
-                    path_ctx.qualified = if is_infer_qualifier {
-                        Qualified::Infer
+                    path_ctx.qualified = if let Some((ty, trait_ref)) = type_anchor {
+                        let ty = match ty {
+                            ast::Type::InferType(_) => None,
+                            ty => sema.resolve_type(&ty),
+                        };
+                        let trait_ = trait_ref.and_then(|it| sema.resolve_trait(&it.path()?));
+                        Qualified::TypeAnchor { ty, trait_ }
                     } else {
-                        let res = sema.resolve_path(&path);
+                        let res = sema.resolve_path(&qualifier);
 
                         // For understanding how and why super_chain_len is calculated the way it
                         // is check the documentation at it's definition
                         let mut segment_count = 0;
-                        let super_count = iter::successors(Some(path.clone()), |p| p.qualifier())
-                            .take_while(|p| {
-                                p.segment()
-                                    .and_then(|s| {
-                                        segment_count += 1;
-                                        s.super_token()
-                                    })
-                                    .is_some()
-                            })
-                            .count();
+                        let super_count =
+                            iter::successors(Some(qualifier.clone()), |p| p.qualifier())
+                                .take_while(|p| {
+                                    p.segment()
+                                        .and_then(|s| {
+                                            segment_count += 1;
+                                            s.super_token()
+                                        })
+                                        .is_some()
+                                })
+                                .count();
 
                         let super_chain_len =
                             if segment_count > super_count { None } else { Some(super_count) };
 
-                        Qualified::With { path, resolution: res, super_chain_len }
+                        Qualified::With { path: qualifier, resolution: res, super_chain_len }
                     }
                 };
             }
@@ -1141,19 +1214,6 @@ fn path_or_use_tree_qualifier(path: &ast::Path) -> Option<(ast::Path, bool)> {
     Some((use_tree.path()?, true))
 }
 
-fn has_ref(token: &SyntaxToken) -> bool {
-    let mut token = token.clone();
-    for skip in [SyntaxKind::IDENT, SyntaxKind::WHITESPACE, T![mut]] {
-        if token.kind() == skip {
-            token = match token.prev_token() {
-                Some(it) => it,
-                None => return false,
-            }
-        }
-    }
-    token.kind() == T![&]
-}
-
 pub(crate) fn is_in_token_of_for_loop(element: SyntaxElement) -> bool {
     // oh my ...
     (|| {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
index c5557bdafb3..50845b3881f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs
@@ -391,3 +391,23 @@ fn foo($0: Foo) {}
         expect![[r#"ty: ?, name: ?"#]],
     );
 }
+
+#[test]
+fn expected_type_ref_prefix_on_field() {
+    check_expected_type_and_name(
+        r#"
+fn foo(_: &mut i32) {}
+struct S {
+    field: i32,
+}
+
+fn main() {
+    let s = S {
+        field: 100,
+    };
+    foo(&mut s.f$0);
+}
+"#,
+        expect!["ty: i32, name: ?"],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 9b25964a608..946134b0ff9 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -1271,8 +1271,8 @@ fn main() {
                 st S []
                 st &mut S [type]
                 st S []
-                fn main() []
                 fn foo(…) []
+                fn main() []
             "#]],
         );
         check_relevance(
@@ -1288,8 +1288,8 @@ fn main() {
                 lc s [type+name+local]
                 st S [type]
                 st S []
-                fn main() []
                 fn foo(…) []
+                fn main() []
             "#]],
         );
         check_relevance(
@@ -1305,8 +1305,8 @@ fn main() {
                 lc ssss [type+local]
                 st S [type]
                 st S []
-                fn main() []
                 fn foo(…) []
+                fn main() []
             "#]],
         );
     }
@@ -1342,12 +1342,11 @@ fn main() {
                 lc &t [type+local]
                 st S []
                 st &S [type]
-                st T []
                 st S []
-                fn main() []
+                st T []
                 fn foo(…) []
+                fn main() []
                 md core []
-                tt Sized []
             "#]],
         )
     }
@@ -1389,12 +1388,11 @@ fn main() {
                 lc &mut t [type+local]
                 st S []
                 st &mut S [type]
-                st T []
                 st S []
-                fn main() []
+                st T []
                 fn foo(…) []
+                fn main() []
                 md core []
-                tt Sized []
             "#]],
         )
     }
@@ -1485,14 +1483,13 @@ fn main() {
             expect![[r#"
                 st S []
                 st &S [type]
-                st T []
                 st S []
-                fn main() []
+                st T []
                 fn bar() []
                 fn &bar() [type]
                 fn foo(…) []
+                fn main() []
                 md core []
-                tt Sized []
             "#]],
         )
     }
@@ -1636,8 +1633,8 @@ fn foo() {
                 ev Foo::B [type_could_unify]
                 fn foo() []
                 en Foo []
-                fn baz() []
                 fn bar() []
+                fn baz() []
             "#]],
         );
     }
@@ -1727,9 +1724,9 @@ fn f() {
 }
 "#,
             expect![[r#"
-                md std []
                 st Buffer []
                 fn f() []
+                md std []
                 tt BufRead (use std::io::BufRead) [requires_import]
                 st BufReader (use std::io::BufReader) [requires_import]
                 st BufWriter (use std::io::BufWriter) [requires_import]
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
index 241de0a1834..4b5535718c5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
@@ -85,7 +85,9 @@ fn render(
                 item.ref_match(ref_match, path_ctx.path.syntax().text_range().start());
             }
             FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => {
-                item.ref_match(ref_match, receiver.syntax().text_range().start());
+                if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) {
+                    item.ref_match(ref_match, original_expr.syntax().text_range().start());
+                }
             }
             _ => (),
         }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
index 03db08a911e..34a384f2f7a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
@@ -6,7 +6,7 @@ use itertools::Itertools;
 use syntax::SmolStr;
 
 use crate::{
-    context::{ParamContext, ParamKind, PatternContext},
+    context::{ParamContext, ParamKind, PathCompletionCtx, PatternContext},
     render::{
         variant::{format_literal_label, visible_fields},
         RenderContext,
@@ -42,6 +42,7 @@ pub(crate) fn render_struct_pat(
 pub(crate) fn render_variant_pat(
     ctx: RenderContext<'_>,
     pattern_ctx: &PatternContext,
+    path_ctx: Option<&PathCompletionCtx>,
     variant: hir::Variant,
     local_name: Option<Name>,
     path: Option<&hir::ModPath>,
@@ -58,9 +59,23 @@ pub(crate) fn render_variant_pat(
             (name.to_smol_str(), name.escaped().to_smol_str())
         }
     };
-    let kind = variant.kind(ctx.db());
-    let label = format_literal_label(name.as_str(), kind);
-    let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?;
+
+    let (label, pat) = match path_ctx {
+        Some(PathCompletionCtx { has_call_parens: true, .. }) => (name, escaped_name.to_string()),
+        _ => {
+            let kind = variant.kind(ctx.db());
+            let label = format_literal_label(name.as_str(), kind);
+            let pat = render_pat(
+                &ctx,
+                pattern_ctx,
+                &escaped_name,
+                kind,
+                &visible_fields,
+                fields_omitted,
+            )?;
+            (label, pat)
+        }
+    };
 
     Some(build_completion(ctx, label, pat, variant))
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index 4be6acbe846..cf826648dcf 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -23,8 +23,6 @@ mod type_pos;
 mod use_tree;
 mod visibility;
 
-use std::mem;
-
 use hir::{db::DefDatabase, PrefixKind, Semantics};
 use ide_db::{
     base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
@@ -107,12 +105,9 @@ fn completion_list_with_config(
 ) -> String {
     // filter out all but one builtintype completion for smaller test outputs
     let items = get_all_items(config, ra_fixture, trigger_character);
-    let mut bt_seen = false;
     let items = items
         .into_iter()
-        .filter(|it| {
-            it.kind() != CompletionItemKind::BuiltinType || !mem::replace(&mut bt_seen, true)
-        })
+        .filter(|it| it.kind() != CompletionItemKind::BuiltinType || it.label() == "u32")
         .filter(|it| include_keywords || it.kind() != CompletionItemKind::Keyword)
         .filter(|it| include_keywords || it.kind() != CompletionItemKind::Snippet)
         .sorted_by_key(|it| (it.kind(), it.label().to_owned(), it.detail().map(ToOwned::to_owned)))
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index ce9d01d337b..925081ebf66 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -44,7 +44,6 @@ fn baz() {
             st Record
             st Tuple
             st Unit
-            tt Trait
             un Union
             ev TupleV(…)     TupleV(u32)
             bt u32
@@ -137,7 +136,6 @@ impl Unit {
             st Record
             st Tuple
             st Unit
-            tt Trait
             tp TypeParam
             un Union
             ev TupleV(…)    TupleV(u32)
@@ -653,3 +651,22 @@ fn main() {
         "]],
     );
 }
+
+#[test]
+fn complete_record_expr_path() {
+    check(
+        r#"
+struct Zulu;
+impl Zulu {
+    fn test() -> Self { }
+}
+fn boi(val: Zulu) { }
+fn main() {
+    boi(Zulu:: $0 {});
+}
+"#,
+        expect![[r#"
+            fn test() fn() -> Zulu
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
index 877b5f21643..30ddbe2dc6f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs
@@ -443,7 +443,7 @@ fn foo() {
 }
 "#,
         expect![[r#"
-            bn TupleVariant(…) TupleVariant($1)$0
+            bn TupleVariant TupleVariant
         "#]],
     );
     check_empty(
@@ -458,7 +458,7 @@ fn foo() {
 }
 "#,
         expect![[r#"
-            bn RecordVariant {…} RecordVariant { field$1 }$0
+            bn RecordVariant RecordVariant
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
index ec32602fa3c..f6accc68e5e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs
@@ -167,7 +167,6 @@ fn main() {
             st Foo
             st Foo {…}              Foo { foo1: u32, foo2: u32 }
             tt Default
-            tt Sized
             bt u32
             kw crate::
             kw self::
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
index ca779c2fc71..033dc99c26c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
@@ -674,7 +674,60 @@ fn bar() -> Bar {
         expect![[r#"
                 fn foo() (as Foo) fn() -> Self
             "#]],
-    )
+    );
+}
+
+#[test]
+fn type_anchor_type() {
+    check(
+        r#"
+trait Foo {
+    fn foo() -> Self;
+}
+struct Bar;
+impl Bar {
+    fn bar() {}
+}
+impl Foo for Bar {
+    fn foo() -> {
+        Bar
+    }
+}
+fn bar() -> Bar {
+    <Bar>::$0
+}
+"#,
+        expect![[r#"
+            fn bar()          fn()
+            fn foo() (as Foo) fn() -> Self
+        "#]],
+    );
+}
+
+#[test]
+fn type_anchor_type_trait() {
+    check(
+        r#"
+trait Foo {
+    fn foo() -> Self;
+}
+struct Bar;
+impl Bar {
+    fn bar() {}
+}
+impl Foo for Bar {
+    fn foo() -> {
+        Bar
+    }
+}
+fn bar() -> Bar {
+    <Bar as Foo>::$0
+}
+"#,
+        expect![[r#"
+            fn foo() (as Foo) fn() -> Self
+        "#]],
+    );
 }
 
 #[test]
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
index d013d6f4b19..3fb49b45d98 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
@@ -13,7 +13,7 @@ mod html;
 #[cfg(test)]
 mod tests;
 
-use hir::{InFile, Name, Semantics};
+use hir::{Name, Semantics};
 use ide_db::{FxHashMap, RootDatabase};
 use syntax::{
     ast, AstNode, AstToken, NodeOrToken, SyntaxKind::*, SyntaxNode, TextRange, WalkEvent, T,
@@ -325,7 +325,7 @@ fn traverse(
             Leave(NodeOrToken::Node(node)) => {
                 // Doc comment highlighting injection, we do this when leaving the node
                 // so that we overwrite the highlighting of the doc comment itself.
-                inject::doc_comment(hl, sema, InFile::new(file_id.into(), &node));
+                inject::doc_comment(hl, sema, file_id, &node);
                 continue;
             }
         };
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
index f779a985a99..f376f9fda7a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
@@ -5,7 +5,8 @@ use std::mem;
 use either::Either;
 use hir::{InFile, Semantics};
 use ide_db::{
-    active_parameter::ActiveParameter, defs::Definition, rust_doc::is_rust_fence, SymbolKind,
+    active_parameter::ActiveParameter, base_db::FileId, defs::Definition, rust_doc::is_rust_fence,
+    SymbolKind,
 };
 use syntax::{
     ast::{self, AstNode, IsString, QuoteOffsets},
@@ -81,16 +82,18 @@ pub(super) fn ra_fixture(
 const RUSTDOC_FENCE_LENGTH: usize = 3;
 const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
 
-/// Injection of syntax highlighting of doctests.
+/// Injection of syntax highlighting of doctests and intra doc links.
 pub(super) fn doc_comment(
     hl: &mut Highlights,
     sema: &Semantics<'_, RootDatabase>,
-    InFile { file_id: src_file_id, value: node }: InFile<&SyntaxNode>,
+    src_file_id: FileId,
+    node: &SyntaxNode,
 ) {
     let (attributes, def) = match doc_attributes(sema, node) {
         Some(it) => it,
         None => return,
     };
+    let src_file_id = src_file_id.into();
 
     // Extract intra-doc links and emit highlights for them.
     if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
new file mode 100644
index 00000000000..8a1d69816e6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_inline.html
@@ -0,0 +1,51 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.label              { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.intra_doc_link     { font-style: italic; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.function.unsafe    { color: #BC8383; }
+.trait.unsafe       { color: #BC8383; }
+.operator.unsafe    { color: #BC8383; }
+.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
+.keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.derive             { color: #94BFF3; font-style: italic; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.control            { font-style: italic; }
+.reference          { font-style: italic; font-weight: bold; }
+
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
+<span class="comment documentation">//! This is an intra doc injection test for modules</span>
+<span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
+<span class="comment documentation">//! This is an intra doc injection test for modules</span>
+
+<span class="keyword">pub</span> <span class="keyword">struct</span> <span class="struct declaration public">Struct</span><span class="semicolon">;</span>
+</code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
new file mode 100644
index 00000000000..c4c3e3dc260
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_module_docs_outline.html
@@ -0,0 +1,50 @@
+
+<style>
+body                { margin: 0; }
+pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
+
+.lifetime           { color: #DFAF8F; font-style: italic; }
+.label              { color: #DFAF8F; font-style: italic; }
+.comment            { color: #7F9F7F; }
+.documentation      { color: #629755; }
+.intra_doc_link     { font-style: italic; }
+.injected           { opacity: 0.65 ; }
+.struct, .enum      { color: #7CB8BB; }
+.enum_variant       { color: #BDE0F3; }
+.string_literal     { color: #CC9393; }
+.field              { color: #94BFF3; }
+.function           { color: #93E0E3; }
+.function.unsafe    { color: #BC8383; }
+.trait.unsafe       { color: #BC8383; }
+.operator.unsafe    { color: #BC8383; }
+.mutable.unsafe     { color: #BC8383; text-decoration: underline; }
+.keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
+.parameter          { color: #94BFF3; }
+.text               { color: #DCDCCC; }
+.type               { color: #7CB8BB; }
+.builtin_type       { color: #8CD0D3; }
+.type_param         { color: #DFAF8F; }
+.attribute          { color: #94BFF3; }
+.numeric_literal    { color: #BFEBBF; }
+.bool_literal       { color: #BFE6EB; }
+.macro              { color: #94BFF3; }
+.derive             { color: #94BFF3; font-style: italic; }
+.module             { color: #AFD8AF; }
+.value_param        { color: #DCDCCC; }
+.variable           { color: #DCDCCC; }
+.format_specifier   { color: #CC696B; }
+.mutable            { text-decoration: underline; }
+.escape_sequence    { color: #94BFF3; }
+.keyword            { color: #F0DFAF; font-weight: bold; }
+.control            { font-style: italic; }
+.reference          { font-style: italic; font-weight: bold; }
+
+.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
+</style>
+<pre><code><span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
+<span class="comment documentation">/// This is an intra doc injection test for modules</span>
+<span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
+<span class="comment documentation">/// This is an intra doc injection test for modules</span>
+<span class="keyword">mod</span> <span class="module declaration">foo</span><span class="semicolon">;</span>
+</code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index 6ba6153178d..99be7c66486 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -915,6 +915,52 @@ fn main() {
 }
 
 #[test]
+fn test_mod_hl_injection() {
+    check_highlighting(
+        r##"
+//- /foo.rs
+//! [Struct]
+//! This is an intra doc injection test for modules
+//! [Struct]
+//! This is an intra doc injection test for modules
+
+pub struct Struct;
+//- /lib.rs crate:foo
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+mod foo;
+"##,
+        expect_file!["./test_data/highlight_module_docs_inline.html"],
+        false,
+    );
+    check_highlighting(
+        r##"
+//- /lib.rs crate:foo
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+/// [crate::foo::Struct]
+/// This is an intra doc injection test for modules
+mod foo;
+//- /foo.rs
+//! [Struct]
+//! This is an intra doc injection test for modules
+//! [Struct]
+//! This is an intra doc injection test for modules
+
+pub struct Struct;
+"##,
+        expect_file!["./test_data/highlight_module_docs_outline.html"],
+        false,
+    );
+}
+
+#[test]
+#[cfg_attr(
+    all(unix, not(target_pointer_width = "64")),
+    ignore = "depends on `DefaultHasher` outputs"
+)]
 fn test_rainbow_highlighting() {
     check_highlighting(
         r#"
diff --git a/src/tools/rust-analyzer/crates/limit/src/lib.rs b/src/tools/rust-analyzer/crates/limit/src/lib.rs
index 3c1da80edb9..d6a706a7cd7 100644
--- a/src/tools/rust-analyzer/crates/limit/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/limit/src/lib.rs
@@ -2,12 +2,13 @@
 
 #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
 
+#[cfg(feature = "tracking")]
 use std::sync::atomic::AtomicUsize;
 
 /// Represents a struct used to enforce a numerical limit.
 pub struct Limit {
     upper_bound: usize,
-    #[allow(unused)]
+    #[cfg(feature = "tracking")]
     max: AtomicUsize,
 }
 
@@ -15,14 +16,22 @@ impl Limit {
     /// Creates a new limit.
     #[inline]
     pub const fn new(upper_bound: usize) -> Self {
-        Self { upper_bound, max: AtomicUsize::new(0) }
+        Self {
+            upper_bound,
+            #[cfg(feature = "tracking")]
+            max: AtomicUsize::new(0),
+        }
     }
 
     /// Creates a new limit.
     #[inline]
     #[cfg(feature = "tracking")]
     pub const fn new_tracking(upper_bound: usize) -> Self {
-        Self { upper_bound, max: AtomicUsize::new(1) }
+        Self {
+            upper_bound,
+            #[cfg(feature = "tracking")]
+            max: AtomicUsize::new(1),
+        }
     }
 
     /// Gets the underlying numeric limit.
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
index f9efcef92a6..8de5d33a193 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
@@ -54,7 +54,7 @@ fn path_for_qualifier(
     mut qual: CompletedMarker,
 ) -> CompletedMarker {
     loop {
-        let use_tree = matches!(p.nth(2), T![*] | T!['{']);
+        let use_tree = mode == Mode::Use && matches!(p.nth(2), T![*] | T!['{']);
         if p.at(T![::]) && !use_tree {
             let path = qual.precede(p);
             p.bump(T![::]);
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
index 4b1858b8ed8..4c205b9cada 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
@@ -39,6 +39,8 @@ pub(crate) struct ProcMacroSrv {
     expanders: HashMap<(PathBuf, SystemTime), dylib::Expander>,
 }
 
+const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024;
+
 impl ProcMacroSrv {
     pub fn expand(&mut self, task: ExpandMacro) -> Result<FlatTree, PanicMessage> {
         let expander = self.expander(task.lib.as_ref()).map_err(|err| {
@@ -66,13 +68,18 @@ impl ProcMacroSrv {
         // FIXME: replace this with std's scoped threads once they stabilize
         // (then remove dependency on crossbeam)
         let result = crossbeam::scope(|s| {
-            let res = s
+            let res = match s
+                .builder()
+                .stack_size(EXPANDER_STACK_SIZE)
+                .name(task.macro_name.clone())
                 .spawn(|_| {
                     expander
                         .expand(&task.macro_name, &macro_body, attributes.as_ref())
                         .map(|it| FlatTree::new(&it))
-                })
-                .join();
+                }) {
+                Ok(handle) => handle.join(),
+                Err(e) => std::panic::resume_unwind(Box::new(e)),
+            };
 
             match res {
                 Ok(res) => res,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs
index 0ada4b73e84..5d1c013c327 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -66,7 +66,9 @@ pub fn load_workspace(
     };
 
     let crate_graph = ws.to_crate_graph(
-        &mut |_, path: &AbsPath| load_proc_macro(proc_macro_client.as_ref(), path, &[]),
+        &mut |_, path: &AbsPath| {
+            load_proc_macro(proc_macro_client.as_ref().map_err(|e| &**e), path, &[])
+        },
         &mut |path: &AbsPath| {
             let contents = loader.load_sync(path);
             let path = vfs::VfsPath::from(path.to_path_buf());
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 9ae361b034e..eaab275bc68 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -303,6 +303,9 @@ impl GlobalState {
         let files_config = self.config.files();
         let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
 
+        let standalone_server_name =
+            format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
+
         if self.proc_macro_clients.is_empty() {
             if let Some((path, args)) = self.config.proc_macro_srv() {
                 self.proc_macro_clients = self
@@ -316,10 +319,8 @@ impl GlobalState {
                             tracing::info!("Found a cargo workspace...");
                             if let Some(sysroot) = sysroot.as_ref() {
                                 tracing::info!("Found a cargo workspace with a sysroot...");
-                                let server_path = sysroot
-                                    .root()
-                                    .join("libexec")
-                                    .join("rust-analyzer-proc-macro-srv");
+                                let server_path =
+                                    sysroot.root().join("libexec").join(&standalone_server_name);
                                 if std::fs::metadata(&server_path).is_ok() {
                                     tracing::info!(
                                         "And the server exists at {}",
@@ -389,7 +390,10 @@ impl GlobalState {
 
             let mut crate_graph = CrateGraph::default();
             for (idx, ws) in self.workspaces.iter().enumerate() {
-                let proc_macro_client = self.proc_macro_clients[idx].as_ref();
+                let proc_macro_client = match self.proc_macro_clients.get(idx) {
+                    Some(res) => res.as_ref().map_err(|e| &**e),
+                    None => Err("Proc macros are disabled"),
+                };
                 let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| {
                     load_proc_macro(
                         proc_macro_client,
@@ -573,7 +577,7 @@ impl SourceRootConfig {
 /// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace`
 /// with an identity dummy expander.
 pub(crate) fn load_proc_macro(
-    server: Result<&ProcMacroServer, &String>,
+    server: Result<&ProcMacroServer, &str>,
     path: &AbsPath,
     dummy_replace: &[Box<str>],
 ) -> ProcMacroLoadResult {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index cf90ba64cff..63309a15521 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -880,7 +880,6 @@ impl ForExpr {
     pub fn for_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![for]) }
     pub fn pat(&self) -> Option<Pat> { support::child(&self.syntax) }
     pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) }
-    pub fn iterable(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -890,7 +889,6 @@ pub struct IfExpr {
 impl ast::HasAttrs for IfExpr {}
 impl IfExpr {
     pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
-    pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn else_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![else]) }
 }
 
@@ -1051,7 +1049,6 @@ pub struct WhileExpr {
 impl ast::HasAttrs for WhileExpr {}
 impl WhileExpr {
     pub fn while_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![while]) }
-    pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -1170,7 +1167,6 @@ pub struct MatchGuard {
 }
 impl MatchGuard {
     pub fn if_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![if]) }
-    pub fn condition(&self) -> Option<Expr> { support::child(&self.syntax) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
index b143df1f83f..bb92c51e9a9 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
@@ -806,6 +806,19 @@ impl ast::GenericParamList {
     }
 }
 
+impl ast::ForExpr {
+    pub fn iterable(&self) -> Option<ast::Expr> {
+        // If the iterable is a BlockExpr, check if the body is missing.
+        // If it is assume the iterable is the expression that is missing instead.
+        let mut exprs = support::children(self.syntax());
+        let first = exprs.next();
+        match first {
+            Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
+            first => first,
+        }
+    }
+}
+
 impl ast::HasLoopBody for ast::ForExpr {
     fn loop_body(&self) -> Option<ast::BlockExpr> {
         let mut exprs = support::children(self.syntax());
@@ -815,6 +828,19 @@ impl ast::HasLoopBody for ast::ForExpr {
     }
 }
 
+impl ast::WhileExpr {
+    pub fn condition(&self) -> Option<ast::Expr> {
+        // If the condition is a BlockExpr, check if the body is missing.
+        // If it is assume the condition is the expression that is missing instead.
+        let mut exprs = support::children(self.syntax());
+        let first = exprs.next();
+        match first {
+            Some(ast::Expr::BlockExpr(_)) => exprs.next().and(first),
+            first => first,
+        }
+    }
+}
+
 impl ast::HasLoopBody for ast::WhileExpr {
     fn loop_body(&self) -> Option<ast::BlockExpr> {
         let mut exprs = support::children(self.syntax());
@@ -835,3 +861,15 @@ impl From<ast::Adt> for ast::Item {
         }
     }
 }
+
+impl ast::IfExpr {
+    pub fn condition(&self) -> Option<ast::Expr> {
+        support::child(&self.syntax)
+    }
+}
+
+impl ast::MatchGuard {
+    pub fn condition(&self) -> Option<ast::Expr> {
+        support::child(&self.syntax)
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
index 4cfb8075cb1..6d276622510 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
@@ -682,6 +682,8 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, label: Option<&String>, r
                     | "value"
                     | "trait"
                     | "self_ty"
+                    | "iterable"
+                    | "condition"
             );
             if manually_implemented {
                 return;
diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md
index 468f2b9e981..76bbd1e9188 100644
--- a/src/tools/rust-analyzer/docs/dev/README.md
+++ b/src/tools/rust-analyzer/docs/dev/README.md
@@ -210,7 +210,8 @@ Release process is handled by `release`, `dist` and `promote` xtasks, `release`
 ./rust-rust-analyzer  # Note the name!
 ```
 
-Additionally, it assumes that the remote for `rust-analyzer` is called `upstream` (I use `origin` to point to my fork).
+The remote for `rust-analyzer` must be called `upstream` (I use `origin` to point to my fork).
+In addition, for `xtask promote` (see below), `rust-rust-analyzer` must have a `rust-analyzer` remote pointing to this repository on GitHub.
 
 `release` calls the GitHub API calls to scrape pull request comments and categorize them in the changelog.
 This step uses the `curl` and `jq` applications, which need to be available in `PATH`.
@@ -225,13 +226,13 @@ Release steps:
    * push it to `upstream`. This triggers GitHub Actions which:
      * runs `cargo xtask dist` to package binaries and VS Code extension
      * makes a GitHub release
-     * pushes VS Code extension to the marketplace
+     * publishes the VS Code extension to the marketplace
    * call the GitHub API for PR details
    * create a new changelog in `rust-analyzer.github.io`
 3. While the release is in progress, fill in the changelog
 4. Commit & push the changelog
 5. Tweet
-6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's submodule.
+6. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's subtree.
    Self-approve the PR.
 
 If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console.
diff --git a/src/tools/rust-analyzer/xtask/src/release.rs b/src/tools/rust-analyzer/xtask/src/release.rs
index 1c5fc64c241..17ada515640 100644
--- a/src/tools/rust-analyzer/xtask/src/release.rs
+++ b/src/tools/rust-analyzer/xtask/src/release.rs
@@ -77,18 +77,12 @@ impl flags::Promote {
         cmd!(sh, "git switch master").run()?;
         cmd!(sh, "git fetch upstream").run()?;
         cmd!(sh, "git reset --hard upstream/master").run()?;
-        cmd!(sh, "git submodule update --recursive").run()?;
 
         let date = date_iso(sh)?;
         let branch = format!("rust-analyzer-{date}");
         cmd!(sh, "git switch -c {branch}").run()?;
-        {
-            let _dir = sh.push_dir("src/tools/rust-analyzer");
-            cmd!(sh, "git fetch origin").run()?;
-            cmd!(sh, "git reset --hard origin/release").run()?;
-        }
-        cmd!(sh, "git add src/tools/rust-analyzer").run()?;
-        cmd!(sh, "git commit -m':arrow_up: rust-analyzer'").run()?;
+        cmd!(sh, "git subtree pull -P src/tools/rust-analyzer rust-analyzer master").run()?;
+
         if !self.dry_run {
             cmd!(sh, "git push -u origin {branch}").run()?;
             cmd!(
diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml
index 00281bf8f01..b1d8b86496a 100644
--- a/src/tools/rustc-workspace-hack/Cargo.toml
+++ b/src/tools/rustc-workspace-hack/Cargo.toml
@@ -79,11 +79,10 @@ crossbeam-utils = { version = "0.8.0", features = ["nightly"] }
 libc = { version = "0.2.79", features = ["align"] }
 # Ensure default features of libz-sys, which are disabled in some scenarios.
 libz-sys = { version = "1.1.2" }
-
-# looks like the only user of deprecated `use_std` feature is `combine`, so this
-# can be removed if/when https://github.com/Marwes/combine/pull/348 be merged and released.
+# The only user of memchr's deprecated `use_std` feature is `combine`, so this can be
+# removed if/when https://github.com/Marwes/combine/pull/348 is merged and released.
 memchr = { version = "2.5", features = ["std", "use_std"] }
-# same for regex
+# Ensure default features of regex, which are disabled in some scenarios.
 regex = { version = "1.5.6" }
 proc-macro2 = { version = "1", features = ["default"] }
 quote = { version = "1", features = ["default"] }
diff --git a/src/tools/x/src/main.rs b/src/tools/x/src/main.rs
index 57d548f313d..9187c3551d7 100644
--- a/src/tools/x/src/main.rs
+++ b/src/tools/x/src/main.rs
@@ -41,9 +41,9 @@ fn python() -> &'static str {
     } else if python2 {
         PYTHON2
     } else {
-        // We would have returned early if we found that python is installed ...
-        // maybe this should panic with an error instead?
-        PYTHON
+        // Python was not found on path, so exit
+        eprintln!("Unable to find python in your PATH. Please check it is installed.");
+        process::exit(1);
     }
 }
 
diff --git a/src/version b/src/version
index 9405730420f..902c74186fb 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.64.0
+1.65.0