about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--.github/workflows/ci.yml118
-rw-r--r--Cargo.lock16
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs6
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs21
-rw-r--r--compiler/rustc_ast/src/visit.rs23
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs131
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs17
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs9
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs2
-rw-r--r--compiler/rustc_ast_passes/src/node_count.rs4
-rw-r--r--compiler/rustc_ast_passes/src/show_span.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs12
-rw-r--r--compiler/rustc_codegen_cranelift/src/archive.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs12
-rw-r--r--compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/metadata.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/toolchain.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs24
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs8
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs15
-rw-r--r--compiler/rustc_codegen_llvm/src/metadata.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/va_arg.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs96
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs45
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs4
-rw-r--r--compiler/rustc_expand/src/config.rs5
-rw-r--r--compiler/rustc_expand/src/expand.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs5
-rw-r--r--compiler/rustc_expand/src/mut_visit/tests.rs5
-rw-r--r--compiler/rustc_expand/src/placeholders.rs4
-rw-r--r--compiler/rustc_feature/src/active.rs6
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs1
-rw-r--r--compiler/rustc_hir/src/definitions.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs9
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs112
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs54
-rw-r--r--compiler/rustc_interface/src/tests.rs2
-rw-r--r--compiler/rustc_interface/src/util.rs6
-rw-r--r--compiler/rustc_lint/src/early.rs10
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs1
-rw-r--r--compiler/rustc_metadata/src/dependency_format.rs2
-rw-r--r--compiler/rustc_metadata/src/locator.rs22
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs16
-rw-r--r--compiler/rustc_middle/Cargo.toml2
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs2
-rw-r--r--compiler/rustc_middle/src/middle/limits.rs6
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs31
-rw-r--r--compiler/rustc_middle/src/traits/chalk.rs68
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs2
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs27
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs13
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs63
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs204
-rw-r--r--compiler/rustc_mir/src/borrow_check/region_infer/mod.rs2
-rw-r--r--compiler/rustc_mir/src/dataflow/framework/engine.rs9
-rw-r--r--compiler/rustc_mir/src/interpret/eval_context.rs6
-rw-r--r--compiler/rustc_mir/src/monomorphize/collector.rs10
-rw-r--r--compiler/rustc_mir/src/monomorphize/partitioning/default.rs2
-rw-r--r--compiler/rustc_mir/src/transform/inline.rs416
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs1
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs6
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs3
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs2
-rw-r--r--compiler/rustc_session/src/config.rs17
-rw-r--r--compiler/rustc_session/src/options.rs4
-rw-r--r--compiler/rustc_session/src/output.rs18
-rw-r--r--compiler/rustc_session/src/session.rs45
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs4
-rw-r--r--compiler/rustc_target/src/abi/call/powerpc64.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/riscv.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/x86.rs4
-rw-r--r--compiler/rustc_target/src/abi/mod.rs4
-rw-r--r--compiler/rustc_target/src/asm/arm.rs2
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_darwin.rs2
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs2
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs2
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_none.rs2
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs2
-rw-r--r--compiler/rustc_target/src/spec/android_base.rs5
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs6
-rw-r--r--compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs2
-rw-r--r--compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/armebv7r_none_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs2
-rw-r--r--compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs2
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv7a_none_eabi.rs6
-rw-r--r--compiler/rustc_target/src/spec/armv7a_none_eabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/armv7r_none_eabi.rs2
-rw-r--r--compiler/rustc_target/src/spec/armv7r_none_eabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs1
-rw-r--r--compiler/rustc_target/src/spec/avr_gnu_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/cloudabi_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/dragonfly_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/freebsd_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/fuchsia_base.rs6
-rw-r--r--compiler/rustc_target/src/spec/haiku_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/hermit_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/hermit_kernel_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs2
-rw-r--r--compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs2
-rw-r--r--compiler/rustc_target/src/spec/i686_apple_darwin.rs2
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_netbsd.rs2
-rw-r--r--compiler/rustc_target/src/spec/illumos_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/l4re_base.rs6
-rw-r--r--compiler/rustc_target/src/spec/linux_base.rs5
-rw-r--r--compiler/rustc_target/src/spec/linux_gnu_base.rs5
-rw-r--r--compiler/rustc_target/src/spec/linux_kernel_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/linux_musl_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/linux_uclibc_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs6
-rw-r--r--compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs6
-rw-r--r--compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs4
-rw-r--r--compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs2
-rw-r--r--compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs4
-rw-r--r--compiler/rustc_target/src/spec/mipsel_sony_psp.rs4
-rw-r--r--compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs2
-rw-r--r--compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs2
-rw-r--r--compiler/rustc_target/src/spec/mipsel_unknown_none.rs2
-rw-r--r--compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs6
-rw-r--r--compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs4
-rw-r--r--compiler/rustc_target/src/spec/mod.rs165
-rw-r--r--compiler/rustc_target/src/spec/msp430_none_elf.rs4
-rw-r--r--compiler/rustc_target/src/spec/netbsd_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs4
-rw-r--r--compiler/rustc_target/src/spec/openbsd_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs8
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs2
-rw-r--r--compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs2
-rw-r--r--compiler/rustc_target/src/spec/redox_base.rs6
-rw-r--r--compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/solaris_base.rs6
-rw-r--r--compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs2
-rw-r--r--compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs4
-rw-r--r--compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs2
-rw-r--r--compiler/rustc_target/src/spec/tests/tests_impl.rs20
-rw-r--r--compiler/rustc_target/src/spec/thumb_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/uefi_msvc_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/vxworks_base.rs10
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs4
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs2
-rw-r--r--compiler/rustc_target/src/spec/wasm32_wasi.rs4
-rw-r--r--compiler/rustc_target/src/spec/windows_gnu_base.rs8
-rw-r--r--compiler/rustc_target/src/spec/windows_msvc_base.rs8
-rw-r--r--compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_darwin.rs2
-rw-r--r--compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs4
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs2
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs2
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2
-rw-r--r--compiler/rustc_traits/Cargo.toml6
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs206
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs381
-rw-r--r--compiler/rustc_traits/src/chalk/mod.rs9
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs37
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs2
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs5
-rw-r--r--compiler/rustc_typeck/src/check/regionck.rs2
-rw-r--r--compiler/rustc_typeck/src/collect.rs2
-rw-r--r--compiler/rustc_typeck/src/collect/item_bounds.rs16
-rw-r--r--config.toml.example12
-rw-r--r--library/alloc/src/collections/btree/append.rs124
-rw-r--r--library/alloc/src/collections/btree/map.rs96
-rw-r--r--library/alloc/src/collections/btree/map/tests.rs53
-rw-r--r--library/alloc/src/collections/btree/merge_iter.rs42
-rw-r--r--library/alloc/src/collections/btree/mod.rs1
-rw-r--r--library/alloc/src/collections/btree/node.rs578
-rw-r--r--library/alloc/src/collections/btree/node/tests.rs37
-rw-r--r--library/alloc/src/collections/btree/search.rs2
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/vec.rs12
-rw-r--r--library/core/src/intrinsics.rs4
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/macros/mod.rs2
-rw-r--r--library/core/src/num/error.rs17
-rw-r--r--library/core/src/num/mod.rs22
-rw-r--r--library/core/src/time.rs40
-rw-r--r--library/core/tests/nonzero.rs4
-rw-r--r--library/core/tests/num/mod.rs65
-rw-r--r--library/core/tests/time.rs97
-rw-r--r--library/std/src/alloc.rs2
-rw-r--r--library/std/src/fs.rs8
-rw-r--r--library/std/src/fs/tests.rs51
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/sys/unix/fs.rs15
-rw-r--r--library/std/src/sys/unix/process/process_common/tests.rs25
-rw-r--r--library/std/src/time.rs2
-rw-r--r--library/std/src/time/tests.rs32
-rw-r--r--src/bootstrap/CHANGELOG.md2
-rw-r--r--src/bootstrap/bootstrap.py19
-rw-r--r--src/bootstrap/builder.rs12
-rw-r--r--src/bootstrap/check.rs4
-rw-r--r--src/bootstrap/compile.rs4
-rw-r--r--src/bootstrap/config.rs26
-rwxr-xr-xsrc/bootstrap/configure.py2
-rw-r--r--src/bootstrap/dist.rs26
-rw-r--r--src/bootstrap/doc.rs8
-rw-r--r--src/bootstrap/lib.rs57
-rw-r--r--src/bootstrap/native.rs4
-rw-r--r--src/bootstrap/sanity.rs2
-rw-r--r--src/bootstrap/test.rs8
-rw-r--r--src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile34
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/Dockerfile7
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/build-gcc.sh3
-rw-r--r--src/ci/github-actions/ci.yml23
-rwxr-xr-xsrc/ci/scripts/should-skip-this.sh4
-rw-r--r--src/doc/rustc/src/platform-support.md10
-rw-r--r--src/doc/unstable-book/src/language-features/cfg-panic.md38
-rw-r--r--src/librustdoc/clean/mod.rs16
-rw-r--r--src/librustdoc/core.rs11
-rw-r--r--src/librustdoc/html/render/cache.rs2
-rw-r--r--src/librustdoc/html/static/settings.css5
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs414
-rw-r--r--src/test/mir-opt/inline/inline-cycle.rs60
-rw-r--r--src/test/mir-opt/inline/inline-diverging.rs40
-rw-r--r--src/test/mir-opt/inline/inline-options.rs19
-rw-r--r--src/test/mir-opt/inline/inline-shims.rs13
-rw-r--r--src/test/mir-opt/inline/inline_cycle.one.Inline.diff27
-rw-r--r--src/test/mir-opt/inline/inline_cycle.two.Inline.diff47
-rw-r--r--src/test/mir-opt/inline/inline_diverging.f.Inline.diff26
-rw-r--r--src/test/mir-opt/inline/inline_diverging.g.Inline.diff52
-rw-r--r--src/test/mir-opt/inline/inline_diverging.h.Inline.diff58
-rw-r--r--src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff2
-rw-r--r--src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff2
-rw-r--r--src/test/mir-opt/inline/inline_options.main.Inline.after.mir56
-rw-r--r--src/test/mir-opt/inline/inline_shims.clone.Inline.diff26
-rw-r--r--src/test/mir-opt/inline/inline_shims.drop.Inline.diff52
-rw-r--r--src/test/rustdoc/external-macro-src.rs7
-rw-r--r--src/test/rustdoc/issue-26606.rs2
-rw-r--r--src/test/rustdoc/thread-local-src.rs2
-rw-r--r--src/test/ui/async-await/issue-74072-lifetime-name-annotations.rs37
-rw-r--r--src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr51
-rw-r--r--src/test/ui/async-await/issue-74497-lifetime-in-opaque.rs19
-rw-r--r--src/test/ui/async-await/issue-74497-lifetime-in-opaque.stderr11
-rw-r--r--src/test/ui/async-await/issues/issue-63388-1.stderr6
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr5
-rw-r--r--src/test/ui/bad/bad-expr-lhs.rs6
-rw-r--r--src/test/ui/bad/bad-expr-lhs.stderr47
-rw-r--r--src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr2
-rw-r--r--src/test/ui/cfg/cfg-panic-abort.rs16
-rw-r--r--src/test/ui/cfg/cfg-panic.rs18
-rw-r--r--src/test/ui/chalkify/arithmetic.rs20
-rw-r--r--src/test/ui/chalkify/trait-objects.rs13
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/associated-consts.rs31
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs16
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr14
-rw-r--r--src/test/ui/const-generics/min_const_generics/macro-fail.rs48
-rw-r--r--src/test/ui/const-generics/min_const_generics/macro-fail.stderr107
-rw-r--r--src/test/ui/const-generics/min_const_generics/macro.rs57
-rw-r--r--src/test/ui/consts/const-block-non-item-statement.rs2
-rw-r--r--src/test/ui/consts/const-fn-destructuring-arg.rs2
-rw-r--r--src/test/ui/consts/const_let_assign.rs2
-rw-r--r--src/test/ui/consts/const_let_assign2.rs2
-rw-r--r--src/test/ui/consts/control-flow/assert.const_panic.stderr (renamed from src/test/ui/consts/control-flow/assert.panic.stderr)0
-rw-r--r--src/test/ui/consts/control-flow/assert.rs6
-rw-r--r--src/test/ui/default-alloc-error-hook.rs2
-rw-r--r--src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs7
-rw-r--r--src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr14
-rw-r--r--src/test/ui/destructuring-assignment/note-unsupported.rs13
-rw-r--r--src/test/ui/destructuring-assignment/note-unsupported.stderr48
-rw-r--r--src/test/ui/destructuring-assignment/tuple_destructure.rs37
-rw-r--r--src/test/ui/destructuring-assignment/tuple_destructure_fail.rs10
-rw-r--r--src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr31
-rw-r--r--src/test/ui/destructuring-assignment/warn-unused-duplication.rs23
-rw-r--r--src/test/ui/destructuring-assignment/warn-unused-duplication.stderr15
-rw-r--r--src/test/ui/feature-gates/feature-gate-cfg-panic.rs11
-rw-r--r--src/test/ui/feature-gates/feature-gate-cfg-panic.stderr21
-rw-r--r--src/test/ui/feature-gates/feature-gate-destructuring_assignment.rs4
-rw-r--r--src/test/ui/feature-gates/feature-gate-destructuring_assignment.stderr14
-rw-r--r--src/test/ui/fmt/format-args-capture.rs13
-rw-r--r--src/test/ui/issues/issue-68696-catch-during-unwind.rs4
-rw-r--r--src/test/ui/issues/issue-76547.nll.stderr20
-rw-r--r--src/test/ui/issues/issue-76547.rs38
-rw-r--r--src/test/ui/issues/issue-76547.stderr25
-rw-r--r--src/test/ui/macros/issue-78892-substitution-in-statement-attr.rs14
-rw-r--r--src/test/ui/nll/issue-58053.stderr4
-rw-r--r--src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs2
-rw-r--r--src/test/ui/regions/region-bound-extra-bound-in-inherent-impl.rs2
-rw-r--r--src/test/ui/regions/region-bound-same-bounds-in-trait-and-impl.rs2
-rw-r--r--src/test/ui/regions/region-object-lifetime-1.rs2
-rw-r--r--src/test/ui/regions/region-object-lifetime-3.rs2
-rw-r--r--src/test/ui/regions/regions-implied-bounds-projection-gap-2.rs2
-rw-r--r--src/test/ui/regions/regions-implied-bounds-projection-gap-3.rs2
-rw-r--r--src/test/ui/regions/regions-implied-bounds-projection-gap-4.rs2
-rw-r--r--src/test/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs2
-rw-r--r--src/test/ui/regions/regions-outlives-nominal-type-enum-region.rs2
-rw-r--r--src/test/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs2
-rw-r--r--src/test/ui/regions/regions-outlives-nominal-type-enum-type.rs2
-rw-r--r--src/test/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs2
-rw-r--r--src/test/ui/regions/regions-outlives-nominal-type-struct-region.rs2
-rw-r--r--src/test/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs2
-rw-r--r--src/test/ui/regions/regions-outlives-nominal-type-struct-type.rs2
-rw-r--r--src/test/ui/regions/regions-outlives-projection-hrtype.rs2
-rw-r--r--src/test/ui/regions/regions-outlives-projection-trait-def.rs2
-rw-r--r--src/test/ui/regions/regions-outlives-scalar.rs2
-rw-r--r--src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr21
-rw-r--r--src/test/ui/self/elision/lt-ref-self-async.stderr42
-rw-r--r--src/test/ui/self/elision/ref-mut-self-async.stderr42
-rw-r--r--src/test/ui/self/elision/ref-mut-struct-async.stderr35
-rw-r--r--src/test/ui/self/elision/ref-self-async.stderr49
-rw-r--r--src/test/ui/self/elision/ref-struct-async.stderr35
-rw-r--r--src/test/ui/test-attrs/test-allow-fail-attr.rs3
-rw-r--r--src/tools/build-manifest/src/main.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/loops.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs8
371 files changed, 4451 insertions, 2554 deletions
diff --git a/.gitattributes b/.gitattributes
index a7de7ce8559..2c5c37007d5 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -3,7 +3,7 @@
 * text=auto eol=lf
 *.cpp rust
 *.h rust
-*.rs rust
+*.rs rust diff=rust
 *.fixed linguist-language=Rust
 src/etc/installer/gfx/* binary
 *.woff binary
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c45832e8153..84e39a4189e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -154,6 +154,11 @@ jobs:
     strategy:
       matrix:
         include:
+          - name: aarch64-gnu
+            os:
+              - self-hosted
+              - ARM64
+              - linux
           - name: arm-android
             os: ubuntu-latest-xl
             env: {}
@@ -178,9 +183,6 @@ jobs:
           - name: dist-i586-gnu-i586-i686-musl
             os: ubuntu-latest-xl
             env: {}
-          - name: dist-i686-freebsd
-            os: ubuntu-latest-xl
-            env: {}
           - name: dist-i686-linux
             os: ubuntu-latest-xl
             env: {}
@@ -497,116 +499,6 @@ jobs:
           AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
           AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
         if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
-  auto-fallible:
-    name: auto-fallible
-    env:
-      CI_JOB_NAME: "${{ matrix.name }}"
-      SCCACHE_BUCKET: rust-lang-gha-caches
-      DEPLOY_BUCKET: rust-lang-gha
-      TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
-      TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues"
-      TOOLSTATE_PUBLISH: 1
-      CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
-      ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
-      CACHE_DOMAIN: ci-caches-gha.rust-lang.org
-    if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'"
-    strategy:
-      fail-fast: false
-      matrix:
-        include:
-          - name: aarch64-gnu
-            os:
-              - self-hosted
-              - ARM64
-              - linux
-    timeout-minutes: 600
-    runs-on: "${{ matrix.os }}"
-    steps:
-      - name: disable git crlf conversion
-        run: git config --global core.autocrlf false
-      - name: checkout the source code
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 2
-      - name: configure the PR in which the error message will be posted
-        run: "echo \"[CI_PR_NUMBER=$num]\""
-        env:
-          num: "${{ github.event.number }}"
-        if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
-      - name: add extra environment variables
-        run: src/ci/scripts/setup-environment.sh
-        env:
-          EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
-        if: success() && !env.SKIP_JOB
-      - name: decide whether to skip this job
-        run: src/ci/scripts/should-skip-this.sh
-        if: success() && !env.SKIP_JOB
-      - name: configure GitHub Actions to kill the build when outdated
-        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'"
-      - name: collect CPU statistics
-        run: src/ci/scripts/collect-cpu-stats.sh
-        if: success() && !env.SKIP_JOB
-      - name: show the current environment
-        run: src/ci/scripts/dump-environment.sh
-        if: success() && !env.SKIP_JOB
-      - name: install awscli
-        run: src/ci/scripts/install-awscli.sh
-        if: success() && !env.SKIP_JOB
-      - name: install sccache
-        run: src/ci/scripts/install-sccache.sh
-        if: success() && !env.SKIP_JOB
-      - name: select Xcode
-        run: src/ci/scripts/select-xcode.sh
-        if: success() && !env.SKIP_JOB
-      - name: install clang
-        run: src/ci/scripts/install-clang.sh
-        if: success() && !env.SKIP_JOB
-      - name: install WIX
-        run: src/ci/scripts/install-wix.sh
-        if: success() && !env.SKIP_JOB
-      - name: ensure the build happens on a partition with enough space
-        run: src/ci/scripts/symlink-build-dir.sh
-        if: success() && !env.SKIP_JOB
-      - name: disable git crlf conversion
-        run: src/ci/scripts/disable-git-crlf-conversion.sh
-        if: success() && !env.SKIP_JOB
-      - name: install MSYS2
-        run: src/ci/scripts/install-msys2.sh
-        if: success() && !env.SKIP_JOB
-      - name: install MinGW
-        run: src/ci/scripts/install-mingw.sh
-        if: success() && !env.SKIP_JOB
-      - name: install ninja
-        run: src/ci/scripts/install-ninja.sh
-        if: success() && !env.SKIP_JOB
-      - name: enable ipv6 on Docker
-        run: src/ci/scripts/enable-docker-ipv6.sh
-        if: success() && !env.SKIP_JOB
-      - name: disable git crlf conversion
-        run: src/ci/scripts/disable-git-crlf-conversion.sh
-        if: success() && !env.SKIP_JOB
-      - name: checkout submodules
-        run: src/ci/scripts/checkout-submodules.sh
-        if: success() && !env.SKIP_JOB
-      - name: ensure line endings are correct
-        run: src/ci/scripts/verify-line-endings.sh
-        if: success() && !env.SKIP_JOB
-      - name: run the build
-        run: src/ci/scripts/run-build-from-ci.sh
-        env:
-          AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
-          AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
-          TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
-        if: success() && !env.SKIP_JOB
-      - name: upload artifacts to S3
-        run: src/ci/scripts/upload-artifacts.sh
-        env:
-          AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
-          AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
-        if: "success() && !env.SKIP_JOB && (github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1')"
   try:
     name: try
     env:
diff --git a/Cargo.lock b/Cargo.lock
index 30b7628120b..45a19fd7963 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -460,9 +460,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.32.0"
+version = "0.36.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d072b2ba723f0bada7c515d8b3725224bc4f5052d2a92dcbeb0b118ff37084a"
+checksum = "9f88ce4deae1dace71e49b7611cfae2d5489de3530d6daba5758043c47ac3a10"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -472,9 +472,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-engine"
-version = "0.32.0"
+version = "0.36.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb5475f6083d6d6c509e1c335c4f69ad04144ac090faa1afb134a53c3695841"
+checksum = "0e34c9b1b10616782143d7f49490f91ae94afaf2202de3ab0b2835e78b4f0ccc"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -485,9 +485,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.32.0"
+version = "0.36.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f60cdb0e18c5455cb6a85e8464aad3622b70476018edfa8845691df66f7e9a05"
+checksum = "63362c629c2014ab639b04029070763fb8224df136d1363d30e9ece4c8877da3"
 dependencies = [
  "chalk-derive",
  "lazy_static",
@@ -495,9 +495,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.32.0"
+version = "0.36.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "981534d499a8476ecc0b520be4d3864757f96211826a75360fbf2cb6fae362ab"
+checksum = "cac338a67af52a7f50bb2f8232e730a3518ce432dbe303246acfe525ddd838c7"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 5c0c8df2e02..2ff65737444 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -66,7 +66,7 @@ impl NestedMetaItem {
         self.meta_item().and_then(|meta_item| meta_item.ident())
     }
     pub fn name_or_empty(&self) -> Symbol {
-        self.ident().unwrap_or(Ident::invalid()).name
+        self.ident().unwrap_or_else(Ident::invalid).name
     }
 
     /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
@@ -139,7 +139,7 @@ impl Attribute {
         }
     }
     pub fn name_or_empty(&self) -> Symbol {
-        self.ident().unwrap_or(Ident::invalid()).name
+        self.ident().unwrap_or_else(Ident::invalid).name
     }
 
     pub fn value_str(&self) -> Option<Symbol> {
@@ -183,7 +183,7 @@ impl MetaItem {
         if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
     }
     pub fn name_or_empty(&self) -> Symbol {
-        self.ident().unwrap_or(Ident::invalid()).name
+        self.ident().unwrap_or_else(Ident::invalid).name
     }
 
     // Example:
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 91ba069cf60..2697b017572 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -210,11 +210,8 @@ pub trait MutVisitor: Sized {
         noop_visit_local(l, self);
     }
 
-    fn visit_mac(&mut self, _mac: &mut MacCall) {
-        panic!("visit_mac disabled by default");
-        // N.B., see note about macros above. If you really want a visitor that
-        // works on macros, use this definition in your trait impl:
-        //   mut_visit::noop_visit_mac(_mac, self);
+    fn visit_mac_call(&mut self, mac: &mut MacCall) {
+        noop_visit_mac(mac, self);
     }
 
     fn visit_macro_def(&mut self, def: &mut MacroDef) {
@@ -494,7 +491,7 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
             vis.visit_id(id);
             visit_vec(bounds, |bound| vis.visit_param_bound(bound));
         }
-        TyKind::MacCall(mac) => vis.visit_mac(mac),
+        TyKind::MacCall(mac) => vis.visit_mac_call(mac),
     }
     vis.visit_span(span);
     visit_lazy_tts(tokens, vis);
@@ -962,7 +959,7 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
             vis.visit_generics(generics);
             visit_bounds(bounds, vis);
         }
-        ItemKind::MacCall(m) => vis.visit_mac(m),
+        ItemKind::MacCall(m) => vis.visit_mac_call(m),
         ItemKind::MacroDef(def) => vis.visit_macro_def(def),
     }
 }
@@ -991,7 +988,7 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
             visit_bounds(bounds, visitor);
             visit_opt(ty, |ty| visitor.visit_ty(ty));
         }
-        AssocItemKind::MacCall(mac) => visitor.visit_mac(mac),
+        AssocItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
     }
     visitor.visit_span(span);
     visit_lazy_tts(tokens, visitor);
@@ -1081,7 +1078,7 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
             visit_bounds(bounds, visitor);
             visit_opt(ty, |ty| visitor.visit_ty(ty));
         }
-        ForeignItemKind::MacCall(mac) => visitor.visit_mac(mac),
+        ForeignItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
     }
     visitor.visit_span(span);
     visit_lazy_tts(tokens, visitor);
@@ -1121,7 +1118,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
             visit_vec(elems, |elem| vis.visit_pat(elem))
         }
         PatKind::Paren(inner) => vis.visit_pat(inner),
-        PatKind::MacCall(mac) => vis.visit_mac(mac),
+        PatKind::MacCall(mac) => vis.visit_mac_call(mac),
     }
     vis.visit_span(span);
     visit_lazy_tts(tokens, vis);
@@ -1287,7 +1284,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
             }
             visit_vec(inputs, |(_c, expr)| vis.visit_expr(expr));
         }
-        ExprKind::MacCall(mac) => vis.visit_mac(mac),
+        ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
         ExprKind::Struct(path, fields, expr) => {
             vis.visit_path(path);
             fields.flat_map_in_place(|field| vis.flat_map_field(field));
@@ -1350,7 +1347,7 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
         StmtKind::Empty => smallvec![StmtKind::Empty],
         StmtKind::MacCall(mut mac) => {
             let MacCallStmt { mac: mac_, style: _, attrs } = mac.deref_mut();
-            vis.visit_mac(mac_);
+            vis.visit_mac_call(mac_);
             visit_thin_attrs(attrs, vis);
             smallvec![StmtKind::MacCall(mac)]
         }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 6f65c0a1efc..72e901fb90f 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -176,13 +176,8 @@ pub trait Visitor<'ast>: Sized {
     fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
         walk_lifetime(self, lifetime)
     }
-    fn visit_mac(&mut self, _mac: &'ast MacCall) {
-        panic!("visit_mac disabled by default");
-        // N.B., see note about macros above.
-        // if you really want a visitor that
-        // works on macros, use this
-        // definition in your trait impl:
-        // visit::walk_mac(self, _mac)
+    fn visit_mac_call(&mut self, mac: &'ast MacCall) {
+        walk_mac(self, mac)
     }
     fn visit_mac_def(&mut self, _mac: &'ast MacroDef, _id: NodeId) {
         // Nothing to do
@@ -346,7 +341,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_param_bound, bounds);
         }
-        ItemKind::MacCall(ref mac) => visitor.visit_mac(mac),
+        ItemKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
         ItemKind::MacroDef(ref ts) => visitor.visit_mac_def(ts, item.id),
     }
     walk_list!(visitor, visit_attribute, &item.attrs);
@@ -414,7 +409,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
         }
         TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
         TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
-        TyKind::MacCall(ref mac) => visitor.visit_mac(mac),
+        TyKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
         TyKind::Never | TyKind::CVarArgs => {}
     }
 }
@@ -532,7 +527,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
         PatKind::Tuple(ref elems) | PatKind::Slice(ref elems) | PatKind::Or(ref elems) => {
             walk_list!(visitor, visit_pat, elems);
         }
-        PatKind::MacCall(ref mac) => visitor.visit_mac(mac),
+        PatKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
     }
 }
 
@@ -557,7 +552,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
             walk_list!(visitor, visit_ty, ty);
         }
         ForeignItemKind::MacCall(mac) => {
-            visitor.visit_mac(mac);
+            visitor.visit_mac_call(mac);
         }
     }
 }
@@ -662,7 +657,7 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
             walk_list!(visitor, visit_ty, ty);
         }
         AssocItemKind::MacCall(mac) => {
-            visitor.visit_mac(mac);
+            visitor.visit_mac_call(mac);
         }
     }
 }
@@ -692,7 +687,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) {
         StmtKind::Empty => {}
         StmtKind::MacCall(ref mac) => {
             let MacCallStmt { ref mac, style: _, ref attrs } = **mac;
-            visitor.visit_mac(mac);
+            visitor.visit_mac_call(mac);
             for attr in attrs.iter() {
                 visitor.visit_attribute(attr);
             }
@@ -823,7 +818,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         ExprKind::Ret(ref optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
         }
-        ExprKind::MacCall(ref mac) => visitor.visit_mac(mac),
+        ExprKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
         ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
         ExprKind::InlineAsm(ref ia) => {
             for (op, _) in &ia.operands {
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index a6ac056b93b..1f2aba2b27e 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -9,6 +9,7 @@ use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
+use rustc_session::parse::feature_err;
 use rustc_span::hygiene::ForLoopLoc;
 use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -146,7 +147,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     hir::ExprKind::Block(self.lower_block(blk, opt_label.is_some()), opt_label)
                 }
                 ExprKind::Assign(ref el, ref er, span) => {
-                    hir::ExprKind::Assign(self.lower_expr(el), self.lower_expr(er), span)
+                    self.lower_expr_assign(el, er, span, e.span)
                 }
                 ExprKind::AssignOp(op, ref el, ref er) => hir::ExprKind::AssignOp(
                     self.lower_binop(op),
@@ -840,6 +841,134 @@ impl<'hir> LoweringContext<'_, 'hir> {
         })
     }
 
+    /// Destructure the LHS of complex assignments.
+    /// For instance, lower `(a, b) = t` to `{ let (lhs1, lhs2) = t; a = lhs1; b = lhs2; }`.
+    fn lower_expr_assign(
+        &mut self,
+        lhs: &Expr,
+        rhs: &Expr,
+        eq_sign_span: Span,
+        whole_span: Span,
+    ) -> hir::ExprKind<'hir> {
+        // Return early in case of an ordinary assignment.
+        fn is_ordinary(lhs: &Expr) -> bool {
+            match &lhs.kind {
+                ExprKind::Tup(..) => false,
+                ExprKind::Paren(e) => {
+                    match e.kind {
+                        // We special-case `(..)` for consistency with patterns.
+                        ExprKind::Range(None, None, RangeLimits::HalfOpen) => false,
+                        _ => is_ordinary(e),
+                    }
+                }
+                _ => true,
+            }
+        }
+        if is_ordinary(lhs) {
+            return hir::ExprKind::Assign(self.lower_expr(lhs), self.lower_expr(rhs), eq_sign_span);
+        }
+        if !self.sess.features_untracked().destructuring_assignment {
+            feature_err(
+                &self.sess.parse_sess,
+                sym::destructuring_assignment,
+                eq_sign_span,
+                "destructuring assignments are unstable",
+            )
+            .span_label(lhs.span, "cannot assign to this expression")
+            .emit();
+        }
+
+        let mut assignments = vec![];
+
+        // The LHS becomes a pattern: `(lhs1, lhs2)`.
+        let pat = self.destructure_assign(lhs, eq_sign_span, &mut assignments);
+        let rhs = self.lower_expr(rhs);
+
+        // Introduce a `let` for destructuring: `let (lhs1, lhs2) = t`.
+        let destructure_let = self.stmt_let_pat(
+            ThinVec::new(),
+            whole_span,
+            Some(rhs),
+            pat,
+            hir::LocalSource::AssignDesugar(eq_sign_span),
+        );
+
+        // `a = lhs1; b = lhs2;`.
+        let stmts = self
+            .arena
+            .alloc_from_iter(std::iter::once(destructure_let).chain(assignments.into_iter()));
+
+        // Wrap everything in a block.
+        hir::ExprKind::Block(&self.block_all(whole_span, stmts, None), None)
+    }
+
+    /// Convert the LHS of a destructuring assignment to a pattern.
+    /// Each sub-assignment is recorded in `assignments`.
+    fn destructure_assign(
+        &mut self,
+        lhs: &Expr,
+        eq_sign_span: Span,
+        assignments: &mut Vec<hir::Stmt<'hir>>,
+    ) -> &'hir hir::Pat<'hir> {
+        match &lhs.kind {
+            // Tuples.
+            ExprKind::Tup(elements) => {
+                let (pats, rest) =
+                    self.destructure_sequence(elements, "tuple", eq_sign_span, assignments);
+                let tuple_pat = hir::PatKind::Tuple(pats, rest.map(|r| r.0));
+                return self.pat_without_dbm(lhs.span, tuple_pat);
+            }
+            ExprKind::Paren(e) => {
+                // We special-case `(..)` for consistency with patterns.
+                if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
+                    let tuple_pat = hir::PatKind::Tuple(&[], Some(0));
+                    return self.pat_without_dbm(lhs.span, tuple_pat);
+                } else {
+                    return self.destructure_assign(e, eq_sign_span, assignments);
+                }
+            }
+            _ => {}
+        }
+        // Treat all other cases as normal lvalue.
+        let ident = Ident::new(sym::lhs, lhs.span);
+        let (pat, binding) = self.pat_ident(lhs.span, ident);
+        let ident = self.expr_ident(lhs.span, ident, binding);
+        let assign = hir::ExprKind::Assign(self.lower_expr(lhs), ident, eq_sign_span);
+        let expr = self.expr(lhs.span, assign, ThinVec::new());
+        assignments.push(self.stmt_expr(lhs.span, expr));
+        pat
+    }
+
+    /// Destructure a sequence of expressions occurring on the LHS of an assignment.
+    /// Such a sequence occurs in a tuple (struct)/slice.
+    /// Return a sequence of corresponding patterns, and the index and the span of `..` if it
+    /// exists.
+    /// Each sub-assignment is recorded in `assignments`.
+    fn destructure_sequence(
+        &mut self,
+        elements: &[AstP<Expr>],
+        ctx: &str,
+        eq_sign_span: Span,
+        assignments: &mut Vec<hir::Stmt<'hir>>,
+    ) -> (&'hir [&'hir hir::Pat<'hir>], Option<(usize, Span)>) {
+        let mut rest = None;
+        let elements =
+            self.arena.alloc_from_iter(elements.iter().enumerate().filter_map(|(i, e)| {
+                // Check for `..` pattern.
+                if let ExprKind::Range(None, None, RangeLimits::HalfOpen) = e.kind {
+                    if let Some((_, prev_span)) = rest {
+                        self.ban_extra_rest_pat(e.span, prev_span, ctx);
+                    } else {
+                        rest = Some((i, e.span));
+                    }
+                    None
+                } else {
+                    Some(self.destructure_assign(e, eq_sign_span, assignments))
+                }
+            }));
+        (elements, rest)
+    }
+
     /// Desugar `<start>..=<end>` into `std::ops::RangeInclusive::new(<start>, <end>)`.
     fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> {
         let e1 = self.lower_expr_mut(e1);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 9a5fd2307d5..549b66e2d36 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2534,6 +2534,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 hir_id,
                 kind: hir::PatKind::Binding(bm, hir_id, ident.with_span_pos(span), None),
                 span,
+                default_binding_modes: true,
             }),
             hir_id,
         )
@@ -2544,7 +2545,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 
     fn pat(&mut self, span: Span, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
-        self.arena.alloc(hir::Pat { hir_id: self.next_id(), kind, span })
+        self.arena.alloc(hir::Pat {
+            hir_id: self.next_id(),
+            kind,
+            span,
+            default_binding_modes: true,
+        })
+    }
+
+    fn pat_without_dbm(&mut self, span: Span, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
+        self.arena.alloc(hir::Pat {
+            hir_id: self.next_id(),
+            kind,
+            span,
+            default_binding_modes: false,
+        })
     }
 
     fn ty_path(
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index a1cbcde1f42..e4e7b24d29e 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -273,11 +273,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
     /// Construct a `Pat` with the `HirId` of `p.id` lowered.
     fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
-        self.arena.alloc(hir::Pat { hir_id: self.lower_node_id(p.id), kind, span: p.span })
+        self.arena.alloc(hir::Pat {
+            hir_id: self.lower_node_id(p.id),
+            kind,
+            span: p.span,
+            default_binding_modes: true,
+        })
     }
 
     /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
-    fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
+    crate fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
         self.diagnostic()
             .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
             .span_label(sp, &format!("can only be used once per {} pattern", ctx))
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index d6585bcc425..bb1d2967d6a 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -796,7 +796,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
     fn visit_expr(&mut self, expr: &'a Expr) {
         match &expr.kind {
-            ExprKind::LlvmInlineAsm(..) if !self.session.target.options.allow_asm => {
+            ExprKind::LlvmInlineAsm(..) if !self.session.target.allow_asm => {
                 struct_span_err!(
                     self.session,
                     expr.span,
diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs
index 706dca2b7f4..6efc78c8842 100644
--- a/compiler/rustc_ast_passes/src/node_count.rs
+++ b/compiler/rustc_ast_passes/src/node_count.rs
@@ -114,9 +114,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_lifetime(self, lifetime)
     }
-    fn visit_mac(&mut self, _mac: &MacCall) {
+    fn visit_mac_call(&mut self, mac: &MacCall) {
         self.count += 1;
-        walk_mac(self, _mac)
+        walk_mac(self, mac)
     }
     fn visit_path(&mut self, path: &Path, _id: NodeId) {
         self.count += 1;
diff --git a/compiler/rustc_ast_passes/src/show_span.rs b/compiler/rustc_ast_passes/src/show_span.rs
index 053aba86222..6cef26a13e6 100644
--- a/compiler/rustc_ast_passes/src/show_span.rs
+++ b/compiler/rustc_ast_passes/src/show_span.rs
@@ -54,10 +54,6 @@ impl<'a> Visitor<'a> for ShowSpanVisitor<'a> {
         }
         visit::walk_ty(self, t);
     }
-
-    fn visit_mac(&mut self, mac: &'a ast::MacCall) {
-        visit::walk_mac(self, mac);
-    }
 }
 
 pub fn run(span_diagnostic: &rustc_errors::Handler, mode: &str, krate: &ast::Crate) {
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 2e52d2a3923..0642edff6b6 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -358,7 +358,7 @@ fn find_type_parameters(
             visit::walk_ty(self, ty)
         }
 
-        fn visit_mac(&mut self, mac: &ast::MacCall) {
+        fn visit_mac_call(&mut self, mac: &ast::MacCall) {
             self.cx.span_err(mac.span(), "`derive` cannot be used on items with type macros");
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index c6ab3faf568..4e91436199a 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -344,10 +344,6 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
         visit::walk_item(self, item);
         self.in_root = prev_in_root;
     }
-
-    fn visit_mac(&mut self, mac: &'a ast::MacCall) {
-        visit::walk_mac(self, mac)
-    }
 }
 
 // Creates a new module which looks like:
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index da74f0aeaa1..9976140d6bd 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -37,7 +37,7 @@ struct TestCtxt<'a> {
 pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) {
     let span_diagnostic = sess.diagnostic();
     let panic_strategy = sess.panic_strategy();
-    let platform_panic_strategy = sess.target.options.panic_strategy;
+    let platform_panic_strategy = sess.target.panic_strategy;
 
     // Check for #![reexport_test_harness_main = "some_name"] which gives the
     // main test function the name `some_name` without hygiene. This needs to be
@@ -130,10 +130,6 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
         }
         smallvec![P(item)]
     }
-
-    fn visit_mac(&mut self, _mac: &mut ast::MacCall) {
-        // Do nothing.
-    }
 }
 
 // Beware, this is duplicated in librustc_passes/entry.rs (with
@@ -201,10 +197,6 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
 
         smallvec![item]
     }
-
-    fn visit_mac(&mut self, _mac: &mut ast::MacCall) {
-        // Do nothing.
-    }
 }
 
 /// Crawl over the crate, inserting test reexports and the test main function
@@ -290,7 +282,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
     let mut test_runner = cx
         .test_runner
         .clone()
-        .unwrap_or(ecx.path(sp, vec![test_id, Ident::from_str_and_span(runner_name, sp)]));
+        .unwrap_or_else(|| ecx.path(sp, vec![test_id, Ident::from_str_and_span(runner_name, sp)]));
 
     test_runner.span = sp;
 
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
index 9a970efbcfd..daf9fa6158f 100644
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ b/compiler/rustc_codegen_cranelift/src/archive.rs
@@ -63,9 +63,9 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
             sess,
             dst: output.to_path_buf(),
             lib_search_paths: archive_search_paths(sess),
-            use_gnu_style_archive: sess.target.options.archive_format == "gnu",
+            use_gnu_style_archive: sess.target.archive_format == "gnu",
             // FIXME fix builtin ranlib on macOS
-            no_builtin_ranlib: sess.target.options.is_like_osx,
+            no_builtin_ranlib: sess.target.is_like_osx,
 
             src_archives,
             entries,
diff --git a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
index 71ef4d22673..cd01acc9a83 100644
--- a/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
@@ -27,8 +27,8 @@ impl rustc_driver::Callbacks for CraneliftPassesCallbacks {
         config.opts.cg.panic = Some(PanicStrategy::Abort);
         config.opts.debugging_opts.panic_abort_tests = true;
         config.opts.maybe_sysroot = Some(
-            config.opts.maybe_sysroot.clone().unwrap_or(
-                std::env::current_exe()
+            config.opts.maybe_sysroot.clone().unwrap_or_else(
+                || std::env::current_exe()
                     .unwrap()
                     .parent()
                     .unwrap()
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index eda77bf19d3..466758f2f86 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -361,13 +361,11 @@ impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> {
     where
         T: TypeFoldable<'tcx> + Copy,
     {
-        if let Some(substs) = self.instance.substs_for_mir_body() {
-            self.tcx
-                .subst_and_normalize_erasing_regions(substs, ty::ParamEnv::reveal_all(), value)
-        } else {
-            self.tcx
-                .normalize_erasing_regions(ty::ParamEnv::reveal_all(), *value)
-        }
+        self.instance.subst_mir_and_normalize_erasing_regions(
+            self.tcx,
+            ty::ParamEnv::reveal_all(),
+            value
+        )
     }
 
     pub(crate) fn clif_type(&self, ty: Ty<'tcx>) -> Option<Type> {
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
index cbf9522b1d7..85e8158af27 100644
--- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
@@ -50,7 +50,7 @@ impl<'tcx> DebugContext<'tcx> {
             // TODO: this should be configurable
             // macOS doesn't seem to support DWARF > 3
             // 5 version is required for md5 file hash
-            version: if tcx.sess.target.options.is_like_osx {
+            version: if tcx.sess.target.is_like_osx {
                 3
             } else {
                 // FIXME change to version 5 once the gdb and lldb shipping with the latest debian
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index ff0b994c9a9..c0245aa1e02 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -320,8 +320,8 @@ fn codegen_global_asm(tcx: TyCtxt<'_>, cgu_name: &str, global_asm: &str) {
     }
 
     if cfg!(not(feature = "inline_asm"))
-        || tcx.sess.target.options.is_like_osx
-        || tcx.sess.target.options.is_like_windows
+        || tcx.sess.target.is_like_osx
+        || tcx.sess.target.is_like_windows
     {
         if global_asm.contains("__rust_probestack") {
             return;
diff --git a/compiler/rustc_codegen_cranelift/src/metadata.rs b/compiler/rustc_codegen_cranelift/src/metadata.rs
index cda2a187ff9..2e3b9fb8364 100644
--- a/compiler/rustc_codegen_cranelift/src/metadata.rs
+++ b/compiler/rustc_codegen_cranelift/src/metadata.rs
@@ -101,7 +101,7 @@ pub(crate) fn write_metadata<P: WriteMetadata>(
     product.add_rustc_section(
         rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx),
         compressed,
-        tcx.sess.target.options.is_like_osx,
+        tcx.sess.target.is_like_osx,
     );
 
     metadata
diff --git a/compiler/rustc_codegen_cranelift/src/toolchain.rs b/compiler/rustc_codegen_cranelift/src/toolchain.rs
index 463afaf7cc5..735c59d70c1 100644
--- a/compiler/rustc_codegen_cranelift/src/toolchain.rs
+++ b/compiler/rustc_codegen_cranelift/src/toolchain.rs
@@ -91,7 +91,7 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
                 } else if stem == "link" || stem == "lld-link" {
                     LinkerFlavor::Msvc
                 } else if stem == "lld" || stem == "rust-lld" {
-                    LinkerFlavor::Lld(sess.target.options.lld_flavor)
+                    LinkerFlavor::Lld(sess.target.lld_flavor)
                 } else {
                     // fall back to the value in the target spec
                     sess.target.linker_flavor
@@ -115,7 +115,7 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
 
     if let Some(ret) = infer_from(
         sess,
-        sess.target.options.linker.clone().map(PathBuf::from),
+        sess.target.linker.clone().map(PathBuf::from),
         Some(sess.target.linker_flavor),
     ) {
         return ret;
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index f7d82ff78fa..a5ea0b2a74c 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen(
         let name = format!("__rust_{}", method.name);
         let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
 
-        if tcx.sess.target.options.default_hidden_visibility {
+        if tcx.sess.target.default_hidden_visibility {
             llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
         }
         if tcx.sess.must_emit_unwind_tables() {
@@ -98,7 +98,7 @@ pub(crate) unsafe fn codegen(
     // -> ! DIFlagNoReturn
     llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn);
 
-    if tcx.sess.target.options.default_hidden_visibility {
+    if tcx.sess.target.default_hidden_visibility {
         llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
     }
     if tcx.sess.must_emit_unwind_tables() {
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index d4872aedd70..87bcce07b34 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -90,8 +90,7 @@ fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
 
         // The function name varies on platforms.
         // See test/CodeGen/mcount.c in clang.
-        let mcount_name =
-            CString::new(cx.sess().target.options.target_mcount.as_str().as_bytes()).unwrap();
+        let mcount_name = CString::new(cx.sess().target.mcount.as_str().as_bytes()).unwrap();
 
         llvm::AddFunctionAttrStringValue(
             llfn,
@@ -105,7 +104,7 @@ fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
 fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     // Only use stack probes if the target specification indicates that we
     // should be using stack probes
-    if !cx.sess().target.options.stack_probes {
+    if !cx.sess().target.stack_probes {
         return;
     }
 
@@ -174,7 +173,6 @@ pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> {
         .split(',')
         .filter(|f| !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s)));
     sess.target
-        .options
         .features
         .split(',')
         .chain(cmdline)
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 595655b2ca2..4e7213853b0 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -206,7 +206,7 @@ impl<'a> LlvmArchiveBuilder<'a> {
     }
 
     fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> {
-        let kind = &*self.config.sess.target.options.archive_format;
+        let kind = &*self.config.sess.target.archive_format;
         kind.parse().map_err(|_| kind)
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index f13c2d312df..e6acb6860be 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -129,13 +129,13 @@ pub fn target_machine_factory(
     let use_softfp = sess.opts.cg.soft_float;
 
     let ffunction_sections =
-        sess.opts.debugging_opts.function_sections.unwrap_or(sess.target.options.function_sections);
+        sess.opts.debugging_opts.function_sections.unwrap_or(sess.target.function_sections);
     let fdata_sections = ffunction_sections;
 
     let code_model = to_llvm_code_model(sess.code_model());
 
     let features = attributes::llvm_target_features(sess).collect::<Vec<_>>();
-    let mut singlethread = sess.target.options.singlethread;
+    let mut singlethread = sess.target.singlethread;
 
     // On the wasm target once the `atomics` feature is enabled that means that
     // we're no longer single-threaded, or otherwise we don't want LLVM to
@@ -151,22 +151,16 @@ pub fn target_machine_factory(
     let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
     let features = features.join(",");
     let features = CString::new(features).unwrap();
-    let abi = SmallCStr::new(&sess.target.options.llvm_abiname);
-    let trap_unreachable = sess.target.options.trap_unreachable;
+    let abi = SmallCStr::new(&sess.target.llvm_abiname);
+    let trap_unreachable = sess.target.trap_unreachable;
     let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;
 
     let asm_comments = sess.asm_comments();
-    let relax_elf_relocations = sess
-        .opts
-        .debugging_opts
-        .relax_elf_relocations
-        .unwrap_or(sess.target.options.relax_elf_relocations);
-
-    let use_init_array = !sess
-        .opts
-        .debugging_opts
-        .use_ctors_section
-        .unwrap_or(sess.target.options.use_ctors_section);
+    let relax_elf_relocations =
+        sess.opts.debugging_opts.relax_elf_relocations.unwrap_or(sess.target.relax_elf_relocations);
+
+    let use_init_array =
+        !sess.opts.debugging_opts.use_ctors_section.unwrap_or(sess.target.use_ctors_section);
 
     Arc::new(move || {
         let tm = unsafe {
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index e2003472d12..367c1f4811c 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -176,7 +176,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
         // should use dllimport for functions.
         if cx.use_dll_storage_attrs
             && tcx.is_dllimport_foreign_item(instance_def_id)
-            && tcx.sess.target.target_env != "gnu"
+            && tcx.sess.target.env != "gnu"
         {
             unsafe {
                 llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 90a51f75e0e..14dd245625d 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -91,7 +91,7 @@ fn set_global_alignment(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Alig
     // The target may require greater alignment for globals than the type does.
     // Note: GCC and Clang also allow `__attribute__((aligned))` on variables,
     // which can force it to be smaller.  Rust doesn't support this yet.
-    if let Some(min) = cx.sess().target.options.min_global_align {
+    if let Some(min) = cx.sess().target.min_global_align {
         match Align::from_bits(min) {
             Ok(min) => align = align.max(min),
             Err(err) => {
@@ -283,7 +283,7 @@ impl CodegenCx<'ll, 'tcx> {
             // argument validation.
             debug_assert!(
                 !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled()
-                    && self.tcx.sess.target.options.is_like_windows
+                    && self.tcx.sess.target.is_like_windows
                     && self.tcx.sess.opts.cg.prefer_dynamic)
             );
 
@@ -435,7 +435,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
                 // will use load-unaligned instructions instead, and thus avoiding the crash.
                 //
                 // We could remove this hack whenever we decide to drop macOS 10.10 support.
-                if self.tcx.sess.target.options.is_like_osx {
+                if self.tcx.sess.target.is_like_osx {
                     // The `inspect` method is okay here because we checked relocations, and
                     // because we are doing this access to inspect the final interpreter state
                     // (not as part of the interpreter execution).
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 253e02bd082..b6e922ca545 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -129,7 +129,7 @@ pub unsafe fn create_module(
     }
 
     // Ensure the data-layout values hardcoded remain the defaults.
-    if sess.target.options.is_builtin {
+    if sess.target.is_builtin {
         let tm = crate::back::write::create_informational_target_machine(tcx.sess);
         llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm);
         llvm::LLVMRustDisposeTargetMachine(tm);
@@ -190,7 +190,7 @@ pub unsafe fn create_module(
     }
 
     // Control Flow Guard is currently only supported by the MSVC linker on Windows.
-    if sess.target.options.is_like_msvc {
+    if sess.target.is_like_msvc {
         match sess.opts.cg.control_flow_guard {
             CFGuard::Disabled => {}
             CFGuard::NoChecks => {
@@ -265,7 +265,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         // linker will take care of everything. Fixing this problem will likely
         // require adding a few attributes to Rust itself (feature gated at the
         // start) and then strongly recommending static linkage on Windows!
-        let use_dll_storage_attrs = tcx.sess.target.options.is_like_windows;
+        let use_dll_storage_attrs = tcx.sess.target.is_like_windows;
 
         let check_overflow = tcx.sess.overflow_checks();
 
@@ -839,7 +839,7 @@ impl CodegenCx<'b, 'tcx> {
             return eh_catch_typeinfo;
         }
         let tcx = self.tcx;
-        assert!(self.sess().target.options.is_like_emscripten);
+        assert!(self.sess().target.is_like_emscripten);
         let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() {
             Some(def_id) => self.get_static(def_id),
             _ => {
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 79721ff7e2d..38f50a6d621 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -67,5 +67,5 @@ pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
 
     !omit_gdb_pretty_printer_section
         && cx.sess().opts.debuginfo != DebugInfo::None
-        && cx.sess().target.options.emit_debug_gdb_scripts
+        && cx.sess().target.emit_debug_gdb_scripts
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 454d43fd4e7..27b81ebcff6 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -870,7 +870,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
 
     // When targeting MSVC, emit MSVC style type names for compatibility with
     // .natvis visualizers (and perhaps other existing native debuggers?)
-    let msvc_like_names = cx.tcx.sess.target.options.is_like_msvc;
+    let msvc_like_names = cx.tcx.sess.target.is_like_msvc;
 
     let (name, encoding) = match t.kind() {
         ty::Never => ("!", DW_ATE_unsigned),
@@ -981,7 +981,7 @@ pub fn compile_unit_metadata(
     // if multiple object files with the same `DW_AT_name` are linked together.
     // As a workaround we generate unique names for each object file. Those do
     // not correspond to an actual source file but that should be harmless.
-    if tcx.sess.target.options.is_like_osx {
+    if tcx.sess.target.is_like_osx {
         name_in_debuginfo.push("@");
         name_in_debuginfo.push(codegen_unit_name);
     }
@@ -1397,7 +1397,7 @@ fn prepare_union_metadata(
 /// on MSVC we have to use the fallback mode, because LLVM doesn't
 /// lower variant parts to PDB.
 fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool {
-    cx.sess().target.options.is_like_msvc
+    cx.sess().target.is_like_msvc
 }
 
 // FIXME(eddyb) maybe precompute this? Right now it's computed once
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 6bb93857d71..5065ff01aed 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -122,12 +122,12 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
         // for macOS to understand. For more info see #11352
         // This can be overridden using --llvm-opts -dwarf-version,N.
         // Android has the same issue (#22398)
-        if let Some(version) = cx.sess().target.options.dwarf_version {
+        if let Some(version) = cx.sess().target.dwarf_version {
             llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), version)
         }
 
         // Indicate that we want CodeView debug information on MSVC
-        if cx.sess().target.options.is_like_msvc {
+        if cx.sess().target.is_like_msvc {
             llvm::LLVMRustAddModuleFlag(cx.llmod, "CodeView\0".as_ptr().cast(), 1)
         }
 
@@ -251,7 +251,7 @@ impl CodegenCx<'ll, '_> {
         // For MSVC, omit the column number.
         // Otherwise, emit it. This mimics clang behaviour.
         // See discussion in https://github.com/rust-lang/rust/issues/42921
-        if self.sess().target.options.is_like_msvc {
+        if self.sess().target.is_like_msvc {
             DebugLoc { file, line, col: None }
         } else {
             DebugLoc { file, line, col }
@@ -387,7 +387,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             });
 
             // Arguments types
-            if cx.sess().target.options.is_like_msvc {
+            if cx.sess().target.is_like_msvc {
                 // FIXME(#42800):
                 // There is a bug in MSDIA that leads to a crash when it encounters
                 // a fixed-size array of `u8` or something zero-sized in a
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 9face778322..0591e0a5c12 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -42,7 +42,7 @@ fn declare_raw_fn(
     // be merged.
     llvm::SetUnnamedAddress(llfn, llvm::UnnamedAddr::Global);
 
-    if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.options.disable_redzone) {
+    if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) {
         llvm::Attribute::NoRedZone.apply_llfn(Function, llfn);
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index e9900e8bc10..d52b3be8cd3 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -367,7 +367,7 @@ fn try_intrinsic(
         bx.store(bx.const_i32(0), dest, ret_align);
     } else if wants_msvc_seh(bx.sess()) {
         codegen_msvc_try(bx, try_func, data, catch_func, dest);
-    } else if bx.sess().target.options.is_like_emscripten {
+    } else if bx.sess().target.is_like_emscripten {
         codegen_emcc_try(bx, try_func, data, catch_func, dest);
     } else {
         codegen_gnu_try(bx, try_func, data, catch_func, dest);
@@ -979,12 +979,14 @@ fn generic_simd_intrinsic(
 
         // Integer vector <i{in_bitwidth} x in_len>:
         let (i_xn, in_elem_bitwidth) = match in_elem.kind() {
-            ty::Int(i) => {
-                (args[0].immediate(), i.bit_width().unwrap_or(bx.data_layout().pointer_size.bits()))
-            }
-            ty::Uint(i) => {
-                (args[0].immediate(), i.bit_width().unwrap_or(bx.data_layout().pointer_size.bits()))
-            }
+            ty::Int(i) => (
+                args[0].immediate(),
+                i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
+            ),
+            ty::Uint(i) => (
+                args[0].immediate(),
+                i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
+            ),
             _ => return_error!(
                 "vector argument `{}`'s element type `{}`, expected integer element type",
                 in_ty,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 9c1e1b8fac0..ab70f72dc61 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -46,7 +46,7 @@ fn require_inited() {
 }
 
 unsafe fn configure_llvm(sess: &Session) {
-    let n_args = sess.opts.cg.llvm_args.len() + sess.target.options.llvm_args.len();
+    let n_args = sess.opts.cg.llvm_args.len() + sess.target.llvm_args.len();
     let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
     let mut llvm_args = Vec::with_capacity(n_args + 1);
 
@@ -57,7 +57,7 @@ unsafe fn configure_llvm(sess: &Session) {
     }
 
     let cg_opts = sess.opts.cg.llvm_args.iter();
-    let tg_opts = sess.target.options.llvm_args.iter();
+    let tg_opts = sess.target.llvm_args.iter();
     let sess_args = cg_opts.chain(tg_opts);
 
     let user_specified_args: FxHashSet<_> =
@@ -84,19 +84,14 @@ unsafe fn configure_llvm(sess: &Session) {
         if !sess.opts.debugging_opts.no_generate_arange_section {
             add("-generate-arange-section", false);
         }
-        match sess
-            .opts
-            .debugging_opts
-            .merge_functions
-            .unwrap_or(sess.target.options.merge_functions)
-        {
+        match sess.opts.debugging_opts.merge_functions.unwrap_or(sess.target.merge_functions) {
             MergeFunctions::Disabled | MergeFunctions::Trampolines => {}
             MergeFunctions::Aliases => {
                 add("-mergefunc-use-aliases", false);
             }
         }
 
-        if sess.target.target_os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
+        if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
             add("-enable-emscripten-cxx-exceptions", false);
         }
 
@@ -215,7 +210,7 @@ fn handle_native(name: &str) -> &str {
 pub fn target_cpu(sess: &Session) -> &str {
     let name = match sess.opts.cg.target_cpu {
         Some(ref s) => &**s,
-        None => &*sess.target.options.cpu,
+        None => &*sess.target.cpu,
     };
 
     handle_native(name)
diff --git a/compiler/rustc_codegen_llvm/src/metadata.rs b/compiler/rustc_codegen_llvm/src/metadata.rs
index 9036428c04b..3912d6a3a48 100644
--- a/compiler/rustc_codegen_llvm/src/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/metadata.rs
@@ -104,7 +104,7 @@ pub fn metadata_section_name(target: &Target) -> &'static str {
     // As a result, we choose a slightly shorter name! As to why
     // `.note.rustc` works on MinGW, that's another good question...
 
-    if target.options.is_like_osx { "__DATA,.rustc" } else { ".rustc" }
+    if target.is_like_osx { "__DATA,.rustc" } else { ".rustc" }
 }
 
 fn read_metadata_section_name(_target: &Target) -> &'static str {
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index b6a0516b8bc..3fc56eecdd0 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -52,7 +52,7 @@ fn emit_direct_ptr_va_arg(
     let next = bx.inbounds_gep(addr, &[full_direct_size]);
     bx.store(next, va_list_addr, bx.tcx().data_layout.pointer_align.abi);
 
-    if size.bytes() < slot_size.bytes() && &*bx.tcx().sess.target.target_endian == "big" {
+    if size.bytes() < slot_size.bytes() && &*bx.tcx().sess.target.endian == "big" {
         let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32);
         let adjusted = bx.inbounds_gep(addr, &[adjusted_size]);
         (bx.bitcast(adjusted, bx.cx().type_ptr_to(llty)), addr_align)
@@ -105,7 +105,7 @@ fn emit_aapcs_va_arg(
     let mut end = bx.build_sibling_block("va_arg.end");
     let zero = bx.const_i32(0);
     let offset_align = Align::from_bytes(4).unwrap();
-    assert!(&*bx.tcx().sess.target.target_endian == "little");
+    assert!(&*bx.tcx().sess.target.endian == "little");
 
     let gr_type = target_ty.is_any_ptr() || target_ty.is_integral();
     let (reg_off, reg_top_index, slot_size) = if gr_type {
@@ -175,22 +175,22 @@ pub(super) fn emit_va_arg(
     let arch = &bx.cx.tcx.sess.target.arch;
     match &**arch {
         // Windows x86
-        "x86" if target.options.is_like_windows => {
+        "x86" if target.is_like_windows => {
             emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(4).unwrap(), false)
         }
         // Generic x86
         "x86" => emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(4).unwrap(), true),
         // Windows AArch64
-        "aarch64" if target.options.is_like_windows => {
+        "aarch64" if target.is_like_windows => {
             emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), false)
         }
         // macOS / iOS AArch64
-        "aarch64" if target.options.is_like_osx => {
+        "aarch64" if target.is_like_osx => {
             emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), true)
         }
         "aarch64" => emit_aapcs_va_arg(bx, addr, target_ty),
         // Windows x86_64
-        "x86_64" if target.options.is_like_windows => {
+        "x86_64" if target.is_like_windows => {
             let target_ty_size = bx.cx.size_of(target_ty).bytes();
             let indirect: bool = target_ty_size > 8 || !target_ty_size.is_power_of_two();
             emit_ptr_va_arg(bx, addr, target_ty, indirect, Align::from_bytes(8).unwrap(), false)
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index ef722ecb599..c477ac6462a 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -7,10 +7,8 @@ use std::path::{Path, PathBuf};
 pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session) -> PathBuf {
     // On Windows, static libraries sometimes show up as libfoo.a and other
     // times show up as foo.lib
-    let oslibname = format!(
-        "{}{}{}",
-        sess.target.options.staticlib_prefix, name, sess.target.options.staticlib_suffix
-    );
+    let oslibname =
+        format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix);
     let unixlibname = format!("lib{}.a", name);
 
     for path in search_paths {
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 63d0a88858e..5a627a0efa3 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -151,9 +151,7 @@ fn get_linker(
         Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker),
         _ => match flavor {
             LinkerFlavor::Lld(f) => Command::lld(linker, f),
-            LinkerFlavor::Msvc
-                if sess.opts.cg.linker.is_none() && sess.target.options.linker.is_none() =>
-            {
+            LinkerFlavor::Msvc if sess.opts.cg.linker.is_none() && sess.target.linker.is_none() => {
                 Command::new(msvc_tool.as_ref().map(|t| t.path()).unwrap_or(linker))
             }
             _ => Command::new(linker),
@@ -165,7 +163,7 @@ fn get_linker(
     // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
     let t = &sess.target;
     if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link))
-        && t.target_vendor == "uwp"
+        && t.vendor == "uwp"
     {
         if let Some(ref tool) = msvc_tool {
             let original_path = tool.path();
@@ -197,7 +195,7 @@ fn get_linker(
     // PATH for the child.
     let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(self_contained);
     let mut msvc_changed_path = false;
-    if sess.target.options.is_like_msvc {
+    if sess.target.is_like_msvc {
         if let Some(ref tool) = msvc_tool {
             cmd.args(tool.args());
             for &(ref k, ref v) in tool.env() {
@@ -365,7 +363,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
             // After adding all files to the archive, we need to update the
             // symbol table of the archive. This currently dies on macOS (see
             // #11162), and isn't necessary there anyway
-            if !sess.target.options.is_like_osx {
+            if !sess.target.is_like_osx {
                 ab.update_symbols();
             }
         }
@@ -476,10 +474,10 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
 
     linker::disable_localization(&mut cmd);
 
-    for &(ref k, ref v) in &sess.target.options.link_env {
+    for &(ref k, ref v) in &sess.target.link_env {
         cmd.env(k, v);
     }
-    for k in &sess.target.options.link_env_remove {
+    for k in &sess.target.link_env_remove {
         cmd.env_remove(k);
     }
 
@@ -515,7 +513,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         // if the linker doesn't support -no-pie then it should not default to
         // linking executables as pie. Different versions of gcc seem to use
         // different quotes in the error message so don't check for them.
-        if sess.target.options.linker_is_gnu
+        if sess.target.linker_is_gnu
             && flavor != LinkerFlavor::Ld
             && (out.contains("unrecognized command line option")
                 || out.contains("unknown argument"))
@@ -535,7 +533,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
 
         // Detect '-static-pie' used with an older version of gcc or clang not supporting it.
         // Fallback from '-static-pie' to '-static' in that case.
-        if sess.target.options.linker_is_gnu
+        if sess.target.linker_is_gnu
             && flavor != LinkerFlavor::Ld
             && (out.contains("unrecognized command line option")
                 || out.contains("unknown argument"))
@@ -548,7 +546,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
             );
             // Mirror `add_(pre,post)_link_objects` to replace CRT objects.
             let self_contained = crt_objects_fallback(sess, crate_type);
-            let opts = &sess.target.options;
+            let opts = &sess.target;
             let pre_objects = if self_contained {
                 &opts.pre_link_objects_fallback
             } else {
@@ -670,7 +668,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
                 // is not a Microsoft LNK error then suggest a way to fix or
                 // install the Visual Studio build tools.
                 if let Some(code) = prog.status.code() {
-                    if sess.target.options.is_like_msvc
+                    if sess.target.is_like_msvc
                         && flavor == LinkerFlavor::Msvc
                         // Respect the command line override
                         && sess.opts.cg.linker.is_none()
@@ -741,7 +739,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
 
             linker_error.emit();
 
-            if sess.target.options.is_like_msvc && linker_not_found {
+            if sess.target.is_like_msvc && linker_not_found {
                 sess.note_without_error(
                     "the msvc targets depend on the msvc linker \
                      but `link.exe` was not found",
@@ -758,7 +756,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
     // On macOS, debuggers need this utility to get run to do some munging of
     // the symbols. Note, though, that if the object files are being preserved
     // for their debug information there's no need for us to run dsymutil.
-    if sess.target.options.is_like_osx
+    if sess.target.is_like_osx
         && sess.opts.debuginfo != DebugInfo::None
         && !preserve_objects_for_their_debuginfo(sess)
     {
@@ -775,9 +773,7 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke
     // executables only.
     let needs_runtime = match crate_type {
         CrateType::Executable => true,
-        CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
-            sess.target.options.is_like_osx
-        }
+        CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => sess.target.is_like_osx,
         CrateType::Rlib | CrateType::Staticlib => false,
     };
 
@@ -846,7 +842,7 @@ pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool
     // If our target enables builtin function lowering in LLVM then the
     // crates providing these functions don't participate in LTO (e.g.
     // no_builtins or compiler builtins crates).
-    !sess.target.options.no_builtins
+    !sess.target.no_builtins
         && (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
 }
 
@@ -906,7 +902,7 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
                 } else if stem == "link" || stem == "lld-link" {
                     LinkerFlavor::Msvc
                 } else if stem == "lld" || stem == "rust-lld" {
-                    LinkerFlavor::Lld(sess.target.options.lld_flavor)
+                    LinkerFlavor::Lld(sess.target.lld_flavor)
                 } else {
                     // fall back to the value in the target spec
                     sess.target.linker_flavor
@@ -926,7 +922,7 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
 
     if let Some(ret) = infer_from(
         sess,
-        sess.target.options.linker.clone().map(PathBuf::from),
+        sess.target.linker.clone().map(PathBuf::from),
         Some(sess.target.linker_flavor),
     ) {
         return ret;
@@ -962,7 +958,7 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
     // Basically as a result this just means that if we're on OSX and we're
     // *not* running dsymutil then the object files are the only source of truth
     // for debug information, so we must preserve them.
-    if sess.target.options.is_like_osx {
+    if sess.target.is_like_osx {
         return !sess.opts.debugging_opts.run_dsymutil;
     }
 
@@ -988,7 +984,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
                 NativeLibKind::StaticNoBundle
                 | NativeLibKind::Dylib
                 | NativeLibKind::Unspecified => {
-                    if sess.target.options.is_like_msvc {
+                    if sess.target.is_like_msvc {
                         Some(format!("{}.lib", name))
                     } else {
                         Some(format!("-l{}", name))
@@ -1070,13 +1066,13 @@ fn exec_linker(
     let mut args = String::new();
     for arg in cmd2.take_args() {
         args.push_str(
-            &Escape { arg: arg.to_str().unwrap(), is_like_msvc: sess.target.options.is_like_msvc }
+            &Escape { arg: arg.to_str().unwrap(), is_like_msvc: sess.target.is_like_msvc }
                 .to_string(),
         );
         args.push('\n');
     }
     let file = tmpdir.join("linker-arguments");
-    let bytes = if sess.target.options.is_like_msvc {
+    let bytes = if sess.target.is_like_msvc {
         let mut out = Vec::with_capacity((1 + args.len()) * 2);
         // start the stream with a UTF-16 BOM
         for c in std::iter::once(0xFEFF).chain(args.encode_utf16()) {
@@ -1192,7 +1188,7 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
     };
 
     // Adjust the output kind to target capabilities.
-    let opts = &sess.target.options;
+    let opts = &sess.target;
     let pic_exe_supported = opts.position_independent_executables;
     let static_pic_exe_supported = opts.static_position_independent_executables;
     let static_dylib_supported = opts.crt_static_allows_dylibs;
@@ -1233,14 +1229,14 @@ fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
         return self_contained;
     }
 
-    match sess.target.options.crt_objects_fallback {
+    match sess.target.crt_objects_fallback {
         // FIXME: Find a better heuristic for "native musl toolchain is available",
         // based on host and linker path, for example.
         // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237).
         Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)),
         Some(CrtObjectsFallback::Mingw) => {
             sess.host == sess.target
-                && sess.target.target_vendor != "uwp"
+                && sess.target.vendor != "uwp"
                 && detect_self_contained_mingw(&sess)
         }
         // FIXME: Figure out cases in which WASM needs to link with a native toolchain.
@@ -1256,7 +1252,7 @@ fn add_pre_link_objects(
     link_output_kind: LinkOutputKind,
     self_contained: bool,
 ) {
-    let opts = &sess.target.options;
+    let opts = &sess.target;
     let objects =
         if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
@@ -1271,7 +1267,7 @@ fn add_post_link_objects(
     link_output_kind: LinkOutputKind,
     self_contained: bool,
 ) {
-    let opts = &sess.target.options;
+    let opts = &sess.target;
     let objects =
         if self_contained { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
@@ -1282,7 +1278,7 @@ fn add_post_link_objects(
 /// Add arbitrary "pre-link" args defined by the target spec or from command line.
 /// FIXME: Determine where exactly these args need to be inserted.
 fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
-    if let Some(args) = sess.target.options.pre_link_args.get(&flavor) {
+    if let Some(args) = sess.target.pre_link_args.get(&flavor) {
         cmd.args(args);
     }
     cmd.args(&sess.opts.debugging_opts.pre_link_args);
@@ -1290,9 +1286,9 @@ fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor)
 
 /// Add a link script embedded in the target, if applicable.
 fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_type: CrateType) {
-    match (crate_type, &sess.target.options.link_script) {
+    match (crate_type, &sess.target.link_script) {
         (CrateType::Cdylib | CrateType::Executable, Some(script)) => {
-            if !sess.target.options.linker_is_gnu {
+            if !sess.target.linker_is_gnu {
                 sess.fatal("can only use link script when linking with GNU-like linker");
             }
 
@@ -1335,15 +1331,15 @@ fn add_late_link_args(
             *ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
         });
     if any_dynamic_crate {
-        if let Some(args) = sess.target.options.late_link_args_dynamic.get(&flavor) {
+        if let Some(args) = sess.target.late_link_args_dynamic.get(&flavor) {
             cmd.args(args);
         }
     } else {
-        if let Some(args) = sess.target.options.late_link_args_static.get(&flavor) {
+        if let Some(args) = sess.target.late_link_args_static.get(&flavor) {
             cmd.args(args);
         }
     }
-    if let Some(args) = sess.target.options.late_link_args.get(&flavor) {
+    if let Some(args) = sess.target.late_link_args.get(&flavor) {
         cmd.args(args);
     }
 }
@@ -1351,7 +1347,7 @@ fn add_late_link_args(
 /// Add arbitrary "post-link" args defined by the target spec.
 /// FIXME: Determine where exactly these args need to be inserted.
 fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
-    if let Some(args) = sess.target.options.post_link_args.get(&flavor) {
+    if let Some(args) = sess.target.post_link_args.get(&flavor) {
         cmd.args(args);
     }
 }
@@ -1453,7 +1449,7 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained:
 /// Add options making relocation sections in the produced ELF files read-only
 /// and suppressing lazy binding.
 fn add_relro_args(cmd: &mut dyn Linker, sess: &Session) {
-    match sess.opts.debugging_opts.relro_level.unwrap_or(sess.target.options.relro_level) {
+    match sess.opts.debugging_opts.relro_level.unwrap_or(sess.target.relro_level) {
         RelroLevel::Full => cmd.full_relro(),
         RelroLevel::Partial => cmd.partial_relro(),
         RelroLevel::Off => cmd.no_relro(),
@@ -1484,9 +1480,9 @@ fn add_rpath_args(
         let mut rpath_config = RPathConfig {
             used_crates: &codegen_results.crate_info.used_crates_dynamic,
             out_filename: out_filename.to_path_buf(),
-            has_rpath: sess.target.options.has_rpath,
-            is_like_osx: sess.target.options.is_like_osx,
-            linker_is_gnu: sess.target.options.linker_is_gnu,
+            has_rpath: sess.target.has_rpath,
+            is_like_osx: sess.target.is_like_osx,
+            linker_is_gnu: sess.target.linker_is_gnu,
             get_install_prefix_lib_path: &mut get_install_prefix_lib_path,
         };
         cmd.args(&rpath::get_rpath_flags(&mut rpath_config));
@@ -1514,7 +1510,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     let base_cmd = get_linker(sess, path, flavor, crt_objects_fallback);
     // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
     // to the linker args construction.
-    assert!(base_cmd.get_args().is_empty() || sess.target.target_vendor == "uwp");
+    assert!(base_cmd.get_args().is_empty() || sess.target.vendor == "uwp");
     let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor, target_cpu);
     let link_output_kind = link_output_kind(sess, crate_type);
 
@@ -1528,7 +1524,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     add_link_script(cmd, sess, tmpdir, crate_type);
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.target.options.is_like_fuchsia && crate_type == CrateType::Executable {
+    if sess.target.is_like_fuchsia && crate_type == CrateType::Executable {
         let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
             "asan/"
         } else {
@@ -1538,7 +1534,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     }
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.target.options.eh_frame_header {
+    if sess.target.eh_frame_header {
         cmd.add_eh_frame_header();
     }
 
@@ -1551,7 +1547,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.target.options.is_like_emscripten {
+    if sess.target.is_like_emscripten {
         cmd.arg("-s");
         cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
             "DISABLE_EXCEPTION_CATCHING=1"
@@ -1579,7 +1575,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     cmd.output_filename(out_filename);
 
     // OBJECT-FILES-NO, AUDIT-ORDER
-    if crate_type == CrateType::Executable && sess.target.options.is_like_windows {
+    if crate_type == CrateType::Executable && sess.target.is_like_windows {
         if let Some(ref s) = codegen_results.windows_subsystem {
             cmd.subsystem(s);
         }
@@ -1623,7 +1619,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     // OBJECT-FILES-NO, AUDIT-ORDER
     // We want to prevent the compiler from accidentally leaking in any system libraries,
     // so by default we tell linkers not to link to any default libraries.
-    if !sess.opts.cg.default_linker_libraries && sess.target.options.no_default_libraries {
+    if !sess.opts.cg.default_linker_libraries && sess.target.no_default_libraries {
         cmd.no_default_libraries();
     }
 
@@ -1843,7 +1839,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
 
     // Converts a library file-stem into a cc -l argument
     fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str {
-        if stem.starts_with("lib") && !target.options.is_like_windows { &stem[3..] } else { stem }
+        if stem.starts_with("lib") && !target.is_like_windows { &stem[3..] } else { stem }
     }
 
     // Adds the static "rlib" versions of all crates to the command line.
@@ -1938,7 +1934,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
                 // though, so we let that object file slide.
                 let skip_because_lto = are_upstream_rust_objects_already_included(sess)
                     && is_rust_object
-                    && (sess.target.options.no_builtins
+                    && (sess.target.no_builtins
                         || !codegen_results.crate_info.is_no_builtins.contains(&cnum));
 
                 if skip_because_cfg_say_so || skip_because_lto {
@@ -2082,9 +2078,9 @@ fn are_upstream_rust_objects_already_included(sess: &Session) -> bool {
 
 fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
     let arch = &sess.target.arch;
-    let os = &sess.target.target_os;
+    let os = &sess.target.os;
     let llvm_target = &sess.target.llvm_target;
-    if sess.target.target_vendor != "apple"
+    if sess.target.vendor != "apple"
         || !matches!(os.as_str(), "ios" | "tvos")
         || flavor != LinkerFlavor::Gcc
     {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 3e13a1daecd..3df956c465e 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -184,7 +184,7 @@ impl<'a> GccLinker<'a> {
         // * On OSX they have their own linker, not binutils'
         // * For WebAssembly the only functional linker is LLD, which doesn't
         //   support hint flags
-        !self.sess.target.options.is_like_osx && self.sess.target.arch != "wasm32"
+        !self.sess.target.is_like_osx && self.sess.target.arch != "wasm32"
     }
 
     // Some platforms take hints about whether a library is static or dynamic.
@@ -232,7 +232,7 @@ impl<'a> GccLinker<'a> {
 
     fn build_dylib(&mut self, out_filename: &Path) {
         // On mac we need to tell the linker to let this library be rpathed
-        if self.sess.target.options.is_like_osx {
+        if self.sess.target.is_like_osx {
             self.cmd.arg("-dynamiclib");
             self.linker_arg("-dylib");
 
@@ -248,7 +248,7 @@ impl<'a> GccLinker<'a> {
             }
         } else {
             self.cmd.arg("-shared");
-            if self.sess.target.options.is_like_windows {
+            if self.sess.target.is_like_windows {
                 // The output filename already contains `dll_suffix` so
                 // the resulting import library will have a name in the
                 // form of libfoo.dll.a
@@ -256,9 +256,9 @@ impl<'a> GccLinker<'a> {
                     out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
                         format!(
                             "{}{}{}",
-                            self.sess.target.options.staticlib_prefix,
+                            self.sess.target.staticlib_prefix,
                             file,
-                            self.sess.target.options.staticlib_suffix
+                            self.sess.target.staticlib_suffix
                         )
                     });
                 if let Some(implib_name) = implib_name {
@@ -280,7 +280,7 @@ impl<'a> Linker for GccLinker<'a> {
     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
         match output_kind {
             LinkOutputKind::DynamicNoPicExe => {
-                if !self.is_ld && self.sess.target.options.linker_is_gnu {
+                if !self.is_ld && self.sess.target.linker_is_gnu {
                     self.cmd.arg("-no-pie");
                 }
             }
@@ -291,7 +291,7 @@ impl<'a> Linker for GccLinker<'a> {
             LinkOutputKind::StaticNoPicExe => {
                 // `-static` works for both gcc wrapper and ld.
                 self.cmd.arg("-static");
-                if !self.is_ld && self.sess.target.options.linker_is_gnu {
+                if !self.is_ld && self.sess.target.linker_is_gnu {
                     self.cmd.arg("-no-pie");
                 }
             }
@@ -320,7 +320,7 @@ impl<'a> Linker for GccLinker<'a> {
         // any `#[link]` attributes in the `libc` crate, see #72782 for details.
         // FIXME: Switch to using `#[link]` attributes in the `libc` crate
         // similarly to other targets.
-        if self.sess.target.target_os == "vxworks"
+        if self.sess.target.os == "vxworks"
             && matches!(
                 output_kind,
                 LinkOutputKind::StaticNoPicExe
@@ -386,7 +386,7 @@ impl<'a> Linker for GccLinker<'a> {
     fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) {
         self.hint_static();
         let target = &self.sess.target;
-        if !target.options.is_like_osx {
+        if !target.is_like_osx {
             self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib));
             self.linker_arg("--no-whole-archive");
         } else {
@@ -400,7 +400,7 @@ impl<'a> Linker for GccLinker<'a> {
 
     fn link_whole_rlib(&mut self, lib: &Path) {
         self.hint_static();
-        if self.sess.target.options.is_like_osx {
+        if self.sess.target.is_like_osx {
             self.linker_arg("-force_load");
             self.linker_arg(&lib);
         } else {
@@ -424,9 +424,9 @@ impl<'a> Linker for GccLinker<'a> {
         // -dead_strip can't be part of the pre_link_args because it's also used
         // for partial linking when using multiple codegen units (-r).  So we
         // insert it here.
-        if self.sess.target.options.is_like_osx {
+        if self.sess.target.is_like_osx {
             self.linker_arg("-dead_strip");
-        } else if self.sess.target.options.is_like_solaris {
+        } else if self.sess.target.is_like_solaris {
             self.linker_arg("-zignore");
 
         // If we're building a dylib, we don't use --gc-sections because LLVM
@@ -440,7 +440,7 @@ impl<'a> Linker for GccLinker<'a> {
     }
 
     fn optimize(&mut self) {
-        if !self.sess.target.options.linker_is_gnu {
+        if !self.sess.target.linker_is_gnu {
             return;
         }
 
@@ -454,7 +454,7 @@ impl<'a> Linker for GccLinker<'a> {
     }
 
     fn pgo_gen(&mut self) {
-        if !self.sess.target.options.linker_is_gnu {
+        if !self.sess.target.linker_is_gnu {
             return;
         }
 
@@ -503,8 +503,7 @@ impl<'a> Linker for GccLinker<'a> {
 
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
         // Symbol visibility in object files typically takes care of this.
-        if crate_type == CrateType::Executable
-            && self.sess.target.options.override_export_symbols.is_none()
+        if crate_type == CrateType::Executable && self.sess.target.override_export_symbols.is_none()
         {
             return;
         }
@@ -513,7 +512,7 @@ impl<'a> Linker for GccLinker<'a> {
         // The object files have far more public symbols than we actually want to export,
         // so we hide them all here.
 
-        if !self.sess.target.options.limit_rdylib_exports {
+        if !self.sess.target.limit_rdylib_exports {
             return;
         }
 
@@ -521,13 +520,13 @@ impl<'a> Linker for GccLinker<'a> {
             return;
         }
 
-        let is_windows = self.sess.target.options.is_like_windows;
+        let is_windows = self.sess.target.is_like_windows;
         let mut arg = OsString::new();
         let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
 
         debug!("EXPORTED SYMBOLS:");
 
-        if self.sess.target.options.is_like_osx {
+        if self.sess.target.is_like_osx {
             // Write a plain, newline-separated list of symbols
             let res: io::Result<()> = try {
                 let mut f = BufWriter::new(File::create(&path)?);
@@ -573,12 +572,12 @@ impl<'a> Linker for GccLinker<'a> {
             }
         }
 
-        if self.sess.target.options.is_like_osx {
+        if self.sess.target.is_like_osx {
             if !self.is_ld {
                 arg.push("-Wl,")
             }
             arg.push("-exported_symbols_list,");
-        } else if self.sess.target.options.is_like_solaris {
+        } else if self.sess.target.is_like_solaris {
             if !self.is_ld {
                 arg.push("-Wl,")
             }
@@ -1203,7 +1202,7 @@ impl<'a> Linker for WasmLd<'a> {
 }
 
 fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
-    if let Some(ref exports) = tcx.sess.target.options.override_export_symbols {
+    if let Some(ref exports) = tcx.sess.target.override_export_symbols {
         return exports.clone();
     }
 
@@ -1293,7 +1292,7 @@ impl<'a> Linker for PtxLinker<'a> {
         // Provide the linker with fallback to internal `target-cpu`.
         self.cmd.arg("--fallback-arch").arg(match self.sess.opts.cg.target_cpu {
             Some(ref s) => s,
-            None => &self.sess.target.options.cpu,
+            None => &self.sess.target.cpu,
         });
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index dd8d751d045..9a6f8cde1b2 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -229,8 +229,7 @@ fn exported_symbols_provider_local(
         // needs to be exported.
         // However, on platforms that don't allow for Rust dylibs, having
         // external linkage is enough for monomorphization to be linked to.
-        let need_visibility =
-            tcx.sess.target.options.dynamic_linking && !tcx.sess.target.options.only_cdylib;
+        let need_visibility = tcx.sess.target.dynamic_linking && !tcx.sess.target.only_cdylib;
 
         let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
 
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 4d2cea18dcc..b34bee3358b 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -139,7 +139,7 @@ impl ModuleConfig {
 
         let emit_obj = if !should_emit_obj {
             EmitObj::None
-        } else if sess.target.options.obj_is_bitcode
+        } else if sess.target.obj_is_bitcode
             || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins)
         {
             // This case is selected if the target uses objects as bitcode, or
@@ -221,11 +221,11 @@ impl ModuleConfig {
                 false
             ),
             emit_obj,
-            bc_cmdline: sess.target.options.bitcode_llvm_cmdline.clone(),
+            bc_cmdline: sess.target.bitcode_llvm_cmdline.clone(),
 
             verify_llvm_ir: sess.verify_llvm_ir(),
             no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes,
-            no_builtins: no_builtins || sess.target.options.no_builtins,
+            no_builtins: no_builtins || sess.target.no_builtins,
 
             // Exclude metadata and allocator modules from time_passes output,
             // since they throw off the "LLVM passes" measurement.
@@ -252,7 +252,7 @@ impl ModuleConfig {
                 .opts
                 .debugging_opts
                 .merge_functions
-                .unwrap_or(sess.target.options.merge_functions)
+                .unwrap_or(sess.target.merge_functions)
             {
                 MergeFunctions::Disabled => false,
                 MergeFunctions::Trampolines | MergeFunctions::Aliases => {
@@ -388,7 +388,7 @@ fn need_bitcode_in_object(sess: &Session) -> bool {
     let requested_for_rlib = sess.opts.cg.embed_bitcode
         && sess.crate_types().contains(&CrateType::Rlib)
         && sess.opts.output_types.contains_key(&OutputType::Exe);
-    let forced_by_target = sess.target.options.forces_embed_bitcode;
+    let forced_by_target = sess.target.forces_embed_bitcode;
     requested_for_rlib || forced_by_target
 }
 
@@ -1865,11 +1865,11 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool {
     // something is wrong with commandline arg validation.
     assert!(
         !(tcx.sess.opts.cg.linker_plugin_lto.enabled()
-            && tcx.sess.target.options.is_like_windows
+            && tcx.sess.target.is_like_windows
             && tcx.sess.opts.cg.prefer_dynamic)
     );
 
-    tcx.sess.target.options.is_like_windows &&
+    tcx.sess.target.is_like_windows &&
         tcx.sess.crate_types().iter().any(|ct| *ct == CrateType::Rlib) &&
     // ThinLTO can't handle this workaround in all cases, so we don't
     // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index afb407b35be..5fe26dbf914 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -326,7 +326,7 @@ fn cast_shift_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 /// currently uses SEH-ish unwinding with DWARF info tables to the side (same as
 /// 64-bit MinGW) instead of "full SEH".
 pub fn wants_msvc_seh(sess: &Session) -> bool {
-    sess.target.options.is_like_msvc
+    sess.target.is_like_msvc
 }
 
 pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
@@ -387,7 +387,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     ) -> Bx::Function {
         // The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
         // depending on whether the target needs `argc` and `argv` to be passed in.
-        let llfty = if cx.sess().target.options.main_needs_argc_argv {
+        let llfty = if cx.sess().target.main_needs_argc_argv {
             cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int())
         } else {
             cx.type_func(&[], cx.type_int())
@@ -459,7 +459,7 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     cx: &'a Bx::CodegenCx,
     bx: &mut Bx,
 ) -> (Bx::Value, Bx::Value) {
-    if cx.sess().target.options.main_needs_argc_argv {
+    if cx.sess().target.main_needs_argc_argv {
         // Params from native `main()` used as args for rust start function
         let param_argc = bx.get_param(0);
         let param_argv = bx.get_param(1);
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index c4c51d146a6..0b49a379070 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -33,7 +33,7 @@ pub fn push_debuginfo_type_name<'tcx>(
 ) {
     // When targeting MSVC, emit C++ style type names for compatibility with
     // .natvis visualizers (and perhaps other existing native debuggers?)
-    let cpp_like_names = tcx.sess.target.options.is_like_msvc;
+    let cpp_like_names = tcx.sess.target.is_like_msvc;
 
     match *t.kind() {
         ty::Bool => output.push_str("bool"),
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 84e82e88e8e..01fd1681593 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -92,15 +92,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         T: Copy + TypeFoldable<'tcx>,
     {
         debug!("monomorphize: self.instance={:?}", self.instance);
-        if let Some(substs) = self.instance.substs_for_mir_body() {
-            self.cx.tcx().subst_and_normalize_erasing_regions(
-                substs,
-                ty::ParamEnv::reveal_all(),
-                &value,
-            )
-        } else {
-            self.cx.tcx().normalize_erasing_regions(ty::ParamEnv::reveal_all(), *value)
-        }
+        self.instance.subst_mir_and_normalize_erasing_regions(
+            self.cx.tcx(),
+            ty::ParamEnv::reveal_all(),
+            value,
+        )
     }
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 7ce110dcbfc..40ae0a13c72 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -502,6 +502,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             }
 
             mir::Rvalue::NullaryOp(mir::NullOp::SizeOf, ty) => {
+                let ty = self.monomorphize(&ty);
                 assert!(bx.cx().type_is_sized(ty));
                 let val = bx.cx().const_usize(bx.cx().layout_of(ty).size.bytes());
                 let tcx = self.cx.tcx();
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index 43bc0c83155..634a20bda9b 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -51,11 +51,11 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
     }
 
     fn type_int(&self) -> Self::Type {
-        match &self.sess().target.target_c_int_width[..] {
+        match &self.sess().target.c_int_width[..] {
             "16" => self.type_i16(),
             "32" => self.type_i32(),
             "64" => self.type_i64(),
-            width => bug!("Unsupported target_c_int_width: {}", width),
+            width => bug!("Unsupported c_int_width: {}", width),
         }
     }
 
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index c2239a2f659..cccbdf778ed 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -545,11 +545,6 @@ impl<'a> MutVisitor for StripUnconfigured<'a> {
         noop_flat_map_assoc_item(configure!(self, item), self)
     }
 
-    fn visit_mac(&mut self, _mac: &mut ast::MacCall) {
-        // Don't configure interpolated AST (cf. issue #34171).
-        // Interpolated AST will get configured once the surrounding tokens are parsed.
-    }
-
     fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
         self.configure_pat(pat);
         noop_visit_pat(pat, self)
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index e06d81d49d1..1b31bd6a305 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -850,8 +850,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
                 visit::walk_item(self, item);
             }
-
-            fn visit_mac(&mut self, _: &'ast ast::MacCall) {}
         }
 
         if !self.cx.ecfg.proc_macro_hygiene() {
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 629e0e702b6..dde65d998d8 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -5,7 +5,6 @@ use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
 use rustc_ast::mut_visit::{self, MutVisitor};
 use rustc_ast::token::{self, NtTT, Token};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing};
-use rustc_ast::MacCall;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{pluralize, PResult};
@@ -27,10 +26,6 @@ impl MutVisitor for Marker {
     fn visit_span(&mut self, span: &mut Span) {
         *span = span.apply_mark(self.0, self.1)
     }
-
-    fn visit_mac(&mut self, mac: &mut MacCall) {
-        mut_visit::noop_visit_mac(mac, self)
-    }
 }
 
 /// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
diff --git a/compiler/rustc_expand/src/mut_visit/tests.rs b/compiler/rustc_expand/src/mut_visit/tests.rs
index 9e65fc2eca7..be0300bad98 100644
--- a/compiler/rustc_expand/src/mut_visit/tests.rs
+++ b/compiler/rustc_expand/src/mut_visit/tests.rs
@@ -1,7 +1,7 @@
 use crate::tests::{matches_codepattern, string_to_crate};
 
 use rustc_ast as ast;
-use rustc_ast::mut_visit::{self, MutVisitor};
+use rustc_ast::mut_visit::MutVisitor;
 use rustc_ast_pretty::pprust;
 use rustc_span::symbol::Ident;
 use rustc_span::with_default_session_globals;
@@ -21,9 +21,6 @@ impl MutVisitor for ToZzIdentMutVisitor {
     fn visit_ident(&mut self, ident: &mut Ident) {
         *ident = Ident::from_str("zz");
     }
-    fn visit_mac(&mut self, mac: &mut ast::MacCall) {
-        mut_visit::noop_visit_mac(mac, self)
-    }
 }
 
 // Maybe add to `expand.rs`.
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index e413564fb3f..f0e5826f403 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -385,8 +385,4 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
             |item| !matches!(item.kind, ast::ItemKind::MacCall(_) if !self.cx.ecfg.keep_macs),
         );
     }
-
-    fn visit_mac(&mut self, _mac: &mut ast::MacCall) {
-        // Do nothing.
-    }
 }
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index ad926a810e6..0df67b63eba 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -610,6 +610,12 @@ declare_features! (
     /// Allows unsized fn parameters.
     (active, unsized_fn_params, "1.49.0", Some(48055), None),
 
+    /// Allows the use of destructuring assignments.
+    (active, destructuring_assignment, "1.49.0", Some(71126), None),
+
+    /// Enables `#[cfg(panic = "...")]` config key.
+    (active, cfg_panic, "1.49.0", Some(77443), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 57ae534590d..5c5cf609ac3 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -33,6 +33,7 @@ const GATED_CFGS: &[GatedCfg] = &[
     ),
     (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)),
     (sym::version, sym::cfg_version, cfg_fn!(cfg_version)),
+    (sym::panic, sym::cfg_panic, cfg_fn!(cfg_panic)),
 ];
 
 /// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 3f109376a3e..d5ade86593e 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -409,7 +409,7 @@ impl Definitions {
     }
 
     pub fn expansion_that_defined(&self, id: LocalDefId) -> ExpnId {
-        self.expansions_that_defined.get(&id).copied().unwrap_or(ExpnId::root())
+        self.expansions_that_defined.get(&id).copied().unwrap_or_else(ExpnId::root)
     }
 
     pub fn parent_module_of_macro_def(&self, expn_id: ExpnId) -> DefId {
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index b9ec18688c5..3c28b48795f 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -732,6 +732,9 @@ pub struct Pat<'hir> {
     pub hir_id: HirId,
     pub kind: PatKind<'hir>,
     pub span: Span,
+    // Whether to use default binding modes.
+    // At present, this is false only for destructuring assignment.
+    pub default_binding_modes: bool,
 }
 
 impl Pat<'_> {
@@ -1680,6 +1683,9 @@ pub enum LocalSource {
     AsyncFn,
     /// A desugared `<expr>.await`.
     AwaitDesugar,
+    /// A desugared `expr = expr`, where the LHS is a tuple, struct or array.
+    /// The span is that of the `=` sign.
+    AssignDesugar(Span),
 }
 
 /// Hints at the original code for a `match _ { .. }`.
@@ -2677,6 +2683,9 @@ impl<'hir> Node<'hir> {
             Node::TraitItem(TraitItem { ident, .. })
             | Node::ImplItem(ImplItem { ident, .. })
             | Node::ForeignItem(ForeignItem { ident, .. })
+            | Node::Field(StructField { ident, .. })
+            | Node::Variant(Variant { ident, .. })
+            | Node::MacroDef(MacroDef { ident, .. })
             | Node::Item(Item { ident, .. }) => Some(*ident),
             _ => None,
         }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index 7ab18e54f7e..59786059fae 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -102,43 +102,89 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             None => String::new(),
         };
 
-        let (span_1, span_2, main_label, span_label) = match (sup_is_ret_type, sub_is_ret_type) {
-            (None, None) => {
-                let (main_label_1, span_label_1) = if ty_sup.hir_id == ty_sub.hir_id {
+        let (span_1, span_2, main_label, span_label, future_return_type) =
+            match (sup_is_ret_type, sub_is_ret_type) {
+                (None, None) => {
+                    let (main_label_1, span_label_1) = if ty_sup.hir_id == ty_sub.hir_id {
+                        (
+                            "this type is declared with multiple lifetimes...".to_owned(),
+                            "...but data with one lifetime flows into the other here".to_owned(),
+                        )
+                    } else {
+                        (
+                            "these two types are declared with different lifetimes...".to_owned(),
+                            format!("...but data{} flows{} here", span_label_var1, span_label_var2),
+                        )
+                    };
+                    (ty_sup.span, ty_sub.span, main_label_1, span_label_1, None)
+                }
+
+                (Some(ret_span), _) => {
+                    let sup_future = self.future_return_type(scope_def_id_sup);
+                    let (return_type, action) = if let Some(_) = sup_future {
+                        ("returned future", "held across an await point")
+                    } else {
+                        ("return type", "returned")
+                    };
+
                     (
-                        "this type is declared with multiple lifetimes...".to_owned(),
-                        "...but data with one lifetime flows into the other here".to_owned(),
+                        ty_sub.span,
+                        ret_span,
+                        format!(
+                            "this parameter and the {} are declared with different lifetimes...",
+                            return_type
+                        ),
+                        format!("...but data{} is {} here", span_label_var1, action),
+                        sup_future,
                     )
-                } else {
+                }
+                (_, Some(ret_span)) => {
+                    let sub_future = self.future_return_type(scope_def_id_sub);
+                    let (return_type, action) = if let Some(_) = sub_future {
+                        ("returned future", "held across an await point")
+                    } else {
+                        ("return type", "returned")
+                    };
+
                     (
-                        "these two types are declared with different lifetimes...".to_owned(),
-                        format!("...but data{} flows{} here", span_label_var1, span_label_var2),
+                        ty_sup.span,
+                        ret_span,
+                        format!(
+                            "this parameter and the {} are declared with different lifetimes...",
+                            return_type
+                        ),
+                        format!("...but data{} is {} here", span_label_var1, action),
+                        sub_future,
                     )
-                };
-                (ty_sup.span, ty_sub.span, main_label_1, span_label_1)
-            }
-
-            (Some(ret_span), _) => (
-                ty_sub.span,
-                ret_span,
-                "this parameter and the return type are declared with different lifetimes..."
-                    .to_owned(),
-                format!("...but data{} is returned here", span_label_var1),
-            ),
-            (_, Some(ret_span)) => (
-                ty_sup.span,
-                ret_span,
-                "this parameter and the return type are declared with different lifetimes..."
-                    .to_owned(),
-                format!("...but data{} is returned here", span_label_var1),
-            ),
-        };
-
-        struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch")
-            .span_label(span_1, main_label)
-            .span_label(span_2, String::new())
-            .span_label(span, span_label)
-            .emit();
+                }
+            };
+
+        let mut e = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
+
+        e.span_label(span_1, main_label);
+        e.span_label(span_2, String::new());
+        e.span_label(span, span_label);
+
+        if let Some(t) = future_return_type {
+            let snip = self
+                .tcx()
+                .sess
+                .source_map()
+                .span_to_snippet(t.span)
+                .ok()
+                .and_then(|s| match (&t.kind, s.as_str()) {
+                    (rustc_hir::TyKind::Tup(&[]), "") => Some("()".to_string()),
+                    (_, "") => None,
+                    _ => Some(s),
+                })
+                .unwrap_or("{unnamed_type}".to_string());
+
+            e.span_label(
+                t.span,
+                &format!("this `async fn` implicitly returns an `impl Future<Output = {}>`", snip),
+            );
+        }
+        e.emit();
         Some(ErrorReported)
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index c055fed43f6..ca93b2777ab 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -85,6 +85,60 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         })
     }
 
+    pub(super) fn future_return_type(
+        &self,
+        local_def_id: LocalDefId,
+    ) -> Option<&rustc_hir::Ty<'_>> {
+        if let Some(hir::IsAsync::Async) = self.asyncness(local_def_id) {
+            if let rustc_middle::ty::Opaque(def_id, _) =
+                self.tcx().type_of(local_def_id).fn_sig(self.tcx()).output().skip_binder().kind()
+            {
+                match self.tcx().hir().get_if_local(*def_id) {
+                    Some(hir::Node::Item(hir::Item {
+                        kind:
+                            hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+                                bounds,
+                                origin: hir::OpaqueTyOrigin::AsyncFn,
+                                ..
+                            }),
+                        ..
+                    })) => {
+                        for b in bounds.iter() {
+                            if let hir::GenericBound::LangItemTrait(
+                                hir::LangItem::Future,
+                                _span,
+                                _hir_id,
+                                generic_args,
+                            ) = b
+                            {
+                                for type_binding in generic_args.bindings.iter() {
+                                    if type_binding.ident.name == rustc_span::sym::Output {
+                                        if let hir::TypeBindingKind::Equality { ty } =
+                                            type_binding.kind
+                                        {
+                                            return Some(ty);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    _ => {}
+                }
+            }
+        }
+        None
+    }
+
+    pub(super) fn asyncness(&self, local_def_id: LocalDefId) -> Option<hir::IsAsync> {
+        // similar to the asyncness fn in rustc_ty::ty
+        let hir_id = self.tcx().hir().local_def_id_to_hir_id(local_def_id);
+        let node = self.tcx().hir().get(hir_id);
+        let fn_like = rustc_middle::hir::map::blocks::FnLikeNode::from_node(node)?;
+
+        Some(fn_like.asyncness())
+    }
+
     // Here, we check for the case where the anonymous region
     // is in the return type.
     // FIXME(#42703) - Need to handle certain cases here.
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index dfc6f691457..1fc2d281e79 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -554,6 +554,8 @@ fn test_debugging_options_tracking_hash() {
     tracked!(function_sections, Some(false));
     tracked!(human_readable_cgu_names, true);
     tracked!(inline_in_all_cgus, Some(true));
+    tracked!(inline_mir_threshold, 123);
+    tracked!(inline_mir_hint_threshold, 123);
     tracked!(insert_sideeffect, true);
     tracked!(instrument_coverage, true);
     tracked!(instrument_mcount, true);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 3ed7d20ae45..d9ec6d51cdf 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -880,12 +880,6 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> {
             })
         }
     }
-
-    // in general the pretty printer processes unexpanded code, so
-    // we override the default `visit_mac` method which panics.
-    fn visit_mac(&mut self, mac: &mut ast::MacCall) {
-        noop_visit_mac(mac, self)
-    }
 }
 
 /// Returns a version string such as "rustc 1.46.0 (04488afe3 2020-08-24)"
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 9aeeb627792..08c147ec3ac 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -270,15 +270,9 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         self.check_id(id);
     }
 
-    fn visit_mac(&mut self, mac: &'a ast::MacCall) {
-        // FIXME(#54110): So, this setup isn't really right. I think
-        // that (a) the librustc_ast visitor ought to be doing this as
-        // part of `walk_mac`, and (b) we should be calling
-        // `visit_path`, *but* that would require a `NodeId`, and I
-        // want to get #53686 fixed quickly. -nmatsakis
-        ast_visit::walk_path(self, &mac.path);
-
+    fn visit_mac_call(&mut self, mac: &'a ast::MacCall) {
         run_early_pass!(self, check_mac, mac);
+        ast_visit::walk_mac(self, mac);
     }
 }
 
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index ff7a145c266..1d0d6980b7a 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2801,6 +2801,7 @@ declare_lint_pass! {
         UNSTABLE_NAME_COLLISIONS,
         IRREFUTABLE_LET_PATTERNS,
         BROKEN_INTRA_DOC_LINKS,
+        PRIVATE_INTRA_DOC_LINKS,
         INVALID_CODEBLOCK_ATTRIBUTES,
         MISSING_CRATE_LEVEL_DOCS,
         MISSING_DOC_CODE_EXAMPLES,
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 44f57cfbe28..c3afc9f048c 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -127,7 +127,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
         if ty == CrateType::Staticlib
             || (ty == CrateType::Executable
                 && sess.crt_static(Some(ty))
-                && !sess.target.options.crt_static_allows_dylibs)
+                && !sess.target.crt_static_allows_dylibs)
         {
             for &cnum in tcx.crates().iter() {
                 if tcx.dep_kind(cnum).macros_only() {
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index d16985b9c2b..c4c025de8b3 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -373,11 +373,10 @@ impl<'a> CrateLocator<'a> {
         seen_paths: &mut FxHashSet<PathBuf>,
     ) -> Result<Option<Library>, CrateError> {
         // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
-        let dylib_prefix =
-            format!("{}{}{}", self.target.options.dll_prefix, self.crate_name, extra_prefix);
+        let dylib_prefix = format!("{}{}{}", self.target.dll_prefix, self.crate_name, extra_prefix);
         let rlib_prefix = format!("lib{}{}", self.crate_name, extra_prefix);
         let staticlib_prefix =
-            format!("{}{}{}", self.target.options.staticlib_prefix, self.crate_name, extra_prefix);
+            format!("{}{}{}", self.target.staticlib_prefix, self.crate_name, extra_prefix);
 
         let mut candidates: FxHashMap<_, (FxHashMap<_, _>, FxHashMap<_, _>, FxHashMap<_, _>)> =
             Default::default();
@@ -405,17 +404,14 @@ impl<'a> CrateLocator<'a> {
                 (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib)
             } else if file.starts_with(&rlib_prefix) && file.ends_with(".rmeta") {
                 (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta)
-            } else if file.starts_with(&dylib_prefix)
-                && file.ends_with(&self.target.options.dll_suffix)
-            {
+            } else if file.starts_with(&dylib_prefix) && file.ends_with(&self.target.dll_suffix) {
                 (
-                    &file
-                        [(dylib_prefix.len())..(file.len() - self.target.options.dll_suffix.len())],
+                    &file[(dylib_prefix.len())..(file.len() - self.target.dll_suffix.len())],
                     CrateFlavor::Dylib,
                 )
             } else {
                 if file.starts_with(&staticlib_prefix)
-                    && file.ends_with(&self.target.options.staticlib_suffix)
+                    && file.ends_with(&self.target.staticlib_suffix)
                 {
                     staticlibs
                         .push(CrateMismatch { path: spf.path.clone(), got: "static".to_string() });
@@ -679,8 +675,8 @@ impl<'a> CrateLocator<'a> {
             };
 
             if file.starts_with("lib") && (file.ends_with(".rlib") || file.ends_with(".rmeta"))
-                || file.starts_with(&self.target.options.dll_prefix)
-                    && file.ends_with(&self.target.options.dll_suffix)
+                || file.starts_with(&self.target.dll_prefix)
+                    && file.ends_with(&self.target.dll_suffix)
             {
                 // Make sure there's at most one rlib and at most one dylib.
                 // Note to take care and match against the non-canonicalized name:
@@ -712,8 +708,8 @@ impl<'a> CrateLocator<'a> {
             crate_name: self.crate_name,
             root: self.root.cloned(),
             triple: self.triple,
-            dll_prefix: self.target.options.dll_prefix.clone(),
-            dll_suffix: self.target.options.dll_suffix.clone(),
+            dll_prefix: self.target.dll_prefix.clone(),
+            dll_suffix: self.target.dll_suffix.clone(),
             rejected_via_hash: self.rejected_via_hash,
             rejected_via_triple: self.rejected_via_triple,
             rejected_via_kind: self.rejected_via_kind,
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 5e65f075ea4..2f7c2c2c405 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -149,7 +149,7 @@ impl Collector<'tcx> {
             }
             return;
         }
-        let is_osx = self.tcx.sess.target.options.is_like_osx;
+        let is_osx = self.tcx.sess.target.is_like_osx;
         if lib.kind == NativeLibKind::Framework && !is_osx {
             let msg = "native frameworks are only available on macOS targets";
             match span {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index c031e0e2e19..746c3b6af12 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -856,7 +856,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                 .tables
                 .children
                 .get(self, index)
-                .unwrap_or(Lazy::empty())
+                .unwrap_or_else(Lazy::empty)
                 .decode(self)
                 .map(|index| ty::FieldDef {
                     did: self.local_def_id(index),
@@ -888,7 +888,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                 .tables
                 .children
                 .get(self, item_id)
-                .unwrap_or(Lazy::empty())
+                .unwrap_or_else(Lazy::empty)
                 .decode(self)
                 .map(|index| self.get_variant(&self.kind(index), index, did, tcx.sess))
                 .collect()
@@ -1075,7 +1075,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
 
         // Iterate over all children.
         let macros_only = self.dep_kind.lock().macros_only();
-        let children = self.root.tables.children.get(self, id).unwrap_or(Lazy::empty());
+        let children = self.root.tables.children.get(self, id).unwrap_or_else(Lazy::empty);
         for child_index in children.decode((self, sess)) {
             if macros_only {
                 continue;
@@ -1098,7 +1098,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                             .tables
                             .children
                             .get(self, child_index)
-                            .unwrap_or(Lazy::empty());
+                            .unwrap_or_else(Lazy::empty);
                         for child_index in child_children.decode((self, sess)) {
                             let kind = self.def_kind(child_index);
                             callback(Export {
@@ -1284,7 +1284,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
     }
 
     fn get_item_variances(&self, id: DefIndex) -> Vec<ty::Variance> {
-        self.root.tables.variances.get(self, id).unwrap_or(Lazy::empty()).decode(self).collect()
+        self.root.tables.variances.get(self, id).unwrap_or_else(Lazy::empty).decode(self).collect()
     }
 
     fn get_ctor_kind(&self, node_id: DefIndex) -> CtorKind {
@@ -1323,7 +1323,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .tables
             .attributes
             .get(self, item_id)
-            .unwrap_or(Lazy::empty())
+            .unwrap_or_else(Lazy::empty)
             .decode((self, sess))
             .collect::<Vec<_>>()
     }
@@ -1333,7 +1333,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .tables
             .children
             .get(self, id)
-            .unwrap_or(Lazy::empty())
+            .unwrap_or_else(Lazy::empty)
             .decode(self)
             .map(|index| respan(self.get_span(index, sess), self.item_ident(index, sess).name))
             .collect()
@@ -1349,7 +1349,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                 .tables
                 .inherent_impls
                 .get(self, id)
-                .unwrap_or(Lazy::empty())
+                .unwrap_or_else(Lazy::empty)
                 .decode(self)
                 .map(|index| self.local_def_id(index)),
         )
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 66532ea02f3..3250f1830de 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -26,7 +26,7 @@ rustc_index = { path = "../rustc_index" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.32.0"
+chalk-ir = "0.36.0"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 measureme = "9.0.0"
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 106fa8c78fa..d86e8987195 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -478,7 +478,7 @@ impl<'hir> Map<'hir> {
     }
 
     pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> {
-        id.as_local().map(|id| self.get(self.local_def_id_to_hir_id(id)))
+        id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
     }
 
     pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index def9e5ebb52..41342764ba7 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -48,10 +48,12 @@ fn update_limit(
                         .unwrap_or(attr.span);
 
                     let error_str = match e.kind() {
-                        IntErrorKind::Overflow => "`limit` is too large",
+                        IntErrorKind::PosOverflow => "`limit` is too large",
                         IntErrorKind::Empty => "`limit` must be a non-negative integer",
                         IntErrorKind::InvalidDigit => "not a valid integer",
-                        IntErrorKind::Underflow => bug!("`limit` should never underflow"),
+                        IntErrorKind::NegOverflow => {
+                            bug!("`limit` should never negatively overflow")
+                        }
                         IntErrorKind::Zero => bug!("zero is a valid `limit`"),
                         kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
                     };
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 391bd8be7e4..0801188b278 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -109,24 +109,21 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
                 args.visit_with(visitor)
             }
             Assert { ref cond, ref msg, .. } => {
-                if cond.visit_with(visitor).is_break() {
-                    use AssertKind::*;
-                    match msg {
-                        BoundsCheck { ref len, ref index } => {
-                            len.visit_with(visitor)?;
-                            index.visit_with(visitor)
-                        }
-                        Overflow(_, l, r) => {
-                            l.visit_with(visitor)?;
-                            r.visit_with(visitor)
-                        }
-                        OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
-                            op.visit_with(visitor)
-                        }
-                        ResumedAfterReturn(_) | ResumedAfterPanic(_) => ControlFlow::CONTINUE,
+                cond.visit_with(visitor)?;
+                use AssertKind::*;
+                match msg {
+                    BoundsCheck { ref len, ref index } => {
+                        len.visit_with(visitor)?;
+                        index.visit_with(visitor)
+                    }
+                    Overflow(_, l, r) => {
+                        l.visit_with(visitor)?;
+                        r.visit_with(visitor)
+                    }
+                    OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
+                        op.visit_with(visitor)
                     }
-                } else {
-                    ControlFlow::CONTINUE
+                    ResumedAfterReturn(_) | ResumedAfterPanic(_) => ControlFlow::CONTINUE,
                 }
             }
             InlineAsm { ref operands, .. } => operands.visit_with(visitor),
diff --git a/compiler/rustc_middle/src/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs
index d8507d08c1b..f864ad8ebcd 100644
--- a/compiler/rustc_middle/src/traits/chalk.rs
+++ b/compiler/rustc_middle/src/traits/chalk.rs
@@ -102,48 +102,6 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> {
         Some(write())
     }
 
-    fn debug_application_ty(
-        application_ty: &chalk_ir::ApplicationTy<Self>,
-        fmt: &mut fmt::Formatter<'_>,
-    ) -> Option<fmt::Result> {
-        match application_ty.name {
-            chalk_ir::TypeName::Ref(mutbl) => {
-                let data = application_ty.substitution.interned();
-                match (&**data[0].interned(), &**data[1].interned()) {
-                    (
-                        chalk_ir::GenericArgData::Lifetime(lifetime),
-                        chalk_ir::GenericArgData::Ty(ty),
-                    ) => Some(match mutbl {
-                        chalk_ir::Mutability::Not => write!(fmt, "(&{:?} {:?})", lifetime, ty),
-                        chalk_ir::Mutability::Mut => write!(fmt, "(&{:?} mut {:?})", lifetime, ty),
-                    }),
-                    _ => unreachable!(),
-                }
-            }
-            chalk_ir::TypeName::Array => {
-                let data = application_ty.substitution.interned();
-                match (&**data[0].interned(), &**data[1].interned()) {
-                    (chalk_ir::GenericArgData::Ty(ty), chalk_ir::GenericArgData::Const(len)) => {
-                        Some(write!(fmt, "[{:?}; {:?}]", ty, len))
-                    }
-                    _ => unreachable!(),
-                }
-            }
-            chalk_ir::TypeName::Slice => {
-                let data = application_ty.substitution.interned();
-                let ty = match &**data[0].interned() {
-                    chalk_ir::GenericArgData::Ty(t) => t,
-                    _ => unreachable!(),
-                };
-                Some(write!(fmt, "[{:?}]", ty))
-            }
-            _ => {
-                let chalk_ir::ApplicationTy { name, substitution } = application_ty;
-                Some(write!(fmt, "{:?}{:?}", name, chalk_ir::debug::Angle(substitution.interned())))
-            }
-        }
-    }
-
     fn debug_substitution(
         substitution: &chalk_ir::Substitution<Self>,
         fmt: &mut fmt::Formatter<'_>,
@@ -174,6 +132,32 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> {
         Some(write!(fmt, "{:?}", clauses.interned()))
     }
 
+    fn debug_ty(ty: &chalk_ir::Ty<Self>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
+        match &ty.interned().kind {
+            chalk_ir::TyKind::Ref(chalk_ir::Mutability::Not, lifetime, ty) => {
+                Some(write!(fmt, "(&{:?} {:?})", lifetime, ty))
+            }
+            chalk_ir::TyKind::Ref(chalk_ir::Mutability::Mut, lifetime, ty) => {
+                Some(write!(fmt, "(&{:?} mut {:?})", lifetime, ty))
+            }
+            chalk_ir::TyKind::Array(ty, len) => Some(write!(fmt, "[{:?}; {:?}]", ty, len)),
+            chalk_ir::TyKind::Slice(ty) => Some(write!(fmt, "[{:?}]", ty)),
+            chalk_ir::TyKind::Tuple(len, substs) => Some((|| {
+                write!(fmt, "(")?;
+                for (idx, substitution) in substs.interned().iter().enumerate() {
+                    if idx == *len && *len != 1 {
+                        // Don't add a trailing comma if the tuple has more than one element
+                        write!(fmt, "{:?}", substitution)?;
+                    } else {
+                        write!(fmt, "{:?},", substitution)?;
+                    }
+                }
+                write!(fmt, ")")
+            })()),
+            _ => None,
+        }
+    }
+
     fn debug_alias(
         alias_ty: &chalk_ir::AliasTy<Self>,
         fmt: &mut fmt::Formatter<'_>,
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index 126257a5b49..63e95f25bb7 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -168,7 +168,7 @@ impl ScalarInt {
     #[inline(always)]
     fn check_data(self) {
         // Using a block `{self.data}` here to force a copy instead of using `self.data`
-        // directly, because `assert_eq` takes references to its arguments and formatting
+        // directly, because `debug_assert_eq` takes references to its arguments and formatting
         // arguments and would thus borrow `self.data`. Since `Self`
         // is a packed struct, that would create a possibly unaligned reference, which
         // is UB.
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 8b3fb875070..306cebd9cb7 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -1,6 +1,6 @@
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::ty::print::{FmtPrinter, Printer};
-use crate::ty::subst::InternalSubsts;
+use crate::ty::subst::{InternalSubsts, Subst};
 use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable};
 use rustc_errors::ErrorReported;
 use rustc_hir::def::Namespace;
@@ -470,10 +470,33 @@ impl<'tcx> Instance<'tcx> {
     /// This function returns `Some(substs)` in the former case and `None` otherwise -- i.e., if
     /// this function returns `None`, then the MIR body does not require substitution during
     /// codegen.
-    pub fn substs_for_mir_body(&self) -> Option<SubstsRef<'tcx>> {
+    fn substs_for_mir_body(&self) -> Option<SubstsRef<'tcx>> {
         if self.def.has_polymorphic_mir_body() { Some(self.substs) } else { None }
     }
 
+    pub fn subst_mir<T>(&self, tcx: TyCtxt<'tcx>, v: &T) -> T
+    where
+        T: TypeFoldable<'tcx> + Copy,
+    {
+        if let Some(substs) = self.substs_for_mir_body() { v.subst(tcx, substs) } else { *v }
+    }
+
+    pub fn subst_mir_and_normalize_erasing_regions<T>(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        v: &T,
+    ) -> T
+    where
+        T: TypeFoldable<'tcx> + Clone,
+    {
+        if let Some(substs) = self.substs_for_mir_body() {
+            tcx.subst_and_normalize_erasing_regions(substs, param_env, v)
+        } else {
+            tcx.normalize_erasing_regions(param_env, v.clone())
+        }
+    }
+
     /// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by
     /// identify parameters if they are determined to be unused in `instance.def`.
     pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 91c3dcbfa81..1e93c3650b8 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2601,15 +2601,14 @@ where
         };
 
         let target = &cx.tcx().sess.target;
-        let target_env_gnu_like = matches!(&target.target_env[..], "gnu" | "musl");
-        let win_x64_gnu =
-            target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu";
+        let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl");
+        let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu";
         let linux_s390x_gnu_like =
-            target.target_os == "linux" && target.arch == "s390x" && target_env_gnu_like;
+            target.os == "linux" && target.arch == "s390x" && target_env_gnu_like;
         let linux_sparc64_gnu_like =
-            target.target_os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
+            target.os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
         let linux_powerpc_gnu_like =
-            target.target_os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
+            target.os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
         let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
 
         // Handle safe Rust thin and fat pointers.
@@ -2775,7 +2774,7 @@ where
                     // anyway, we control all calls to it in libstd.
                     Abi::Vector { .. }
                         if abi != SpecAbi::PlatformIntrinsic
-                            && cx.tcx().sess.target.options.simd_types_indirect =>
+                            && cx.tcx().sess.target.simd_types_indirect =>
                     {
                         arg.make_indirect();
                         return;
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index aa5a696b09c..0042b4a3a42 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2795,10 +2795,50 @@ impl<'tcx> TyCtxt<'tcx> {
             .filter(|item| item.kind == AssocKind::Fn && item.defaultness.has_value())
     }
 
+    fn item_name_from_hir(self, def_id: DefId) -> Option<Ident> {
+        self.hir().get_if_local(def_id).and_then(|node| node.ident())
+    }
+
+    fn item_name_from_def_id(self, def_id: DefId) -> Option<Symbol> {
+        if def_id.index == CRATE_DEF_INDEX {
+            Some(self.original_crate_name(def_id.krate))
+        } else {
+            let def_key = self.def_key(def_id);
+            match def_key.disambiguated_data.data {
+                // The name of a constructor is that of its parent.
+                rustc_hir::definitions::DefPathData::Ctor => self.item_name_from_def_id(DefId {
+                    krate: def_id.krate,
+                    index: def_key.parent.unwrap(),
+                }),
+                _ => def_key.disambiguated_data.data.get_opt_name(),
+            }
+        }
+    }
+
+    /// Look up the name of an item across crates. This does not look at HIR.
+    ///
+    /// When possible, this function should be used for cross-crate lookups over
+    /// [`opt_item_name`] to avoid invalidating the incremental cache. If you
+    /// need to handle items without a name, or HIR items that will not be
+    /// serialized cross-crate, or if you need the span of the item, use
+    /// [`opt_item_name`] instead.
+    ///
+    /// [`opt_item_name`]: Self::opt_item_name
+    pub fn item_name(self, id: DefId) -> Symbol {
+        // Look at cross-crate items first to avoid invalidating the incremental cache
+        // unless we have to.
+        self.item_name_from_def_id(id).unwrap_or_else(|| {
+            bug!("item_name: no name for {:?}", self.def_path(id));
+        })
+    }
+
+    /// Look up the name and span of an item or [`Node`].
+    ///
+    /// See [`item_name`][Self::item_name] for more information.
     pub fn opt_item_name(self, def_id: DefId) -> Option<Ident> {
-        def_id
-            .as_local()
-            .and_then(|def_id| self.hir().get(self.hir().local_def_id_to_hir_id(def_id)).ident())
+        // Look at the HIR first so the span will be correct if this is a local item.
+        self.item_name_from_hir(def_id)
+            .or_else(|| self.item_name_from_def_id(def_id).map(Ident::with_dummy_span))
     }
 
     pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> {
@@ -2921,23 +2961,6 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    pub fn item_name(self, id: DefId) -> Symbol {
-        if id.index == CRATE_DEF_INDEX {
-            self.original_crate_name(id.krate)
-        } else {
-            let def_key = self.def_key(id);
-            match def_key.disambiguated_data.data {
-                // The name of a constructor is that of its parent.
-                rustc_hir::definitions::DefPathData::Ctor => {
-                    self.item_name(DefId { krate: id.krate, index: def_key.parent.unwrap() })
-                }
-                _ => def_key.disambiguated_data.data.get_opt_name().unwrap_or_else(|| {
-                    bug!("item_name: no name for {:?}", self.def_path(id));
-                }),
-            }
-        }
-    }
-
     /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
     pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
         match instance {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 8ff4adda606..1e4fd0921ee 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -63,7 +63,7 @@ thread_local! {
 /// Avoids running any queries during any prints that occur
 /// during the closure. This may alter the appearance of some
 /// types (e.g. forcing verbose printing for opaque types).
-/// This method is used during some queries (e.g. `predicates_of`
+/// This method is used during some queries (e.g. `explicit_item_bounds`
 /// for opaque types), to ensure that any debug printing that
 /// occurs during the query computation does not end up recursively
 /// calling the same query.
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
index 2e5a231fef0..2a90fb042dd 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
@@ -6,8 +6,8 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_middle::ty::print::RegionHighlightMode;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, RegionVid, Ty};
-use rustc_span::symbol::kw;
-use rustc_span::{symbol::Symbol, Span, DUMMY_SP};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{Span, DUMMY_SP};
 
 use crate::borrow_check::{nll::ToRegionVid, universal_regions::DefiningTy, MirBorrowckCtxt};
 
@@ -39,7 +39,7 @@ crate enum RegionNameSource {
     /// The region corresponding to a closure upvar.
     AnonRegionFromUpvar(Span, String),
     /// The region corresponding to the return type of a closure.
-    AnonRegionFromOutput(Span, String, String),
+    AnonRegionFromOutput(RegionNameHighlight, String),
     /// The region from a type yielded by a generator.
     AnonRegionFromYieldTy(Span, String),
     /// An anonymous region from an async fn.
@@ -57,6 +57,10 @@ crate enum RegionNameHighlight {
     /// The anonymous region corresponds to a region where the type annotation is completely missing
     /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
     CannotMatchHirTy(Span, String),
+    /// The anonymous region corresponds to a region where the type annotation is completely missing
+    /// from the code, and *even if* we print out the full name of the type, the region name won't
+    /// be included. This currently occurs for opaque types like `impl Future`.
+    Occluded(Span, String),
 }
 
 impl RegionName {
@@ -81,13 +85,14 @@ impl RegionName {
             | RegionNameSource::NamedFreeRegion(span)
             | RegionNameSource::SynthesizedFreeEnvRegion(span, _)
             | RegionNameSource::AnonRegionFromUpvar(span, _)
-            | RegionNameSource::AnonRegionFromOutput(span, _, _)
             | RegionNameSource::AnonRegionFromYieldTy(span, _)
             | RegionNameSource::AnonRegionFromAsyncFn(span) => Some(span),
-            RegionNameSource::AnonRegionFromArgument(ref highlight) => match *highlight {
+            RegionNameSource::AnonRegionFromArgument(ref highlight)
+            | RegionNameSource::AnonRegionFromOutput(ref highlight, _) => match *highlight {
                 RegionNameHighlight::MatchedHirTy(span)
                 | RegionNameHighlight::MatchedAdtAndSegment(span)
-                | RegionNameHighlight::CannotMatchHirTy(span, _) => Some(span),
+                | RegionNameHighlight::CannotMatchHirTy(span, _)
+                | RegionNameHighlight::Occluded(span, _) => Some(span),
             },
         }
     }
@@ -112,6 +117,7 @@ impl RegionName {
                 diag.span_label(*span, format!("has type `{}`", type_name));
             }
             RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::MatchedHirTy(span))
+            | RegionNameSource::AnonRegionFromOutput(RegionNameHighlight::MatchedHirTy(span), _)
             | RegionNameSource::AnonRegionFromAsyncFn(span) => {
                 diag.span_label(
                     *span,
@@ -120,16 +126,44 @@ impl RegionName {
             }
             RegionNameSource::AnonRegionFromArgument(
                 RegionNameHighlight::MatchedAdtAndSegment(span),
+            )
+            | RegionNameSource::AnonRegionFromOutput(
+                RegionNameHighlight::MatchedAdtAndSegment(span),
+                _,
             ) => {
                 diag.span_label(*span, format!("let's call this `{}`", self));
             }
+            RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::Occluded(
+                span,
+                type_name,
+            )) => {
+                diag.span_label(
+                    *span,
+                    format!("lifetime `{}` appears in the type {}", self, type_name),
+                );
+            }
+            RegionNameSource::AnonRegionFromOutput(
+                RegionNameHighlight::Occluded(span, type_name),
+                mir_description,
+            ) => {
+                diag.span_label(
+                    *span,
+                    format!(
+                        "return type{} `{}` contains a lifetime `{}`",
+                        mir_description, type_name, self
+                    ),
+                );
+            }
             RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => {
                 diag.span_label(
                     *span,
                     format!("lifetime `{}` appears in the type of `{}`", self, upvar_name),
                 );
             }
-            RegionNameSource::AnonRegionFromOutput(span, mir_description, type_name) => {
+            RegionNameSource::AnonRegionFromOutput(
+                RegionNameHighlight::CannotMatchHirTy(span, type_name),
+                mir_description,
+            ) => {
                 diag.span_label(*span, format!("return type{} is {}", mir_description, type_name));
             }
             RegionNameSource::AnonRegionFromYieldTy(span, type_name) => {
@@ -349,19 +383,21 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             argument_index,
         );
 
-        self.get_argument_hir_ty_for_highlighting(argument_index)
+        let highlight = self
+            .get_argument_hir_ty_for_highlighting(argument_index)
             .and_then(|arg_hir_ty| self.highlight_if_we_can_match_hir_ty(fr, arg_ty, arg_hir_ty))
-            .or_else(|| {
+            .unwrap_or_else(|| {
                 // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to
                 // the anonymous region. If it succeeds, the `synthesize_region_name` call below
                 // will increment the counter, "reserving" the number we just used.
                 let counter = *self.next_region_name.try_borrow().unwrap();
                 self.highlight_if_we_cannot_match_hir_ty(fr, arg_ty, span, counter)
-            })
-            .map(|highlight| RegionName {
-                name: self.synthesize_region_name(),
-                source: RegionNameSource::AnonRegionFromArgument(highlight),
-            })
+            });
+
+        Some(RegionName {
+            name: self.synthesize_region_name(),
+            source: RegionNameSource::AnonRegionFromArgument(highlight),
+        })
     }
 
     fn get_argument_hir_ty_for_highlighting(
@@ -399,7 +435,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         ty: Ty<'tcx>,
         span: Span,
         counter: usize,
-    ) -> Option<RegionNameHighlight> {
+    ) -> RegionNameHighlight {
         let mut highlight = RegionHighlightMode::default();
         highlight.highlighting_region_vid(needle_fr, counter);
         let type_name =
@@ -411,9 +447,9 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         );
         if type_name.find(&format!("'{}", counter)).is_some() {
             // Only add a label if we can confirm that a region was labelled.
-            Some(RegionNameHighlight::CannotMatchHirTy(span, type_name))
+            RegionNameHighlight::CannotMatchHirTy(span, type_name)
         } else {
-            None
+            RegionNameHighlight::Occluded(span, type_name)
         }
     }
 
@@ -643,6 +679,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
     /// or be early bound (named, not in argument).
     fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Option<RegionName> {
         let tcx = self.infcx.tcx;
+        let hir = tcx.hir();
 
         let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
         debug!("give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty);
@@ -650,42 +687,123 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
             return None;
         }
 
-        let mut highlight = RegionHighlightMode::default();
-        highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
-        let type_name =
-            self.infcx.extract_inference_diagnostics_data(return_ty.into(), Some(highlight)).name;
+        let mir_hir_id = self.mir_hir_id();
 
-        let (return_span, mir_description) = match tcx.hir().get(self.mir_hir_id()) {
+        let (return_span, mir_description, hir_ty) = match hir.get(mir_hir_id) {
             hir::Node::Expr(hir::Expr {
-                kind: hir::ExprKind::Closure(_, return_ty, _, span, gen_move),
-                ..
-            }) => (
-                match return_ty.output {
-                    hir::FnRetTy::DefaultReturn(_) => tcx.sess.source_map().end_point(*span),
-                    hir::FnRetTy::Return(_) => return_ty.output.span(),
-                },
-                if gen_move.is_some() { " of generator" } else { " of closure" },
-            ),
-            hir::Node::ImplItem(hir::ImplItem {
-                kind: hir::ImplItemKind::Fn(method_sig, _),
+                kind: hir::ExprKind::Closure(_, return_ty, body_id, span, _),
                 ..
-            }) => (method_sig.decl.output.span(), ""),
-            _ => (self.body.span, ""),
+            }) => {
+                let (mut span, mut hir_ty) = match return_ty.output {
+                    hir::FnRetTy::DefaultReturn(_) => {
+                        (tcx.sess.source_map().end_point(*span), None)
+                    }
+                    hir::FnRetTy::Return(hir_ty) => (return_ty.output.span(), Some(hir_ty)),
+                };
+                let mir_description = match hir.body(*body_id).generator_kind {
+                    Some(hir::GeneratorKind::Async(gen)) => match gen {
+                        hir::AsyncGeneratorKind::Block => " of async block",
+                        hir::AsyncGeneratorKind::Closure => " of async closure",
+                        hir::AsyncGeneratorKind::Fn => {
+                            let parent_item = hir.get(hir.get_parent_item(mir_hir_id));
+                            let output = &parent_item
+                                .fn_decl()
+                                .expect("generator lowered from async fn should be in fn")
+                                .output;
+                            span = output.span();
+                            if let hir::FnRetTy::Return(ret) = output {
+                                hir_ty = Some(self.get_future_inner_return_ty(*ret));
+                            }
+                            " of async function"
+                        }
+                    },
+                    Some(hir::GeneratorKind::Gen) => " of generator",
+                    None => " of closure",
+                };
+                (span, mir_description, hir_ty)
+            }
+            node => match node.fn_decl() {
+                Some(fn_decl) => {
+                    let hir_ty = match fn_decl.output {
+                        hir::FnRetTy::DefaultReturn(_) => None,
+                        hir::FnRetTy::Return(ty) => Some(ty),
+                    };
+                    (fn_decl.output.span(), "", hir_ty)
+                }
+                None => (self.body.span, "", None),
+            },
         };
 
+        let highlight = hir_ty
+            .and_then(|hir_ty| self.highlight_if_we_can_match_hir_ty(fr, return_ty, hir_ty))
+            .unwrap_or_else(|| {
+                // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to
+                // the anonymous region. If it succeeds, the `synthesize_region_name` call below
+                // will increment the counter, "reserving" the number we just used.
+                let counter = *self.next_region_name.try_borrow().unwrap();
+                self.highlight_if_we_cannot_match_hir_ty(fr, return_ty, return_span, counter)
+            });
+
         Some(RegionName {
-            // This counter value will already have been used, so this function will increment it
-            // so the next value will be used next and return the region name that would have been
-            // used.
             name: self.synthesize_region_name(),
-            source: RegionNameSource::AnonRegionFromOutput(
-                return_span,
-                mir_description.to_string(),
-                type_name,
-            ),
+            source: RegionNameSource::AnonRegionFromOutput(highlight, mir_description.to_string()),
         })
     }
 
+    /// From the [`hir::Ty`] of an async function's lowered return type,
+    /// retrieve the `hir::Ty` representing the type the user originally wrote.
+    ///
+    /// e.g. given the function:
+    ///
+    /// ```
+    /// async fn foo() -> i32 {}
+    /// ```
+    ///
+    /// this function, given the lowered return type of `foo`, an [`OpaqueDef`] that implements `Future<Output=i32>`,
+    /// returns the `i32`.
+    ///
+    /// [`OpaqueDef`]: hir::TyKind::OpaqueDef
+    fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
+        let hir = self.infcx.tcx.hir();
+
+        if let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind {
+            let opaque_ty = hir.item(id.id);
+            if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+                bounds:
+                    [hir::GenericBound::LangItemTrait(
+                        hir::LangItem::Future,
+                        _,
+                        _,
+                        hir::GenericArgs {
+                            bindings:
+                                [hir::TypeBinding {
+                                    ident: Ident { name: sym::Output, .. },
+                                    kind: hir::TypeBindingKind::Equality { ty },
+                                    ..
+                                }],
+                            ..
+                        },
+                    )],
+                ..
+            }) = opaque_ty.kind
+            {
+                ty
+            } else {
+                span_bug!(
+                    hir_ty.span,
+                    "bounds from lowered return type of async fn did not match expected format: {:?}",
+                    opaque_ty
+                );
+            }
+        } else {
+            span_bug!(
+                hir_ty.span,
+                "lowered return type of async fn is not OpaqueDef: {:?}",
+                hir_ty
+            );
+        }
+    }
+
     fn give_name_if_anonymous_region_appears_in_yield_ty(
         &self,
         fr: RegionVid,
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index ac8ab71a1dc..a5a7012852d 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -582,7 +582,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             self.check_member_constraints(infcx, &mut errors_buffer);
         }
 
-        let outlives_requirements = outlives_requirements.unwrap_or(vec![]);
+        let outlives_requirements = outlives_requirements.unwrap_or_default();
 
         if outlives_requirements.is_empty() {
             (None, errors_buffer)
diff --git a/compiler/rustc_mir/src/dataflow/framework/engine.rs b/compiler/rustc_mir/src/dataflow/framework/engine.rs
index 1b7264f86a2..3f9f558223b 100644
--- a/compiler/rustc_mir/src/dataflow/framework/engine.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/engine.rs
@@ -208,12 +208,19 @@ where
             }
         }
 
+        // `state` is not actually used between iterations;
+        // this is just an optimization to avoid reallocating
+        // every iteration.
         let mut state = analysis.bottom_value(body);
         while let Some(bb) = dirty_queue.pop() {
             let bb_data = &body[bb];
 
-            // Apply the block transfer function, using the cached one if it exists.
+            // Set the state to the entry state of the block.
+            // This is equivalent to `state = entry_sets[bb].clone()`,
+            // but it saves an allocation, thus improving compile times.
             state.clone_from(&entry_sets[bb]);
+
+            // Apply the block transfer function, using the cached one if it exists.
             match &apply_trans_for_block {
                 Some(apply) => apply(bb, &mut state),
                 None => A::Direction::apply_effects_in_block(&analysis, &mut state, bb, bb_data),
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index 8d0c8c18537..0f86a181a55 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -505,11 +505,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
         value: T,
     ) -> T {
-        if let Some(substs) = frame.instance.substs_for_mir_body() {
-            self.tcx.subst_and_normalize_erasing_regions(substs, self.param_env, &value)
-        } else {
-            self.tcx.normalize_erasing_regions(self.param_env, value)
-        }
+        frame.instance.subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, &value)
     }
 
     /// The `substs` are assumed to already be in our interpreter "universe" (param_env).
diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs
index 417176564b9..938181abff2 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -543,11 +543,11 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> {
         T: TypeFoldable<'tcx>,
     {
         debug!("monomorphize: self.instance={:?}", self.instance);
-        if let Some(substs) = self.instance.substs_for_mir_body() {
-            self.tcx.subst_and_normalize_erasing_regions(substs, ty::ParamEnv::reveal_all(), &value)
-        } else {
-            self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), value)
-        }
+        self.instance.subst_mir_and_normalize_erasing_regions(
+            self.tcx,
+            ty::ParamEnv::reveal_all(),
+            &value,
+        )
     }
 }
 
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
index 5083a45b539..037b80e4bf2 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
+++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
@@ -532,7 +532,7 @@ fn mono_item_visibility(
 }
 
 fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility {
-    if !tcx.sess.target.options.default_hidden_visibility {
+    if !tcx.sess.target.default_hidden_visibility {
         return Visibility::Default;
     }
 
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index f3d2ab9590e..7737672dbde 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -1,24 +1,20 @@
 //! Inlining pass for MIR functions
 
 use rustc_attr as attr;
+use rustc_hir as hir;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::Idx;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
-use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
 use rustc_span::{hygiene::ExpnKind, ExpnData, Span};
 use rustc_target::spec::abi::Abi;
 
 use super::simplify::{remove_dead_blocks, CfgSimplifier};
 use crate::transform::MirPass;
-use std::collections::VecDeque;
 use std::iter;
-use std::ops::RangeFrom;
-
-const DEFAULT_THRESHOLD: usize = 50;
-const HINT_THRESHOLD: usize = 100;
+use std::ops::{Range, RangeFrom};
 
 const INSTR_COST: usize = 5;
 const CALL_PENALTY: usize = 25;
@@ -32,140 +28,135 @@ pub struct Inline;
 #[derive(Copy, Clone, Debug)]
 struct CallSite<'tcx> {
     callee: Instance<'tcx>,
-    bb: BasicBlock,
+    block: BasicBlock,
+    target: Option<BasicBlock>,
     source_info: SourceInfo,
 }
 
 impl<'tcx> MirPass<'tcx> for Inline {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
-            if tcx.sess.opts.debugging_opts.instrument_coverage {
-                // The current implementation of source code coverage injects code region counters
-                // into the MIR, and assumes a 1-to-1 correspondence between MIR and source-code-
-                // based function.
-                debug!("function inlining is disabled when compiling with `instrument_coverage`");
-            } else {
-                Inliner {
-                    tcx,
-                    param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
-                    codegen_fn_attrs: tcx.codegen_fn_attrs(body.source.def_id()),
-                }
-                .run_pass(body);
-            }
+        if tcx.sess.opts.debugging_opts.mir_opt_level < 2 {
+            return;
         }
+
+        if tcx.sess.opts.debugging_opts.instrument_coverage {
+            // The current implementation of source code coverage injects code region counters
+            // into the MIR, and assumes a 1-to-1 correspondence between MIR and source-code-
+            // based function.
+            debug!("function inlining is disabled when compiling with `instrument_coverage`");
+            return;
+        }
+
+        if inline(tcx, body) {
+            debug!("running simplify cfg on {:?}", body.source);
+            CfgSimplifier::new(body).simplify();
+            remove_dead_blocks(body);
+        }
+    }
+}
+
+fn inline(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
+    let def_id = body.source.def_id();
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+
+    // Only do inlining into fn bodies.
+    if !tcx.hir().body_owner_kind(hir_id).is_fn_or_closure() {
+        return false;
     }
+    if body.source.promoted.is_some() {
+        return false;
+    }
+
+    let mut this = Inliner {
+        tcx,
+        param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
+        codegen_fn_attrs: tcx.codegen_fn_attrs(body.source.def_id()),
+        hir_id,
+        history: Vec::new(),
+        changed: false,
+    };
+    let blocks = BasicBlock::new(0)..body.basic_blocks().next_index();
+    this.process_blocks(body, blocks);
+    this.changed
 }
 
 struct Inliner<'tcx> {
     tcx: TyCtxt<'tcx>,
     param_env: ParamEnv<'tcx>,
+    /// Caller codegen attributes.
     codegen_fn_attrs: &'tcx CodegenFnAttrs,
+    /// Caller HirID.
+    hir_id: hir::HirId,
+    /// Stack of inlined instances.
+    history: Vec<Instance<'tcx>>,
+    /// Indicates that the caller body has been modified.
+    changed: bool,
 }
 
 impl Inliner<'tcx> {
-    fn run_pass(&self, caller_body: &mut Body<'tcx>) {
-        // Keep a queue of callsites to try inlining on. We take
-        // advantage of the fact that queries detect cycles here to
-        // allow us to try and fetch the fully optimized MIR of a
-        // call; if it succeeds, we can inline it and we know that
-        // they do not call us.  Otherwise, we just don't try to
-        // inline.
-        //
-        // We use a queue so that we inline "broadly" before we inline
-        // in depth. It is unclear if this is the best heuristic,
-        // really, but that's true of all the heuristics in this
-        // file. =)
-
-        let mut callsites = VecDeque::new();
-
-        let def_id = caller_body.source.def_id();
-
-        // Only do inlining into fn bodies.
-        let self_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-        if self.tcx.hir().body_owner_kind(self_hir_id).is_fn_or_closure()
-            && caller_body.source.promoted.is_none()
-        {
-            for (bb, bb_data) in caller_body.basic_blocks().iter_enumerated() {
-                if let Some(callsite) = self.get_valid_function_call(bb, bb_data, caller_body) {
-                    callsites.push_back(callsite);
-                }
+    fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) {
+        for bb in blocks {
+            let callsite = match self.get_valid_function_call(bb, &caller_body[bb], caller_body) {
+                None => continue,
+                Some(it) => it,
+            };
+
+            if !self.is_mir_available(&callsite.callee, caller_body) {
+                debug!("MIR unavailable {}", callsite.callee);
+                continue;
             }
-        } else {
-            return;
-        }
 
-        let mut changed = false;
-        while let Some(callsite) = callsites.pop_front() {
-            debug!("checking whether to inline callsite {:?}", callsite);
+            let callee_body = self.tcx.instance_mir(callsite.callee.def);
+            if !self.should_inline(callsite, callee_body) {
+                continue;
+            }
 
-            if let InstanceDef::Item(_) = callsite.callee.def {
-                if !self.tcx.is_mir_available(callsite.callee.def_id()) {
-                    debug!("checking whether to inline callsite {:?} - MIR unavailable", callsite,);
-                    continue;
-                }
+            if !self.tcx.consider_optimizing(|| {
+                format!("Inline {:?} into {}", callee_body.span, callsite.callee)
+            }) {
+                return;
             }
 
-            let callee_body = if let Some(callee_def_id) = callsite.callee.def_id().as_local() {
-                let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id);
-                // Avoid a cycle here by only using `instance_mir` only if we have
-                // a lower `HirId` than the callee. This ensures that the callee will
-                // not inline us. This trick only works without incremental compilation.
-                // So don't do it if that is enabled. Also avoid inlining into generators,
-                // since their `optimized_mir` is used for layout computation, which can
-                // create a cycle, even when no attempt is made to inline the function
-                // in the other direction.
-                if !self.tcx.dep_graph.is_fully_enabled()
-                    && self_hir_id < callee_hir_id
-                    && caller_body.generator_kind.is_none()
-                {
-                    self.tcx.instance_mir(callsite.callee.def)
-                } else {
-                    continue;
-                }
-            } else {
-                // This cannot result in a cycle since the callee MIR is from another crate
-                // and is already optimized.
-                self.tcx.instance_mir(callsite.callee.def)
-            };
+            let callee_body = callsite.callee.subst_mir_and_normalize_erasing_regions(
+                self.tcx,
+                self.param_env,
+                callee_body,
+            );
 
-            let callee_body: &Body<'tcx> = &*callee_body;
+            let old_blocks = caller_body.basic_blocks().next_index();
+            self.inline_call(callsite, caller_body, callee_body);
+            let new_blocks = old_blocks..caller_body.basic_blocks().next_index();
+            self.changed = true;
 
-            let callee_body = if self.consider_optimizing(callsite, callee_body) {
-                self.tcx.subst_and_normalize_erasing_regions(
-                    &callsite.callee.substs,
-                    self.param_env,
-                    callee_body,
-                )
-            } else {
-                continue;
-            };
+            self.history.push(callsite.callee);
+            self.process_blocks(caller_body, new_blocks);
+            self.history.pop();
+        }
+    }
 
-            let start = caller_body.basic_blocks().len();
-            debug!("attempting to inline callsite {:?} - body={:?}", callsite, callee_body);
-            if !self.inline_call(callsite, caller_body, callee_body) {
-                debug!("attempting to inline callsite {:?} - failure", callsite);
-                continue;
-            }
-            debug!("attempting to inline callsite {:?} - success", callsite);
-
-            // Add callsites from inlined function
-            for (bb, bb_data) in caller_body.basic_blocks().iter_enumerated().skip(start) {
-                if let Some(new_callsite) = self.get_valid_function_call(bb, bb_data, caller_body) {
-                    // Don't inline the same function multiple times.
-                    if callsite.callee != new_callsite.callee {
-                        callsites.push_back(new_callsite);
-                    }
-                }
+    fn is_mir_available(&self, callee: &Instance<'tcx>, caller_body: &Body<'tcx>) -> bool {
+        if let InstanceDef::Item(_) = callee.def {
+            if !self.tcx.is_mir_available(callee.def_id()) {
+                return false;
             }
-
-            changed = true;
         }
 
-        // Simplify if we inlined anything.
-        if changed {
-            debug!("running simplify cfg on {:?}", caller_body.source);
-            CfgSimplifier::new(caller_body).simplify();
-            remove_dead_blocks(caller_body);
+        if let Some(callee_def_id) = callee.def_id().as_local() {
+            let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id);
+            // Avoid a cycle here by only using `instance_mir` only if we have
+            // a lower `HirId` than the callee. This ensures that the callee will
+            // not inline us. This trick only works without incremental compilation.
+            // So don't do it if that is enabled. Also avoid inlining into generators,
+            // since their `optimized_mir` is used for layout computation, which can
+            // create a cycle, even when no attempt is made to inline the function
+            // in the other direction.
+            !self.tcx.dep_graph.is_fully_enabled()
+                && self.hir_id < callee_hir_id
+                && caller_body.generator_kind.is_none()
+        } else {
+            // This cannot result in a cycle since the callee MIR is from another crate
+            // and is already optimized.
+            true
         }
     }
 
@@ -182,7 +173,7 @@ impl Inliner<'tcx> {
 
         // Only consider direct calls to functions
         let terminator = bb_data.terminator();
-        if let TerminatorKind::Call { func: ref op, .. } = terminator.kind {
+        if let TerminatorKind::Call { func: ref op, ref destination, .. } = terminator.kind {
             if let ty::FnDef(callee_def_id, substs) = *op.ty(caller_body, self.tcx).kind() {
                 // To resolve an instance its substs have to be fully normalized, so
                 // we do this here.
@@ -196,21 +187,18 @@ impl Inliner<'tcx> {
                     return None;
                 }
 
-                return Some(CallSite { callee, bb, source_info: terminator.source_info });
+                return Some(CallSite {
+                    callee,
+                    block: bb,
+                    target: destination.map(|(_, target)| target),
+                    source_info: terminator.source_info,
+                });
             }
         }
 
         None
     }
 
-    fn consider_optimizing(&self, callsite: CallSite<'tcx>, callee_body: &Body<'tcx>) -> bool {
-        debug!("consider_optimizing({:?})", callsite);
-        self.should_inline(callsite, callee_body)
-            && self.tcx.consider_optimizing(|| {
-                format!("Inline {:?} into {:?}", callee_body.span, callsite)
-            })
-    }
-
     fn should_inline(&self, callsite: CallSite<'tcx>, callee_body: &Body<'tcx>) -> bool {
         debug!("should_inline({:?})", callsite);
         let tcx = self.tcx;
@@ -262,7 +250,11 @@ impl Inliner<'tcx> {
             }
         }
 
-        let mut threshold = if hinted { HINT_THRESHOLD } else { DEFAULT_THRESHOLD };
+        let mut threshold = if hinted {
+            self.tcx.sess.opts.debugging_opts.inline_mir_hint_threshold
+        } else {
+            self.tcx.sess.opts.debugging_opts.inline_mir_threshold
+        };
 
         // Significantly lower the threshold for inlining cold functions
         if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
@@ -309,7 +301,7 @@ impl Inliner<'tcx> {
                     work_list.push(target);
                     // If the place doesn't actually need dropping, treat it like
                     // a regular goto.
-                    let ty = place.ty(callee_body, tcx).subst(tcx, callsite.callee.substs).ty;
+                    let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty);
                     if ty.needs_drop(tcx, self.param_env) {
                         cost += CALL_PENALTY;
                         if let Some(unwind) = unwind {
@@ -330,7 +322,18 @@ impl Inliner<'tcx> {
                 }
 
                 TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => {
-                    if let ty::FnDef(def_id, _) = *f.literal.ty.kind() {
+                    if let ty::FnDef(def_id, substs) =
+                        *callsite.callee.subst_mir(self.tcx, &f.literal.ty).kind()
+                    {
+                        let substs = self.tcx.normalize_erasing_regions(self.param_env, substs);
+                        if let Ok(Some(instance)) =
+                            Instance::resolve(self.tcx, self.param_env, def_id, substs)
+                        {
+                            if callsite.callee == instance || self.history.contains(&instance) {
+                                debug!("`callee is recursive - not inlining");
+                                return false;
+                            }
+                        }
                         // Don't give intrinsics the extra penalty for calls
                         let f = tcx.fn_sig(def_id);
                         if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
@@ -371,8 +374,7 @@ impl Inliner<'tcx> {
         let ptr_size = tcx.data_layout.pointer_size.bytes();
 
         for v in callee_body.vars_and_temps_iter() {
-            let v = &callee_body.local_decls[v];
-            let ty = v.ty.subst(tcx, callsite.callee.substs);
+            let ty = callsite.callee.subst_mir(self.tcx, &callee_body.local_decls[v].ty);
             // Cost of the var is the size in machine-words, if we know
             // it.
             if let Some(size) = type_size_of(tcx, self.param_env, ty) {
@@ -401,13 +403,10 @@ impl Inliner<'tcx> {
         callsite: CallSite<'tcx>,
         caller_body: &mut Body<'tcx>,
         mut callee_body: Body<'tcx>,
-    ) -> bool {
-        let terminator = caller_body[callsite.bb].terminator.take().unwrap();
+    ) {
+        let terminator = caller_body[callsite.block].terminator.take().unwrap();
         match terminator.kind {
-            // FIXME: Handle inlining of diverging calls
-            TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => {
-                debug!("inlined {:?} into {:?}", callsite.callee, caller_body.source);
-
+            TerminatorKind::Call { args, destination, cleanup, .. } => {
                 // If the call is something like `a[*i] = f(i)`, where
                 // `i : &mut usize`, then just duplicating the `a[*i]`
                 // Place could result in two different locations if `f`
@@ -424,35 +423,31 @@ impl Inliner<'tcx> {
                     false
                 }
 
-                let dest = if dest_needs_borrow(destination.0) {
-                    trace!("creating temp for return destination");
-                    let dest = Rvalue::Ref(
-                        self.tcx.lifetimes.re_erased,
-                        BorrowKind::Mut { allow_two_phase_borrow: false },
-                        destination.0,
-                    );
-
-                    let ty = dest.ty(caller_body, self.tcx);
-
-                    let temp = LocalDecl::new(ty, callsite.source_info.span);
-
-                    let tmp = caller_body.local_decls.push(temp);
-                    let tmp = Place::from(tmp);
-
-                    let stmt = Statement {
-                        source_info: callsite.source_info,
-                        kind: StatementKind::Assign(box (tmp, dest)),
-                    };
-                    caller_body[callsite.bb].statements.push(stmt);
-                    self.tcx.mk_place_deref(tmp)
+                let dest = if let Some((destination_place, _)) = destination {
+                    if dest_needs_borrow(destination_place) {
+                        trace!("creating temp for return destination");
+                        let dest = Rvalue::Ref(
+                            self.tcx.lifetimes.re_erased,
+                            BorrowKind::Mut { allow_two_phase_borrow: false },
+                            destination_place,
+                        );
+                        let dest_ty = dest.ty(caller_body, self.tcx);
+                        let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty));
+                        caller_body[callsite.block].statements.push(Statement {
+                            source_info: callsite.source_info,
+                            kind: StatementKind::Assign(box (temp, dest)),
+                        });
+                        self.tcx.mk_place_deref(temp)
+                    } else {
+                        destination_place
+                    }
                 } else {
-                    destination.0
+                    trace!("creating temp for return place");
+                    Place::from(self.new_call_temp(caller_body, &callsite, callee_body.return_ty()))
                 };
 
-                let return_block = destination.1;
-
                 // Copy the arguments if needed.
-                let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, return_block);
+                let args: Vec<_> = self.make_call_args(args, &callsite, caller_body);
 
                 let mut integrator = Integrator {
                     args: &args,
@@ -460,7 +455,7 @@ impl Inliner<'tcx> {
                     new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
                     new_blocks: BasicBlock::new(caller_body.basic_blocks().len())..,
                     destination: dest,
-                    return_block,
+                    return_block: callsite.target,
                     cleanup_block: cleanup,
                     in_cleanup_block: false,
                     tcx: self.tcx,
@@ -509,7 +504,7 @@ impl Inliner<'tcx> {
                 caller_body.var_debug_info.extend(callee_body.var_debug_info.drain(..));
                 caller_body.basic_blocks_mut().extend(callee_body.basic_blocks_mut().drain(..));
 
-                caller_body[callsite.bb].terminator = Some(Terminator {
+                caller_body[callsite.block].terminator = Some(Terminator {
                     source_info: callsite.source_info,
                     kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) },
                 });
@@ -523,14 +518,8 @@ impl Inliner<'tcx> {
                         matches!(constant.literal.val, ConstKind::Unevaluated(_, _, _))
                     }),
                 );
-
-                true
-            }
-            kind => {
-                caller_body[callsite.bb].terminator =
-                    Some(Terminator { source_info: terminator.source_info, kind });
-                false
             }
+            kind => bug!("unexpected terminator kind {:?}", kind),
         }
     }
 
@@ -539,7 +528,6 @@ impl Inliner<'tcx> {
         args: Vec<Operand<'tcx>>,
         callsite: &CallSite<'tcx>,
         caller_body: &mut Body<'tcx>,
-        return_block: BasicBlock,
     ) -> Vec<Local> {
         let tcx = self.tcx;
 
@@ -570,18 +558,8 @@ impl Inliner<'tcx> {
         // `callee_body.spread_arg == None`, instead of special-casing closures.
         if tcx.is_closure(callsite.callee.def_id()) {
             let mut args = args.into_iter();
-            let self_ = self.create_temp_if_necessary(
-                args.next().unwrap(),
-                callsite,
-                caller_body,
-                return_block,
-            );
-            let tuple = self.create_temp_if_necessary(
-                args.next().unwrap(),
-                callsite,
-                caller_body,
-                return_block,
-            );
+            let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
+            let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
             assert!(args.next().is_none());
 
             let tuple = Place::from(tuple);
@@ -601,13 +579,13 @@ impl Inliner<'tcx> {
                     Operand::Move(tcx.mk_place_field(tuple, Field::new(i), ty.expect_ty()));
 
                 // Spill to a local to make e.g., `tmp0`.
-                self.create_temp_if_necessary(tuple_field, callsite, caller_body, return_block)
+                self.create_temp_if_necessary(tuple_field, callsite, caller_body)
             });
 
             closure_ref_arg.chain(tuple_tmp_args).collect()
         } else {
             args.into_iter()
-                .map(|a| self.create_temp_if_necessary(a, callsite, caller_body, return_block))
+                .map(|a| self.create_temp_if_necessary(a, callsite, caller_body))
                 .collect()
         }
     }
@@ -619,46 +597,52 @@ impl Inliner<'tcx> {
         arg: Operand<'tcx>,
         callsite: &CallSite<'tcx>,
         caller_body: &mut Body<'tcx>,
-        return_block: BasicBlock,
     ) -> Local {
-        // FIXME: Analysis of the usage of the arguments to avoid
-        // unnecessary temporaries.
-
+        // Reuse the operand if it is a moved temporary.
         if let Operand::Move(place) = &arg {
             if let Some(local) = place.as_local() {
                 if caller_body.local_kind(local) == LocalKind::Temp {
-                    // Reuse the operand if it's a temporary already
                     return local;
                 }
             }
         }
 
+        // Otherwise, create a temporary for the argument.
         trace!("creating temp for argument {:?}", arg);
-        // Otherwise, create a temporary for the arg
-        let arg = Rvalue::Use(arg);
-
-        let ty = arg.ty(caller_body, self.tcx);
-
-        let arg_tmp = LocalDecl::new(ty, callsite.source_info.span);
-        let arg_tmp = caller_body.local_decls.push(arg_tmp);
-
-        caller_body[callsite.bb].statements.push(Statement {
+        let arg_ty = arg.ty(caller_body, self.tcx);
+        let local = self.new_call_temp(caller_body, callsite, arg_ty);
+        caller_body[callsite.block].statements.push(Statement {
             source_info: callsite.source_info,
-            kind: StatementKind::StorageLive(arg_tmp),
+            kind: StatementKind::Assign(box (Place::from(local), Rvalue::Use(arg))),
         });
-        caller_body[callsite.bb].statements.push(Statement {
+        local
+    }
+
+    /// Introduces a new temporary into the caller body that is live for the duration of the call.
+    fn new_call_temp(
+        &self,
+        caller_body: &mut Body<'tcx>,
+        callsite: &CallSite<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Local {
+        let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span));
+
+        caller_body[callsite.block].statements.push(Statement {
             source_info: callsite.source_info,
-            kind: StatementKind::Assign(box (Place::from(arg_tmp), arg)),
+            kind: StatementKind::StorageLive(local),
         });
-        caller_body[return_block].statements.insert(
-            0,
-            Statement {
-                source_info: callsite.source_info,
-                kind: StatementKind::StorageDead(arg_tmp),
-            },
-        );
-
-        arg_tmp
+
+        if let Some(block) = callsite.target {
+            caller_body[block].statements.insert(
+                0,
+                Statement {
+                    source_info: callsite.source_info,
+                    kind: StatementKind::StorageDead(local),
+                },
+            );
+        }
+
+        local
     }
 }
 
@@ -683,7 +667,7 @@ struct Integrator<'a, 'tcx> {
     new_scopes: RangeFrom<SourceScope>,
     new_blocks: RangeFrom<BasicBlock>,
     destination: Place<'tcx>,
-    return_block: BasicBlock,
+    return_block: Option<BasicBlock>,
     cleanup_block: Option<BasicBlock>,
     in_cleanup_block: bool,
     tcx: TyCtxt<'tcx>,
@@ -742,6 +726,12 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
     }
 
     fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
+        for elem in place.projection {
+            // FIXME: Make sure that return place is not used in an indexing projection, since it
+            // won't be rebased as it is supposed to be.
+            assert_ne!(ProjectionElem::Index(RETURN_PLACE), elem);
+        }
+
         // If this is the `RETURN_PLACE`, we need to rebase any projections onto it.
         let dest_proj_len = self.destination.projection.len();
         if place.local == RETURN_PLACE && dest_proj_len > 0 {
@@ -823,7 +813,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
                 }
             }
             TerminatorKind::Return => {
-                terminator.kind = TerminatorKind::Goto { target: self.return_block };
+                terminator.kind = if let Some(tgt) = self.return_block {
+                    TerminatorKind::Goto { target: tgt }
+                } else {
+                    TerminatorKind::Unreachable
+                }
             }
             TerminatorKind::Resume => {
                 if let Some(tgt) = self.cleanup_block {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 205ad850c0c..14ed93f1127 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -69,6 +69,7 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
             hir::LocalSource::ForLoopDesugar => ("`for` loop binding", None),
             hir::LocalSource::AsyncFn => ("async fn binding", None),
             hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
+            hir::LocalSource::AssignDesugar(_) => ("destructuring assignment binding", None),
         };
         self.check_irrefutable(&loc.pat, msg, sp);
         self.check_patterns(&loc.pat);
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 196790a0ab3..ee9a6dca5ad 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,6 +1,6 @@
 use super::{Parser, PathStyle};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
-use rustc_ast::mut_visit::{noop_visit_mac, noop_visit_pat, MutVisitor};
+use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
 use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::{self as ast, AttrVec, Attribute, FieldPat, MacCall, Pat, PatKind, RangeEnd};
@@ -570,10 +570,6 @@ impl<'a> Parser<'a> {
     fn make_all_value_bindings_mutable(pat: &mut P<Pat>) -> bool {
         struct AddMut(bool);
         impl MutVisitor for AddMut {
-            fn visit_mac(&mut self, mac: &mut MacCall) {
-                noop_visit_mac(mac, self);
-            }
-
             fn visit_pat(&mut self, pat: &mut P<Pat>) {
                 if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind
                 {
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 9537321026e..1d02c9aa637 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -336,8 +336,9 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
         ast_visit::walk_lifetime(self, lifetime)
     }
 
-    fn visit_mac(&mut self, mac: &'v ast::MacCall) {
+    fn visit_mac_call(&mut self, mac: &'v ast::MacCall) {
         self.record("MacCall", Id::None, mac);
+        ast_visit::walk_mac(self, mac)
     }
 
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v ast::PathSegment) {
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 8650ee05d37..4273d600004 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -26,7 +26,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem
     if items.eh_personality().is_none() {
         items.missing.push(LangItem::EhPersonality);
     }
-    if tcx.sess.target.options.is_like_emscripten && items.eh_catch_typeinfo().is_none() {
+    if tcx.sess.target.is_like_emscripten && items.eh_catch_typeinfo().is_none() {
         items.missing.push(LangItem::EhCatchTypeinfo);
     }
 
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index b632bfbed30..87687339370 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -735,15 +735,15 @@ pub const fn default_lib_output() -> CrateType {
 }
 
 pub fn default_configuration(sess: &Session) -> CrateConfig {
-    let end = &sess.target.target_endian;
+    let end = &sess.target.endian;
     let arch = &sess.target.arch;
     let wordsz = sess.target.pointer_width.to_string();
-    let os = &sess.target.target_os;
-    let env = &sess.target.target_env;
-    let vendor = &sess.target.target_vendor;
+    let os = &sess.target.os;
+    let env = &sess.target.env;
+    let vendor = &sess.target.vendor;
     let min_atomic_width = sess.target.min_atomic_width();
     let max_atomic_width = sess.target.max_atomic_width();
-    let atomic_cas = sess.target.options.atomic_cas;
+    let atomic_cas = sess.target.atomic_cas;
     let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
         sess.fatal(&err);
     });
@@ -752,7 +752,7 @@ pub fn default_configuration(sess: &Session) -> CrateConfig {
     ret.reserve(6); // the minimum number of insertions
     // Target bindings.
     ret.insert((sym::target_os, Some(Symbol::intern(os))));
-    if let Some(ref fam) = sess.target.options.target_family {
+    if let Some(ref fam) = sess.target.os_family {
         ret.insert((sym::target_family, Some(Symbol::intern(fam))));
         if fam == "windows" {
             ret.insert((sym::windows, None));
@@ -765,7 +765,7 @@ pub fn default_configuration(sess: &Session) -> CrateConfig {
     ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
     ret.insert((sym::target_env, Some(Symbol::intern(env))));
     ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
-    if sess.target.options.has_elf_tls {
+    if sess.target.has_elf_tls {
         ret.insert((sym::target_thread_local, None));
     }
     for &(i, align) in &[
@@ -793,6 +793,9 @@ pub fn default_configuration(sess: &Session) -> CrateConfig {
         }
     }
 
+    let panic_strategy = sess.panic_strategy();
+    ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
+
     for s in sess.opts.debugging_opts.sanitizer {
         let symbol = Symbol::intern(&s.to_string());
         ret.insert((sym::sanitize, Some(symbol)));
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index ceed730e25b..1cd3d11e321 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -929,6 +929,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         (default: no)"),
     incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
         "verify incr. comp. hashes of green query instances (default: no)"),
+    inline_mir_threshold: usize = (50, parse_uint, [TRACKED],
+        "a default MIR inlining threshold (default: 50)"),
+    inline_mir_hint_threshold: usize = (100, parse_uint, [TRACKED],
+        "inlining threshold for functions with inline hint (default: 100)"),
     inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "control whether `#[inline]` functions are in all CGUs"),
     input_stats: bool = (false, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index 130c3a06122..777eea3f68d 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -150,17 +150,15 @@ pub fn filename_for_input(
     match crate_type {
         CrateType::Rlib => outputs.out_directory.join(&format!("lib{}.rlib", libname)),
         CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => {
-            let (prefix, suffix) =
-                (&sess.target.options.dll_prefix, &sess.target.options.dll_suffix);
+            let (prefix, suffix) = (&sess.target.dll_prefix, &sess.target.dll_suffix);
             outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix))
         }
         CrateType::Staticlib => {
-            let (prefix, suffix) =
-                (&sess.target.options.staticlib_prefix, &sess.target.options.staticlib_suffix);
+            let (prefix, suffix) = (&sess.target.staticlib_prefix, &sess.target.staticlib_suffix);
             outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix))
         }
         CrateType::Executable => {
-            let suffix = &sess.target.options.exe_suffix;
+            let suffix = &sess.target.exe_suffix;
             let out_filename = outputs.path(OutputType::Exe);
             if suffix.is_empty() { out_filename } else { out_filename.with_extension(&suffix[1..]) }
         }
@@ -177,29 +175,29 @@ pub fn filename_for_input(
 /// interaction with Rust code through static library is the only
 /// option for now
 pub fn default_output_for_target(sess: &Session) -> CrateType {
-    if !sess.target.options.executables { CrateType::Staticlib } else { CrateType::Executable }
+    if !sess.target.executables { CrateType::Staticlib } else { CrateType::Executable }
 }
 
 /// Checks if target supports crate_type as output
 pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool {
     match crate_type {
         CrateType::Cdylib | CrateType::Dylib | CrateType::ProcMacro => {
-            if !sess.target.options.dynamic_linking {
+            if !sess.target.dynamic_linking {
                 return true;
             }
-            if sess.crt_static(Some(crate_type)) && !sess.target.options.crt_static_allows_dylibs {
+            if sess.crt_static(Some(crate_type)) && !sess.target.crt_static_allows_dylibs {
                 return true;
             }
         }
         _ => {}
     }
-    if sess.target.options.only_cdylib {
+    if sess.target.only_cdylib {
         match crate_type {
             CrateType::ProcMacro | CrateType::Dylib => return true,
             _ => {}
         }
     }
-    if !sess.target.options.executables && crate_type == CrateType::Executable {
+    if !sess.target.executables && crate_type == CrateType::Executable {
         return true;
     }
 
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 0b7c35a8afd..98b7f03df38 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -663,7 +663,7 @@ impl Session {
     /// Calculates the flavor of LTO to use for this compilation.
     pub fn lto(&self) -> config::Lto {
         // If our target has codegen requirements ignore the command line
-        if self.target.options.requires_lto {
+        if self.target.requires_lto {
             return config::Lto::Fat;
         }
 
@@ -731,7 +731,7 @@ impl Session {
     /// Returns the panic strategy for this compile session. If the user explicitly selected one
     /// using '-C panic', use that, otherwise use the panic strategy defined by the target.
     pub fn panic_strategy(&self) -> PanicStrategy {
-        self.opts.cg.panic.unwrap_or(self.target.options.panic_strategy)
+        self.opts.cg.panic.unwrap_or(self.target.panic_strategy)
     }
     pub fn fewer_names(&self) -> bool {
         let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
@@ -755,9 +755,9 @@ impl Session {
 
     /// Check whether this compile session and crate type use static crt.
     pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool {
-        if !self.target.options.crt_static_respected {
+        if !self.target.crt_static_respected {
             // If the target does not opt in to crt-static support, use its default.
-            return self.target.options.crt_static_default;
+            return self.target.crt_static_default;
         }
 
         let requested_features = self.opts.cg.target_feature.split(',');
@@ -774,20 +774,20 @@ impl Session {
             // We can't check `#![crate_type = "proc-macro"]` here.
             false
         } else {
-            self.target.options.crt_static_default
+            self.target.crt_static_default
         }
     }
 
     pub fn relocation_model(&self) -> RelocModel {
-        self.opts.cg.relocation_model.unwrap_or(self.target.options.relocation_model)
+        self.opts.cg.relocation_model.unwrap_or(self.target.relocation_model)
     }
 
     pub fn code_model(&self) -> Option<CodeModel> {
-        self.opts.cg.code_model.or(self.target.options.code_model)
+        self.opts.cg.code_model.or(self.target.code_model)
     }
 
     pub fn tls_model(&self) -> TlsModel {
-        self.opts.debugging_opts.tls_model.unwrap_or(self.target.options.tls_model)
+        self.opts.debugging_opts.tls_model.unwrap_or(self.target.tls_model)
     }
 
     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
@@ -798,7 +798,7 @@ impl Session {
         } else if let Some(x) = self.opts.cg.force_frame_pointers {
             x
         } else {
-            !self.target.options.eliminate_frame_pointer
+            !self.target.eliminate_frame_pointer
         }
     }
 
@@ -822,7 +822,7 @@ impl Session {
         // value, if it is provided, or disable them, if not.
         if self.panic_strategy() == PanicStrategy::Unwind {
             true
-        } else if self.target.options.requires_uwtable {
+        } else if self.target.requires_uwtable {
             true
         } else {
             self.opts.cg.force_unwind_tables.unwrap_or(false)
@@ -993,7 +993,7 @@ impl Session {
         if let Some(n) = self.opts.cli_forced_codegen_units {
             return n;
         }
-        if let Some(n) = self.target.options.default_codegen_units {
+        if let Some(n) = self.target.default_codegen_units {
             return n as usize;
         }
 
@@ -1078,11 +1078,11 @@ impl Session {
     pub fn needs_plt(&self) -> bool {
         // Check if the current target usually needs PLT to be enabled.
         // The user can use the command line flag to override it.
-        let needs_plt = self.target.options.needs_plt;
+        let needs_plt = self.target.needs_plt;
 
         let dbg_opts = &self.opts.debugging_opts;
 
-        let relro_level = dbg_opts.relro_level.unwrap_or(self.target.options.relro_level);
+        let relro_level = dbg_opts.relro_level.unwrap_or(self.target.relro_level);
 
         // Only enable this optimization by default if full relro is also enabled.
         // In this case, lazy binding was already unavailable, so nothing is lost.
@@ -1106,7 +1106,7 @@ impl Session {
         match self.opts.cg.link_dead_code {
             Some(explicitly_set) => explicitly_set,
             None => {
-                self.opts.debugging_opts.instrument_coverage && !self.target.options.is_like_msvc
+                self.opts.debugging_opts.instrument_coverage && !self.target.is_like_msvc
                 // Issue #76038: (rustc `-Clink-dead-code` causes MSVC linker to produce invalid
                 // binaries when LLVM InstrProf counters are enabled). As described by this issue,
                 // the "link dead code" option produces incorrect binaries when compiled and linked
@@ -1305,9 +1305,9 @@ pub fn build_session(
         early_error(sopts.error_format, &format!("Error loading host specification: {}", e))
     });
 
-    let loader = file_loader.unwrap_or(Box::new(RealFileLoader));
+    let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
     let hash_kind = sopts.debugging_opts.src_hash_algorithm.unwrap_or_else(|| {
-        if target_cfg.options.is_like_msvc {
+        if target_cfg.is_like_msvc {
             SourceFileHashAlgorithm::Sha1
         } else {
             SourceFileHashAlgorithm::Md5
@@ -1417,11 +1417,8 @@ pub fn build_session(
         if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
     };
 
-    let asm_arch = if target_cfg.options.allow_asm {
-        InlineAsmArch::from_str(&target_cfg.arch).ok()
-    } else {
-        None
-    };
+    let asm_arch =
+        if target_cfg.allow_asm { InlineAsmArch::from_str(&target_cfg.arch).ok() } else { None };
 
     let sess = Session {
         target: target_cfg,
@@ -1487,7 +1484,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     // the `dllimport` attributes and `__imp_` symbols in that case.
     if sess.opts.cg.linker_plugin_lto.enabled()
         && sess.opts.cg.prefer_dynamic
-        && sess.target.options.is_like_windows
+        && sess.target.is_like_windows
     {
         sess.err(
             "Linker plugin based LTO is not supported together with \
@@ -1515,7 +1512,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             );
         }
 
-        if sess.target.options.requires_uwtable && !include_uwtables {
+        if sess.target.requires_uwtable && !include_uwtables {
             sess.err(
                 "target requires unwind tables, they cannot be disabled with \
                      `-C force-unwind-tables=no`.",
@@ -1530,7 +1527,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     // We should only display this error if we're actually going to run PGO.
     // If we're just supposed to print out some data, don't show the error (#61002).
     if sess.opts.cg.profile_generate.enabled()
-        && sess.target.options.is_like_msvc
+        && sess.target.is_like_msvc
         && sess.panic_strategy() == PanicStrategy::Unwind
         && sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs)
     {
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 1a6c45b6c80..ad58f89d87d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -326,6 +326,7 @@ symbols! {
         cfg_attr,
         cfg_attr_multi,
         cfg_doctest,
+        cfg_panic,
         cfg_sanitize,
         cfg_target_feature,
         cfg_target_has_atomic,
@@ -434,6 +435,7 @@ symbols! {
         deref_mut,
         deref_target,
         derive,
+        destructuring_assignment,
         diagnostic,
         direct,
         discriminant_kind,
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 507ae10877b..429a3375cd8 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -562,7 +562,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             "x86_64" => {
                 if abi == spec::abi::Abi::SysV64 {
                     x86_64::compute_abi_info(cx, self);
-                } else if abi == spec::abi::Abi::Win64 || cx.target_spec().options.is_like_windows {
+                } else if abi == spec::abi::Abi::Win64 || cx.target_spec().is_like_windows {
                     x86_win64::compute_abi_info(self);
                 } else {
                     x86_64::compute_abi_info(cx, self);
@@ -584,7 +584,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             "nvptx64" => nvptx64::compute_abi_info(self),
             "hexagon" => hexagon::compute_abi_info(self),
             "riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
-            "wasm32" if cx.target_spec().target_os != "emscripten" => {
+            "wasm32" if cx.target_spec().os != "emscripten" => {
                 wasm32_bindgen_compat::compute_abi_info(self)
             }
             "wasm32" | "asmjs" => wasm32::compute_abi_info(cx, self),
diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs
index b740707320f..8c2a9d09a3d 100644
--- a/compiler/rustc_target/src/abi/call/powerpc64.rs
+++ b/compiler/rustc_target/src/abi/call/powerpc64.rs
@@ -119,7 +119,7 @@ where
     Ty: TyAndLayoutMethods<'a, C> + Copy,
     C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
 {
-    let abi = if cx.target_spec().target_env == "musl" {
+    let abi = if cx.target_spec().env == "musl" {
         ELFv2
     } else {
         match cx.data_layout().endian {
diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs
index 47530eeacd0..782c661c31f 100644
--- a/compiler/rustc_target/src/abi/call/riscv.rs
+++ b/compiler/rustc_target/src/abi/call/riscv.rs
@@ -323,7 +323,7 @@ where
     Ty: TyAndLayoutMethods<'a, C> + Copy,
     C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
 {
-    let flen = match &cx.target_spec().options.llvm_abiname[..] {
+    let flen = match &cx.target_spec().llvm_abiname[..] {
         "ilp32f" | "lp64f" => 32,
         "ilp32d" | "lp64d" => 64,
         _ => 0,
diff --git a/compiler/rustc_target/src/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs
index df3dd5d9208..07bf1e94c61 100644
--- a/compiler/rustc_target/src/abi/call/x86.rs
+++ b/compiler/rustc_target/src/abi/call/x86.rs
@@ -41,10 +41,10 @@ where
             // http://www.angelcode.com/dev/callconv/callconv.html
             // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
             let t = cx.target_spec();
-            if t.options.abi_return_struct_as_int {
+            if t.abi_return_struct_as_int {
                 // According to Clang, everyone but MSVC returns single-element
                 // float aggregates directly in a floating-point register.
-                if !t.options.is_like_msvc && is_single_fp_element(cx, fn_abi.ret.layout) {
+                if !t.is_like_msvc && is_single_fp_element(cx, fn_abi.ret.layout) {
                     match fn_abi.ret.layout.size.bytes() {
                         4 => fn_abi.ret.cast_to(Reg::f32()),
                         8 => fn_abi.ret.cast_to(Reg::f64()),
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index d3c31773c1e..a43080b09e9 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -156,11 +156,11 @@ impl TargetDataLayout {
             Endian::Little => "little",
             Endian::Big => "big",
         };
-        if endian_str != target.target_endian {
+        if endian_str != target.endian {
             return Err(format!(
                 "inconsistent target specification: \"data-layout\" claims \
                                 architecture is {}-endian, while \"target-endian\" is `{}`",
-                endian_str, target.target_endian
+                endian_str, target.endian
             ));
         }
 
diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs
index 85a136b94aa..28000916e0c 100644
--- a/compiler/rustc_target/src/asm/arm.rs
+++ b/compiler/rustc_target/src/asm/arm.rs
@@ -61,7 +61,7 @@ impl ArmInlineAsmRegClass {
 
 // This uses the same logic as useR7AsFramePointer in LLVM
 fn frame_pointer_is_r7(mut has_feature: impl FnMut(&str) -> bool, target: &Target) -> bool {
-    target.options.is_like_osx || (!target.options.is_like_windows && has_feature("thumb-mode"))
+    target.is_like_osx || (!target.is_like_windows && has_feature("thumb-mode"))
 }
 
 fn frame_pointer_r11(
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
index 098651614d0..7de809f7622 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
@@ -19,6 +19,6 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
         arch: arch.to_string(),
-        options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
+        options: TargetOptions { mcount: "\u{1}mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
index 9d9698a440d..58c72af4e76 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
@@ -1,7 +1,7 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
+    let mut base = super::linux_gnu_base::opts();
     base.max_atomic_width = Some(128);
 
     Target {
@@ -11,7 +11,7 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}_mcount".to_string(),
+            mcount: "\u{1}_mcount".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
index 2dd703b66ff..7bbfc8ec0f7 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}_mcount".to_string(),
+            mcount: "\u{1}_mcount".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
index 81e383ca5f1..09efbdbb293 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
@@ -10,6 +10,6 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
+        options: TargetOptions { mcount: "__mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
index 1088807f2c2..d0ad45153d6 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
@@ -10,7 +10,7 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOp
 
 pub fn target() -> Target {
     let opts = TargetOptions {
-        target_vendor: String::new(),
+        vendor: String::new(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         features: "+strict-align,+neon,+fp-armv8".to_string(),
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
index 044c9fa1de8..41bd2182905 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
@@ -10,7 +10,7 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOp
 
 pub fn target() -> Target {
     let opts = TargetOptions {
-        target_vendor: String::new(),
+        vendor: String::new(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         features: "+strict-align,-neon,-fp-armv8".to_string(),
diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs
index 1bd5eb6988c..f6fbe7cd5f6 100644
--- a/compiler/rustc_target/src/spec/android_base.rs
+++ b/compiler/rustc_target/src/spec/android_base.rs
@@ -1,15 +1,14 @@
 use crate::spec::{LinkerFlavor, TargetOptions};
 
 pub fn opts() -> TargetOptions {
-    let mut base = super::linux_base::opts();
-    base.target_os = "android".to_string();
+    let mut base = super::linux_gnu_base::opts();
+    base.os = "android".to_string();
     // Many of the symbols defined in compiler-rt are also defined in libgcc.
     // Android's linker doesn't like that by default.
     base.pre_link_args
         .get_mut(&LinkerFlavor::Gcc)
         .unwrap()
         .push("-Wl,--allow-multiple-definition".to_string());
-    base.is_like_android = true;
     base.dwarf_version = Some(2);
     base.position_independent_executables = true;
     base.has_elf_tls = false;
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 045d9967f30..e271a6dec40 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -17,13 +17,13 @@ pub fn opts(os: &str) -> TargetOptions {
     let version = macos_deployment_target();
 
     TargetOptions {
-        target_os: os.to_string(),
-        target_vendor: "apple".to_string(),
+        os: os.to_string(),
+        vendor: "apple".to_string(),
         // macOS has -dead_strip, which doesn't rely on function_sections
         function_sections: false,
         dynamic_linking: true,
         executables: true,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         is_like_osx: true,
         dwarf_version: Some(2),
         has_rpath: true,
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
index dca0b1ec2e4..c41cf6e521a 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
@@ -1,7 +1,7 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
+    let mut base = super::linux_gnu_base::opts();
     base.max_atomic_width = Some(64);
     Target {
         llvm_target: "arm-unknown-linux-gnueabi".to_string(),
@@ -12,7 +12,7 @@ pub fn target() -> Target {
         options: TargetOptions {
             features: "+strict-align,+v6".to_string(),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
index ee71ae61972..f2143966c1d 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
@@ -1,7 +1,7 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
+    let mut base = super::linux_gnu_base::opts();
     base.max_atomic_width = Some(64);
     Target {
         llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
@@ -12,7 +12,7 @@ pub fn target() -> Target {
         options: TargetOptions {
             features: "+strict-align,+v6,+vfp2,-d32".to_string(),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
index 6938a043602..53ff1001c20 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
@@ -17,7 +17,7 @@ pub fn target() -> Target {
         arch: "arm".to_string(),
         options: TargetOptions {
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}mcount".to_string(),
+            mcount: "\u{1}mcount".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
index 4adf3a33893..6d8a5f9f88b 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
@@ -17,7 +17,7 @@ pub fn target() -> Target {
         arch: "arm".to_string(),
         options: TargetOptions {
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}mcount".to_string(),
+            mcount: "\u{1}mcount".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
index 7bfa5baecb5..36856305723 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
@@ -11,8 +11,8 @@ pub fn target() -> Target {
         arch: "arm".to_string(),
 
         options: TargetOptions {
-            target_endian: "big".to_string(),
-            target_vendor: String::new(),
+            endian: "big".to_string(),
+            vendor: String::new(),
             linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             executables: true,
             linker: Some("rust-lld".to_owned()),
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
index 7afc933a28f..2ff3c8950c4 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
@@ -11,8 +11,8 @@ pub fn target() -> Target {
         arch: "arm".to_string(),
 
         options: TargetOptions {
-            target_endian: "big".to_string(),
-            target_vendor: String::new(),
+            endian: "big".to_string(),
+            vendor: String::new(),
             linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             executables: true,
             linker: Some("rust-lld".to_owned()),
diff --git a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
index c58fa7407b4..e1ba72bf83b 100644
--- a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
@@ -1,7 +1,7 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = super::linux_base::opts();
+    let base = super::linux_gnu_base::opts();
     Target {
         llvm_target: "armv4t-unknown-linux-gnueabi".to_string(),
         pointer_width: 32,
@@ -13,7 +13,7 @@ pub fn target() -> Target {
             // Atomic operations provided by compiler-builtins
             max_atomic_width: Some(32),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            mcount: "\u{1}__gnu_mcount_nc".to_string(),
             has_thumb_interworking: true,
             ..base
         },
diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
index 049a031398a..3ac8d53564d 100644
--- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
@@ -1,7 +1,7 @@
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = super::linux_base::opts();
+    let base = super::linux_gnu_base::opts();
     Target {
         llvm_target: "armv5te-unknown-linux-gnueabi".to_string(),
         pointer_width: 32,
@@ -13,7 +13,7 @@ pub fn target() -> Target {
             // Atomic operations provided by compiler-builtins
             max_atomic_width: Some(32),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            mcount: "\u{1}__gnu_mcount_nc".to_string(),
             has_thumb_interworking: true,
             ..base
         },
diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
index 77cf8bb76d3..40d405c30a2 100644
--- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
@@ -16,7 +16,7 @@ pub fn target() -> Target {
             // Atomic operations provided by compiler-builtins
             max_atomic_width: Some(32),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}mcount".to_string(),
+            mcount: "\u{1}mcount".to_string(),
             has_thumb_interworking: true,
             ..base
         },
diff --git a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
index 981d615f684..a149bd983b7 100644
--- a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
@@ -9,11 +9,11 @@ pub fn target() -> Target {
         arch: "arm".to_string(),
 
         options: TargetOptions {
-            target_env: "gnueabihf".to_string(),
+            env: "gnueabihf".to_string(),
             features: "+v6,+vfp2,-d32".to_string(),
             max_atomic_width: Some(64),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
index 8417a8f2801..6c81a458b9b 100644
--- a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
@@ -10,10 +10,10 @@ pub fn target() -> Target {
         arch: "arm".to_string(),
 
         options: TargetOptions {
-            target_env: "eabihf".to_string(),
+            env: "eabihf".to_string(),
             features: "+v6,+vfp2,-d32".to_string(),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "__mcount".to_string(),
+            mcount: "__mcount".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs
index 921640d0aa6..d47ee541b25 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs
@@ -13,6 +13,6 @@ pub fn target() -> Target {
         pointer_width: 32,
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-        options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
+        options: TargetOptions { mcount: "\u{1}mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
index 88d5c86cfab..6f24c6818fc 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
@@ -9,11 +9,11 @@ pub fn target() -> Target {
         arch: "arm".to_string(),
 
         options: TargetOptions {
-            target_env: "gnueabihf".to_string(),
+            env: "gnueabihf".to_string(),
             features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
             max_atomic_width: Some(64),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
index 2a31bf4e332..ae6b8286f08 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
@@ -4,7 +4,7 @@ use crate::spec::{Target, TargetOptions};
 // hardfloat.
 
 pub fn target() -> Target {
-    let base = super::linux_base::opts();
+    let base = super::linux_gnu_base::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabi".to_string(),
         pointer_width: 32,
@@ -16,7 +16,7 @@ pub fn target() -> Target {
             cpu: "generic".to_string(),
             max_atomic_width: Some(64),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
index d04400b79df..48c16b620fd 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
@@ -4,7 +4,7 @@ use crate::spec::{Target, TargetOptions};
 // thumb-mode. See the thumbv7neon variant for enabling both.
 
 pub fn target() -> Target {
-    let base = super::linux_base::opts();
+    let base = super::linux_gnu_base::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         pointer_width: 32,
@@ -17,7 +17,7 @@ pub fn target() -> Target {
             cpu: "generic".to_string(),
             max_atomic_width: Some(64),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
index ebbbd61fc11..9f9f1bd79b0 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
@@ -21,7 +21,7 @@ pub fn target() -> Target {
             cpu: "generic".to_string(),
             max_atomic_width: Some(64),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}mcount".to_string(),
+            mcount: "\u{1}mcount".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
index ee603aa0684..59deee30ef2 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
@@ -20,7 +20,7 @@ pub fn target() -> Target {
             cpu: "generic".to_string(),
             max_atomic_width: Some(64),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}mcount".to_string(),
+            mcount: "\u{1}mcount".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
index 09c531ebc8a..660525704c1 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
@@ -9,12 +9,12 @@ pub fn target() -> Target {
         arch: "arm".to_string(),
 
         options: TargetOptions {
-            target_env: "eabihf".to_string(),
+            env: "eabihf".to_string(),
             features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
             cpu: "generic".to_string(),
             max_atomic_width: Some(64),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "__mcount".to_string(),
+            mcount: "__mcount".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
index b6b34e27562..742b403cff9 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
@@ -10,8 +10,8 @@
 // bare-metal binaries (the `gcc` linker has the advantage that it knows where C
 // libraries and crt*.o are but it's not much of an advantage here); LLD is also
 // faster
-// - `target_os` set to `none`. rationale: matches `thumb` targets
-// - `target_{env,vendor}` set to an empty string. rationale: matches `thumb`
+// - `os` set to `none`. rationale: matches `thumb` targets
+// - `env` and `vendor` are set to an empty string. rationale: matches `thumb`
 // targets
 // - `panic_strategy` set to `abort`. rationale: matches `thumb` targets
 // - `relocation-model` set to `static`; also no PIE, no relro and no dynamic
@@ -21,7 +21,7 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOp
 
 pub fn target() -> Target {
     let opts = TargetOptions {
-        target_vendor: String::new(),
+        vendor: String::new(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         features: "+v7,+thumb2,+soft-float,-neon,+strict-align".to_string(),
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
index 8b9df361844..b9cda18d6b4 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
@@ -9,7 +9,7 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOp
 
 pub fn target() -> Target {
     let opts = TargetOptions {
-        target_vendor: String::new(),
+        vendor: String::new(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         features: "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align".to_string(),
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
index fdd74d27619..440c2434907 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
         arch: "arm".to_string(),
 
         options: TargetOptions {
-            target_vendor: String::new(),
+            vendor: String::new(),
             linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             executables: true,
             linker: Some("rust-lld".to_owned()),
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
index 7baafea90b9..c1bf332a72d 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
         arch: "arm".to_string(),
 
         options: TargetOptions {
-            target_vendor: String::new(),
+            vendor: String::new(),
             linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             executables: true,
             linker: Some("rust-lld".to_owned()),
diff --git a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
index 1c3f5c4f9e8..b1adefe1a51 100644
--- a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
@@ -3,7 +3,6 @@ use super::{wasm32_unknown_emscripten, LinkerFlavor, Target};
 pub fn target() -> Target {
     let mut target = wasm32_unknown_emscripten::target();
     target
-        .options
         .post_link_args
         .entry(LinkerFlavor::Em)
         .or_default()
diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs
index 268af87cfe9..9cc10032c71 100644
--- a/compiler/rustc_target/src/spec/avr_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs
@@ -10,8 +10,8 @@ pub fn target(target_cpu: String) -> Target {
         llvm_target: "avr-unknown-unknown".to_string(),
         pointer_width: 16,
         options: TargetOptions {
-            target_c_int_width: "16".to_string(),
-            target_os: "unknown".to_string(),
+            c_int_width: "16".to_string(),
+            os: "unknown".to_string(),
             cpu: target_cpu.clone(),
             exe_suffix: ".elf".to_string(),
 
diff --git a/compiler/rustc_target/src/spec/cloudabi_base.rs b/compiler/rustc_target/src/spec/cloudabi_base.rs
index 0053adb8552..20a095742ec 100644
--- a/compiler/rustc_target/src/spec/cloudabi_base.rs
+++ b/compiler/rustc_target/src/spec/cloudabi_base.rs
@@ -12,9 +12,9 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_os: "cloudabi".to_string(),
+        os: "cloudabi".to_string(),
         executables: true,
-        target_family: None,
+        os_family: None,
         linker_is_gnu: true,
         pre_link_args: args,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs
index a182e37dd80..b96de7ab1ed 100644
--- a/compiler/rustc_target/src/spec/dragonfly_base.rs
+++ b/compiler/rustc_target/src/spec/dragonfly_base.rs
@@ -16,10 +16,10 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_os: "dragonfly".to_string(),
+        os: "dragonfly".to_string(),
         dynamic_linking: true,
         executables: true,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         pre_link_args: args,
diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs
index 25535117743..c70c492716b 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -16,10 +16,10 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_os: "freebsd".to_string(),
+        os: "freebsd".to_string(),
         dynamic_linking: true,
         executables: true,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         pre_link_args: args,
diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs
index 97998eed886..e467c7c8f21 100644
--- a/compiler/rustc_target/src/spec/fuchsia_base.rs
+++ b/compiler/rustc_target/src/spec/fuchsia_base.rs
@@ -20,14 +20,14 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_os: "fuchsia".to_string(),
-        target_vendor: String::new(),
+        os: "fuchsia".to_string(),
+        vendor: String::new(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         lld_flavor: LldFlavor::Ld,
         dynamic_linking: true,
         executables: true,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         is_like_fuchsia: true,
         linker_is_gnu: true,
         has_rpath: false,
diff --git a/compiler/rustc_target/src/spec/haiku_base.rs b/compiler/rustc_target/src/spec/haiku_base.rs
index 3d9dd44e786..ec87645c4fa 100644
--- a/compiler/rustc_target/src/spec/haiku_base.rs
+++ b/compiler/rustc_target/src/spec/haiku_base.rs
@@ -2,11 +2,11 @@ use crate::spec::{RelroLevel, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
-        target_os: "haiku".to_string(),
+        os: "haiku".to_string(),
         dynamic_linking: true,
         executables: true,
         has_rpath: false,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         relro_level: RelroLevel::Full,
         linker_is_gnu: true,
         ..Default::default()
diff --git a/compiler/rustc_target/src/spec/hermit_base.rs b/compiler/rustc_target/src/spec/hermit_base.rs
index 2953646afd0..a75158a0ea0 100644
--- a/compiler/rustc_target/src/spec/hermit_base.rs
+++ b/compiler/rustc_target/src/spec/hermit_base.rs
@@ -9,7 +9,7 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_os: "hermit".to_string(),
+        os: "hermit".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         executables: true,
@@ -20,7 +20,7 @@ pub fn opts() -> TargetOptions {
         position_independent_executables: true,
         static_position_independent_executables: true,
         relocation_model: RelocModel::Pic,
-        target_family: None,
+        os_family: None,
         tls_model: TlsModel::InitialExec,
         ..Default::default()
     }
diff --git a/compiler/rustc_target/src/spec/hermit_kernel_base.rs b/compiler/rustc_target/src/spec/hermit_kernel_base.rs
index 7d06cbd62f5..622f0d9a471 100644
--- a/compiler/rustc_target/src/spec/hermit_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/hermit_kernel_base.rs
@@ -9,7 +9,7 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_os: "hermit".to_string(),
+        os: "hermit".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         disable_redzone: true,
         linker: Some("rust-lld".to_owned()),
@@ -21,7 +21,7 @@ pub fn opts() -> TargetOptions {
         position_independent_executables: true,
         static_position_independent_executables: true,
         relocation_model: RelocModel::Pic,
-        target_family: None,
+        os_family: None,
         tls_model: TlsModel::InitialExec,
         ..Default::default()
     }
diff --git a/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs
index 664b9d5d515..4a7779a6df0 100644
--- a/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs
@@ -2,7 +2,7 @@ use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::i686_pc_windows_msvc::target();
-    base.options.cpu = "pentium".to_string();
+    base.cpu = "pentium".to_string();
     base.llvm_target = "i586-pc-windows-msvc".to_string();
     base
 }
diff --git a/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs
index 3276f1d0094..7c92dda8a9d 100644
--- a/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs
@@ -2,7 +2,7 @@ use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::i686_unknown_linux_gnu::target();
-    base.options.cpu = "pentium".to_string();
+    base.cpu = "pentium".to_string();
     base.llvm_target = "i586-unknown-linux-gnu".to_string();
     base
 }
diff --git a/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs
index 5fbf0487226..1fea02bbee8 100644
--- a/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs
@@ -2,7 +2,7 @@ use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::i686_unknown_linux_musl::target();
-    base.options.cpu = "pentium".to_string();
+    base.cpu = "pentium".to_string();
     base.llvm_target = "i586-unknown-linux-musl".to_string();
     base
 }
diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
index ac295aa3587..0ab40340928 100644
--- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
@@ -22,6 +22,6 @@ pub fn target() -> Target {
             f64:32:64-f80:128-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
+        options: TargetOptions { mcount: "\u{1}mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
index 62b02d841c2..083c115d084 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
+    let mut base = super::linux_gnu_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
index 2568fabfb05..c22139b5875 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
@@ -14,6 +14,6 @@ pub fn target() -> Target {
             f64:32:64-f80:32-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
+        options: TargetOptions { mcount: "__mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs
index 625f7b18b25..d9b5716c041 100644
--- a/compiler/rustc_target/src/spec/illumos_base.rs
+++ b/compiler/rustc_target/src/spec/illumos_base.rs
@@ -16,11 +16,11 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_os: "illumos".to_string(),
+        os: "illumos".to_string(),
         dynamic_linking: true,
         executables: true,
         has_rpath: true,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         is_like_solaris: true,
         limit_rdylib_exports: false, // Linker doesn't support this
         eliminate_frame_pointer: false,
diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs
index 6d1e610d0e9..660fae5f5c7 100644
--- a/compiler/rustc_target/src/spec/l4re_base.rs
+++ b/compiler/rustc_target/src/spec/l4re_base.rs
@@ -17,15 +17,15 @@ pub fn opts() -> TargetOptions {
     args.insert(LinkerFlavor::Gcc, vec![]);
 
     TargetOptions {
-        target_os: "l4re".to_string(),
-        target_env: "uclibc".to_string(),
+        os: "l4re".to_string(),
+        env: "uclibc".to_string(),
         linker_flavor: LinkerFlavor::Ld,
         executables: true,
         has_elf_tls: false,
         panic_strategy: PanicStrategy::Abort,
         linker: Some("ld".to_string()),
         pre_link_args: args,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs
index b3a850591fd..0631644ad63 100644
--- a/compiler/rustc_target/src/spec/linux_base.rs
+++ b/compiler/rustc_target/src/spec/linux_base.rs
@@ -19,11 +19,10 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
+        os: "linux".to_string(),
         dynamic_linking: true,
         executables: true,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         pre_link_args: args,
diff --git a/compiler/rustc_target/src/spec/linux_gnu_base.rs b/compiler/rustc_target/src/spec/linux_gnu_base.rs
new file mode 100644
index 00000000000..3d940ceaf02
--- /dev/null
+++ b/compiler/rustc_target/src/spec/linux_gnu_base.rs
@@ -0,0 +1,5 @@
+use crate::spec::TargetOptions;
+
+pub fn opts() -> TargetOptions {
+    TargetOptions { env: "gnu".to_string(), ..super::linux_base::opts() }
+}
diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs
index 9c883f9a188..a5fc1649e7f 100644
--- a/compiler/rustc_target/src/spec/linux_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs
@@ -8,7 +8,7 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_env: "gnu".to_string(),
+        env: "gnu".to_string(),
         disable_redzone: true,
         panic_strategy: PanicStrategy::Abort,
         stack_probes: true,
diff --git a/compiler/rustc_target/src/spec/linux_musl_base.rs b/compiler/rustc_target/src/spec/linux_musl_base.rs
index 3a44d3326eb..5038a967d0a 100644
--- a/compiler/rustc_target/src/spec/linux_musl_base.rs
+++ b/compiler/rustc_target/src/spec/linux_musl_base.rs
@@ -4,7 +4,7 @@ use crate::spec::TargetOptions;
 pub fn opts() -> TargetOptions {
     let mut base = super::linux_base::opts();
 
-    base.target_env = "musl".to_string();
+    base.env = "musl".to_string();
     base.pre_link_objects_fallback = crt_objects::pre_musl_fallback();
     base.post_link_objects_fallback = crt_objects::post_musl_fallback();
     base.crt_objects_fallback = Some(CrtObjectsFallback::Musl);
diff --git a/compiler/rustc_target/src/spec/linux_uclibc_base.rs b/compiler/rustc_target/src/spec/linux_uclibc_base.rs
index ce7c79c1644..ef6d50656e4 100644
--- a/compiler/rustc_target/src/spec/linux_uclibc_base.rs
+++ b/compiler/rustc_target/src/spec/linux_uclibc_base.rs
@@ -1,5 +1,5 @@
 use crate::spec::TargetOptions;
 
 pub fn opts() -> TargetOptions {
-    TargetOptions { target_env: "uclibc".to_string(), ..super::linux_base::opts() }
+    TargetOptions { env: "uclibc".to_string(), ..super::linux_base::opts() }
 }
diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
index f0a266a63af..daa0d9da172 100644
--- a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
@@ -7,14 +7,14 @@ pub fn target() -> Target {
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
         options: TargetOptions {
-            target_endian: "big".to_string(),
+            endian: "big".to_string(),
             // NOTE(mips64r2) matches C toolchain
             cpu: "mips64r2".to_string(),
             features: "+mips64r2".to_string(),
             max_atomic_width: Some(64),
-            target_mcount: "_mcount".to_string(),
+            mcount: "_mcount".to_string(),
 
-            ..super::linux_base::opts()
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
index 805a965bc0f..db8d0c04e6f 100644
--- a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
@@ -11,10 +11,6 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
-        options: TargetOptions {
-            target_endian: "big".to_string(),
-            target_mcount: "_mcount".to_string(),
-            ..base
-        },
+        options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
index f47b058bd08..d767705b045 100644
--- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
@@ -11,9 +11,9 @@ pub fn target() -> Target {
             cpu: "mips64r2".to_string(),
             features: "+mips64r2".to_string(),
             max_atomic_width: Some(64),
-            target_mcount: "_mcount".to_string(),
+            mcount: "_mcount".to_string(),
 
-            ..super::linux_base::opts()
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
index 5c985eb842c..766ed69df4b 100644
--- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
@@ -11,6 +11,6 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
-        options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions { mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
index 1fc66861364..a7ec1f19c9d 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
@@ -7,13 +7,13 @@ pub fn target() -> Target {
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
         options: TargetOptions {
-            target_endian: "big".to_string(),
+            endian: "big".to_string(),
             cpu: "mips32r2".to_string(),
             features: "+mips32r2,+fpxx,+nooddspreg".to_string(),
             max_atomic_width: Some(32),
-            target_mcount: "_mcount".to_string(),
+            mcount: "_mcount".to_string(),
 
-            ..super::linux_base::opts()
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
index ed03f5d990e..1ebe577bc1c 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
@@ -11,10 +11,6 @@ pub fn target() -> Target {
         pointer_width: 32,
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
-        options: TargetOptions {
-            target_endian: "big".to_string(),
-            target_mcount: "_mcount".to_string(),
-            ..base
-        },
+        options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
index fa1d789bfa8..2123d5e1a0f 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
@@ -7,11 +7,11 @@ pub fn target() -> Target {
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
         options: TargetOptions {
-            target_endian: "big".to_string(),
+            endian: "big".to_string(),
             cpu: "mips32r2".to_string(),
             features: "+mips32r2,+soft-float".to_string(),
             max_atomic_width: Some(32),
-            target_mcount: "_mcount".to_string(),
+            mcount: "_mcount".to_string(),
 
             ..super::linux_uclibc_base::opts()
         },
diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
index 3f426e2e5fe..08c290e6ff1 100644
--- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
+++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
@@ -15,8 +15,8 @@ pub fn target() -> Target {
         arch: "mips".to_string(),
 
         options: TargetOptions {
-            target_os: "psp".to_string(),
-            target_vendor: "sony".to_string(),
+            os: "psp".to_string(),
+            vendor: "sony".to_string(),
             linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             cpu: "mips2".to_string(),
             executables: true,
diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs
index 16fbab58140..9cb2a13c7d4 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs
@@ -11,9 +11,9 @@ pub fn target() -> Target {
             cpu: "mips32r2".to_string(),
             features: "+mips32r2,+fpxx,+nooddspreg".to_string(),
             max_atomic_width: Some(32),
-            target_mcount: "_mcount".to_string(),
+            mcount: "_mcount".to_string(),
 
-            ..super::linux_base::opts()
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs
index d1b603cd9de..3374cdd4485 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs
@@ -11,6 +11,6 @@ pub fn target() -> Target {
         pointer_width: 32,
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
-        options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions { mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs
index a09f7ad0121..0831eb7a0a7 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs
@@ -11,7 +11,7 @@ pub fn target() -> Target {
             cpu: "mips32r2".to_string(),
             features: "+mips32r2,+soft-float".to_string(),
             max_atomic_width: Some(32),
-            target_mcount: "_mcount".to_string(),
+            mcount: "_mcount".to_string(),
 
             ..super::linux_uclibc_base::opts()
         },
diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs
index 60c4c3bb051..a8005927a7b 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs
@@ -14,7 +14,7 @@ pub fn target() -> Target {
         arch: "mips".to_string(),
 
         options: TargetOptions {
-            target_vendor: String::new(),
+            vendor: String::new(),
             linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             cpu: "mips32r2".to_string(),
             features: "+mips32r2,+soft-float,+noabicalls".to_string(),
diff --git a/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
index 417ee6e043b..11b3734a105 100644
--- a/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
@@ -7,13 +7,13 @@ pub fn target() -> Target {
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
         options: TargetOptions {
-            target_endian: "big".to_string(),
+            endian: "big".to_string(),
             cpu: "mips32r6".to_string(),
             features: "+mips32r6".to_string(),
             max_atomic_width: Some(32),
-            target_mcount: "_mcount".to_string(),
+            mcount: "_mcount".to_string(),
 
-            ..super::linux_base::opts()
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs
index cf273c6ab2b..06a5f40d69b 100644
--- a/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs
@@ -11,9 +11,9 @@ pub fn target() -> Target {
             cpu: "mips32r6".to_string(),
             features: "+mips32r6".to_string(),
             max_atomic_width: Some(32),
-            target_mcount: "_mcount".to_string(),
+            mcount: "_mcount".to_string(),
 
-            ..super::linux_base::opts()
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
index 1d82395f536..6282c9e1d54 100644
--- a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
@@ -7,14 +7,14 @@ pub fn target() -> Target {
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
         options: TargetOptions {
-            target_endian: "big".to_string(),
+            endian: "big".to_string(),
             // NOTE(mips64r6) matches C toolchain
             cpu: "mips64r6".to_string(),
             features: "+mips64r6".to_string(),
             max_atomic_width: Some(64),
-            target_mcount: "_mcount".to_string(),
+            mcount: "_mcount".to_string(),
 
-            ..super::linux_base::opts()
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
index aadd36235bf..589d7acba68 100644
--- a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
@@ -11,9 +11,9 @@ pub fn target() -> Target {
             cpu: "mips64r6".to_string(),
             features: "+mips64r6".to_string(),
             max_atomic_width: Some(64),
-            target_mcount: "_mcount".to_string(),
+            mcount: "_mcount".to_string(),
 
-            ..super::linux_base::opts()
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 895114b026e..f949bf95a50 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -37,8 +37,9 @@
 use crate::spec::abi::{lookup as lookup_abi, Abi};
 use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
 use rustc_serialize::json::{Json, ToJson};
+use rustc_span::symbol::{sym, Symbol};
 use std::collections::BTreeMap;
-use std::ops::Deref;
+use std::ops::{Deref, DerefMut};
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 use std::{fmt, io};
@@ -63,6 +64,7 @@ mod hermit_kernel_base;
 mod illumos_base;
 mod l4re_base;
 mod linux_base;
+mod linux_gnu_base;
 mod linux_kernel_base;
 mod linux_musl_base;
 mod linux_uclibc_base;
@@ -176,6 +178,13 @@ impl PanicStrategy {
             PanicStrategy::Abort => "abort",
         }
     }
+
+    pub fn desc_symbol(&self) -> Symbol {
+        match *self {
+            PanicStrategy::Unwind => sym::unwind,
+            PanicStrategy::Abort => sym::abort,
+        }
+    }
 }
 
 impl ToJson for PanicStrategy {
@@ -446,7 +455,7 @@ macro_rules! supported_targets {
                 $( $($triple)|+ => $module::target(), )+
                 _ => return None,
             };
-            t.options.is_builtin = true;
+            t.is_builtin = true;
             debug!("got builtin target: {:?}", t);
             Some(t)
         }
@@ -691,21 +700,25 @@ impl HasTargetSpec for Target {
 ///
 /// This has an implementation of `Default`, see each field for what the default is. In general,
 /// these try to take "minimal defaults" that don't assume anything about the runtime they run in.
+///
+/// `TargetOptions` as a separate structure is mostly an implementation detail of `Target`
+/// construction, all its fields logically belong to `Target` and available from `Target`
+/// through `Deref` impls.
 #[derive(PartialEq, Clone, Debug)]
 pub struct TargetOptions {
     /// Whether the target is built-in or loaded from a custom target specification.
     pub is_builtin: bool,
 
     /// String to use as the `target_endian` `cfg` variable. Defaults to "little".
-    pub target_endian: String,
+    pub endian: String,
     /// Width of c_int type. Defaults to "32".
-    pub target_c_int_width: String,
+    pub c_int_width: String,
     /// OS name to use for conditional compilation. Defaults to "none".
-    pub target_os: String,
+    pub os: String,
     /// Environment name to use for conditional compilation. Defaults to "".
-    pub target_env: String,
+    pub env: String,
     /// Vendor name to use for conditional compilation. Defaults to "unknown".
-    pub target_vendor: String,
+    pub vendor: String,
     /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
     /// on the command line. Defaults to `LinkerFlavor::Gcc`.
     pub linker_flavor: LinkerFlavor,
@@ -796,7 +809,7 @@ pub struct TargetOptions {
     /// String to append to the name of every static library. Defaults to ".a".
     pub staticlib_suffix: String,
     /// OS family to use for conditional compilation. Valid options: "unix", "windows".
-    pub target_family: Option<String>,
+    pub os_family: Option<String>,
     /// Whether the target toolchain's ABI supports returning small structs as an integer.
     pub abi_return_struct_as_int: bool,
     /// Whether the target toolchain is like macOS's. Only useful for compiling against iOS/macOS,
@@ -811,9 +824,6 @@ pub struct TargetOptions {
     /// library naming convention. Defaults to false.
     pub is_like_windows: bool,
     pub is_like_msvc: bool,
-    /// Whether the target toolchain is like Android's. Only useful for compiling against Android.
-    /// Defaults to false.
-    pub is_like_android: bool,
     /// Whether the target toolchain is like Emscripten's. Only useful for compiling with
     /// Emscripten toolchain.
     /// Defaults to false.
@@ -957,7 +967,7 @@ pub struct TargetOptions {
     pub merge_functions: MergeFunctions,
 
     /// Use platform dependent mcount function
-    pub target_mcount: String,
+    pub mcount: String,
 
     /// LLVM ABI name, corresponds to the '-mabi' parameter available in multilib C compilers
     pub llvm_abiname: String,
@@ -988,11 +998,11 @@ impl Default for TargetOptions {
     fn default() -> TargetOptions {
         TargetOptions {
             is_builtin: false,
-            target_endian: "little".to_string(),
-            target_c_int_width: "32".to_string(),
-            target_os: "none".to_string(),
-            target_env: String::new(),
-            target_vendor: "unknown".to_string(),
+            endian: "little".to_string(),
+            c_int_width: "32".to_string(),
+            os: "none".to_string(),
+            env: String::new(),
+            vendor: "unknown".to_string(),
             linker_flavor: LinkerFlavor::Gcc,
             linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
             lld_flavor: LldFlavor::Ld,
@@ -1016,12 +1026,11 @@ impl Default for TargetOptions {
             exe_suffix: String::new(),
             staticlib_prefix: "lib".to_string(),
             staticlib_suffix: ".a".to_string(),
-            target_family: None,
+            os_family: None,
             abi_return_struct_as_int: false,
             is_like_osx: false,
             is_like_solaris: false,
             is_like_windows: false,
-            is_like_android: false,
             is_like_emscripten: false,
             is_like_msvc: false,
             is_like_fuchsia: false,
@@ -1073,7 +1082,7 @@ impl Default for TargetOptions {
             limit_rdylib_exports: true,
             override_export_symbols: None,
             merge_functions: MergeFunctions::Aliases,
-            target_mcount: "mcount".to_string(),
+            mcount: "mcount".to_string(),
             llvm_abiname: "".to_string(),
             relax_elf_relocations: false,
             llvm_args: vec![],
@@ -1094,13 +1103,18 @@ impl Deref for Target {
         &self.options
     }
 }
+impl DerefMut for Target {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.options
+    }
+}
 
 impl Target {
     /// Given a function ABI, turn it into the correct ABI for this target.
     pub fn adjust_abi(&self, abi: Abi) -> Abi {
         match abi {
             Abi::System => {
-                if self.options.is_like_windows && self.arch == "x86" {
+                if self.is_like_windows && self.arch == "x86" {
                     Abi::Stdcall
                 } else {
                     Abi::C
@@ -1110,7 +1124,7 @@ impl Target {
             // See https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
             // and the individual pages for __stdcall et al.
             Abi::Stdcall | Abi::Fastcall | Abi::Vectorcall | Abi::Thiscall => {
-                if self.options.is_like_windows && self.arch != "x86" { Abi::C } else { abi }
+                if self.is_like_windows && self.arch != "x86" { Abi::C } else { abi }
             }
             Abi::EfiApi => {
                 if self.arch == "x86_64" {
@@ -1126,17 +1140,17 @@ impl Target {
     /// Minimum integer size in bits that this target can perform atomic
     /// operations on.
     pub fn min_atomic_width(&self) -> u64 {
-        self.options.min_atomic_width.unwrap_or(8)
+        self.min_atomic_width.unwrap_or(8)
     }
 
     /// Maximum integer size in bits that this target can perform atomic
     /// operations on.
     pub fn max_atomic_width(&self) -> u64 {
-        self.options.max_atomic_width.unwrap_or_else(|| self.pointer_width.into())
+        self.max_atomic_width.unwrap_or_else(|| self.pointer_width.into())
     }
 
     pub fn is_abi_supported(&self, abi: Abi) -> bool {
-        abi.generic() || !self.options.unsupported_abis.contains(&abi)
+        abi.generic() || !self.unsupported_abis.contains(&abi)
     }
 
     /// Loads a target descriptor from a JSON object.
@@ -1169,19 +1183,19 @@ impl Target {
             ($key_name:ident) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(s) = obj.find(&name).and_then(Json::as_string) {
-                    base.options.$key_name = s.to_string();
+                    base.$key_name = s.to_string();
                 }
             } );
             ($key_name:ident = $json_name:expr) => ( {
                 let name = $json_name;
                 if let Some(s) = obj.find(&name).and_then(Json::as_string) {
-                    base.options.$key_name = s.to_string();
+                    base.$key_name = s.to_string();
                 }
             } );
             ($key_name:ident, bool) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(s) = obj.find(&name).and_then(Json::as_boolean) {
-                    base.options.$key_name = s;
+                    base.$key_name = s;
                 }
             } );
             ($key_name:ident, Option<u32>) => ( {
@@ -1190,20 +1204,20 @@ impl Target {
                     if s < 1 || s > 5 {
                         return Err("Not a valid DWARF version number".to_string());
                     }
-                    base.options.$key_name = Some(s as u32);
+                    base.$key_name = Some(s as u32);
                 }
             } );
             ($key_name:ident, Option<u64>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(s) = obj.find(&name).and_then(Json::as_u64) {
-                    base.options.$key_name = Some(s);
+                    base.$key_name = Some(s);
                 }
             } );
             ($key_name:ident, MergeFunctions) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<MergeFunctions>() {
-                        Ok(mergefunc) => base.options.$key_name = mergefunc,
+                        Ok(mergefunc) => base.$key_name = mergefunc,
                         _ => return Some(Err(format!("'{}' is not a valid value for \
                                                       merge-functions. Use 'disabled', \
                                                       'trampolines', or 'aliases'.",
@@ -1216,7 +1230,7 @@ impl Target {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<RelocModel>() {
-                        Ok(relocation_model) => base.options.$key_name = relocation_model,
+                        Ok(relocation_model) => base.$key_name = relocation_model,
                         _ => return Some(Err(format!("'{}' is not a valid relocation model. \
                                                       Run `rustc --print relocation-models` to \
                                                       see the list of supported values.", s))),
@@ -1228,7 +1242,7 @@ impl Target {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<CodeModel>() {
-                        Ok(code_model) => base.options.$key_name = Some(code_model),
+                        Ok(code_model) => base.$key_name = Some(code_model),
                         _ => return Some(Err(format!("'{}' is not a valid code model. \
                                                       Run `rustc --print code-models` to \
                                                       see the list of supported values.", s))),
@@ -1240,7 +1254,7 @@ impl Target {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<TlsModel>() {
-                        Ok(tls_model) => base.options.$key_name = tls_model,
+                        Ok(tls_model) => base.$key_name = tls_model,
                         _ => return Some(Err(format!("'{}' is not a valid TLS model. \
                                                       Run `rustc --print tls-models` to \
                                                       see the list of supported values.", s))),
@@ -1252,8 +1266,8 @@ impl Target {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s {
-                        "unwind" => base.options.$key_name = PanicStrategy::Unwind,
-                        "abort" => base.options.$key_name = PanicStrategy::Abort,
+                        "unwind" => base.$key_name = PanicStrategy::Unwind,
+                        "abort" => base.$key_name = PanicStrategy::Abort,
                         _ => return Some(Err(format!("'{}' is not a valid value for \
                                                       panic-strategy. Use 'unwind' or 'abort'.",
                                                      s))),
@@ -1265,7 +1279,7 @@ impl Target {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<RelroLevel>() {
-                        Ok(level) => base.options.$key_name = level,
+                        Ok(level) => base.$key_name = level,
                         _ => return Some(Err(format!("'{}' is not a valid value for \
                                                       relro-level. Use 'full', 'partial, or 'off'.",
                                                       s))),
@@ -1276,7 +1290,7 @@ impl Target {
             ($key_name:ident, list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(v) = obj.find(&name).and_then(Json::as_array) {
-                    base.options.$key_name = v.iter()
+                    base.$key_name = v.iter()
                         .map(|a| a.as_string().unwrap().to_string())
                         .collect();
                 }
@@ -1284,7 +1298,7 @@ impl Target {
             ($key_name:ident, opt_list) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(v) = obj.find(&name).and_then(Json::as_array) {
-                    base.options.$key_name = Some(v.iter()
+                    base.$key_name = Some(v.iter()
                         .map(|a| a.as_string().unwrap().to_string())
                         .collect());
                 }
@@ -1292,7 +1306,15 @@ impl Target {
             ($key_name:ident, optional) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(o) = obj.find(&name[..]) {
-                    base.options.$key_name = o
+                    base.$key_name = o
+                        .as_string()
+                        .map(|s| s.to_string() );
+                }
+            } );
+            ($key_name:ident = $json_name:expr, optional) => ( {
+                let name = $json_name;
+                if let Some(o) = obj.find(&name[..]) {
+                    base.$key_name = o
                         .as_string()
                         .map(|s| s.to_string() );
                 }
@@ -1301,7 +1323,7 @@ impl Target {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     if let Some(flavor) = LldFlavor::from_str(&s) {
-                        base.options.$key_name = flavor;
+                        base.$key_name = flavor;
                     } else {
                         return Some(Err(format!(
                             "'{}' is not a valid value for lld-flavor. \
@@ -1315,7 +1337,7 @@ impl Target {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match LinkerFlavor::from_str(s) {
-                        Some(linker_flavor) => base.options.$key_name = linker_flavor,
+                        Some(linker_flavor) => base.$key_name = linker_flavor,
                         _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
                                                       Use {}", s, LinkerFlavor::one_of()))),
                     }
@@ -1326,7 +1348,7 @@ impl Target {
                 let name = (stringify!($key_name)).replace("_", "-");
                 obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| {
                     match s.parse::<CrtObjectsFallback>() {
-                        Ok(fallback) => base.options.$key_name = Some(fallback),
+                        Ok(fallback) => base.$key_name = Some(fallback),
                         _ => return Some(Err(format!("'{}' is not a valid CRT objects fallback. \
                                                       Use 'musl', 'mingw' or 'wasm'", s))),
                     }
@@ -1358,7 +1380,7 @@ impl Target {
 
                         args.insert(kind, v);
                     }
-                    base.options.$key_name = args;
+                    base.$key_name = args;
                 }
             } );
             ($key_name:ident, link_args) => ( {
@@ -1385,7 +1407,7 @@ impl Target {
 
                         args.insert(flavor, v);
                     }
-                    base.options.$key_name = args;
+                    base.$key_name = args;
                 }
             } );
             ($key_name:ident, env) => ( {
@@ -1397,7 +1419,7 @@ impl Target {
                             if p.len() == 2 {
                                 let k = p[0].to_string();
                                 let v = p[1].to_string();
-                                base.options.$key_name.push((k, v));
+                                base.$key_name.push((k, v));
                             }
                         }
                     }
@@ -1406,11 +1428,11 @@ impl Target {
         }
 
         key!(is_builtin, bool);
-        key!(target_endian);
-        key!(target_c_int_width);
-        key!(target_os = "os");
-        key!(target_env = "env");
-        key!(target_vendor = "vendor");
+        key!(endian = "target_endian");
+        key!(c_int_width = "target_c_int_width");
+        key!(os);
+        key!(env);
+        key!(vendor);
         key!(linker_flavor, LinkerFlavor)?;
         key!(linker, optional);
         key!(lld_flavor, LldFlavor)?;
@@ -1444,14 +1466,13 @@ impl Target {
         key!(exe_suffix);
         key!(staticlib_prefix);
         key!(staticlib_suffix);
-        key!(target_family, optional);
+        key!(os_family = "target_family", optional);
         key!(abi_return_struct_as_int, bool);
         key!(is_like_osx, bool);
         key!(is_like_solaris, bool);
         key!(is_like_windows, bool);
         key!(is_like_msvc, bool);
         key!(is_like_emscripten, bool);
-        key!(is_like_android, bool);
         key!(is_like_fuchsia, bool);
         key!(dwarf_version, Option<u32>);
         key!(linker_is_gnu, bool);
@@ -1490,7 +1511,7 @@ impl Target {
         key!(limit_rdylib_exports, bool);
         key!(override_export_symbols, opt_list);
         key!(merge_functions, MergeFunctions)?;
-        key!(target_mcount);
+        key!(mcount = "target_mcount");
         key!(llvm_abiname);
         key!(relax_elf_relocations, bool);
         key!(llvm_args, list);
@@ -1513,7 +1534,7 @@ impl Target {
                                 ));
                             }
 
-                            base.options.unsupported_abis.push(abi)
+                            base.unsupported_abis.push(abi)
                         }
                         None => {
                             return Err(format!(
@@ -1602,21 +1623,20 @@ impl ToJson for Target {
         macro_rules! target_option_val {
             ($attr:ident) => {{
                 let name = (stringify!($attr)).replace("_", "-");
-                if default.$attr != self.options.$attr {
-                    d.insert(name, self.options.$attr.to_json());
+                if default.$attr != self.$attr {
+                    d.insert(name, self.$attr.to_json());
                 }
             }};
             ($attr:ident, $key_name:expr) => {{
                 let name = $key_name;
-                if default.$attr != self.options.$attr {
-                    d.insert(name.to_string(), self.options.$attr.to_json());
+                if default.$attr != self.$attr {
+                    d.insert(name.to_string(), self.$attr.to_json());
                 }
             }};
             (link_args - $attr:ident) => {{
                 let name = (stringify!($attr)).replace("_", "-");
-                if default.$attr != self.options.$attr {
+                if default.$attr != self.$attr {
                     let obj = self
-                        .options
                         .$attr
                         .iter()
                         .map(|(k, v)| (k.desc().to_owned(), v.clone()))
@@ -1626,9 +1646,8 @@ impl ToJson for Target {
             }};
             (env - $attr:ident) => {{
                 let name = (stringify!($attr)).replace("_", "-");
-                if default.$attr != self.options.$attr {
+                if default.$attr != self.$attr {
                     let obj = self
-                        .options
                         .$attr
                         .iter()
                         .map(|&(ref k, ref v)| k.clone() + "=" + &v)
@@ -1644,11 +1663,11 @@ impl ToJson for Target {
         target_val!(data_layout);
 
         target_option_val!(is_builtin);
-        target_option_val!(target_endian);
-        target_option_val!(target_c_int_width);
-        target_option_val!(target_os, "os");
-        target_option_val!(target_env, "env");
-        target_option_val!(target_vendor, "vendor");
+        target_option_val!(endian, "target_endian");
+        target_option_val!(c_int_width, "target_c_int_width");
+        target_option_val!(os);
+        target_option_val!(env);
+        target_option_val!(vendor);
         target_option_val!(linker_flavor);
         target_option_val!(linker);
         target_option_val!(lld_flavor);
@@ -1682,14 +1701,13 @@ impl ToJson for Target {
         target_option_val!(exe_suffix);
         target_option_val!(staticlib_prefix);
         target_option_val!(staticlib_suffix);
-        target_option_val!(target_family);
+        target_option_val!(os_family, "target_family");
         target_option_val!(abi_return_struct_as_int);
         target_option_val!(is_like_osx);
         target_option_val!(is_like_solaris);
         target_option_val!(is_like_windows);
         target_option_val!(is_like_msvc);
         target_option_val!(is_like_emscripten);
-        target_option_val!(is_like_android);
         target_option_val!(is_like_fuchsia);
         target_option_val!(dwarf_version);
         target_option_val!(linker_is_gnu);
@@ -1728,7 +1746,7 @@ impl ToJson for Target {
         target_option_val!(limit_rdylib_exports);
         target_option_val!(override_export_symbols);
         target_option_val!(merge_functions);
-        target_option_val!(target_mcount);
+        target_option_val!(mcount, "target_mcount");
         target_option_val!(llvm_abiname);
         target_option_val!(relax_elf_relocations);
         target_option_val!(llvm_args);
@@ -1736,11 +1754,10 @@ impl ToJson for Target {
         target_option_val!(eh_frame_header);
         target_option_val!(has_thumb_interworking);
 
-        if default.unsupported_abis != self.options.unsupported_abis {
+        if default.unsupported_abis != self.unsupported_abis {
             d.insert(
                 "unsupported-abis".to_string(),
-                self.options
-                    .unsupported_abis
+                self.unsupported_abis
                     .iter()
                     .map(|&name| Abi::name(name).to_json())
                     .collect::<Vec<_>>()
diff --git a/compiler/rustc_target/src/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs
index 48b6d1be9ce..ef966cb702e 100644
--- a/compiler/rustc_target/src/spec/msp430_none_elf.rs
+++ b/compiler/rustc_target/src/spec/msp430_none_elf.rs
@@ -8,8 +8,8 @@ pub fn target() -> Target {
         arch: "msp430".to_string(),
 
         options: TargetOptions {
-            target_c_int_width: "16".to_string(),
-            target_vendor: String::new(),
+            c_int_width: "16".to_string(),
+            vendor: String::new(),
             executables: true,
 
             // The LLVM backend currently can't generate object files. To
diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs
index 437b50b6f11..a77d60bd9d7 100644
--- a/compiler/rustc_target/src/spec/netbsd_base.rs
+++ b/compiler/rustc_target/src/spec/netbsd_base.rs
@@ -14,10 +14,10 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_os: "netbsd".to_string(),
+        os: "netbsd".to_string(),
         dynamic_linking: true,
         executables: true,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         linker_is_gnu: true,
         no_default_libraries: false,
         has_rpath: true,
diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
index f759724445e..3c9c7d578fb 100644
--- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
@@ -9,8 +9,8 @@ pub fn target() -> Target {
         pointer_width: 64,
 
         options: TargetOptions {
-            target_os: "cuda".to_string(),
-            target_vendor: "nvidia".to_string(),
+            os: "cuda".to_string(),
+            vendor: "nvidia".to_string(),
             linker_flavor: LinkerFlavor::PtxLinker,
             // The linker can be installed from `crates.io`.
             linker: Some("rust-ptx-linker".to_string()),
diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs
index 5e83e79d9ed..2b40a1ed945 100644
--- a/compiler/rustc_target/src/spec/openbsd_base.rs
+++ b/compiler/rustc_target/src/spec/openbsd_base.rs
@@ -16,10 +16,10 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_os: "openbsd".to_string(),
+        os: "openbsd".to_string(),
         dynamic_linking: true,
         executables: true,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         abi_return_struct_as_int: true,
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
index 3d20f15b391..626865aa242 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
@@ -11,10 +11,6 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "E-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
-        options: TargetOptions {
-            target_endian: "big".to_string(),
-            target_mcount: "_mcount".to_string(),
-            ..base
-        },
+        options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
index e52643eb893..03322818d33 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, RelroLevel, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
+    let mut base = super::linux_gnu_base::opts();
     base.cpu = "ppc64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
@@ -15,10 +15,6 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "E-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
-        options: TargetOptions {
-            target_endian: "big".to_string(),
-            target_mcount: "_mcount".to_string(),
-            ..base
-        },
+        options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
index 315192929ac..231539756f3 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
@@ -11,10 +11,6 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "E-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
-        options: TargetOptions {
-            target_endian: "big".to_string(),
-            target_mcount: "_mcount".to_string(),
-            ..base
-        },
+        options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
index a31256761a4..1c83e3e64d4 100644
--- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
@@ -11,6 +11,6 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "E-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
-        options: TargetOptions { target_endian: "big".to_string(), ..base },
+        options: TargetOptions { endian: "big".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
index 4cf296c3fa7..07e0bf81bc7 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
+    let mut base = super::linux_gnu_base::opts();
     base.cpu = "ppc64le".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
@@ -11,6 +11,6 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "e-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
-        options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions { mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
index 41756028cbe..41c78a5f276 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
@@ -11,6 +11,6 @@ pub fn target() -> Target {
         pointer_width: 64,
         data_layout: "e-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
-        options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions { mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
index f3ec02c10d2..3a9271247b0 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
+    let mut base = super::linux_gnu_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.max_atomic_width = Some(32);
 
@@ -10,10 +10,6 @@ pub fn target() -> Target {
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
-        options: TargetOptions {
-            target_endian: "big".to_string(),
-            target_mcount: "_mcount".to_string(),
-            ..base
-        },
+        options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
index 4e3ffca0a08..105a0b21aaf 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
+    let mut base = super::linux_gnu_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mspe".to_string());
     base.max_atomic_width = Some(32);
 
@@ -10,10 +10,6 @@ pub fn target() -> Target {
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
-        options: TargetOptions {
-            target_endian: "big".to_string(),
-            target_mcount: "_mcount".to_string(),
-            ..base
-        },
+        options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
index 1d5c19b5420..49d32944789 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
@@ -10,10 +10,6 @@ pub fn target() -> Target {
         pointer_width: 32,
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
-        options: TargetOptions {
-            target_endian: "big".to_string(),
-            target_mcount: "_mcount".to_string(),
-            ..base
-        },
+        options: TargetOptions { endian: "big".to_string(), mcount: "_mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
index 4d7eb8d0100..387d6cdc456 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
@@ -11,8 +11,8 @@ pub fn target() -> Target {
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
         options: TargetOptions {
-            target_endian: "big".to_string(),
-            target_mcount: "__mcount".to_string(),
+            endian: "big".to_string(),
+            mcount: "__mcount".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
index dc6a4e28a3d..20ffa07b997 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
@@ -12,7 +12,7 @@ pub fn target() -> Target {
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
         options: TargetOptions {
-            target_endian: "big".to_string(),
+            endian: "big".to_string(),
             features: "+secure-plt".to_string(),
             ..base
         },
diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
index 1ce3fa21918..0e713fccd23 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
@@ -12,7 +12,7 @@ pub fn target() -> Target {
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
         options: TargetOptions {
-            target_endian: "big".to_string(),
+            endian: "big".to_string(),
             // feature msync would disable instruction 'fsync' which is not supported by fsl_p1p2
             features: "+secure-plt,+msync".to_string(),
             ..base
diff --git a/compiler/rustc_target/src/spec/redox_base.rs b/compiler/rustc_target/src/spec/redox_base.rs
index 04409a1cd04..5ef705878a8 100644
--- a/compiler/rustc_target/src/spec/redox_base.rs
+++ b/compiler/rustc_target/src/spec/redox_base.rs
@@ -19,11 +19,11 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_os: "redox".to_string(),
-        target_env: "relibc".to_string(),
+        os: "redox".to_string(),
+        env: "relibc".to_string(),
         dynamic_linking: true,
         executables: true,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         pre_link_args: args,
diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
index f9405d9dfb6..cf5e0201d08 100644
--- a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
@@ -13,7 +13,7 @@ pub fn target() -> Target {
             features: "+m,+a,+f,+d,+c".to_string(),
             llvm_abiname: "ilp32d".to_string(),
             max_atomic_width: Some(32),
-            ..super::linux_base::opts()
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
index 3b7ff47a540..84f28413fcb 100644
--- a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
@@ -13,7 +13,7 @@ pub fn target() -> Target {
             features: "+m,+a,+f,+d,+c".to_string(),
             llvm_abiname: "lp64d".to_string(),
             max_atomic_width: Some(64),
-            ..super::linux_base::opts()
+            ..super::linux_gnu_base::opts()
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
index 69b880cdb81..d6e8e6ee220 100644
--- a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
@@ -1,8 +1,8 @@
 use crate::spec::Target;
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
-    base.target_endian = "big".to_string();
+    let mut base = super::linux_gnu_base::opts();
+    base.endian = "big".to_string();
     // z10 is the oldest CPU supported by LLVM
     base.cpu = "z10".to_string();
     // FIXME: The data_layout string below and the ABI implementation in
diff --git a/compiler/rustc_target/src/spec/solaris_base.rs b/compiler/rustc_target/src/spec/solaris_base.rs
index 1454d83e936..33e0cf8e967 100644
--- a/compiler/rustc_target/src/spec/solaris_base.rs
+++ b/compiler/rustc_target/src/spec/solaris_base.rs
@@ -2,12 +2,12 @@ use crate::spec::TargetOptions;
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
-        target_os: "solaris".to_string(),
-        target_vendor: "sun".to_string(),
+        os: "solaris".to_string(),
+        vendor: "sun".to_string(),
         dynamic_linking: true,
         executables: true,
         has_rpath: true,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         is_like_solaris: true,
         limit_rdylib_exports: false, // Linker doesn't support this
         eh_frame_header: false,
diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
index f02b01a514b..e9b5520ac3d 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
@@ -1,8 +1,8 @@
 use crate::spec::Target;
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
-    base.target_endian = "big".to_string();
+    let mut base = super::linux_gnu_base::opts();
+    base.endian = "big".to_string();
     base.cpu = "v9".to_string();
     base.max_atomic_width = Some(64);
 
diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
index de35bb8fe14..c8e90f832d0 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
@@ -12,8 +12,8 @@ pub fn target() -> Target {
         data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
         arch: "sparc64".to_string(),
         options: TargetOptions {
-            target_endian: "big".to_string(),
-            target_mcount: "__mcount".to_string(),
+            endian: "big".to_string(),
+            mcount: "__mcount".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
index 301c91e432c..630ce6123f9 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
@@ -2,7 +2,7 @@ use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
-    base.target_endian = "big".to_string();
+    base.endian = "big".to_string();
     base.cpu = "v9".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
diff --git a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
index 071175819f4..aae186b2293 100644
--- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
@@ -1,8 +1,8 @@
 use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
-    base.target_endian = "big".to_string();
+    let mut base = super::linux_gnu_base::opts();
+    base.endian = "big".to_string();
     base.cpu = "v9".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mv8plus".to_string());
diff --git a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
index e8c30dcbf85..5f99e0b14f9 100644
--- a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
@@ -2,7 +2,7 @@ use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::solaris_base::opts();
-    base.target_endian = "big".to_string();
+    base.endian = "big".to_string();
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
     // llvm calls this "v9"
     base.cpu = "v9".to_string();
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index d06ab368e1c..f348df7d5a7 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -14,27 +14,27 @@ impl Target {
         assert_eq!(
             self.linker_flavor == LinkerFlavor::Msvc
                 || self.linker_flavor == LinkerFlavor::Lld(LldFlavor::Link),
-            self.options.lld_flavor == LldFlavor::Link,
+            self.lld_flavor == LldFlavor::Link,
         );
         for args in &[
-            &self.options.pre_link_args,
-            &self.options.late_link_args,
-            &self.options.late_link_args_dynamic,
-            &self.options.late_link_args_static,
-            &self.options.post_link_args,
+            &self.pre_link_args,
+            &self.late_link_args,
+            &self.late_link_args_dynamic,
+            &self.late_link_args_static,
+            &self.post_link_args,
         ] {
             assert_eq!(
                 args.get(&LinkerFlavor::Msvc),
                 args.get(&LinkerFlavor::Lld(LldFlavor::Link)),
             );
             if args.contains_key(&LinkerFlavor::Msvc) {
-                assert_eq!(self.options.lld_flavor, LldFlavor::Link);
+                assert_eq!(self.lld_flavor, LldFlavor::Link);
             }
         }
         assert!(
-            (self.options.pre_link_objects_fallback.is_empty()
-                && self.options.post_link_objects_fallback.is_empty())
-                || self.options.crt_objects_fallback.is_some()
+            (self.pre_link_objects_fallback.is_empty()
+                && self.post_link_objects_fallback.is_empty())
+                || self.crt_objects_fallback.is_some()
         );
     }
 }
diff --git a/compiler/rustc_target/src/spec/thumb_base.rs b/compiler/rustc_target/src/spec/thumb_base.rs
index cc955799d2f..e5504675027 100644
--- a/compiler/rustc_target/src/spec/thumb_base.rs
+++ b/compiler/rustc_target/src/spec/thumb_base.rs
@@ -32,7 +32,7 @@ use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOpti
 pub fn opts() -> TargetOptions {
     // See rust-lang/rfcs#1645 for a discussion about these defaults
     TargetOptions {
-        target_vendor: String::new(),
+        vendor: String::new(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         executables: true,
         // In most cases, LLD is good enough
diff --git a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs
index 561da4d15cd..352d2468743 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs
@@ -7,7 +7,7 @@ use crate::spec::{Target, TargetOptions};
 // https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
 
 pub fn target() -> Target {
-    let base = super::linux_base::opts();
+    let base = super::linux_gnu_base::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         pointer_width: 32,
diff --git a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs
index 5b1fc74bdd0..a788167aede 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs
@@ -24,7 +24,7 @@ pub fn target() -> Target {
             cpu: "generic".to_string(),
             max_atomic_width: Some(64),
             unsupported_abis: super::arm_base::unsupported_abis(),
-            target_mcount: "\u{1}mcount".to_string(),
+            mcount: "\u{1}mcount".to_string(),
             ..base
         },
     }
diff --git a/compiler/rustc_target/src/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs
index 91a39f7b9b4..79fe77495e7 100644
--- a/compiler/rustc_target/src/spec/uefi_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/uefi_msvc_base.rs
@@ -37,7 +37,7 @@ pub fn opts() -> TargetOptions {
         .extend(pre_link_args_msvc);
 
     TargetOptions {
-        target_os: "uefi".to_string(),
+        os: "uefi".to_string(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
         disable_redzone: true,
         exe_suffix: ".efi".to_string(),
diff --git a/compiler/rustc_target/src/spec/vxworks_base.rs b/compiler/rustc_target/src/spec/vxworks_base.rs
index e8044e4dc1a..70bc9ce3e0e 100644
--- a/compiler/rustc_target/src/spec/vxworks_base.rs
+++ b/compiler/rustc_target/src/spec/vxworks_base.rs
@@ -17,14 +17,14 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
-        target_os: "vxworks".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "wrs".to_string(),
+        os: "vxworks".to_string(),
+        env: "gnu".to_string(),
+        vendor: "wrs".to_string(),
         linker: Some("wr-c++".to_string()),
         exe_suffix: ".vxe".to_string(),
         dynamic_linking: true,
         executables: true,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         linker_is_gnu: true,
         has_rpath: true,
         pre_link_args: args,
@@ -34,7 +34,7 @@ pub fn opts() -> TargetOptions {
         crt_static_respected: true,
         crt_static_allows_dylibs: true,
         // VxWorks needs to implement this to support profiling
-        target_mcount: "_mcount".to_string(),
+        mcount: "_mcount".to_string(),
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index dbafe362f2a..c12757b8f98 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -17,7 +17,7 @@ pub fn target() -> Target {
     );
 
     let opts = TargetOptions {
-        target_os: "emscripten".to_string(),
+        os: "emscripten".to_string(),
         linker_flavor: LinkerFlavor::Em,
         // emcc emits two files - a .js file to instantiate the wasm and supply platform
         // functionality, and a .wasm file.
@@ -27,7 +27,7 @@ pub fn target() -> Target {
         is_like_emscripten: true,
         panic_strategy: PanicStrategy::Unwind,
         post_link_args,
-        target_family: Some("unix".to_string()),
+        os_family: Some("unix".to_string()),
         ..wasm32_base::options()
     };
     Target {
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
index 4401772788b..6037aa5b430 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
@@ -15,7 +15,7 @@ use super::{LinkerFlavor, LldFlavor, Target};
 
 pub fn target() -> Target {
     let mut options = wasm32_base::options();
-    options.target_os = "unknown".to_string();
+    options.os = "unknown".to_string();
     options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm);
     let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
 
diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs
index 6f5316e30f6..9c697674f39 100644
--- a/compiler/rustc_target/src/spec/wasm32_wasi.rs
+++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs
@@ -78,8 +78,8 @@ use super::{crt_objects, LinkerFlavor, LldFlavor, Target};
 pub fn target() -> Target {
     let mut options = wasm32_base::options();
 
-    options.target_os = "wasi".to_string();
-    options.target_vendor = String::new();
+    options.os = "wasi".to_string();
+    options.vendor = String::new();
     options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm);
     options
         .pre_link_args
diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs
index 37188a59eb5..f556a13a519 100644
--- a/compiler/rustc_target/src/spec/windows_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs
@@ -62,9 +62,9 @@ pub fn opts() -> TargetOptions {
     late_link_args_static.insert(LinkerFlavor::Lld(LldFlavor::Ld), static_unwind_libs);
 
     TargetOptions {
-        target_os: "windows".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "pc".to_string(),
+        os: "windows".to_string(),
+        env: "gnu".to_string(),
+        vendor: "pc".to_string(),
         // FIXME(#13846) this should be enabled for windows
         function_sections: false,
         linker: Some("gcc".to_string()),
@@ -75,7 +75,7 @@ pub fn opts() -> TargetOptions {
         exe_suffix: ".exe".to_string(),
         staticlib_prefix: "lib".to_string(),
         staticlib_suffix: ".a".to_string(),
-        target_family: Some("windows".to_string()),
+        os_family: Some("windows".to_string()),
         is_like_windows: true,
         allows_weak_linkage: false,
         pre_link_args,
diff --git a/compiler/rustc_target/src/spec/windows_msvc_base.rs b/compiler/rustc_target/src/spec/windows_msvc_base.rs
index c1101623867..c041245e328 100644
--- a/compiler/rustc_target/src/spec/windows_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/windows_msvc_base.rs
@@ -4,16 +4,16 @@ pub fn opts() -> TargetOptions {
     let base = super::msvc_base::opts();
 
     TargetOptions {
-        target_os: "windows".to_string(),
-        target_env: "msvc".to_string(),
-        target_vendor: "pc".to_string(),
+        os: "windows".to_string(),
+        env: "msvc".to_string(),
+        vendor: "pc".to_string(),
         dynamic_linking: true,
         dll_prefix: String::new(),
         dll_suffix: ".dll".to_string(),
         exe_suffix: ".exe".to_string(),
         staticlib_prefix: String::new(),
         staticlib_suffix: ".lib".to_string(),
-        target_family: Some("windows".to_string()),
+        os_family: Some("windows".to_string()),
         crt_static_allows_dylibs: true,
         crt_static_respected: true,
         requires_uwtable: true,
diff --git a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
index 225b94c3755..67d1be399b3 100644
--- a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
@@ -25,7 +25,7 @@ pub fn opts() -> TargetOptions {
     late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs);
 
     TargetOptions {
-        target_vendor: "uwp".to_string(),
+        vendor: "uwp".to_string(),
         executables: false,
         limit_rdylib_exports: false,
         late_link_args,
diff --git a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs
index 380d685dacf..700ee5ec646 100644
--- a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs
@@ -3,7 +3,7 @@ use crate::spec::{LinkerFlavor, LldFlavor, TargetOptions};
 pub fn opts() -> TargetOptions {
     let mut opts = super::windows_msvc_base::opts();
 
-    opts.target_vendor = "uwp".to_string();
+    opts.vendor = "uwp".to_string();
     let pre_link_args_msvc = vec!["/APPCONTAINER".to_string(), "mincore.lib".to_string()];
     opts.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().extend(pre_link_args_msvc.clone());
     opts.pre_link_args
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
index 6cd4daa7a74..edb33fe6e2b 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -24,6 +24,6 @@ pub fn target() -> Target {
         data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
         arch: arch.to_string(),
-        options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
+        options: TargetOptions { mcount: "\u{1}mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
index 550d308ed8f..74fb6f0a834 100644
--- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
@@ -55,9 +55,9 @@ pub fn target() -> Target {
         "TEXT_SIZE",
     ];
     let opts = TargetOptions {
-        target_os: "unknown".into(),
-        target_env: "sgx".into(),
-        target_vendor: "fortanix".into(),
+        os: "unknown".into(),
+        env: "sgx".into(),
+        vendor: "fortanix".into(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         dynamic_linking: false,
         executables: true,
diff --git a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
index 511a4559935..095c6f15c77 100644
--- a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
@@ -2,7 +2,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
-    base.target_vendor = "rumprun".to_string();
+    base.vendor = "rumprun".to_string();
     base.cpu = "x86-64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.linker = Some("x86_64-rumprun-netbsd-gcc".to_string());
@@ -20,6 +20,6 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
         arch: "x86_64".to_string(),
-        options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
+        options: TargetOptions { mcount: "__mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
index 1f368ff1611..f127dd49bc4 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
+    let mut base = super::linux_gnu_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
index 375b22fd92b..0cae5752848 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
-    let mut base = super::linux_base::opts();
+    let mut base = super::linux_gnu_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string());
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
index 656ef90892c..7e91a6ddbe2 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
@@ -13,6 +13,6 @@ pub fn target() -> Target {
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
         arch: "x86_64".to_string(),
-        options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
+        options: TargetOptions { mcount: "__mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 638a8253e7e..e1721a5a88a 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -512,6 +512,13 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
                 block = &self.body.basic_blocks()[next];
             } else {
                 assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap());
+                // `AbstractConst`s should not contain any promoteds as they require references which
+                // are not allowed.
+                assert!(!self.nodes.iter().any(|n| matches!(
+                    n.node,
+                    Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(_, _, Some(_)), ty: _ })
+                )));
+
                 self.nodes[self.locals[mir::RETURN_PLACE]].used = true;
                 if let Some(&unused) = self.nodes.iter().find(|n| !n.used) {
                     self.error(Some(unused.span), "dead code")?;
@@ -609,6 +616,10 @@ pub(super) fn try_unify<'tcx>(
         (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
             let a_ct = a_ct.subst(tcx, a.substs);
             let b_ct = b_ct.subst(tcx, b.substs);
+            if a_ct.ty != b_ct.ty {
+                return false;
+            }
+
             match (a_ct.val, b_ct.val) {
                 // We can just unify errors with everything to reduce the amount of
                 // emitted errors here.
@@ -621,6 +632,12 @@ pub(super) fn try_unify<'tcx>(
                 // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This
                 // means that we only allow inference variables if they are equal.
                 (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val,
+                // We may want to instead recurse into unevaluated constants here. That may require some
+                // care to prevent infinite recursion, so let's just ignore this for now.
+                (
+                    ty::ConstKind::Unevaluated(a_def, a_substs, None),
+                    ty::ConstKind::Unevaluated(b_def, b_substs, None),
+                ) => a_def == b_def && a_substs == b_substs,
                 // FIXME(const_evaluatable_checked): We may want to either actually try
                 // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like
                 // this, for now we just return false here.
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 4cc4bc0acda..a91f693f175 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -279,7 +279,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     /// tracking is not enabled, just returns an empty vector.
     pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> {
         assert!(self.intercrate);
-        self.intercrate_ambiguity_causes.take().unwrap_or(vec![])
+        self.intercrate_ambiguity_causes.take().unwrap_or_default()
     }
 
     pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> {
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml
index a54fe08394e..8bd9e29629d 100644
--- a/compiler/rustc_traits/Cargo.toml
+++ b/compiler/rustc_traits/Cargo.toml
@@ -12,9 +12,9 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
-chalk-ir = "0.32.0"
-chalk-solve = "0.32.0"
-chalk-engine = "0.32.0"
+chalk-ir = "0.36.0"
+chalk-solve = "0.36.0"
+chalk-engine = "0.36.0"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 rustc_infer = { path = "../rustc_infer" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index e5ae899a2f3..c5a46b1003d 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -37,7 +37,7 @@ impl<'tcx> RustIrDatabase<'tcx> {
         def_id: DefId,
         bound_vars: SubstsRef<'tcx>,
     ) -> Vec<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
-        let predicates = self.interner.tcx.predicates_of(def_id).predicates;
+        let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates;
         let mut regions_substitutor =
             lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
         predicates
@@ -118,34 +118,27 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
             .map(|i| chalk_ir::AssocTypeId(i.def_id))
             .collect();
 
-        let well_known = if self.interner.tcx.lang_items().sized_trait() == Some(def_id) {
+        let lang_items = self.interner.tcx.lang_items();
+        let well_known = if lang_items.sized_trait() == Some(def_id) {
             Some(chalk_solve::rust_ir::WellKnownTrait::Sized)
-        } else if self.interner.tcx.lang_items().copy_trait() == Some(def_id) {
+        } else if lang_items.copy_trait() == Some(def_id) {
             Some(chalk_solve::rust_ir::WellKnownTrait::Copy)
-        } else if self.interner.tcx.lang_items().clone_trait() == Some(def_id) {
+        } else if lang_items.clone_trait() == Some(def_id) {
             Some(chalk_solve::rust_ir::WellKnownTrait::Clone)
-        } else if self.interner.tcx.lang_items().drop_trait() == Some(def_id) {
+        } else if lang_items.drop_trait() == Some(def_id) {
             Some(chalk_solve::rust_ir::WellKnownTrait::Drop)
-        } else if self.interner.tcx.lang_items().fn_trait() == Some(def_id) {
+        } else if lang_items.fn_trait() == Some(def_id) {
             Some(chalk_solve::rust_ir::WellKnownTrait::Fn)
-        } else if self
-            .interner
-            .tcx
-            .lang_items()
-            .fn_once_trait()
-            .map(|t| def_id == t)
-            .unwrap_or(false)
-        {
+        } else if lang_items.fn_once_trait() == Some(def_id) {
             Some(chalk_solve::rust_ir::WellKnownTrait::FnOnce)
-        } else if self
-            .interner
-            .tcx
-            .lang_items()
-            .fn_mut_trait()
-            .map(|t| def_id == t)
-            .unwrap_or(false)
-        {
+        } else if lang_items.fn_mut_trait() == Some(def_id) {
             Some(chalk_solve::rust_ir::WellKnownTrait::FnMut)
+        } else if lang_items.unsize_trait() == Some(def_id) {
+            Some(chalk_solve::rust_ir::WellKnownTrait::Unsize)
+        } else if lang_items.unpin_trait() == Some(def_id) {
+            Some(chalk_solve::rust_ir::WellKnownTrait::Unpin)
+        } else if lang_items.coerce_unsized_trait() == Some(def_id) {
+            Some(chalk_solve::rust_ir::WellKnownTrait::CoerceUnsized)
         } else {
             None
         };
@@ -281,11 +274,20 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
             where_clauses,
         };
 
+        let associated_ty_value_ids: Vec<_> = self
+            .interner
+            .tcx
+            .associated_items(def_id)
+            .in_definition_order()
+            .filter(|i| i.kind == AssocKind::Type)
+            .map(|i| chalk_solve::rust_ir::AssociatedTyValueId(i.def_id))
+            .collect();
+
         Arc::new(chalk_solve::rust_ir::ImplDatum {
-            polarity: chalk_solve::rust_ir::Polarity::Positive,
+            polarity: self.interner.tcx.impl_polarity(def_id).lower_into(&self.interner),
             binders: chalk_ir::Binders::new(binders, value),
             impl_type: chalk_solve::rust_ir::ImplType::Local,
-            associated_ty_value_ids: vec![],
+            associated_ty_value_ids,
         })
     }
 
@@ -324,19 +326,19 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
     fn impl_provided_for(
         &self,
         auto_trait_id: chalk_ir::TraitId<RustInterner<'tcx>>,
-        app_ty: &chalk_ir::ApplicationTy<RustInterner<'tcx>>,
+        chalk_ty: &chalk_ir::TyKind<RustInterner<'tcx>>,
     ) -> bool {
         use chalk_ir::Scalar::*;
-        use chalk_ir::TypeName::*;
+        use chalk_ir::TyKind::*;
 
         let trait_def_id = auto_trait_id.0;
         let all_impls = self.interner.tcx.all_impls(trait_def_id);
         for impl_def_id in all_impls {
             let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap();
             let self_ty = trait_ref.self_ty();
-            let provides = match (self_ty.kind(), app_ty.name) {
-                (&ty::Adt(impl_adt_def, ..), Adt(id)) => impl_adt_def.did == id.0.did,
-                (_, AssociatedType(_ty_id)) => {
+            let provides = match (self_ty.kind(), chalk_ty) {
+                (&ty::Adt(impl_adt_def, ..), Adt(id, ..)) => impl_adt_def.did == id.0.did,
+                (_, AssociatedType(_ty_id, ..)) => {
                     // FIXME(chalk): See https://github.com/rust-lang/rust/pull/77152#discussion_r494484774
                     false
                 }
@@ -365,10 +367,10 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                     (ast::FloatTy::F32, chalk_ir::FloatTy::F32)
                         | (ast::FloatTy::F64, chalk_ir::FloatTy::F64)
                 ),
-                (&ty::Tuple(..), Tuple(..)) => true,
-                (&ty::Array(..), Array) => true,
-                (&ty::Slice(..), Slice) => true,
-                (&ty::RawPtr(type_and_mut), Raw(mutability)) => {
+                (&ty::Tuple(substs), Tuple(len, _)) => substs.len() == *len,
+                (&ty::Array(..), Array(..)) => true,
+                (&ty::Slice(..), Slice(..)) => true,
+                (&ty::RawPtr(type_and_mut), Raw(mutability, _)) => {
                     match (type_and_mut.mutbl, mutability) {
                         (ast::Mutability::Mut, chalk_ir::Mutability::Mut) => true,
                         (ast::Mutability::Mut, chalk_ir::Mutability::Not) => false,
@@ -376,17 +378,19 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                         (ast::Mutability::Not, chalk_ir::Mutability::Not) => true,
                     }
                 }
-                (&ty::Ref(.., mutability1), Ref(mutability2)) => match (mutability1, mutability2) {
-                    (ast::Mutability::Mut, chalk_ir::Mutability::Mut) => true,
-                    (ast::Mutability::Mut, chalk_ir::Mutability::Not) => false,
-                    (ast::Mutability::Not, chalk_ir::Mutability::Mut) => false,
-                    (ast::Mutability::Not, chalk_ir::Mutability::Not) => true,
-                },
-                (&ty::Opaque(def_id, ..), OpaqueType(opaque_ty_id)) => def_id == opaque_ty_id.0,
-                (&ty::FnDef(def_id, ..), FnDef(fn_def_id)) => def_id == fn_def_id.0,
+                (&ty::Ref(.., mutability1), Ref(mutability2, ..)) => {
+                    match (mutability1, mutability2) {
+                        (ast::Mutability::Mut, chalk_ir::Mutability::Mut) => true,
+                        (ast::Mutability::Mut, chalk_ir::Mutability::Not) => false,
+                        (ast::Mutability::Not, chalk_ir::Mutability::Mut) => false,
+                        (ast::Mutability::Not, chalk_ir::Mutability::Not) => true,
+                    }
+                }
+                (&ty::Opaque(def_id, ..), OpaqueType(opaque_ty_id, ..)) => def_id == opaque_ty_id.0,
+                (&ty::FnDef(def_id, ..), FnDef(fn_def_id, ..)) => def_id == fn_def_id.0,
                 (&ty::Str, Str) => true,
                 (&ty::Never, Never) => true,
-                (&ty::Closure(def_id, ..), Closure(closure_id)) => def_id == closure_id.0,
+                (&ty::Closure(def_id, ..), Closure(closure_id, _)) => def_id == closure_id.0,
                 (&ty::Foreign(def_id), Foreign(foreign_def_id)) => def_id == foreign_def_id.0,
                 (&ty::Error(..), Error) => false,
                 _ => false,
@@ -404,24 +408,38 @@ 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 = match assoc_item.container {
-            AssocItemContainer::TraitContainer(def_id) => def_id,
-            _ => unimplemented!("Not possible??"),
+        let (impl_id, trait_id) = match assoc_item.container {
+            AssocItemContainer::TraitContainer(def_id) => (def_id, def_id),
+            AssocItemContainer::ImplContainer(def_id) => {
+                (def_id, self.interner.tcx.impl_trait_ref(def_id).unwrap().def_id)
+            }
         };
         match assoc_item.kind {
             AssocKind::Type => {}
             _ => unimplemented!("Not possible??"),
         }
+
+        let trait_item = self
+            .interner
+            .tcx
+            .associated_items(trait_id)
+            .find_by_name_and_kind(self.interner.tcx, assoc_item.ident, assoc_item.kind, trait_id)
+            .unwrap();
         let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
         let binders = binders_for(&self.interner, bound_vars);
-        let ty = self.interner.tcx.type_of(def_id);
+        let ty = self
+            .interner
+            .tcx
+            .type_of(def_id)
+            .subst(self.interner.tcx, bound_vars)
+            .lower_into(&self.interner);
 
         Arc::new(chalk_solve::rust_ir::AssociatedTyValue {
             impl_id: chalk_ir::ImplId(impl_id),
-            associated_ty_id: chalk_ir::AssocTypeId(def_id),
+            associated_ty_id: chalk_ir::AssocTypeId(trait_item.def_id),
             value: chalk_ir::Binders::new(
                 binders,
-                chalk_solve::rust_ir::AssociatedTyValueBound { ty: ty.lower_into(&self.interner) },
+                chalk_solve::rust_ir::AssociatedTyValueBound { ty },
             ),
         })
     }
@@ -441,19 +459,61 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
         &self,
         opaque_ty_id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>,
     ) -> Arc<chalk_solve::rust_ir::OpaqueTyDatum<RustInterner<'tcx>>> {
-        let bound_vars = bound_vars_for_item(self.interner.tcx, opaque_ty_id.0);
-        let binders = binders_for(&self.interner, bound_vars);
+        let bound_vars = ty::fold::shift_vars(
+            self.interner.tcx,
+            &bound_vars_for_item(self.interner.tcx, opaque_ty_id.0),
+            1,
+        );
         let where_clauses = self.where_clauses_for(opaque_ty_id.0, bound_vars);
-        let bounds = self.bounds_for(opaque_ty_id.0, bound_vars);
+
+        let identity_substs = InternalSubsts::identity_for_item(self.interner.tcx, opaque_ty_id.0);
+
+        let bounds =
+            self.interner
+                .tcx
+                .explicit_item_bounds(opaque_ty_id.0)
+                .iter()
+                .map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars))
+                .map(|bound| {
+                    bound.fold_with(&mut ty::fold::BottomUpFolder {
+                        tcx: self.interner.tcx,
+                        ty_op: |ty| {
+                            if let ty::Opaque(def_id, substs) = *ty.kind() {
+                                if def_id == opaque_ty_id.0 && substs == identity_substs {
+                                    return self.interner.tcx.mk_ty(ty::Bound(
+                                        ty::INNERMOST,
+                                        ty::BoundTy::from(ty::BoundVar::from_u32(0)),
+                                    ));
+                                }
+                            }
+                            ty
+                        },
+                        lt_op: |lt| lt,
+                        ct_op: |ct| ct,
+                    })
+                })
+                .filter_map(|bound| {
+                    LowerInto::<
+                    Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>
+                >::lower_into(bound, &self.interner)
+                })
+                .collect();
+
+        // Binder for the bound variable representing the concrete impl Trait type.
+        let existential_binder = chalk_ir::VariableKinds::from1(
+            &self.interner,
+            chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
+        );
 
         let value = chalk_solve::rust_ir::OpaqueTyDatumBound {
-            bounds: chalk_ir::Binders::new(binders.clone(), bounds),
-            where_clauses: chalk_ir::Binders::new(binders, where_clauses),
+            bounds: chalk_ir::Binders::new(existential_binder.clone(), bounds),
+            where_clauses: chalk_ir::Binders::new(existential_binder, where_clauses),
         };
 
+        let binders = binders_for(&self.interner, bound_vars);
         Arc::new(chalk_solve::rust_ir::OpaqueTyDatum {
             opaque_ty_id,
-            bound: chalk_ir::Binders::empty(&self.interner, value),
+            bound: chalk_ir::Binders::new(binders, value),
         })
     }
 
@@ -506,17 +566,11 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
         substs: &chalk_ir::Substitution<RustInterner<'tcx>>,
     ) -> chalk_solve::rust_ir::ClosureKind {
         let kind = &substs.as_slice(&self.interner)[substs.len(&self.interner) - 3];
-        match kind.assert_ty_ref(&self.interner).data(&self.interner) {
-            chalk_ir::TyData::Apply(apply) => match apply.name {
-                chalk_ir::TypeName::Scalar(scalar) => match scalar {
-                    chalk_ir::Scalar::Int(int_ty) => match int_ty {
-                        chalk_ir::IntTy::I8 => chalk_solve::rust_ir::ClosureKind::Fn,
-                        chalk_ir::IntTy::I16 => chalk_solve::rust_ir::ClosureKind::FnMut,
-                        chalk_ir::IntTy::I32 => chalk_solve::rust_ir::ClosureKind::FnOnce,
-                        _ => bug!("bad closure kind"),
-                    },
-                    _ => bug!("bad closure kind"),
-                },
+        match kind.assert_ty_ref(&self.interner).kind(&self.interner) {
+            chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(int_ty)) => match int_ty {
+                chalk_ir::IntTy::I8 => chalk_solve::rust_ir::ClosureKind::Fn,
+                chalk_ir::IntTy::I16 => chalk_solve::rust_ir::ClosureKind::FnMut,
+                chalk_ir::IntTy::I32 => chalk_solve::rust_ir::ClosureKind::FnOnce,
                 _ => bug!("bad closure kind"),
             },
             _ => bug!("bad closure kind"),
@@ -530,23 +584,19 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
     ) -> chalk_ir::Binders<chalk_solve::rust_ir::FnDefInputsAndOutputDatum<RustInterner<'tcx>>>
     {
         let sig = &substs.as_slice(&self.interner)[substs.len(&self.interner) - 2];
-        match sig.assert_ty_ref(&self.interner).data(&self.interner) {
-            chalk_ir::TyData::Function(f) => {
+        match sig.assert_ty_ref(&self.interner).kind(&self.interner) {
+            chalk_ir::TyKind::Function(f) => {
                 let substitution = f.substitution.as_slice(&self.interner);
                 let return_type =
                     substitution.last().unwrap().assert_ty_ref(&self.interner).clone();
                 // Closure arguments are tupled
                 let argument_tuple = substitution[0].assert_ty_ref(&self.interner);
-                let argument_types = match argument_tuple.data(&self.interner) {
-                    chalk_ir::TyData::Apply(apply) => match apply.name {
-                        chalk_ir::TypeName::Tuple(_) => apply
-                            .substitution
-                            .iter(&self.interner)
-                            .map(|arg| arg.assert_ty_ref(&self.interner))
-                            .cloned()
-                            .collect(),
-                        _ => bug!("Expecting closure FnSig args to be tupled."),
-                    },
+                let argument_types = match argument_tuple.kind(&self.interner) {
+                    chalk_ir::TyKind::Tuple(_len, substitution) => substitution
+                        .iter(&self.interner)
+                        .map(|arg| arg.assert_ty_ref(&self.interner))
+                        .cloned()
+                        .collect(),
                     _ => bug!("Expecting closure FnSig args to be tupled."),
                 };
 
@@ -637,7 +687,7 @@ fn binders_for<'tcx>(
         bound_vars.iter().map(|arg| match arg.unpack() {
             ty::subst::GenericArgKind::Lifetime(_re) => chalk_ir::VariableKind::Lifetime,
             ty::subst::GenericArgKind::Type(_ty) => {
-                chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General)
+                chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
             }
             ty::subst::GenericArgKind::Const(c) => {
                 chalk_ir::VariableKind::Const(c.ty.lower_into(interner))
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 01c4dd12487..c4e2c7f839d 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -31,11 +31,12 @@
 //! not. To lower anything wrapped in a `Binder`, we first deeply find any bound
 //! variables from the current `Binder`.
 
+use rustc_ast::ast;
 use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner};
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{
-    self, Binder, BoundRegion, Region, RegionKind, Ty, TyCtxt, TyKind, TypeFoldable, TypeVisitor,
+    self, Binder, BoundRegion, Region, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor,
 };
 use rustc_span::def_id::DefId;
 
@@ -240,24 +241,16 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq<RustInterner<'tcx>>>
 
 impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
     fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'tcx>> {
-        use chalk_ir::TyData;
         use rustc_ast as ast;
-        use TyKind::*;
 
-        let empty = || chalk_ir::Substitution::empty(interner);
-        let struct_ty =
-            |def_id| chalk_ir::TypeName::Adt(chalk_ir::AdtId(interner.tcx.adt_def(def_id)));
-        let apply = |name, substitution| {
-            TyData::Apply(chalk_ir::ApplicationTy { name, substitution }).intern(interner)
-        };
-        let int = |i| apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Int(i)), empty());
-        let uint = |i| apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Uint(i)), empty());
-        let float = |f| apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Float(f)), empty());
+        let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i));
+        let uint = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Uint(i));
+        let float = |f| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Float(f));
 
         match *self.kind() {
-            Bool => apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Bool), empty()),
-            Char => apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Char), empty()),
-            Int(ty) => match ty {
+            ty::Bool => chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Bool),
+            ty::Char => chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Char),
+            ty::Int(ty) => match ty {
                 ast::IntTy::Isize => int(chalk_ir::IntTy::Isize),
                 ast::IntTy::I8 => int(chalk_ir::IntTy::I8),
                 ast::IntTy::I16 => int(chalk_ir::IntTy::I16),
@@ -265,7 +258,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
                 ast::IntTy::I64 => int(chalk_ir::IntTy::I64),
                 ast::IntTy::I128 => int(chalk_ir::IntTy::I128),
             },
-            Uint(ty) => match ty {
+            ty::Uint(ty) => match ty {
                 ast::UintTy::Usize => uint(chalk_ir::UintTy::Usize),
                 ast::UintTy::U8 => uint(chalk_ir::UintTy::U8),
                 ast::UintTy::U16 => uint(chalk_ir::UintTy::U16),
@@ -273,80 +266,35 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
                 ast::UintTy::U64 => uint(chalk_ir::UintTy::U64),
                 ast::UintTy::U128 => uint(chalk_ir::UintTy::U128),
             },
-            Float(ty) => match ty {
+            ty::Float(ty) => match ty {
                 ast::FloatTy::F32 => float(chalk_ir::FloatTy::F32),
                 ast::FloatTy::F64 => float(chalk_ir::FloatTy::F64),
             },
-            Adt(def, substs) => apply(struct_ty(def.did), substs.lower_into(interner)),
-            Foreign(def_id) => apply(chalk_ir::TypeName::Foreign(ForeignDefId(def_id)), empty()),
-            Str => apply(chalk_ir::TypeName::Str, empty()),
-            Array(ty, len) => {
-                let value = match len.val {
-                    ty::ConstKind::Value(val) => {
-                        chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: val })
-                    }
-                    ty::ConstKind::Bound(db, bound) => {
-                        chalk_ir::ConstValue::BoundVar(chalk_ir::BoundVar::new(
-                            chalk_ir::DebruijnIndex::new(db.as_u32()),
-                            bound.index(),
-                        ))
-                    }
-                    _ => unimplemented!("Const not implemented. {:?}", len.val),
-                };
-                apply(
-                    chalk_ir::TypeName::Array,
-                    chalk_ir::Substitution::from_iter(
-                        interner,
-                        &[
-                            chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner),
-                            chalk_ir::GenericArgData::Const(
-                                chalk_ir::ConstData { ty: len.ty.lower_into(interner), value }
-                                    .intern(interner),
-                            )
-                            .intern(interner),
-                        ],
-                    ),
-                )
+            ty::Adt(def, substs) => {
+                chalk_ir::TyKind::Adt(chalk_ir::AdtId(def), substs.lower_into(interner))
             }
-            Slice(ty) => apply(
-                chalk_ir::TypeName::Slice,
-                chalk_ir::Substitution::from1(
-                    interner,
-                    chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner),
-                ),
-            ),
-            RawPtr(ptr) => {
-                let name = match ptr.mutbl {
-                    ast::Mutability::Mut => chalk_ir::TypeName::Raw(chalk_ir::Mutability::Mut),
-                    ast::Mutability::Not => chalk_ir::TypeName::Raw(chalk_ir::Mutability::Not),
-                };
-                apply(name, chalk_ir::Substitution::from1(interner, ptr.ty.lower_into(interner)))
+            ty::Foreign(def_id) => chalk_ir::TyKind::Foreign(ForeignDefId(def_id)),
+            ty::Str => chalk_ir::TyKind::Str,
+            ty::Array(ty, len) => {
+                chalk_ir::TyKind::Array(ty.lower_into(interner), len.lower_into(interner))
             }
-            Ref(region, ty, mutability) => {
-                let name = match mutability {
-                    ast::Mutability::Mut => chalk_ir::TypeName::Ref(chalk_ir::Mutability::Mut),
-                    ast::Mutability::Not => chalk_ir::TypeName::Ref(chalk_ir::Mutability::Not),
-                };
-                apply(
-                    name,
-                    chalk_ir::Substitution::from_iter(
-                        interner,
-                        &[
-                            chalk_ir::GenericArgData::Lifetime(region.lower_into(interner))
-                                .intern(interner),
-                            chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner),
-                        ],
-                    ),
-                )
+            ty::Slice(ty) => chalk_ir::TyKind::Slice(ty.lower_into(interner)),
+
+            ty::RawPtr(ptr) => {
+                chalk_ir::TyKind::Raw(ptr.mutbl.lower_into(interner), ptr.ty.lower_into(interner))
             }
-            FnDef(def_id, substs) => apply(
-                chalk_ir::TypeName::FnDef(chalk_ir::FnDefId(def_id)),
-                substs.lower_into(interner),
+            ty::Ref(region, ty, mutability) => chalk_ir::TyKind::Ref(
+                mutability.lower_into(interner),
+                region.lower_into(interner),
+                ty.lower_into(interner),
             ),
-            FnPtr(sig) => {
+            ty::FnDef(def_id, substs) => {
+                chalk_ir::TyKind::FnDef(chalk_ir::FnDefId(def_id), substs.lower_into(interner))
+            }
+            ty::FnPtr(sig) => {
                 let (inputs_and_outputs, binders, _named_regions) =
                     collect_bound_vars(interner, interner.tcx, &sig.inputs_and_output());
-                TyData::Function(chalk_ir::FnPointer {
+                chalk_ir::TyKind::Function(chalk_ir::FnPointer {
                     num_binders: binders.len(interner),
                     sig: sig.lower_into(interner),
                     substitution: chalk_ir::Substitution::from_iter(
@@ -356,148 +304,115 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
                         }),
                     ),
                 })
-                .intern(interner)
             }
-            Dynamic(predicates, region) => TyData::Dyn(chalk_ir::DynTy {
+            ty::Dynamic(predicates, region) => chalk_ir::TyKind::Dyn(chalk_ir::DynTy {
                 bounds: predicates.lower_into(interner),
                 lifetime: region.lower_into(interner),
-            })
-            .intern(interner),
-            Closure(def_id, substs) => apply(
-                chalk_ir::TypeName::Closure(chalk_ir::ClosureId(def_id)),
-                substs.lower_into(interner),
-            ),
-            Generator(_def_id, _substs, _) => unimplemented!(),
-            GeneratorWitness(_) => unimplemented!(),
-            Never => apply(chalk_ir::TypeName::Never, empty()),
-            Tuple(substs) => {
-                apply(chalk_ir::TypeName::Tuple(substs.len()), substs.lower_into(interner))
+            }),
+            ty::Closure(def_id, substs) => {
+                chalk_ir::TyKind::Closure(chalk_ir::ClosureId(def_id), substs.lower_into(interner))
             }
-            Projection(proj) => TyData::Alias(proj.lower_into(interner)).intern(interner),
-            Opaque(def_id, substs) => {
-                TyData::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
+            ty::Generator(_def_id, _substs, _) => unimplemented!(),
+            ty::GeneratorWitness(_) => unimplemented!(),
+            ty::Never => chalk_ir::TyKind::Never,
+            ty::Tuple(substs) => chalk_ir::TyKind::Tuple(substs.len(), substs.lower_into(interner)),
+            ty::Projection(proj) => chalk_ir::TyKind::Alias(proj.lower_into(interner)),
+            ty::Opaque(def_id, substs) => {
+                chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
                     opaque_ty_id: chalk_ir::OpaqueTyId(def_id),
                     substitution: substs.lower_into(interner),
                 }))
-                .intern(interner)
             }
             // This should have been done eagerly prior to this, and all Params
             // should have been substituted to placeholders
-            Param(_) => panic!("Lowering Param when not expected."),
-            Bound(db, bound) => TyData::BoundVar(chalk_ir::BoundVar::new(
+            ty::Param(_) => panic!("Lowering Param when not expected."),
+            ty::Bound(db, bound) => chalk_ir::TyKind::BoundVar(chalk_ir::BoundVar::new(
                 chalk_ir::DebruijnIndex::new(db.as_u32()),
                 bound.var.index(),
-            ))
-            .intern(interner),
-            Placeholder(_placeholder) => TyData::Placeholder(chalk_ir::PlaceholderIndex {
-                ui: chalk_ir::UniverseIndex { counter: _placeholder.universe.as_usize() },
-                idx: _placeholder.name.as_usize(),
-            })
-            .intern(interner),
-            Infer(_infer) => unimplemented!(),
-            Error(_) => apply(chalk_ir::TypeName::Error, empty()),
+            )),
+            ty::Placeholder(_placeholder) => {
+                chalk_ir::TyKind::Placeholder(chalk_ir::PlaceholderIndex {
+                    ui: chalk_ir::UniverseIndex { counter: _placeholder.universe.as_usize() },
+                    idx: _placeholder.name.as_usize(),
+                })
+            }
+            ty::Infer(_infer) => unimplemented!(),
+            ty::Error(_) => chalk_ir::TyKind::Error,
         }
+        .intern(interner)
     }
 }
 
 impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> {
     fn lower_into(self, interner: &RustInterner<'tcx>) -> Ty<'tcx> {
-        use chalk_ir::TyData;
-        use rustc_ast::ast;
+        use chalk_ir::TyKind;
 
-        let kind = match self.data(interner) {
-            TyData::Apply(application_ty) => match application_ty.name {
-                chalk_ir::TypeName::Adt(struct_id) => {
-                    ty::Adt(struct_id.0, application_ty.substitution.lower_into(interner))
-                }
-                chalk_ir::TypeName::Scalar(scalar) => match scalar {
-                    chalk_ir::Scalar::Bool => ty::Bool,
-                    chalk_ir::Scalar::Char => ty::Char,
-                    chalk_ir::Scalar::Int(int_ty) => match int_ty {
-                        chalk_ir::IntTy::Isize => ty::Int(ast::IntTy::Isize),
-                        chalk_ir::IntTy::I8 => ty::Int(ast::IntTy::I8),
-                        chalk_ir::IntTy::I16 => ty::Int(ast::IntTy::I16),
-                        chalk_ir::IntTy::I32 => ty::Int(ast::IntTy::I32),
-                        chalk_ir::IntTy::I64 => ty::Int(ast::IntTy::I64),
-                        chalk_ir::IntTy::I128 => ty::Int(ast::IntTy::I128),
-                    },
-                    chalk_ir::Scalar::Uint(int_ty) => match int_ty {
-                        chalk_ir::UintTy::Usize => ty::Uint(ast::UintTy::Usize),
-                        chalk_ir::UintTy::U8 => ty::Uint(ast::UintTy::U8),
-                        chalk_ir::UintTy::U16 => ty::Uint(ast::UintTy::U16),
-                        chalk_ir::UintTy::U32 => ty::Uint(ast::UintTy::U32),
-                        chalk_ir::UintTy::U64 => ty::Uint(ast::UintTy::U64),
-                        chalk_ir::UintTy::U128 => ty::Uint(ast::UintTy::U128),
-                    },
-                    chalk_ir::Scalar::Float(float_ty) => match float_ty {
-                        chalk_ir::FloatTy::F32 => ty::Float(ast::FloatTy::F32),
-                        chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64),
-                    },
+        let kind = match self.kind(interner) {
+            TyKind::Adt(struct_id, substitution) => {
+                ty::Adt(struct_id.0, substitution.lower_into(interner))
+            }
+            TyKind::Scalar(scalar) => match scalar {
+                chalk_ir::Scalar::Bool => ty::Bool,
+                chalk_ir::Scalar::Char => ty::Char,
+                chalk_ir::Scalar::Int(int_ty) => match int_ty {
+                    chalk_ir::IntTy::Isize => ty::Int(ast::IntTy::Isize),
+                    chalk_ir::IntTy::I8 => ty::Int(ast::IntTy::I8),
+                    chalk_ir::IntTy::I16 => ty::Int(ast::IntTy::I16),
+                    chalk_ir::IntTy::I32 => ty::Int(ast::IntTy::I32),
+                    chalk_ir::IntTy::I64 => ty::Int(ast::IntTy::I64),
+                    chalk_ir::IntTy::I128 => ty::Int(ast::IntTy::I128),
+                },
+                chalk_ir::Scalar::Uint(int_ty) => match int_ty {
+                    chalk_ir::UintTy::Usize => ty::Uint(ast::UintTy::Usize),
+                    chalk_ir::UintTy::U8 => ty::Uint(ast::UintTy::U8),
+                    chalk_ir::UintTy::U16 => ty::Uint(ast::UintTy::U16),
+                    chalk_ir::UintTy::U32 => ty::Uint(ast::UintTy::U32),
+                    chalk_ir::UintTy::U64 => ty::Uint(ast::UintTy::U64),
+                    chalk_ir::UintTy::U128 => ty::Uint(ast::UintTy::U128),
+                },
+                chalk_ir::Scalar::Float(float_ty) => match float_ty {
+                    chalk_ir::FloatTy::F32 => ty::Float(ast::FloatTy::F32),
+                    chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64),
                 },
-                chalk_ir::TypeName::Array => {
-                    let substs = application_ty.substitution.as_slice(interner);
-                    let ty = substs[0].assert_ty_ref(interner).lower_into(interner);
-                    let c = substs[1].assert_const_ref(interner).lower_into(interner);
-                    ty::Array(ty, interner.tcx.mk_const(c))
-                }
-                chalk_ir::TypeName::FnDef(id) => {
-                    ty::FnDef(id.0, application_ty.substitution.lower_into(interner))
-                }
-                chalk_ir::TypeName::Closure(closure) => {
-                    ty::Closure(closure.0, application_ty.substitution.lower_into(interner))
-                }
-                chalk_ir::TypeName::Generator(_) => unimplemented!(),
-                chalk_ir::TypeName::GeneratorWitness(_) => unimplemented!(),
-                chalk_ir::TypeName::Never => ty::Never,
-                chalk_ir::TypeName::Tuple(_size) => {
-                    ty::Tuple(application_ty.substitution.lower_into(interner))
-                }
-                chalk_ir::TypeName::Slice => ty::Slice(
-                    application_ty.substitution.as_slice(interner)[0]
-                        .ty(interner)
-                        .unwrap()
-                        .lower_into(interner),
-                ),
-                chalk_ir::TypeName::Raw(mutbl) => ty::RawPtr(ty::TypeAndMut {
-                    ty: application_ty.substitution.as_slice(interner)[0]
-                        .ty(interner)
-                        .unwrap()
-                        .lower_into(interner),
-                    mutbl: match mutbl {
-                        chalk_ir::Mutability::Mut => ast::Mutability::Mut,
-                        chalk_ir::Mutability::Not => ast::Mutability::Not,
-                    },
-                }),
-                chalk_ir::TypeName::Ref(mutbl) => ty::Ref(
-                    application_ty.substitution.as_slice(interner)[0]
-                        .lifetime(interner)
-                        .unwrap()
-                        .lower_into(interner),
-                    application_ty.substitution.as_slice(interner)[1]
-                        .ty(interner)
-                        .unwrap()
-                        .lower_into(interner),
-                    match mutbl {
-                        chalk_ir::Mutability::Mut => ast::Mutability::Mut,
-                        chalk_ir::Mutability::Not => ast::Mutability::Not,
-                    },
-                ),
-                chalk_ir::TypeName::Str => ty::Str,
-                chalk_ir::TypeName::OpaqueType(opaque_ty) => {
-                    ty::Opaque(opaque_ty.0, application_ty.substitution.lower_into(interner))
-                }
-                chalk_ir::TypeName::AssociatedType(assoc_ty) => ty::Projection(ty::ProjectionTy {
-                    substs: application_ty.substitution.lower_into(interner),
-                    item_def_id: assoc_ty.0,
-                }),
-                chalk_ir::TypeName::Foreign(def_id) => ty::Foreign(def_id.0),
-                chalk_ir::TypeName::Error => unimplemented!(),
             },
-            TyData::Placeholder(placeholder) => ty::Placeholder(ty::Placeholder {
+            TyKind::Array(ty, c) => {
+                let ty = ty.lower_into(interner);
+                let c = c.lower_into(interner);
+                ty::Array(ty, interner.tcx.mk_const(c))
+            }
+            TyKind::FnDef(id, substitution) => ty::FnDef(id.0, substitution.lower_into(interner)),
+            TyKind::Closure(closure, substitution) => {
+                ty::Closure(closure.0, substitution.lower_into(interner))
+            }
+            TyKind::Generator(..) => unimplemented!(),
+            TyKind::GeneratorWitness(..) => unimplemented!(),
+            TyKind::Never => ty::Never,
+            TyKind::Tuple(_len, substitution) => ty::Tuple(substitution.lower_into(interner)),
+            TyKind::Slice(ty) => ty::Slice(ty.lower_into(interner)),
+            TyKind::Raw(mutbl, ty) => ty::RawPtr(ty::TypeAndMut {
+                ty: ty.lower_into(interner),
+                mutbl: mutbl.lower_into(interner),
+            }),
+            TyKind::Ref(mutbl, lifetime, ty) => ty::Ref(
+                lifetime.lower_into(interner),
+                ty.lower_into(interner),
+                mutbl.lower_into(interner),
+            ),
+            TyKind::Str => ty::Str,
+            TyKind::OpaqueType(opaque_ty, substitution) => {
+                ty::Opaque(opaque_ty.0, substitution.lower_into(interner))
+            }
+            TyKind::AssociatedType(assoc_ty, substitution) => ty::Projection(ty::ProjectionTy {
+                substs: substitution.lower_into(interner),
+                item_def_id: assoc_ty.0,
+            }),
+            TyKind::Foreign(def_id) => ty::Foreign(def_id.0),
+            TyKind::Error => return interner.tcx.ty_error(),
+            TyKind::Placeholder(placeholder) => ty::Placeholder(ty::Placeholder {
                 universe: ty::UniverseIndex::from_usize(placeholder.ui.counter),
                 name: ty::BoundVar::from_usize(placeholder.idx),
             }),
-            chalk_ir::TyData::Alias(alias_ty) => match alias_ty {
+            TyKind::Alias(alias_ty) => match alias_ty {
                 chalk_ir::AliasTy::Projection(projection) => ty::Projection(ty::ProjectionTy {
                     item_def_id: projection.associated_ty_id.0,
                     substs: projection.substitution.lower_into(interner),
@@ -506,16 +421,16 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> {
                     ty::Opaque(opaque.opaque_ty_id.0, opaque.substitution.lower_into(interner))
                 }
             },
-            TyData::Function(_quantified_ty) => unimplemented!(),
-            TyData::BoundVar(_bound) => ty::Bound(
+            TyKind::Function(_quantified_ty) => unimplemented!(),
+            TyKind::BoundVar(_bound) => ty::Bound(
                 ty::DebruijnIndex::from_usize(_bound.debruijn.depth() as usize),
                 ty::BoundTy {
                     var: ty::BoundVar::from_usize(_bound.index),
                     kind: ty::BoundTyKind::Anon,
                 },
             ),
-            TyData::InferenceVar(_, _) => unimplemented!(),
-            TyData::Dyn(_) => unimplemented!(),
+            TyKind::InferenceVar(_, _) => unimplemented!(),
+            TyKind::Dyn(_) => unimplemented!(),
         };
         interner.tcx.mk_ty(kind)
     }
@@ -706,8 +621,16 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru
         self,
         interner: &RustInterner<'tcx>,
     ) -> chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<RustInterner<'tcx>>> {
+        // `Self` has one binder:
+        // Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>
+        // The return type has two:
+        // Binders<&[Binders<WhereClause<I>>]>
+        // This means that any variables that are escaping `self` need to be
+        // shifted in by one so that they are still escaping.
+        let shifted_predicates = ty::fold::shift_vars(interner.tcx, &self, 1);
+
         let (predicates, binders, _named_regions) =
-            collect_bound_vars(interner, interner.tcx, &self);
+            collect_bound_vars(interner, interner.tcx, &shifted_predicates);
         let self_ty = interner.tcx.mk_ty(ty::Bound(
             // This is going to be wrapped in a binder
             ty::DebruijnIndex::from_usize(1),
@@ -716,7 +639,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru
         let where_clauses = predicates.into_iter().map(|predicate| match predicate {
             ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => {
                 chalk_ir::Binders::new(
-                    chalk_ir::VariableKinds::empty(interner),
+                    binders.clone(),
                     chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef {
                         trait_id: chalk_ir::TraitId(def_id),
                         substitution: interner
@@ -727,25 +650,34 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders<chalk_ir::QuantifiedWhereClauses<Ru
                 )
             }
             ty::ExistentialPredicate::Projection(predicate) => chalk_ir::Binders::new(
-                chalk_ir::VariableKinds::empty(interner),
+                binders.clone(),
                 chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq {
                     alias: chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
                         associated_ty_id: chalk_ir::AssocTypeId(predicate.item_def_id),
-                        substitution: predicate.substs.lower_into(interner),
+                        substitution: interner
+                            .tcx
+                            .mk_substs_trait(self_ty, predicate.substs)
+                            .lower_into(interner),
                     }),
                     ty: predicate.ty.lower_into(interner),
                 }),
             ),
             ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new(
-                chalk_ir::VariableKinds::empty(interner),
+                binders.clone(),
                 chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef {
                     trait_id: chalk_ir::TraitId(def_id),
                     substitution: interner.tcx.mk_substs_trait(self_ty, &[]).lower_into(interner),
                 }),
             ),
         });
+
+        // Binder for the bound variable representing the concrete underlying type.
+        let existential_binder = chalk_ir::VariableKinds::from1(
+            interner,
+            chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
+        );
         let value = chalk_ir::QuantifiedWhereClauses::from_iter(interner, where_clauses);
-        chalk_ir::Binders::new(binders, value)
+        chalk_ir::Binders::new(existential_binder, value)
     }
 }
 
@@ -818,6 +750,35 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::TraitBound<RustInterner<'tcx>>>
     }
 }
 
+impl<'tcx> LowerInto<'tcx, chalk_ir::Mutability> for ast::Mutability {
+    fn lower_into(self, _interner: &RustInterner<'tcx>) -> chalk_ir::Mutability {
+        match self {
+            rustc_ast::Mutability::Mut => chalk_ir::Mutability::Mut,
+            rustc_ast::Mutability::Not => chalk_ir::Mutability::Not,
+        }
+    }
+}
+
+impl<'tcx> LowerInto<'tcx, ast::Mutability> for chalk_ir::Mutability {
+    fn lower_into(self, _interner: &RustInterner<'tcx>) -> ast::Mutability {
+        match self {
+            chalk_ir::Mutability::Mut => ast::Mutability::Mut,
+            chalk_ir::Mutability::Not => ast::Mutability::Not,
+        }
+    }
+}
+
+impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::Polarity> for ty::ImplPolarity {
+    fn lower_into(self, _interner: &RustInterner<'tcx>) -> chalk_solve::rust_ir::Polarity {
+        match self {
+            ty::ImplPolarity::Positive => chalk_solve::rust_ir::Polarity::Positive,
+            ty::ImplPolarity::Negative => chalk_solve::rust_ir::Polarity::Negative,
+            // FIXME(chalk) reservation impls
+            ty::ImplPolarity::Reservation => chalk_solve::rust_ir::Polarity::Negative,
+        }
+    }
+}
+
 impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>>>
     for ty::ProjectionPredicate<'tcx>
 {
@@ -910,7 +871,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
             ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
                 match self.parameters.entry(bound_ty.var.as_u32()) {
                     Entry::Vacant(entry) => {
-                        entry.insert(chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General));
+                        entry.insert(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General));
                     }
                     Entry::Occupied(entry) => match entry.get() {
                         chalk_ir::VariableKind::Ty(_) => {}
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index f174a92274e..b117e28875e 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -69,15 +69,15 @@ crate fn evaluate_goal<'tcx>(
                     CanonicalVarKind::PlaceholderRegion(_ui) => unimplemented!(),
                     CanonicalVarKind::Ty(ty) => match ty {
                         CanonicalTyVarKind::General(ui) => chalk_ir::WithKind::new(
-                            chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General),
+                            chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
                             chalk_ir::UniverseIndex { counter: ui.index() },
                         ),
                         CanonicalTyVarKind::Int => chalk_ir::WithKind::new(
-                            chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Integer),
+                            chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::Integer),
                             chalk_ir::UniverseIndex::root(),
                         ),
                         CanonicalTyVarKind::Float => chalk_ir::WithKind::new(
-                            chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Float),
+                            chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::Float),
                             chalk_ir::UniverseIndex::root(),
                         ),
                     },
@@ -97,7 +97,8 @@ crate fn evaluate_goal<'tcx>(
     use chalk_solve::Solver;
     let mut solver = chalk_engine::solve::SLGSolver::new(32, None);
     let db = ChalkRustIrDatabase { interner, reempty_placeholder };
-    let solution = chalk_solve::logging::with_tracing_logs(|| solver.solve(&db, &lowered_goal));
+    let solution = solver.solve(&db, &lowered_goal);
+    debug!(?obligation, ?solution, "evaluatate goal");
 
     // Ideally, the code to convert *back* to rustc types would live close to
     // the code to convert *from* rustc types. Right now though, we don't
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 324aa1a66a6..af19ad08c1d 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -718,39 +718,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         );
     }
 
-    fn is_destructuring_place_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> bool {
-        match &expr.kind {
-            ExprKind::Array(comps) | ExprKind::Tup(comps) => {
-                comps.iter().all(|e| self.is_destructuring_place_expr(e))
-            }
-            ExprKind::Struct(_path, fields, rest) => {
-                rest.as_ref().map(|e| self.is_destructuring_place_expr(e)).unwrap_or(true)
-                    && fields.iter().all(|f| self.is_destructuring_place_expr(&f.expr))
-            }
-            _ => expr.is_syntactic_place_expr(),
-        }
-    }
-
     pub(crate) fn check_lhs_assignable(
         &self,
         lhs: &'tcx hir::Expr<'tcx>,
         err_code: &'static str,
         expr_span: &Span,
     ) {
-        if !lhs.is_syntactic_place_expr() {
-            // FIXME: Make this use SessionDiagnostic once error codes can be dynamically set.
-            let mut err = self.tcx.sess.struct_span_err_with_code(
-                *expr_span,
-                "invalid left-hand side of assignment",
-                DiagnosticId::Error(err_code.into()),
-            );
-            err.span_label(lhs.span, "cannot assign to this expression");
-            if self.is_destructuring_place_expr(lhs) {
-                err.note("destructuring assignments are not currently supported");
-                err.note("for more information, see https://github.com/rust-lang/rfcs/issues/372");
-            }
-            err.emit();
+        if lhs.is_syntactic_place_expr() {
+            return;
         }
+
+        // FIXME: Make this use SessionDiagnostic once error codes can be dynamically set.
+        let mut err = self.tcx.sess.struct_span_err_with_code(
+            *expr_span,
+            "invalid left-hand side of assignment",
+            DiagnosticId::Error(err_code.into()),
+        );
+        err.span_label(lhs.span, "cannot assign to this expression");
+        err.emit();
     }
 
     /// Type check assignment expression `expr` of form `lhs = rhs`.
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index f87e6b607d4..0bb7b464f16 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -118,7 +118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         closure_def_id: DefId,
     ) -> Vec<DeferredCallResolution<'tcx>> {
         let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
-        deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![])
+        deferred_call_resolutions.remove(&closure_def_id).unwrap_or_default()
     }
 
     pub fn tag(&self) -> String {
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index d403e259398..713b24e583a 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -244,7 +244,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ProbeScope::AllTraits,
                 |probe_cx| Ok(probe_cx.candidate_method_names()),
             )
-            .unwrap_or(vec![]);
+            .unwrap_or_default();
         method_names
             .iter()
             .flat_map(|&method_name| {
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index f76f42dea1e..6489b7838d6 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -270,6 +270,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ///
     /// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
     fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> AdjustMode {
+        // When we perform destructuring assignment, we disable default match bindings, which are
+        // unintuitive in this context.
+        if !pat.default_binding_modes {
+            return AdjustMode::Reset;
+        }
         match &pat.kind {
             // Type checking these product-like types successfully always require
             // that the expected type be of those types and not reference types.
diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs
index ba0f22513a1..7b31b9f3915 100644
--- a/compiler/rustc_typeck/src/check/regionck.rs
+++ b/compiler/rustc_typeck/src/check/regionck.rs
@@ -577,7 +577,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> {
     fn link_pattern(&self, discr_cmt: PlaceWithHirId<'tcx>, root_pat: &hir::Pat<'_>) {
         debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat);
         ignore_err!(self.with_mc(|mc| {
-            mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id }| {
+            mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, hir::Pat { kind, span, hir_id, .. }| {
                 // `ref x` pattern
                 if let PatKind::Binding(..) = kind {
                     if let Some(ty::BindByReference(mutbl)) =
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index f014ea3d5a9..b431de90369 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -2653,7 +2653,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                             set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
                         match segments.as_slice() {
                             [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
-                                if !tcx.sess.target.options.has_thumb_interworking {
+                                if !tcx.sess.target.has_thumb_interworking {
                                     struct_span_err!(
                                         tcx.sess.diagnostic(),
                                         attr.span,
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index 9c29ceeb593..e596dd1a396 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -61,23 +61,23 @@ fn opaque_type_bounds<'tcx>(
     bounds: &'tcx [hir::GenericBound<'tcx>],
     span: Span,
 ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
-    let item_ty =
-        tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id));
+    ty::print::with_no_queries(|| {
+        let item_ty =
+            tcx.mk_opaque(opaque_def_id, InternalSubsts::identity_for_item(tcx, opaque_def_id));
 
-    let bounds = ty::print::with_no_queries(|| {
-        AstConv::compute_bounds(
+        let bounds = AstConv::compute_bounds(
             &ItemCtxt::new(tcx, opaque_def_id),
             item_ty,
             bounds,
             SizedByDefault::Yes,
             span,
         )
-    });
+        .predicates(tcx, item_ty);
 
-    let bounds = bounds.predicates(tcx, item_ty);
-    debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
+        debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
 
-    tcx.arena.alloc_slice(&bounds)
+        tcx.arena.alloc_slice(&bounds)
+    })
 }
 
 pub(super) fn explicit_item_bounds(
diff --git a/config.toml.example b/config.toml.example
index 1edb390e0fe..c9e18388750 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -138,6 +138,9 @@ changelog-seen = 2
 # Whether or not to specify `-DLLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN=YES`
 #allow-old-toolchain = false
 
+# Whether to include the Polly optimizer.
+#polly = false
+
 # =============================================================================
 # General build configuration options
 # =============================================================================
@@ -583,6 +586,15 @@ changelog-seen = 2
 # build native code.
 #android-ndk = "/path/to/ndk"
 
+# Build the sanitizer runtimes for this target.
+# This option will override the same option under [build] section.
+#sanitizers = false
+
+# Build the profiler runtime for this target(required when compiling with options that depend
+# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`).
+# This option will override the same option under [build] section.
+#profiler = false
+
 # Force static or dynamic linkage of the standard library for this target. If
 # this target is a host for rustc, this will also affect the linkage of the
 # compiler itself. This is useful for building rustc on targets that normally
diff --git a/library/alloc/src/collections/btree/append.rs b/library/alloc/src/collections/btree/append.rs
new file mode 100644
index 00000000000..e0362b2f37d
--- /dev/null
+++ b/library/alloc/src/collections/btree/append.rs
@@ -0,0 +1,124 @@
+use super::map::MIN_LEN;
+use super::merge_iter::MergeIterInner;
+use super::node::{self, ForceResult::*, Root};
+use core::iter::FusedIterator;
+
+impl<K, V> Root<K, V> {
+    /// Appends all key-value pairs from the union of two ascending iterators,
+    /// incrementing a `length` variable along the way. The latter makes it
+    /// easier for the caller to avoid a leak when a drop handler panicks.
+    ///
+    /// If both iterators produce the same key, this method drops the pair from
+    /// the left iterator and appends the pair from the right iterator.
+    ///
+    /// If you want the tree to end up in a strictly ascending order, like for
+    /// a `BTreeMap`, both iterators should produce keys in strictly ascending
+    /// order, each greater than all keys in the tree, including any keys
+    /// already in the tree upon entry.
+    pub fn append_from_sorted_iters<I>(&mut self, left: I, right: I, length: &mut usize)
+    where
+        K: Ord,
+        I: Iterator<Item = (K, V)> + FusedIterator,
+    {
+        // We prepare to merge `left` and `right` into a sorted sequence in linear time.
+        let iter = MergeIter(MergeIterInner::new(left, right));
+
+        // Meanwhile, we build a tree from the sorted sequence in linear time.
+        self.bulk_push(iter, length)
+    }
+
+    /// Pushes all key-value pairs to the end of the tree, incrementing a
+    /// `length` variable along the way. The latter makes it easier for the
+    /// caller to avoid a leak when the iterator panicks.
+    fn bulk_push<I>(&mut self, iter: I, length: &mut usize)
+    where
+        I: Iterator<Item = (K, V)>,
+    {
+        let mut cur_node = self.node_as_mut().last_leaf_edge().into_node();
+        // Iterate through all key-value pairs, pushing them into nodes at the right level.
+        for (key, value) in iter {
+            // Try to push key-value pair into the current leaf node.
+            if cur_node.len() < node::CAPACITY {
+                cur_node.push(key, value);
+            } else {
+                // No space left, go up and push there.
+                let mut open_node;
+                let mut test_node = cur_node.forget_type();
+                loop {
+                    match test_node.ascend() {
+                        Ok(parent) => {
+                            let parent = parent.into_node();
+                            if parent.len() < node::CAPACITY {
+                                // Found a node with space left, push here.
+                                open_node = parent;
+                                break;
+                            } else {
+                                // Go up again.
+                                test_node = parent.forget_type();
+                            }
+                        }
+                        Err(_) => {
+                            // We are at the top, create a new root node and push there.
+                            open_node = self.push_internal_level();
+                            break;
+                        }
+                    }
+                }
+
+                // Push key-value pair and new right subtree.
+                let tree_height = open_node.height() - 1;
+                let mut right_tree = Root::new_leaf();
+                for _ in 0..tree_height {
+                    right_tree.push_internal_level();
+                }
+                open_node.push(key, value, right_tree);
+
+                // Go down to the right-most leaf again.
+                cur_node = open_node.forget_type().last_leaf_edge().into_node();
+            }
+
+            // Increment length every iteration, to make sure the map drops
+            // the appended elements even if advancing the iterator panicks.
+            *length += 1;
+        }
+        self.fix_right_edge();
+    }
+
+    fn fix_right_edge(&mut self) {
+        // Handle underfull nodes, start from the top.
+        let mut cur_node = self.node_as_mut();
+        while let Internal(internal) = cur_node.force() {
+            // Check if right-most child is underfull.
+            let mut last_edge = internal.last_edge();
+            let right_child_len = last_edge.reborrow().descend().len();
+            if right_child_len < MIN_LEN {
+                // We need to steal.
+                let mut last_kv = match last_edge.left_kv() {
+                    Ok(left) => left,
+                    Err(_) => unreachable!(),
+                };
+                last_kv.bulk_steal_left(MIN_LEN - right_child_len);
+                last_edge = last_kv.right_edge();
+            }
+
+            // Go further down.
+            cur_node = last_edge.descend();
+        }
+    }
+}
+
+// An iterator for merging two sorted sequences into one
+struct MergeIter<K, V, I: Iterator<Item = (K, V)>>(MergeIterInner<I>);
+
+impl<K: Ord, V, I> Iterator for MergeIter<K, V, I>
+where
+    I: Iterator<Item = (K, V)> + FusedIterator,
+{
+    type Item = (K, V);
+
+    /// If two keys are equal, returns the key-value pair from the right source.
+    fn next(&mut self) -> Option<(K, V)> {
+        let (a_next, b_next) = self.0.nexts(|a: &(K, V), b: &(K, V)| K::cmp(&a.0, &b.0));
+        b_next.or(a_next)
+    }
+}
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 07c23d29e20..49122f53d33 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -9,7 +9,6 @@ use core::ops::{Index, RangeBounds};
 use core::ptr;
 
 use super::borrow::DormantMutRef;
-use super::merge_iter::MergeIterInner;
 use super::node::{self, marker, ForceResult::*, Handle, NodeRef};
 use super::search::{self, SearchResult::*};
 use super::unwrap_unchecked;
@@ -458,9 +457,6 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for RangeMut<'_, K, V> {
     }
 }
 
-// An iterator for merging two sorted sequences into one
-struct MergeIter<K, V, I: Iterator<Item = (K, V)>>(MergeIterInner<I>);
-
 impl<K: Ord, V> BTreeMap<K, V> {
     /// Makes a new empty BTreeMap.
     ///
@@ -908,13 +904,10 @@ impl<K: Ord, V> BTreeMap<K, V> {
             return;
         }
 
-        // First, we merge `self` and `other` into a sorted sequence in linear time.
         let self_iter = mem::take(self).into_iter();
         let other_iter = mem::take(other).into_iter();
-        let iter = MergeIter(MergeIterInner::new(self_iter, other_iter));
-
-        // Second, we build a tree from the sorted sequence in linear time.
-        self.from_sorted_iter(iter);
+        let root = BTreeMap::ensure_is_owned(&mut self.root);
+        root.append_from_sorted_iters(self_iter, other_iter, &mut self.length)
     }
 
     /// Constructs a double-ended iterator over a sub-range of elements in the map.
@@ -1039,78 +1032,6 @@ impl<K: Ord, V> BTreeMap<K, V> {
         }
     }
 
-    fn from_sorted_iter<I: Iterator<Item = (K, V)>>(&mut self, iter: I) {
-        let root = Self::ensure_is_owned(&mut self.root);
-        let mut cur_node = root.node_as_mut().last_leaf_edge().into_node();
-        // Iterate through all key-value pairs, pushing them into nodes at the right level.
-        for (key, value) in iter {
-            // Try to push key-value pair into the current leaf node.
-            if cur_node.len() < node::CAPACITY {
-                cur_node.push(key, value);
-            } else {
-                // No space left, go up and push there.
-                let mut open_node;
-                let mut test_node = cur_node.forget_type();
-                loop {
-                    match test_node.ascend() {
-                        Ok(parent) => {
-                            let parent = parent.into_node();
-                            if parent.len() < node::CAPACITY {
-                                // Found a node with space left, push here.
-                                open_node = parent;
-                                break;
-                            } else {
-                                // Go up again.
-                                test_node = parent.forget_type();
-                            }
-                        }
-                        Err(_) => {
-                            // We are at the top, create a new root node and push there.
-                            open_node = root.push_internal_level();
-                            break;
-                        }
-                    }
-                }
-
-                // Push key-value pair and new right subtree.
-                let tree_height = open_node.height() - 1;
-                let mut right_tree = node::Root::new_leaf();
-                for _ in 0..tree_height {
-                    right_tree.push_internal_level();
-                }
-                open_node.push(key, value, right_tree);
-
-                // Go down to the right-most leaf again.
-                cur_node = open_node.forget_type().last_leaf_edge().into_node();
-            }
-
-            self.length += 1;
-        }
-        Self::fix_right_edge(root)
-    }
-
-    fn fix_right_edge(root: &mut node::Root<K, V>) {
-        // Handle underfull nodes, start from the top.
-        let mut cur_node = root.node_as_mut();
-        while let Internal(internal) = cur_node.force() {
-            // Check if right-most child is underfull.
-            let mut last_edge = internal.last_edge();
-            let right_child_len = last_edge.reborrow().descend().len();
-            if right_child_len < MIN_LEN {
-                // We need to steal.
-                let mut last_kv = match last_edge.left_kv() {
-                    Ok(left) => left,
-                    Err(_) => unreachable!(),
-                };
-                last_kv.bulk_steal_left(MIN_LEN - right_child_len);
-                last_edge = last_kv.right_edge();
-            }
-
-            // Go further down.
-            cur_node = last_edge.descend();
-        }
-    }
-
     /// Splits the collection into two at the given key. Returns everything after the given key,
     /// including the key.
     ///
@@ -2220,18 +2141,5 @@ impl<K, V> BTreeMap<K, V> {
     }
 }
 
-impl<K: Ord, V, I> Iterator for MergeIter<K, V, I>
-where
-    I: Iterator<Item = (K, V)> + ExactSizeIterator + FusedIterator,
-{
-    type Item = (K, V);
-
-    /// If two keys are equal, returns the key/value-pair from the right source.
-    fn next(&mut self) -> Option<(K, V)> {
-        let (a_next, b_next) = self.0.nexts(|a: &(K, V), b: &(K, V)| K::cmp(&a.0, &b.0));
-        b_next.or(a_next)
-    }
-}
-
 #[cfg(test)]
 mod tests;
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index d5b1c600d93..dd3ebcccf76 100644
--- a/library/alloc/src/collections/btree/map/tests.rs
+++ b/library/alloc/src/collections/btree/map/tests.rs
@@ -42,7 +42,7 @@ fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>
     }
 }
 
-impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
+impl<K, V> BTreeMap<K, V> {
     /// Panics if the map (or the code navigating it) is corrupted.
     fn check(&self)
     where
@@ -54,14 +54,14 @@ impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
             assert!(root_node.ascend().is_err());
             root_node.assert_back_pointers();
 
-            let counted = root_node.assert_ascending();
-            assert_eq!(self.length, counted);
             assert_eq!(self.length, root_node.calc_length());
 
             root_node.assert_min_len(if root_node.height() > 0 { 1 } else { 0 });
         } else {
             assert_eq!(self.length, 0);
         }
+
+        self.assert_ascending();
     }
 
     /// Returns the height of the root, if any.
@@ -79,10 +79,28 @@ impl<'a, K: 'a, V: 'a> BTreeMap<K, V> {
             String::from("not yet allocated")
         }
     }
+
+    /// Asserts that the keys are in strictly ascending order.
+    fn assert_ascending(&self)
+    where
+        K: Copy + Debug + Ord,
+    {
+        let mut num_seen = 0;
+        let mut keys = self.keys();
+        if let Some(mut previous) = keys.next() {
+            num_seen = 1;
+            for next in keys {
+                assert!(previous < next, "{:?} >= {:?}", previous, next);
+                previous = next;
+                num_seen += 1;
+            }
+        }
+        assert_eq!(num_seen, self.len());
+    }
 }
 
 impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal> {
-    pub fn assert_min_len(self, min_len: usize) {
+    fn assert_min_len(self, min_len: usize) {
         assert!(self.len() >= min_len, "{} < {}", self.len(), min_len);
         if let node::ForceResult::Internal(node) = self.force() {
             for idx in 0..=node.len() {
@@ -1667,6 +1685,33 @@ create_append_test!(test_append_239, 239);
 #[cfg(not(miri))] // Miri is too slow
 create_append_test!(test_append_1700, 1700);
 
+#[test]
+fn test_append_drop_leak() {
+    static DROPS: AtomicUsize = AtomicUsize::new(0);
+
+    struct D;
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            if DROPS.fetch_add(1, Ordering::SeqCst) == 0 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut left = BTreeMap::new();
+    let mut right = BTreeMap::new();
+    left.insert(0, D);
+    left.insert(1, D); // first to be dropped during append
+    left.insert(2, D);
+    right.insert(1, D);
+    right.insert(2, D);
+
+    catch_unwind(move || left.append(&mut right)).unwrap_err();
+
+    assert_eq!(DROPS.load(Ordering::SeqCst), 4); // Rust issue #47949 ate one little piggy
+}
+
 fn rand_data(len: usize) -> Vec<(u32, u32)> {
     assert!(len * 2 <= 70029); // from that point on numbers repeat
     let mut rng = DeterministicRng::new();
diff --git a/library/alloc/src/collections/btree/merge_iter.rs b/library/alloc/src/collections/btree/merge_iter.rs
index 88e6f86c2c6..7f23d93b990 100644
--- a/library/alloc/src/collections/btree/merge_iter.rs
+++ b/library/alloc/src/collections/btree/merge_iter.rs
@@ -2,27 +2,25 @@ use core::cmp::Ordering;
 use core::fmt::{self, Debug};
 use core::iter::FusedIterator;
 
-/// Core of an iterator that merges the output of two ascending iterators,
+/// Core of an iterator that merges the output of two strictly ascending iterators,
 /// for instance a union or a symmetric difference.
-pub struct MergeIterInner<I>
-where
-    I: Iterator,
-{
+pub struct MergeIterInner<I: Iterator> {
     a: I,
     b: I,
     peeked: Option<Peeked<I>>,
 }
 
-/// Benchmarks faster than wrapping both iterators in a Peekable.
+/// Benchmarks faster than wrapping both iterators in a Peekable,
+/// probably because we can afford to impose a FusedIterator bound.
 #[derive(Clone, Debug)]
 enum Peeked<I: Iterator> {
     A(I::Item),
     B(I::Item),
 }
 
-impl<I> Clone for MergeIterInner<I>
+impl<I: Iterator> Clone for MergeIterInner<I>
 where
-    I: Clone + Iterator,
+    I: Clone,
     I::Item: Clone,
 {
     fn clone(&self) -> Self {
@@ -30,20 +28,17 @@ where
     }
 }
 
-impl<I> Debug for MergeIterInner<I>
+impl<I: Iterator> Debug for MergeIterInner<I>
 where
-    I: Iterator + Debug,
+    I: Debug,
     I::Item: Debug,
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("MergeIterInner").field(&self.a).field(&self.b).finish()
+        f.debug_tuple("MergeIterInner").field(&self.a).field(&self.b).field(&self.peeked).finish()
     }
 }
 
-impl<I> MergeIterInner<I>
-where
-    I: ExactSizeIterator + FusedIterator,
-{
+impl<I: Iterator> MergeIterInner<I> {
     /// Creates a new core for an iterator merging a pair of sources.
     pub fn new(a: I, b: I) -> Self {
         MergeIterInner { a, b, peeked: None }
@@ -52,13 +47,17 @@ where
     /// Returns the next pair of items stemming from the pair of sources
     /// being merged. If both returned options contain a value, that value
     /// is equal and occurs in both sources. If one of the returned options
-    /// contains a value, that value doesn't occur in the other source.
-    /// If neither returned option contains a value, iteration has finished
-    /// and subsequent calls will return the same empty pair.
+    /// contains a value, that value doesn't occur in the other source (or
+    /// the sources are not strictly ascending). If neither returned option
+    /// contains a value, iteration has finished and subsequent calls will
+    /// return the same empty pair.
     pub fn nexts<Cmp: Fn(&I::Item, &I::Item) -> Ordering>(
         &mut self,
         cmp: Cmp,
-    ) -> (Option<I::Item>, Option<I::Item>) {
+    ) -> (Option<I::Item>, Option<I::Item>)
+    where
+        I: FusedIterator,
+    {
         let mut a_next;
         let mut b_next;
         match self.peeked.take() {
@@ -86,7 +85,10 @@ where
     }
 
     /// Returns a pair of upper bounds for the `size_hint` of the final iterator.
-    pub fn lens(&self) -> (usize, usize) {
+    pub fn lens(&self) -> (usize, usize)
+    where
+        I: ExactSizeIterator,
+    {
         match self.peeked {
             Some(Peeked::A(_)) => (1 + self.a.len(), self.b.len()),
             Some(Peeked::B(_)) => (self.a.len(), 1 + self.b.len()),
diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs
index 7bf1706dd6d..ebcbb0e467c 100644
--- a/library/alloc/src/collections/btree/mod.rs
+++ b/library/alloc/src/collections/btree/mod.rs
@@ -1,3 +1,4 @@
+mod append;
 mod borrow;
 pub mod map;
 mod mem;
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index c8d3de9e5cd..dbf9031620e 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -32,7 +32,6 @@ use core::cmp::Ordering;
 use core::marker::PhantomData;
 use core::mem::{self, MaybeUninit};
 use core::ptr::{self, NonNull, Unique};
-use core::slice;
 
 use crate::alloc::{AllocRef, Global, Layout};
 use crate::boxed::Box;
@@ -120,11 +119,11 @@ struct BoxedNode<K, V> {
 
 impl<K, V> BoxedNode<K, V> {
     fn from_leaf(node: Box<LeafNode<K, V>>) -> Self {
-        BoxedNode { ptr: Box::into_unique(node).0 }
+        BoxedNode { ptr: Unique::from(Box::leak(node)) }
     }
 
     fn from_internal(node: Box<InternalNode<K, V>>) -> Self {
-        BoxedNode { ptr: Unique::from(&mut Box::leak(node).data) }
+        BoxedNode { ptr: Unique::from(Box::leak(node)).cast() }
     }
 
     fn as_ptr(&self) -> NonNull<LeafNode<K, V>> {
@@ -189,6 +188,11 @@ impl<K, V> Root<K, V> {
         NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
     }
 
+    /// Packs the reference, aware of type and height, into a type-agnostic pointer.
+    fn into_boxed_node(self) -> BoxedNode<K, V> {
+        self.node
+    }
+
     /// Adds a new internal node with a single edge pointing to the previous root node,
     /// make that new node the root node, and return it. This increases the height by 1
     /// and is the opposite of `pop_internal_level`.
@@ -218,15 +222,16 @@ impl<K, V> Root<K, V> {
     pub fn pop_internal_level(&mut self) {
         assert!(self.height > 0);
 
-        let top = self.node.ptr;
+        let top = BoxedNode::as_ptr(&self.node);
 
         let mut internal_node = unsafe { self.internal_node_as_mut() };
-        self.node = unsafe { internal_node.as_internal_mut().edges[0].assume_init_read() };
+        let internal_node = NodeRef::as_internal_mut(&mut internal_node);
+        self.node = unsafe { internal_node.edges[0].assume_init_read() };
         self.height -= 1;
-        self.node_as_mut().as_leaf_mut().parent = None;
+        self.node_as_mut().clear_parent_link();
 
         unsafe {
-            Global.dealloc(NonNull::from(top).cast(), Layout::new::<InternalNode<K, V>>());
+            Global.dealloc(top.cast(), Layout::new::<InternalNode<K, V>>());
         }
     }
 }
@@ -236,21 +241,49 @@ impl<K, V> Root<K, V> {
 // internal use of `NodeRef` because we stay completely generic over `K` and `V`.
 // However, whenever a public type wraps `NodeRef`, make sure that it has the
 // correct variance.
+///
 /// A reference to a node.
 ///
 /// This type has a number of parameters that controls how it acts:
-/// - `BorrowType`: This can be `Immut<'a>`, `Mut<'a>` or `ValMut<'a>' for some `'a`
-///    or `Owned`.
-///    When this is `Immut<'a>`, the `NodeRef` acts roughly like `&'a Node`,
-///    when this is `Mut<'a>`, the `NodeRef` acts roughly like `&'a mut Node`,
-///    when this is `ValMut<'a>`, the `NodeRef` acts as immutable with respect
-///    to keys and tree structure, but allows mutable references to values,
-///    and when this is `Owned`, the `NodeRef` acts roughly like `Box<Node>`.
-/// - `K` and `V`: These control what types of things are stored in the nodes.
+/// - `BorrowType`: A dummy type that describes the kind of borrow and carries a lifetime.
+///    - When this is `Immut<'a>`, the `NodeRef` acts roughly like `&'a Node`.
+///    - When this is `ValMut<'a>`, the `NodeRef` acts roughly like `&'a Node`
+///      with respect to keys and tree structure, but also allows many
+///      mutable references to values throughout the tree to coexist.
+///    - When this is `Mut<'a>`, the `NodeRef` acts roughly like `&'a mut Node`,
+///      although insert methods allow a mutable pointer to a value to coexist.
+///    - When this is `Owned`, the `NodeRef` acts roughly like `Box<Node>`,
+///      but does not have a destructor, and must be cleaned up manually.
+/// - `K` and `V`: These are the types of keys and values stored in the nodes.
 /// - `Type`: This can be `Leaf`, `Internal`, or `LeafOrInternal`. When this is
 ///   `Leaf`, the `NodeRef` points to a leaf node, when this is `Internal` the
 ///   `NodeRef` points to an internal node, and when this is `LeafOrInternal` the
 ///   `NodeRef` could be pointing to either type of node.
+///   `Type` is named `NodeType` when used outside `NodeRef`.
+///
+/// Both `BorrowType` and `NodeType` restrict what methods we implement, to
+/// exploit static type safety. There are limitations in the way we can apply
+/// such restrictions:
+/// - For each type parameter, we can only define a method either generically
+///   or for one particular type. For example, we cannot define a method like
+///   `key_at` generically for all `BorrowType`, because we want to return
+///   `&'a K` for most choices of `BorrowType`, but plain `K` for `Owned`.
+///   We cannot define `key_at` once for all types that have a lifetime.
+///   Therefore, we define it only for the least powerful type `Immut<'a>`.
+/// - We cannot get implicit coercion from say `Mut<'a>` to `Immut<'a>`.
+///   Therefore, we have to explicitly call `reborrow` on a more powerfull
+///   `NodeRef` in order to reach a method like `key_at`.
+/// - All methods on `NodeRef` that return some kind of reference, except
+///   `reborrow` and `reborrow_mut`, take `self` by value and not by reference.
+///   This avoids silently returning a second reference somewhere in the tree.
+///   That is irrelevant when `BorrowType` is `Immut<'a>`, but the rule does
+///   no harm because we make those `NodeRef` implicitly `Copy`.
+///   The rule also avoids implicitly returning the lifetime of `&self`,
+///   instead of the lifetime contained in `BorrowType`.
+///   An exception to this rule are the insert functions.
+/// - Given the above, we need a `reborrow_mut` to explicitly copy a `Mut<'a>`
+///   `NodeRef` whenever we want to invoke a method returning an extra reference
+///   somewhere in the tree.
 pub struct NodeRef<BorrowType, K, V, Type> {
     /// The number of levels below the node, a property of the node that cannot be
     /// entirely described by `Type` and that the node does not store itself either.
@@ -277,30 +310,45 @@ unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef<marker::Mut<'
 unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef<marker::ValMut<'a>, K, V, Type> {}
 unsafe impl<K: Send, V: Send, Type> Send for NodeRef<marker::Owned, K, V, Type> {}
 
+impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
+    /// Unpack a node reference that was packed by `Root::into_boxed_node`.
+    fn from_boxed_node(boxed_node: BoxedNode<K, V>, height: usize) -> Self {
+        NodeRef { height, node: boxed_node.as_ptr(), _marker: PhantomData }
+    }
+}
+
+impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
+    /// Unpack a node reference that was packed as `NodeRef::parent`.
+    fn from_internal(node: NonNull<InternalNode<K, V>>, height: usize) -> Self {
+        debug_assert!(height > 0);
+        NodeRef { height, node: node.cast(), _marker: PhantomData }
+    }
+}
+
 impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
-    /// Exposes the data of an internal node for reading.
+    /// Exposes the data of an internal node.
     ///
-    /// Returns a raw ptr to avoid invalidating other references to this node,
-    /// which is possible when BorrowType is marker::ValMut.
-    fn as_internal_ptr(&self) -> *const InternalNode<K, V> {
-        self.node.as_ptr() as *const InternalNode<K, V>
+    /// Returns a raw ptr to avoid invalidating other references to this node.
+    fn as_internal_ptr(this: &Self) -> *mut InternalNode<K, V> {
+        // SAFETY: the static node type is `Internal`.
+        this.node.as_ptr() as *mut InternalNode<K, V>
     }
 }
 
-impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
-    /// Exposes the data of an internal node for reading,
-    /// when we know we have exclusive access.
-    fn as_internal(&mut self) -> &InternalNode<K, V> {
-        unsafe { &*self.as_internal_ptr() }
+impl<'a, K, V> NodeRef<marker::Immut<'a>, K, V, marker::Internal> {
+    /// Exposes the data of an internal node in an immutable tree.
+    fn as_internal(this: &Self) -> &'a InternalNode<K, V> {
+        let ptr = Self::as_internal_ptr(this);
+        // SAFETY: there can be no mutable references into this tree borrowed as `Immut`.
+        unsafe { &*ptr }
     }
 }
 
 impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
-    /// Exposes the data of an internal node for writing.
-    ///
-    /// We don't need to return a raw ptr because we have unique access to the entire node.
-    fn as_internal_mut(&mut self) -> &mut InternalNode<K, V> {
-        unsafe { &mut *(self.node.as_ptr() as *mut InternalNode<K, V>) }
+    /// Offers exclusive access to the data of an internal node.
+    fn as_internal_mut(this: &mut Self) -> &'a mut InternalNode<K, V> {
+        let ptr = Self::as_internal_ptr(this);
+        unsafe { &mut *ptr }
     }
 }
 
@@ -312,7 +360,7 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
     pub fn len(&self) -> usize {
         // Crucially, we only access the `len` field here. If BorrowType is marker::ValMut,
         // there might be outstanding mutable references to values that we must not invalidate.
-        unsafe { usize::from((*self.as_leaf_ptr()).len) }
+        unsafe { usize::from((*Self::as_leaf_ptr(self)).len) }
     }
 
     /// Returns the height of this node with respect to the leaf level. Zero height means the
@@ -322,48 +370,49 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
     }
 
     /// Temporarily takes out another, immutable reference to the same node.
-    fn reborrow(&self) -> NodeRef<marker::Immut<'_>, K, V, Type> {
+    pub fn reborrow(&self) -> NodeRef<marker::Immut<'_>, K, V, Type> {
         NodeRef { height: self.height, node: self.node, _marker: PhantomData }
     }
 
     /// Exposes the leaf portion of any leaf or internal node.
     ///
-    /// Returns a raw ptr to avoid invalidating other references to this node,
-    /// which is possible when BorrowType is marker::ValMut.
-    fn as_leaf_ptr(&self) -> *const LeafNode<K, V> {
+    /// Returns a raw ptr to avoid invalidating other references to this node.
+    fn as_leaf_ptr(this: &Self) -> *mut LeafNode<K, V> {
         // The node must be valid for at least the LeafNode portion.
         // This is not a reference in the NodeRef type because we don't know if
         // it should be unique or shared.
-        self.node.as_ptr()
+        this.node.as_ptr()
     }
+}
 
-    /// Borrows a reference to one of the keys stored in the node.
+impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
+    /// Exposes one of the keys stored in the node.
     ///
     /// # Safety
     /// The node has more than `idx` initialized elements.
-    pub unsafe fn key_at(&self, idx: usize) -> &K {
-        unsafe { self.reborrow().into_key_at(idx) }
+    pub unsafe fn key_at(self, idx: usize) -> &'a K {
+        debug_assert!(idx < self.len());
+        unsafe { Self::as_leaf(&self).keys.get_unchecked(idx).assume_init_ref() }
     }
 
-    /// Borrows a reference to one of the values stored in the node.
+    /// Exposes one of the values stored in the node.
     ///
     /// # Safety
     /// The node has more than `idx` initialized elements.
-    unsafe fn val_at(&self, idx: usize) -> &V {
-        unsafe { self.reborrow().into_val_at(idx) }
+    unsafe fn val_at(self, idx: usize) -> &'a V {
+        debug_assert!(idx < self.len());
+        unsafe { Self::as_leaf(&self).vals.get_unchecked(idx).assume_init_ref() }
     }
 }
 
-impl<BorrowType, K, V> NodeRef<BorrowType, K, V, marker::Internal> {
-    /// Borrows a reference to the contents of one of the edges that delimit
-    /// the elements of the node, without invalidating other references.
+impl<'a, K, V> NodeRef<marker::Immut<'a>, K, V, marker::Internal> {
+    /// Exposes the contents of one of the edges in the node.
     ///
     /// # Safety
     /// The node has more than `idx` initialized elements.
-    unsafe fn edge_at(&self, idx: usize) -> &BoxedNode<K, V> {
+    unsafe fn edge_at(self, idx: usize) -> &'a BoxedNode<K, V> {
         debug_assert!(idx <= self.len());
-        let node = self.as_internal_ptr();
-        unsafe { (*node).edges.get_unchecked(idx).assume_init_ref() }
+        unsafe { Self::as_internal(&self).edges.get_unchecked(idx).assume_init_ref() }
     }
 }
 
@@ -380,15 +429,11 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
     ) -> Result<Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::Edge>, Self> {
         // We need to use raw pointers to nodes because, if BorrowType is marker::ValMut,
         // there might be outstanding mutable references to values that we must not invalidate.
-        let leaf_ptr = self.as_leaf_ptr();
+        let leaf_ptr: *const _ = Self::as_leaf_ptr(&self);
         unsafe { (*leaf_ptr).parent }
             .as_ref()
             .map(|parent| Handle {
-                node: NodeRef {
-                    height: self.height + 1,
-                    node: parent.cast(),
-                    _marker: PhantomData,
-                },
+                node: NodeRef::from_internal(*parent, self.height + 1),
                 idx: unsafe { usize::from((*leaf_ptr).parent_idx.assume_init()) },
                 _marker: PhantomData,
             })
@@ -420,11 +465,11 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
 }
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
-    /// Exposes the data of a leaf node for reading in an immutable tree.
-    fn into_leaf(self) -> &'a LeafNode<K, V> {
-        // SAFETY: we can access the entire node freely and do no need raw pointers,
-        // because there can be no mutable references to this Immut tree.
-        unsafe { &(*self.as_leaf_ptr()) }
+    /// Exposes the leaf portion of any leaf or internal node in an immutable tree.
+    fn as_leaf(this: &Self) -> &'a LeafNode<K, V> {
+        let ptr = Self::as_leaf_ptr(this);
+        // SAFETY: there can be no mutable references into this tree borrowed as `Immut`.
+        unsafe { &*ptr }
     }
 }
 
@@ -473,139 +518,155 @@ impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
         NodeRef { height: self.height, node: self.node, _marker: PhantomData }
     }
 
-    /// Exposes the leaf portion of any leaf or internal node for writing.
-    ///
-    /// We don't need to return a raw ptr because we have unique access to the entire node.
-    fn as_leaf_mut(&mut self) -> &'a mut LeafNode<K, V> {
-        unsafe { &mut (*self.node.as_ptr()) }
+    /// Offers exclusive access to the leaf portion of any leaf or internal node.
+    fn as_leaf_mut(this: &mut Self) -> &'a mut LeafNode<K, V> {
+        let ptr = Self::as_leaf_ptr(this);
+        // SAFETY: we have exclusive access to the entire node.
+        unsafe { &mut *ptr }
     }
+}
 
-    /// Borrows a mutable reference to one of the keys stored in the node.
+impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
+    /// Offers exclusive access to a part of the key storage area.
     ///
     /// # Safety
     /// The node has more than `idx` initialized elements.
-    unsafe fn key_mut_at(&mut self, idx: usize) -> &mut K {
-        unsafe { self.reborrow_mut().into_key_mut_at(idx) }
+    unsafe fn into_key_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit<K> {
+        debug_assert!(idx < self.len());
+        unsafe { Self::as_leaf_mut(&mut self).keys.get_unchecked_mut(idx) }
     }
 
-    /// Borrows a mutable reference to one of the values stored in the node.
+    /// Offers exclusive access to a part of the value storage area.
     ///
     /// # Safety
     /// The node has more than `idx` initialized elements.
-    unsafe fn val_mut_at(&mut self, idx: usize) -> &mut V {
-        unsafe { self.reborrow_mut().into_val_mut_at(idx) }
-    }
-
-    fn keys_mut(&mut self) -> &mut [K]
-    where
-        K: 'a,
-        V: 'a,
-    {
-        // SAFETY: the caller will not be able to call further methods on self
-        // until the key slice reference is dropped, as we have unique access
-        // for the lifetime of the borrow.
-        // SAFETY: The keys of a node must always be initialized up to length.
-        unsafe {
-            slice::from_raw_parts_mut(
-                MaybeUninit::slice_as_mut_ptr(&mut self.as_leaf_mut().keys),
-                self.len(),
-            )
-        }
-    }
-
-    fn vals_mut(&mut self) -> &mut [V]
-    where
-        K: 'a,
-        V: 'a,
-    {
-        // SAFETY: the caller will not be able to call further methods on self
-        // until the value slice reference is dropped, as we have unique access
-        // for the lifetime of the borrow.
-        // SAFETY: The values of a node must always be initialized up to length.
-        unsafe {
-            slice::from_raw_parts_mut(
-                MaybeUninit::slice_as_mut_ptr(&mut self.as_leaf_mut().vals),
-                self.len(),
-            )
-        }
+    unsafe fn into_val_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit<V> {
+        debug_assert!(idx < self.len());
+        unsafe { Self::as_leaf_mut(&mut self).vals.get_unchecked_mut(idx) }
     }
 }
 
-impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
-    fn edges_mut(&mut self) -> &mut [BoxedNode<K, V>] {
-        unsafe {
-            slice::from_raw_parts_mut(
-                MaybeUninit::slice_as_mut_ptr(&mut self.as_internal_mut().edges),
-                self.len() + 1,
-            )
-        }
+impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
+    /// Offers exclusive access to a part of the storage area for edge contents.
+    ///
+    /// # Safety
+    /// The node has at least `idx` initialized elements.
+    unsafe fn into_edge_area_mut_at(mut self, idx: usize) -> &'a mut MaybeUninit<BoxedNode<K, V>> {
+        debug_assert!(idx <= self.len());
+        unsafe { Self::as_internal_mut(&mut self).edges.get_unchecked_mut(idx) }
     }
 }
 
 impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
-    /// # Safety
-    /// The node has more than `idx` initialized elements.
-    unsafe fn into_key_at(self, idx: usize) -> &'a K {
-        unsafe { self.into_leaf().keys.get_unchecked(idx).assume_init_ref() }
+    /// Exposes the entire key storage area in the node,
+    /// regardless of the node's current length,
+    /// having exclusive access to the entire node.
+    unsafe fn key_area(self) -> &'a [MaybeUninit<K>] {
+        Self::as_leaf(&self).keys.as_slice()
     }
 
-    /// # Safety
-    /// The node has more than `idx` initialized elements.
-    unsafe fn into_val_at(self, idx: usize) -> &'a V {
-        unsafe { self.into_leaf().vals.get_unchecked(idx).assume_init_ref() }
+    /// Exposes the entire value storage area in the node,
+    /// regardless of the node's current length,
+    /// having exclusive access to the entire node.
+    unsafe fn val_area(self) -> &'a [MaybeUninit<V>] {
+        Self::as_leaf(&self).vals.as_slice()
     }
 }
 
-impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
-    /// # Safety
-    /// The node has more than `idx` initialized elements.
-    unsafe fn into_key_mut_at(mut self, idx: usize) -> &'a mut K {
-        debug_assert!(idx < self.len());
+impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::Internal> {
+    /// Exposes the entire storage area for edge contents in the node,
+    /// regardless of the node's current length,
+    /// having exclusive access to the entire node.
+    unsafe fn edge_area(self) -> &'a [MaybeUninit<BoxedNode<K, V>>] {
+        Self::as_internal(&self).edges.as_slice()
+    }
+}
 
-        let leaf = self.as_leaf_mut();
-        unsafe { leaf.keys.get_unchecked_mut(idx).assume_init_mut() }
+impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
+    /// Offers exclusive access to a sized slice of key storage area in the node.
+    unsafe fn into_key_area_slice(mut self) -> &'a mut [MaybeUninit<K>] {
+        let len = self.len();
+        // SAFETY: the caller will not be able to call further methods on self
+        // until the key slice reference is dropped, as we have unique access
+        // for the lifetime of the borrow.
+        unsafe { Self::as_leaf_mut(&mut self).keys.get_unchecked_mut(..len) }
     }
 
-    /// # Safety
-    /// The node has more than `idx` initialized elements.
-    unsafe fn into_val_mut_at(mut self, idx: usize) -> &'a mut V {
-        debug_assert!(idx < self.len());
+    /// Offers exclusive access to a sized slice of value storage area in the node.
+    unsafe fn into_val_area_slice(mut self) -> &'a mut [MaybeUninit<V>] {
+        let len = self.len();
+        // SAFETY: the caller will not be able to call further methods on self
+        // until the value slice reference is dropped, as we have unique access
+        // for the lifetime of the borrow.
+        unsafe { Self::as_leaf_mut(&mut self).vals.get_unchecked_mut(..len) }
+    }
+}
 
-        let leaf = self.as_leaf_mut();
-        unsafe { leaf.vals.get_unchecked_mut(idx).assume_init_mut() }
+impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
+    /// Offers exclusive access to a sized slice of storage area for edge contents in the node.
+    unsafe fn into_edge_area_slice(mut self) -> &'a mut [MaybeUninit<BoxedNode<K, V>>] {
+        let len = self.len();
+        // SAFETY: the caller will not be able to call further methods on self
+        // until the edge slice reference is dropped, as we have unique access
+        // for the lifetime of the borrow.
+        unsafe { Self::as_internal_mut(&mut self).edges.get_unchecked_mut(..len + 1) }
     }
 }
 
 impl<'a, K, V, Type> NodeRef<marker::ValMut<'a>, K, V, Type> {
     /// # Safety
-    /// The node has more than `idx` initialized elements.
-    unsafe fn into_key_val_mut_at(self, idx: usize) -> (&'a K, &'a mut V) {
+    /// - The node has more than `idx` initialized elements.
+    /// - The keys and values of the node must be initialized up to its current length.
+    unsafe fn into_key_val_mut_at(mut self, idx: usize) -> (&'a K, &'a mut V) {
         // We only create a reference to the one element we are interested in,
         // to avoid aliasing with outstanding references to other elements,
         // in particular, those returned to the caller in earlier iterations.
-        let leaf = self.node.as_ptr();
+        let leaf = Self::as_leaf_ptr(&mut self);
         let keys = unsafe { &raw const (*leaf).keys };
         let vals = unsafe { &raw mut (*leaf).vals };
         // We must coerce to unsized array pointers because of Rust issue #74679.
         let keys: *const [_] = keys;
         let vals: *mut [_] = vals;
-        // SAFETY: The keys and values of a node must always be initialized up to length.
         let key = unsafe { (&*keys.get_unchecked(idx)).assume_init_ref() };
         let val = unsafe { (&mut *vals.get_unchecked_mut(idx)).assume_init_mut() };
         (key, val)
     }
 }
 
+impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
+    /// Exposes exclusive access to the length of the node.
+    pub fn into_len_mut(mut self) -> &'a mut u16 {
+        &mut (*Self::as_leaf_mut(&mut self)).len
+    }
+}
+
+impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
+    /// Set or clear the node's link to its parent edge,
+    /// without invalidating other references to the node.
+    fn set_parent_link(&mut self, parent: NonNull<InternalNode<K, V>>, parent_idx: usize) {
+        let leaf = Self::as_leaf_ptr(self);
+        unsafe { (*leaf).parent = Some(parent) };
+        unsafe { (*leaf).parent_idx.write(parent_idx as u16) };
+    }
+
+    /// Clear the node's link to its parent edge, freeing it from its tree.
+    /// This only makes sense when there are no other references to the node.
+    fn clear_parent_link(&mut self) {
+        let leaf = Self::as_leaf_mut(self);
+        leaf.parent = None;
+    }
+}
+
 impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
     /// Adds a key/value pair to the end of the node.
     pub fn push(&mut self, key: K, val: V) {
-        let len = &mut self.as_leaf_mut().len;
+        let len = unsafe { self.reborrow_mut().into_len_mut() };
         let idx = usize::from(*len);
         assert!(idx < CAPACITY);
         *len += 1;
         unsafe {
-            ptr::write(self.key_mut_at(idx), key);
-            ptr::write(self.val_mut_at(idx), val);
+            self.reborrow_mut().into_key_area_mut_at(idx).write(key);
+            self.reborrow_mut().into_val_area_mut_at(idx).write(val);
         }
     }
 
@@ -614,10 +675,10 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
         assert!(self.len() < CAPACITY);
 
         unsafe {
-            slice_insert(self.keys_mut(), 0, key);
-            slice_insert(self.vals_mut(), 0, val);
+            *self.reborrow_mut().into_len_mut() += 1;
+            slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key);
+            slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val);
         }
-        self.as_leaf_mut().len += 1;
     }
 }
 
@@ -643,14 +704,14 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
     pub fn push(&mut self, key: K, val: V, edge: Root<K, V>) {
         assert!(edge.height == self.height - 1);
 
-        let len = &mut self.as_leaf_mut().len;
+        let len = unsafe { self.reborrow_mut().into_len_mut() };
         let idx = usize::from(*len);
         assert!(idx < CAPACITY);
         *len += 1;
         unsafe {
-            ptr::write(self.key_mut_at(idx), key);
-            ptr::write(self.val_mut_at(idx), val);
-            self.as_internal_mut().edges.get_unchecked_mut(idx + 1).write(edge.node);
+            self.reborrow_mut().into_key_area_mut_at(idx).write(key);
+            self.reborrow_mut().into_val_area_mut_at(idx).write(val);
+            self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.into_boxed_node());
             Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link();
         }
     }
@@ -662,13 +723,12 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
         assert!(self.len() < CAPACITY);
 
         unsafe {
-            slice_insert(self.keys_mut(), 0, key);
-            slice_insert(self.vals_mut(), 0, val);
-            slice_insert(self.edges_mut(), 0, edge.node);
+            *self.reborrow_mut().into_len_mut() += 1;
+            slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key);
+            slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val);
+            slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.into_boxed_node());
         }
 
-        self.as_leaf_mut().len += 1;
-
         self.correct_all_childrens_parent_links();
     }
 }
@@ -683,19 +743,21 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
         let idx = self.len() - 1;
 
         unsafe {
-            let key = ptr::read(self.key_at(idx));
-            let val = ptr::read(self.val_at(idx));
+            let key = ptr::read(self.reborrow().key_at(idx));
+            let val = ptr::read(self.reborrow().val_at(idx));
             let edge = match self.reborrow_mut().force() {
                 ForceResult::Leaf(_) => None,
                 ForceResult::Internal(internal) => {
-                    let edge = ptr::read(internal.edge_at(idx + 1));
-                    let mut new_root = Root { node: edge, height: internal.height - 1 };
-                    new_root.node_as_mut().as_leaf_mut().parent = None;
-                    Some(new_root)
+                    let boxed_node = ptr::read(internal.reborrow().edge_at(idx + 1));
+                    let mut edge = Root { node: boxed_node, height: internal.height - 1 };
+                    // In practice, clearing the parent is a waste of time, because we will
+                    // insert the node elsewhere and set its parent link again.
+                    edge.node_as_mut().clear_parent_link();
+                    Some(edge)
                 }
             };
 
-            self.as_leaf_mut().len -= 1;
+            *self.reborrow_mut().into_len_mut() -= 1;
             (key, val, edge)
         }
     }
@@ -709,29 +771,35 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal> {
         let old_len = self.len();
 
         unsafe {
-            let key = slice_remove(self.keys_mut(), 0);
-            let val = slice_remove(self.vals_mut(), 0);
+            let key = slice_remove(self.reborrow_mut().into_key_area_slice(), 0);
+            let val = slice_remove(self.reborrow_mut().into_val_area_slice(), 0);
             let edge = match self.reborrow_mut().force() {
                 ForceResult::Leaf(_) => None,
                 ForceResult::Internal(mut internal) => {
-                    let edge = slice_remove(internal.edges_mut(), 0);
-                    let mut new_root = Root { node: edge, height: internal.height - 1 };
-                    new_root.node_as_mut().as_leaf_mut().parent = None;
+                    let boxed_node =
+                        slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0);
+                    let mut edge = Root { node: boxed_node, height: internal.height - 1 };
+                    // In practice, clearing the parent is a waste of time, because we will
+                    // insert the node elsewhere and set its parent link again.
+                    edge.node_as_mut().clear_parent_link();
 
                     internal.correct_childrens_parent_links(0..old_len);
 
-                    Some(new_root)
+                    Some(edge)
                 }
             };
 
-            self.as_leaf_mut().len -= 1;
+            *self.reborrow_mut().into_len_mut() -= 1;
 
             (key, val, edge)
         }
     }
 
     fn into_kv_pointers_mut(mut self) -> (*mut K, *mut V) {
-        (self.keys_mut().as_mut_ptr(), self.vals_mut().as_mut_ptr())
+        let leaf = Self::as_leaf_mut(&mut self);
+        let keys = MaybeUninit::slice_as_mut_ptr(&mut leaf.keys);
+        let vals = MaybeUninit::slice_as_mut_ptr(&mut leaf.vals);
+        (keys, vals)
     }
 }
 
@@ -816,7 +884,7 @@ impl<BorrowType, K, V, NodeType> NodeRef<BorrowType, K, V, NodeType> {
     /// Could be a public implementation of PartialEq, but only used in this module.
     fn eq(&self, other: &Self) -> bool {
         let Self { node, height, _marker: _ } = self;
-        if *node == other.node {
+        if node.eq(&other.node) {
             debug_assert_eq!(*height, other.height);
             true
         } else {
@@ -924,11 +992,11 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
         debug_assert!(self.node.len() < CAPACITY);
 
         unsafe {
-            slice_insert(self.node.keys_mut(), self.idx, key);
-            slice_insert(self.node.vals_mut(), self.idx, val);
-            self.node.as_leaf_mut().len += 1;
+            *self.node.reborrow_mut().into_len_mut() += 1;
+            slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key);
+            slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val);
 
-            self.node.val_mut_at(self.idx)
+            self.node.reborrow_mut().into_val_area_mut_at(self.idx).assume_init_mut()
         }
     }
 }
@@ -964,12 +1032,12 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
 impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::Edge> {
     /// Fixes the parent pointer and index in the child node below this edge. This is useful
     /// when the ordering of edges has been changed, such as in the various `insert` methods.
-    fn correct_parent_link(mut self) {
-        let idx = self.idx as u16;
-        let ptr = NonNull::new(self.node.as_internal_mut());
+    fn correct_parent_link(self) {
+        // Create backpointer without invalidating other references to the node.
+        let ptr = unsafe { NonNull::new_unchecked(NodeRef::as_internal_ptr(&self.node)) };
+        let idx = self.idx;
         let mut child = self.descend();
-        child.as_leaf_mut().parent = ptr;
-        child.as_leaf_mut().parent_idx.write(idx);
+        child.set_parent_link(ptr, idx);
     }
 }
 
@@ -981,11 +1049,12 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
         debug_assert!(self.node.len() < CAPACITY);
         debug_assert!(edge.height == self.node.height - 1);
 
+        let boxed_node = edge.into_boxed_node();
         unsafe {
-            slice_insert(self.node.keys_mut(), self.idx, key);
-            slice_insert(self.node.vals_mut(), self.idx, val);
-            slice_insert(self.node.edges_mut(), self.idx + 1, edge.node);
-            self.node.as_leaf_mut().len += 1;
+            *self.node.reborrow_mut().into_len_mut() += 1;
+            slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key);
+            slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val);
+            slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, boxed_node);
 
             self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len());
         }
@@ -1073,28 +1142,25 @@ impl<BorrowType, K, V> Handle<NodeRef<BorrowType, K, V, marker::Internal>, marke
         // node pointer is dereferenced, we access the edges array with a
         // reference (Rust issue #73987) and invalidate any other references
         // to or inside the array, should any be around.
-        let internal_node = self.node.as_internal_ptr();
-        NodeRef {
-            height: self.node.height - 1,
-            node: unsafe { (&*(*internal_node).edges.get_unchecked(self.idx).as_ptr()).as_ptr() },
-            _marker: PhantomData,
-        }
+        let parent_ptr = NodeRef::as_internal_ptr(&self.node);
+        let boxed_node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() };
+        NodeRef::from_boxed_node(boxed_node, self.node.height - 1)
     }
 }
 
 impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Immut<'a>, K, V, NodeType>, marker::KV> {
     pub fn into_kv(self) -> (&'a K, &'a V) {
-        (unsafe { self.node.into_key_at(self.idx) }, unsafe { self.node.into_val_at(self.idx) })
+        (unsafe { self.node.key_at(self.idx) }, unsafe { self.node.val_at(self.idx) })
     }
 }
 
 impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
     pub fn into_key_mut(self) -> &'a mut K {
-        unsafe { self.node.into_key_mut_at(self.idx) }
+        unsafe { self.node.into_key_area_mut_at(self.idx).assume_init_mut() }
     }
 
     pub fn into_val_mut(self) -> &'a mut V {
-        unsafe { self.node.into_val_mut_at(self.idx) }
+        unsafe { self.node.into_val_area_mut_at(self.idx).assume_init_mut() }
     }
 }
 
@@ -1106,12 +1172,14 @@ impl<'a, K, V, NodeType> Handle<NodeRef<marker::ValMut<'a>, K, V, NodeType>, mar
 
 impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>, marker::KV> {
     pub fn kv_mut(&mut self) -> (&mut K, &mut V) {
-        // We cannot call into_key_mut_at and into_val_mut_at, because calling the second one
+        // We cannot call separate key and value methods, because calling the second one
         // invalidates the reference returned by the first.
-        let leaf = self.node.as_leaf_mut();
-        let key = unsafe { leaf.keys.get_unchecked_mut(self.idx).assume_init_mut() };
-        let val = unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() };
-        (key, val)
+        unsafe {
+            let leaf = NodeRef::as_leaf_mut(&mut self.node.reborrow_mut());
+            let key = leaf.keys.get_unchecked_mut(self.idx).assume_init_mut();
+            let val = leaf.vals.get_unchecked_mut(self.idx).assume_init_mut();
+            (key, val)
+        }
     }
 }
 
@@ -1127,23 +1195,23 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>
     /// by taking care of leaf data.
     fn split_leaf_data(&mut self, new_node: &mut LeafNode<K, V>) -> (K, V) {
         let new_len = self.split_new_node_len();
+        new_node.len = new_len as u16;
         unsafe {
-            let k = ptr::read(self.node.key_at(self.idx));
-            let v = ptr::read(self.node.val_at(self.idx));
+            let k = ptr::read(self.node.reborrow().key_at(self.idx));
+            let v = ptr::read(self.node.reborrow().val_at(self.idx));
 
             ptr::copy_nonoverlapping(
-                self.node.key_at(self.idx + 1),
-                MaybeUninit::slice_as_mut_ptr(&mut new_node.keys),
+                self.node.reborrow().key_area().as_ptr().add(self.idx + 1),
+                new_node.keys.as_mut_ptr(),
                 new_len,
             );
             ptr::copy_nonoverlapping(
-                self.node.val_at(self.idx + 1),
-                MaybeUninit::slice_as_mut_ptr(&mut new_node.vals),
+                self.node.reborrow().val_area().as_ptr().add(self.idx + 1),
+                new_node.vals.as_mut_ptr(),
                 new_len,
             );
 
-            self.node.as_leaf_mut().len = self.idx as u16;
-            new_node.len = new_len as u16;
+            *self.node.reborrow_mut().into_len_mut() = self.idx as u16;
             (k, v)
         }
     }
@@ -1174,9 +1242,9 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
         mut self,
     ) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
         unsafe {
-            let k = slice_remove(self.node.keys_mut(), self.idx);
-            let v = slice_remove(self.node.vals_mut(), self.idx);
-            self.node.as_leaf_mut().len -= 1;
+            let k = slice_remove(self.node.reborrow_mut().into_key_area_slice(), self.idx);
+            let v = slice_remove(self.node.reborrow_mut().into_val_area_slice(), self.idx);
+            *self.node.reborrow_mut().into_len_mut() -= 1;
             ((k, v), self.left_edge())
         }
     }
@@ -1205,11 +1273,11 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
     pub fn split(mut self) -> (NodeRef<marker::Mut<'a>, K, V, marker::Internal>, K, V, Root<K, V>) {
         unsafe {
             let mut new_node = Box::new(InternalNode::new());
-            // Move edges out before reducing length:
             let new_len = self.split_new_node_len();
+            // Move edges out before reducing length:
             ptr::copy_nonoverlapping(
-                self.node.edge_at(self.idx + 1),
-                MaybeUninit::slice_as_mut_ptr(&mut new_node.edges),
+                self.node.reborrow().edge_area().as_ptr().add(self.idx + 1),
+                new_node.edges.as_mut_ptr(),
                 new_len + 1,
             );
             let (k, v) = self.split_leaf_data(&mut new_node.data);
@@ -1241,31 +1309,28 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
         assert!(left_len + right_len < CAPACITY);
 
         unsafe {
-            ptr::write(
-                left_node.keys_mut().get_unchecked_mut(left_len),
-                slice_remove(self.node.keys_mut(), self.idx),
-            );
+            *left_node.reborrow_mut().into_len_mut() += right_len as u16 + 1;
+
+            let parent_key = slice_remove(self.node.reborrow_mut().into_key_area_slice(), self.idx);
+            left_node.reborrow_mut().into_key_area_mut_at(left_len).write(parent_key);
             ptr::copy_nonoverlapping(
-                right_node.key_at(0),
-                left_node.keys_mut().as_mut_ptr().add(left_len + 1),
+                right_node.reborrow().key_area().as_ptr(),
+                left_node.reborrow_mut().into_key_area_slice().as_mut_ptr().add(left_len + 1),
                 right_len,
             );
-            ptr::write(
-                left_node.vals_mut().get_unchecked_mut(left_len),
-                slice_remove(self.node.vals_mut(), self.idx),
-            );
+
+            let parent_val = slice_remove(self.node.reborrow_mut().into_val_area_slice(), self.idx);
+            left_node.reborrow_mut().into_val_area_mut_at(left_len).write(parent_val);
             ptr::copy_nonoverlapping(
-                right_node.val_at(0),
-                left_node.vals_mut().as_mut_ptr().add(left_len + 1),
+                right_node.reborrow().val_area().as_ptr(),
+                left_node.reborrow_mut().into_val_area_slice().as_mut_ptr().add(left_len + 1),
                 right_len,
             );
 
-            slice_remove(&mut self.node.edges_mut(), self.idx + 1);
+            slice_remove(&mut self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1);
             let self_len = self.node.len();
             self.node.correct_childrens_parent_links(self.idx + 1..self_len);
-            self.node.as_leaf_mut().len -= 1;
-
-            left_node.as_leaf_mut().len += right_len as u16 + 1;
+            *self.node.reborrow_mut().into_len_mut() -= 1;
 
             if self.node.height > 1 {
                 // SAFETY: the height of the nodes being merged is one below the height
@@ -1273,8 +1338,8 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
                 let mut left_node = left_node.cast_to_internal_unchecked();
                 let right_node = right_node.cast_to_internal_unchecked();
                 ptr::copy_nonoverlapping(
-                    right_node.edge_at(0),
-                    left_node.edges_mut().as_mut_ptr().add(left_len + 1),
+                    right_node.reborrow().edge_area().as_ptr(),
+                    left_node.reborrow_mut().into_edge_area_slice().as_mut_ptr().add(left_len + 1),
                     right_len + 1,
                 );
 
@@ -1360,13 +1425,14 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
                 move_kv(left_kv, new_left_len, parent_kv, 0, 1);
             }
 
-            left_node.as_leaf_mut().len -= count as u16;
-            right_node.as_leaf_mut().len += count as u16;
+            *left_node.reborrow_mut().into_len_mut() -= count as u16;
+            *right_node.reborrow_mut().into_len_mut() += count as u16;
 
             match (left_node.force(), right_node.force()) {
                 (ForceResult::Internal(left), ForceResult::Internal(mut right)) => {
                     // Make room for stolen edges.
-                    let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr();
+                    let left = left.reborrow();
+                    let right_edges = right.reborrow_mut().into_edge_area_slice().as_mut_ptr();
                     ptr::copy(right_edges, right_edges.add(count), right_len + 1);
                     right.correct_childrens_parent_links(count..count + right_len + 1);
 
@@ -1415,15 +1481,15 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
                 ptr::copy(right_kv.1.add(count), right_kv.1, new_right_len);
             }
 
-            left_node.as_leaf_mut().len += count as u16;
-            right_node.as_leaf_mut().len -= count as u16;
+            *left_node.reborrow_mut().into_len_mut() += count as u16;
+            *right_node.reborrow_mut().into_len_mut() -= count as u16;
 
             match (left_node.force(), right_node.force()) {
                 (ForceResult::Internal(left), ForceResult::Internal(mut right)) => {
-                    move_edges(right.reborrow_mut(), 0, left, left_len + 1, count);
+                    move_edges(right.reborrow(), 0, left, left_len + 1, count);
 
                     // Fix right indexing.
-                    let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr();
+                    let right_edges = right.reborrow_mut().into_edge_area_slice().as_mut_ptr();
                     ptr::copy(right_edges.add(count), right_edges, new_right_len + 1);
                     right.correct_childrens_parent_links(0..=new_right_len);
                 }
@@ -1448,16 +1514,16 @@ unsafe fn move_kv<K, V>(
 }
 
 // Source and destination must have the same height.
-unsafe fn move_edges<K, V>(
-    mut source: NodeRef<marker::Mut<'_>, K, V, marker::Internal>,
+unsafe fn move_edges<'a, K: 'a, V: 'a>(
+    source: NodeRef<marker::Immut<'a>, K, V, marker::Internal>,
     source_offset: usize,
-    mut dest: NodeRef<marker::Mut<'_>, K, V, marker::Internal>,
+    mut dest: NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
     dest_offset: usize,
     count: usize,
 ) {
-    let source_ptr = source.as_internal().edges.as_ptr();
-    let dest_ptr = dest.as_internal_mut().edges.as_mut_ptr();
     unsafe {
+        let source_ptr = source.edge_area().as_ptr();
+        let dest_ptr = dest.reborrow_mut().into_edge_area_slice().as_mut_ptr();
         ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count);
         dest.correct_childrens_parent_links(dest_offset..dest_offset + count);
     }
@@ -1553,11 +1619,12 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, ma
 
                 move_kv(left_kv, left_new_len, right_kv, 0, right_new_len);
 
-                left_node.as_leaf_mut().len = left_new_len as u16;
-                right_node.as_leaf_mut().len = right_new_len as u16;
+                *left_node.reborrow_mut().into_len_mut() = left_new_len as u16;
+                *right_node.reborrow_mut().into_len_mut() = right_new_len as u16;
 
                 match (left_node.force(), right_node.force()) {
                     (ForceResult::Internal(left), ForceResult::Internal(right)) => {
+                        let left = left.reborrow();
                         move_edges(left, left_new_len + 1, right, 1, right_new_len);
                     }
                     (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {}
@@ -1606,17 +1673,34 @@ pub mod marker {
     pub enum Edge {}
 }
 
-unsafe fn slice_insert<T>(slice: &mut [T], idx: usize, val: T) {
+/// Inserts a value into a slice of initialized elements followed by one uninitialized element.
+///
+/// # Safety
+/// The slice has more than `idx` elements.
+unsafe fn slice_insert<T>(slice: &mut [MaybeUninit<T>], idx: usize, val: T) {
     unsafe {
-        ptr::copy(slice.as_ptr().add(idx), slice.as_mut_ptr().add(idx + 1), slice.len() - idx);
-        ptr::write(slice.get_unchecked_mut(idx), val);
+        let len = slice.len();
+        debug_assert!(len > idx);
+        let slice_ptr = slice.as_mut_ptr();
+        if len > idx + 1 {
+            ptr::copy(slice_ptr.add(idx), slice_ptr.add(idx + 1), len - idx - 1);
+        }
+        (*slice_ptr.add(idx)).write(val);
     }
 }
 
-unsafe fn slice_remove<T>(slice: &mut [T], idx: usize) -> T {
+/// Removes and returns a value from a slice of all initialized elements, leaving behind one
+/// trailing uninitialized element.
+///
+/// # Safety
+/// The slice has more than `idx` elements.
+unsafe fn slice_remove<T>(slice: &mut [MaybeUninit<T>], idx: usize) -> T {
     unsafe {
-        let ret = ptr::read(slice.get_unchecked(idx));
-        ptr::copy(slice.as_ptr().add(idx + 1), slice.as_mut_ptr().add(idx), slice.len() - idx - 1);
+        let len = slice.len();
+        debug_assert!(idx < len);
+        let slice_ptr = slice.as_mut_ptr();
+        let ret = (*slice_ptr.add(idx)).assume_init_read();
+        ptr::copy(slice_ptr.add(idx + 1), slice_ptr.add(idx), len - idx - 1);
         ret
     }
 }
diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs
index d6527057c5d..38c75de34ee 100644
--- a/library/alloc/src/collections/btree/node/tests.rs
+++ b/library/alloc/src/collections/btree/node/tests.rs
@@ -17,43 +17,6 @@ impl<'a, K: 'a, V: 'a> NodeRef<marker::Immut<'a>, K, V, marker::LeafOrInternal>
         }
     }
 
-    /// Asserts that the keys are in strictly ascending order.
-    /// Returns how many keys it encountered.
-    pub fn assert_ascending(self) -> usize
-    where
-        K: Copy + Debug + Ord,
-    {
-        struct SeriesChecker<T> {
-            num_seen: usize,
-            previous: Option<T>,
-        }
-        impl<T: Copy + Debug + Ord> SeriesChecker<T> {
-            fn is_ascending(&mut self, next: T) {
-                if let Some(previous) = self.previous {
-                    assert!(previous < next, "{:?} >= {:?}", previous, next);
-                }
-                self.previous = Some(next);
-                self.num_seen += 1;
-            }
-        }
-
-        let mut checker = SeriesChecker { num_seen: 0, previous: None };
-        self.visit_nodes_in_order(|pos| match pos {
-            navigate::Position::Leaf(node) => {
-                for idx in 0..node.len() {
-                    let key = *unsafe { node.key_at(idx) };
-                    checker.is_ascending(key);
-                }
-            }
-            navigate::Position::InternalKV(kv) => {
-                let key = *kv.into_kv().0;
-                checker.is_ascending(key);
-            }
-            navigate::Position::Internal(_) => {}
-        });
-        checker.num_seen
-    }
-
     pub fn dump_keys(self) -> String
     where
         K: Debug,
diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs
index 1526c0673c6..701d5ec73e2 100644
--- a/library/alloc/src/collections/btree/search.rs
+++ b/library/alloc/src/collections/btree/search.rs
@@ -72,7 +72,7 @@ where
     // is an index -- not a reference.
     let len = node.len();
     for i in 0..len {
-        let k = unsafe { node.key_at(i) };
+        let k = unsafe { node.reborrow().key_at(i) };
         match key.cmp(k.borrow()) {
             Ordering::Greater => {}
             Ordering::Equal => return (i, true),
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 15092d463ec..f21fc8854d0 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -78,6 +78,7 @@
 #![cfg_attr(test, feature(new_uninit))]
 #![feature(allocator_api)]
 #![feature(array_chunks)]
+#![feature(array_methods)]
 #![feature(array_value_iter)]
 #![feature(array_windows)]
 #![feature(allow_internal_unstable)]
diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs
index 202e3a83638..2c8bc3d53ef 100644
--- a/library/alloc/src/vec.rs
+++ b/library/alloc/src/vec.rs
@@ -2136,10 +2136,8 @@ impl<T> InPlaceDrop<T> {
 impl<T> Drop for InPlaceDrop<T> {
     #[inline]
     fn drop(&mut self) {
-        if mem::needs_drop::<T>() {
-            unsafe {
-                ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len()));
-            }
+        unsafe {
+            ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len()));
         }
     }
 }
@@ -2871,10 +2869,8 @@ impl<T> IntoIter<T> {
     }
 
     fn drop_remaining(&mut self) {
-        if mem::needs_drop::<T>() {
-            unsafe {
-                ptr::drop_in_place(self.as_mut_slice());
-            }
+        unsafe {
+            ptr::drop_in_place(self.as_mut_slice());
         }
         self.ptr = self.end;
     }
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 0e3129607a6..433f0129306 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -788,7 +788,7 @@ extern "rust-intrinsic" {
 
     /// The size of the referenced value in bytes.
     ///
-    /// The stabilized version of this intrinsic is [`size_of_val`].
+    /// The stabilized version of this intrinsic is [`mem::size_of_val`].
     #[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")]
     pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
     /// The required alignment of the referenced value.
@@ -1704,7 +1704,7 @@ extern "rust-intrinsic" {
     /// Returns the number of variants of the type `T` cast to a `usize`;
     /// if `T` has no variants, returns 0. Uninhabited variants will be counted.
     ///
-    /// The to-be-stabilized version of this intrinsic is [`variant_count`].
+    /// The to-be-stabilized version of this intrinsic is [`mem::variant_count`].
     #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
     pub fn variant_count<T>() -> usize;
 
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index ea560288c28..41202546566 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -159,6 +159,7 @@
 #![feature(slice_ptr_get)]
 #![feature(no_niche)] // rust-lang/rust#68303
 #![feature(unsafe_block_in_unsafe_fn)]
+#![feature(int_error_matching)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 #[prelude_import]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 079d9f6006a..fe3eff04b4a 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -318,7 +318,7 @@ macro_rules! r#try {
 
 /// Writes formatted data into a buffer.
 ///
-/// This macro accepts a format string, a list of arguments, and a 'writer'. Arguments will be
+/// This macro accepts a 'writer', a format string, and a list of arguments. Arguments will be
 /// formatted according to the specified format string and the result will be passed to the writer.
 /// The writer may be any value with a `write_fmt` method; generally this comes from an
 /// implementation of either the [`fmt::Write`] or the [`io::Write`] trait. The macro
diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs
index aab17155186..9d8c8c86291 100644
--- a/library/core/src/num/error.rs
+++ b/library/core/src/num/error.rs
@@ -98,15 +98,18 @@ pub enum IntErrorKind {
     ///
     /// Among other causes, this variant will be constructed when parsing an empty string.
     Empty,
-    /// Contains an invalid digit.
+    /// Contains an invalid digit in its context.
     ///
     /// Among other causes, this variant will be constructed when parsing a string that
-    /// contains a letter.
+    /// contains a non-ASCII char.
+    ///
+    /// This variant is also constructed when a `+` or `-` is misplaced within a string
+    /// either on its own or in the middle of a number.
     InvalidDigit,
     /// Integer is too large to store in target integer type.
-    Overflow,
+    PosOverflow,
     /// Integer is too small to store in target integer type.
-    Underflow,
+    NegOverflow,
     /// Value was Zero
     ///
     /// This variant will be emitted when the parsing string has a value of zero, which
@@ -119,7 +122,7 @@ impl ParseIntError {
     #[unstable(
         feature = "int_error_matching",
         reason = "it can be useful to match errors when making error messages \
-                  for integer parsing",
+              for integer parsing",
         issue = "22639"
     )]
     pub fn kind(&self) -> &IntErrorKind {
@@ -136,8 +139,8 @@ impl ParseIntError {
         match self.kind {
             IntErrorKind::Empty => "cannot parse integer from empty string",
             IntErrorKind::InvalidDigit => "invalid digit found in string",
-            IntErrorKind::Overflow => "number too large to fit in target type",
-            IntErrorKind::Underflow => "number too small to fit in target type",
+            IntErrorKind::PosOverflow => "number too large to fit in target type",
+            IntErrorKind::NegOverflow => "number too small to fit in target type",
             IntErrorKind::Zero => "number would be zero for non-zero type",
         }
     }
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index c90887b89d0..9f5ae57b74a 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -63,7 +63,12 @@ pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, No
 #[stable(feature = "try_from", since = "1.34.0")]
 pub use error::TryFromIntError;
 
-#[unstable(feature = "int_error_matching", issue = "22639")]
+#[unstable(
+    feature = "int_error_matching",
+    reason = "it can be useful to match errors when making error messages \
+              for integer parsing",
+    issue = "22639"
+)]
 pub use error::IntErrorKind;
 
 macro_rules! usize_isize_to_xe_bytes_doc {
@@ -830,15 +835,14 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
     let src = src.as_bytes();
 
     let (is_positive, digits) = match src[0] {
+        b'+' | b'-' if src[1..].is_empty() => {
+            return Err(PIE { kind: InvalidDigit });
+        }
         b'+' => (true, &src[1..]),
         b'-' if is_signed_ty => (false, &src[1..]),
         _ => (true, src),
     };
 
-    if digits.is_empty() {
-        return Err(PIE { kind: Empty });
-    }
-
     let mut result = T::from_u32(0);
     if is_positive {
         // The number is positive
@@ -849,11 +853,11 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
             };
             result = match result.checked_mul(radix) {
                 Some(result) => result,
-                None => return Err(PIE { kind: Overflow }),
+                None => return Err(PIE { kind: PosOverflow }),
             };
             result = match result.checked_add(x) {
                 Some(result) => result,
-                None => return Err(PIE { kind: Overflow }),
+                None => return Err(PIE { kind: PosOverflow }),
             };
         }
     } else {
@@ -865,11 +869,11 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
             };
             result = match result.checked_mul(radix) {
                 Some(result) => result,
-                None => return Err(PIE { kind: Underflow }),
+                None => return Err(PIE { kind: NegOverflow }),
             };
             result = match result.checked_sub(x) {
                 Some(result) => result,
-                None => return Err(PIE { kind: Underflow }),
+                None => return Err(PIE { kind: NegOverflow }),
             };
         }
     }
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 6dc542dee58..88b4e2a2436 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -108,18 +108,20 @@ impl Duration {
     #[unstable(feature = "duration_constants", issue = "57391")]
     pub const NANOSECOND: Duration = Duration::from_nanos(1);
 
-    /// The minimum duration.
+    /// A duration of zero time.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(duration_constants)]
+    /// #![feature(duration_zero)]
     /// use std::time::Duration;
     ///
-    /// assert_eq!(Duration::MIN, Duration::new(0, 0));
+    /// let duration = Duration::ZERO;
+    /// assert!(duration.is_zero());
+    /// assert_eq!(duration.as_nanos(), 0);
     /// ```
-    #[unstable(feature = "duration_constants", issue = "57391")]
-    pub const MIN: Duration = Duration::from_nanos(0);
+    #[unstable(feature = "duration_zero", issue = "73544")]
+    pub const ZERO: Duration = Duration::from_nanos(0);
 
     /// The maximum duration.
     ///
@@ -166,24 +168,6 @@ impl Duration {
         Duration { secs, nanos }
     }
 
-    /// Creates a new `Duration` that spans no time.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(duration_zero)]
-    /// use std::time::Duration;
-    ///
-    /// let duration = Duration::zero();
-    /// assert!(duration.is_zero());
-    /// assert_eq!(duration.as_nanos(), 0);
-    /// ```
-    #[unstable(feature = "duration_zero", issue = "73544")]
-    #[inline]
-    pub const fn zero() -> Duration {
-        Duration { secs: 0, nanos: 0 }
-    }
-
     /// Creates a new `Duration` from the specified number of whole seconds.
     ///
     /// # Examples
@@ -277,7 +261,7 @@ impl Duration {
     /// #![feature(duration_zero)]
     /// use std::time::Duration;
     ///
-    /// assert!(Duration::zero().is_zero());
+    /// assert!(Duration::ZERO.is_zero());
     /// assert!(Duration::new(0, 0).is_zero());
     /// assert!(Duration::from_nanos(0).is_zero());
     /// assert!(Duration::from_secs(0).is_zero());
@@ -536,18 +520,18 @@ impl Duration {
         }
     }
 
-    /// Saturating `Duration` subtraction. Computes `self - other`, returning [`Duration::MIN`]
+    /// Saturating `Duration` subtraction. Computes `self - other`, returning [`Duration::ZERO`]
     /// if the result would be negative or if overflow occurred.
     ///
     /// # Examples
     ///
     /// ```
     /// #![feature(duration_saturating_ops)]
-    /// #![feature(duration_constants)]
+    /// #![feature(duration_zero)]
     /// use std::time::Duration;
     ///
     /// assert_eq!(Duration::new(0, 1).saturating_sub(Duration::new(0, 0)), Duration::new(0, 1));
-    /// assert_eq!(Duration::new(0, 0).saturating_sub(Duration::new(0, 1)), Duration::MIN);
+    /// assert_eq!(Duration::new(0, 0).saturating_sub(Duration::new(0, 1)), Duration::ZERO);
     /// ```
     #[unstable(feature = "duration_saturating_ops", issue = "76416")]
     #[inline]
@@ -555,7 +539,7 @@ impl Duration {
     pub const fn saturating_sub(self, rhs: Duration) -> Duration {
         match self.checked_sub(rhs) {
             Some(res) => res,
-            None => Duration::MIN,
+            None => Duration::ZERO,
         }
     }
 
diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs
index 825e5e63b59..fb1293c99bb 100644
--- a/library/core/tests/nonzero.rs
+++ b/library/core/tests/nonzero.rs
@@ -135,11 +135,11 @@ fn test_from_str() {
     );
     assert_eq!(
         "-129".parse::<NonZeroI8>().err().map(|e| e.kind().clone()),
-        Some(IntErrorKind::Underflow)
+        Some(IntErrorKind::NegOverflow)
     );
     assert_eq!(
         "257".parse::<NonZeroU8>().err().map(|e| e.kind().clone()),
-        Some(IntErrorKind::Overflow)
+        Some(IntErrorKind::PosOverflow)
     );
 }
 
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 190528fd445..49e5cc0eaa5 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -2,10 +2,11 @@ use core::cmp::PartialEq;
 use core::convert::{TryFrom, TryInto};
 use core::fmt::Debug;
 use core::marker::Copy;
-use core::num::TryFromIntError;
+use core::num::{IntErrorKind, ParseIntError, TryFromIntError};
 use core::ops::{Add, Div, Mul, Rem, Sub};
 use core::option::Option;
-use core::option::Option::{None, Some};
+use core::option::Option::None;
+use core::str::FromStr;
 
 #[macro_use]
 mod int_macros;
@@ -67,6 +68,15 @@ where
     assert_eq!(ten.rem(two), ten % two);
 }
 
+/// Helper function for asserting number parsing returns a specific error
+fn test_parse<T>(num_str: &str, expected: Result<T, IntErrorKind>)
+where
+    T: FromStr<Err = ParseIntError>,
+    Result<T, IntErrorKind>: PartialEq + Debug,
+{
+    assert_eq!(num_str.parse::<T>().map_err(|e| e.kind().clone()), expected)
+}
+
 #[test]
 fn from_str_issue7588() {
     let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
@@ -77,49 +87,52 @@ fn from_str_issue7588() {
 
 #[test]
 fn test_int_from_str_overflow() {
-    assert_eq!("127".parse::<i8>().ok(), Some(127i8));
-    assert_eq!("128".parse::<i8>().ok(), None);
+    test_parse::<i8>("127", Ok(127));
+    test_parse::<i8>("128", Err(IntErrorKind::PosOverflow));
 
-    assert_eq!("-128".parse::<i8>().ok(), Some(-128i8));
-    assert_eq!("-129".parse::<i8>().ok(), None);
+    test_parse::<i8>("-128", Ok(-128));
+    test_parse::<i8>("-129", Err(IntErrorKind::NegOverflow));
 
-    assert_eq!("32767".parse::<i16>().ok(), Some(32_767i16));
-    assert_eq!("32768".parse::<i16>().ok(), None);
+    test_parse::<i16>("32767", Ok(32_767));
+    test_parse::<i16>("32768", Err(IntErrorKind::PosOverflow));
 
-    assert_eq!("-32768".parse::<i16>().ok(), Some(-32_768i16));
-    assert_eq!("-32769".parse::<i16>().ok(), None);
+    test_parse::<i16>("-32768", Ok(-32_768));
+    test_parse::<i16>("-32769", Err(IntErrorKind::NegOverflow));
 
-    assert_eq!("2147483647".parse::<i32>().ok(), Some(2_147_483_647i32));
-    assert_eq!("2147483648".parse::<i32>().ok(), None);
+    test_parse::<i32>("2147483647", Ok(2_147_483_647));
+    test_parse::<i32>("2147483648", Err(IntErrorKind::PosOverflow));
 
-    assert_eq!("-2147483648".parse::<i32>().ok(), Some(-2_147_483_648i32));
-    assert_eq!("-2147483649".parse::<i32>().ok(), None);
+    test_parse::<i32>("-2147483648", Ok(-2_147_483_648));
+    test_parse::<i32>("-2147483649", Err(IntErrorKind::NegOverflow));
 
-    assert_eq!("9223372036854775807".parse::<i64>().ok(), Some(9_223_372_036_854_775_807i64));
-    assert_eq!("9223372036854775808".parse::<i64>().ok(), None);
+    test_parse::<i64>("9223372036854775807", Ok(9_223_372_036_854_775_807));
+    test_parse::<i64>("9223372036854775808", Err(IntErrorKind::PosOverflow));
 
-    assert_eq!("-9223372036854775808".parse::<i64>().ok(), Some(-9_223_372_036_854_775_808i64));
-    assert_eq!("-9223372036854775809".parse::<i64>().ok(), None);
+    test_parse::<i64>("-9223372036854775808", Ok(-9_223_372_036_854_775_808));
+    test_parse::<i64>("-9223372036854775809", Err(IntErrorKind::NegOverflow));
 }
 
 #[test]
 fn test_leading_plus() {
-    assert_eq!("+127".parse::<u8>().ok(), Some(127));
-    assert_eq!("+9223372036854775807".parse::<i64>().ok(), Some(9223372036854775807));
+    test_parse::<u8>("+127", Ok(127));
+    test_parse::<i64>("+9223372036854775807", Ok(9223372036854775807));
 }
 
 #[test]
 fn test_invalid() {
-    assert_eq!("--129".parse::<i8>().ok(), None);
-    assert_eq!("++129".parse::<i8>().ok(), None);
-    assert_eq!("Съешь".parse::<u8>().ok(), None);
+    test_parse::<i8>("--129", Err(IntErrorKind::InvalidDigit));
+    test_parse::<i8>("++129", Err(IntErrorKind::InvalidDigit));
+    test_parse::<u8>("Съешь", Err(IntErrorKind::InvalidDigit));
+    test_parse::<u8>("123Hello", Err(IntErrorKind::InvalidDigit));
+    test_parse::<i8>("--", Err(IntErrorKind::InvalidDigit));
+    test_parse::<i8>("-", Err(IntErrorKind::InvalidDigit));
+    test_parse::<i8>("+", Err(IntErrorKind::InvalidDigit));
+    test_parse::<u8>("-1", Err(IntErrorKind::InvalidDigit));
 }
 
 #[test]
 fn test_empty() {
-    assert_eq!("-".parse::<i8>().ok(), None);
-    assert_eq!("+".parse::<i8>().ok(), None);
-    assert_eq!("".parse::<u8>().ok(), None);
+    test_parse::<u8>("", Err(IntErrorKind::Empty));
 }
 
 #[test]
diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs
index 7c43885040b..f14639e0d58 100644
--- a/library/core/tests/time.rs
+++ b/library/core/tests/time.rs
@@ -108,24 +108,24 @@ fn sub() {
 
 #[test]
 fn checked_sub() {
-    let zero = Duration::new(0, 0);
-    let one_nano = Duration::new(0, 1);
-    let one_sec = Duration::new(1, 0);
-    assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1)));
-    assert_eq!(one_sec.checked_sub(one_nano), Some(Duration::new(0, 999_999_999)));
-    assert_eq!(zero.checked_sub(one_nano), None);
-    assert_eq!(zero.checked_sub(one_sec), None);
+    assert_eq!(Duration::NANOSECOND.checked_sub(Duration::ZERO), Some(Duration::NANOSECOND));
+    assert_eq!(
+        Duration::SECOND.checked_sub(Duration::NANOSECOND),
+        Some(Duration::new(0, 999_999_999))
+    );
+    assert_eq!(Duration::ZERO.checked_sub(Duration::NANOSECOND), None);
+    assert_eq!(Duration::ZERO.checked_sub(Duration::SECOND), None);
 }
 
 #[test]
 fn saturating_sub() {
-    let zero = Duration::new(0, 0);
-    let one_nano = Duration::new(0, 1);
-    let one_sec = Duration::new(1, 0);
-    assert_eq!(one_nano.saturating_sub(zero), Duration::new(0, 1));
-    assert_eq!(one_sec.saturating_sub(one_nano), Duration::new(0, 999_999_999));
-    assert_eq!(zero.saturating_sub(one_nano), Duration::MIN);
-    assert_eq!(zero.saturating_sub(one_sec), Duration::MIN);
+    assert_eq!(Duration::NANOSECOND.saturating_sub(Duration::ZERO), Duration::NANOSECOND);
+    assert_eq!(
+        Duration::SECOND.saturating_sub(Duration::NANOSECOND),
+        Duration::new(0, 999_999_999)
+    );
+    assert_eq!(Duration::ZERO.saturating_sub(Duration::NANOSECOND), Duration::ZERO);
+    assert_eq!(Duration::ZERO.saturating_sub(Duration::SECOND), Duration::ZERO);
 }
 
 #[test]
@@ -337,87 +337,82 @@ fn duration_const() {
     const SUB_SEC_NANOS: u32 = DURATION.subsec_nanos();
     assert_eq!(SUB_SEC_NANOS, 123_456_789);
 
-    const ZERO: Duration = Duration::zero();
-    assert_eq!(ZERO, Duration::new(0, 0));
-
-    const IS_ZERO: bool = ZERO.is_zero();
+    const IS_ZERO: bool = Duration::ZERO.is_zero();
     assert!(IS_ZERO);
 
-    const ONE: Duration = Duration::new(1, 0);
-
-    const SECONDS: u64 = ONE.as_secs();
+    const SECONDS: u64 = Duration::SECOND.as_secs();
     assert_eq!(SECONDS, 1);
 
     const FROM_SECONDS: Duration = Duration::from_secs(1);
-    assert_eq!(FROM_SECONDS, ONE);
+    assert_eq!(FROM_SECONDS, Duration::SECOND);
 
-    const SECONDS_F32: f32 = ONE.as_secs_f32();
+    const SECONDS_F32: f32 = Duration::SECOND.as_secs_f32();
     assert_eq!(SECONDS_F32, 1.0);
 
     const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0);
-    assert_eq!(FROM_SECONDS_F32, ONE);
+    assert_eq!(FROM_SECONDS_F32, Duration::SECOND);
 
-    const SECONDS_F64: f64 = ONE.as_secs_f64();
+    const SECONDS_F64: f64 = Duration::SECOND.as_secs_f64();
     assert_eq!(SECONDS_F64, 1.0);
 
     const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0);
-    assert_eq!(FROM_SECONDS_F64, ONE);
+    assert_eq!(FROM_SECONDS_F64, Duration::SECOND);
 
-    const MILLIS: u128 = ONE.as_millis();
+    const MILLIS: u128 = Duration::SECOND.as_millis();
     assert_eq!(MILLIS, 1_000);
 
     const FROM_MILLIS: Duration = Duration::from_millis(1_000);
-    assert_eq!(FROM_MILLIS, ONE);
+    assert_eq!(FROM_MILLIS, Duration::SECOND);
 
-    const MICROS: u128 = ONE.as_micros();
+    const MICROS: u128 = Duration::SECOND.as_micros();
     assert_eq!(MICROS, 1_000_000);
 
     const FROM_MICROS: Duration = Duration::from_micros(1_000_000);
-    assert_eq!(FROM_MICROS, ONE);
+    assert_eq!(FROM_MICROS, Duration::SECOND);
 
-    const NANOS: u128 = ONE.as_nanos();
+    const NANOS: u128 = Duration::SECOND.as_nanos();
     assert_eq!(NANOS, 1_000_000_000);
 
     const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000);
-    assert_eq!(FROM_NANOS, ONE);
+    assert_eq!(FROM_NANOS, Duration::SECOND);
 
     const MAX: Duration = Duration::new(u64::MAX, 999_999_999);
 
-    const CHECKED_ADD: Option<Duration> = MAX.checked_add(ONE);
+    const CHECKED_ADD: Option<Duration> = MAX.checked_add(Duration::SECOND);
     assert_eq!(CHECKED_ADD, None);
 
-    const CHECKED_SUB: Option<Duration> = ZERO.checked_sub(ONE);
+    const CHECKED_SUB: Option<Duration> = Duration::ZERO.checked_sub(Duration::SECOND);
     assert_eq!(CHECKED_SUB, None);
 
-    const CHECKED_MUL: Option<Duration> = ONE.checked_mul(1);
-    assert_eq!(CHECKED_MUL, Some(ONE));
+    const CHECKED_MUL: Option<Duration> = Duration::SECOND.checked_mul(1);
+    assert_eq!(CHECKED_MUL, Some(Duration::SECOND));
 
-    const MUL_F32: Duration = ONE.mul_f32(1.0);
-    assert_eq!(MUL_F32, ONE);
+    const MUL_F32: Duration = Duration::SECOND.mul_f32(1.0);
+    assert_eq!(MUL_F32, Duration::SECOND);
 
-    const MUL_F64: Duration = ONE.mul_f64(1.0);
-    assert_eq!(MUL_F64, ONE);
+    const MUL_F64: Duration = Duration::SECOND.mul_f64(1.0);
+    assert_eq!(MUL_F64, Duration::SECOND);
 
-    const CHECKED_DIV: Option<Duration> = ONE.checked_div(1);
-    assert_eq!(CHECKED_DIV, Some(ONE));
+    const CHECKED_DIV: Option<Duration> = Duration::SECOND.checked_div(1);
+    assert_eq!(CHECKED_DIV, Some(Duration::SECOND));
 
-    const DIV_F32: Duration = ONE.div_f32(1.0);
-    assert_eq!(DIV_F32, ONE);
+    const DIV_F32: Duration = Duration::SECOND.div_f32(1.0);
+    assert_eq!(DIV_F32, Duration::SECOND);
 
-    const DIV_F64: Duration = ONE.div_f64(1.0);
-    assert_eq!(DIV_F64, ONE);
+    const DIV_F64: Duration = Duration::SECOND.div_f64(1.0);
+    assert_eq!(DIV_F64, Duration::SECOND);
 
-    const DIV_DURATION_F32: f32 = ONE.div_duration_f32(ONE);
+    const DIV_DURATION_F32: f32 = Duration::SECOND.div_duration_f32(Duration::SECOND);
     assert_eq!(DIV_DURATION_F32, 1.0);
 
-    const DIV_DURATION_F64: f64 = ONE.div_duration_f64(ONE);
+    const DIV_DURATION_F64: f64 = Duration::SECOND.div_duration_f64(Duration::SECOND);
     assert_eq!(DIV_DURATION_F64, 1.0);
 
-    const SATURATING_ADD: Duration = MAX.saturating_add(ONE);
+    const SATURATING_ADD: Duration = MAX.saturating_add(Duration::SECOND);
     assert_eq!(SATURATING_ADD, MAX);
 
-    const SATURATING_SUB: Duration = ZERO.saturating_sub(ONE);
-    assert_eq!(SATURATING_SUB, ZERO);
+    const SATURATING_SUB: Duration = Duration::ZERO.saturating_sub(Duration::SECOND);
+    assert_eq!(SATURATING_SUB, Duration::ZERO);
 
     const SATURATING_MUL: Duration = MAX.saturating_mul(2);
     assert_eq!(SATURATING_MUL, MAX);
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index dd760062380..375b015ccc8 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -316,7 +316,7 @@ pub fn take_alloc_error_hook() -> fn(Layout) {
 }
 
 fn default_alloc_error_hook(layout: Layout) {
-    dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
+    dumb_print(format_args!("memory allocation of {} bytes failed\n", layout.size()));
 }
 
 #[cfg(not(test))]
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 161bfe3795c..c256f556b3c 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1701,10 +1701,14 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
 /// The `dst` path will be a link pointing to the `src` path. Note that systems
 /// often require these two paths to both be located on the same filesystem.
 ///
+/// If `src` names a symbolic link, it is platform-specific whether the symbolic
+/// link is followed. On platforms where it's possible to not follow it, it is
+/// not followed, and the created hard link points to the symbolic link itself.
+///
 /// # Platform-specific behavior
 ///
-/// This function currently corresponds to the `link` function on Unix
-/// and the `CreateHardLink` function on Windows.
+/// This function currently corresponds to the `linkat` function with no flags
+/// on Unix and the `CreateHardLink` function on Windows.
 /// Note that, this [may change in the future][changes].
 ///
 /// [changes]: io#platform-specific-behavior
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index 38fd470a1c3..0642dca8e48 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1336,3 +1336,54 @@ fn metadata_access_times() {
         }
     }
 }
+
+/// Test creating hard links to symlinks.
+#[test]
+fn symlink_hard_link() {
+    let tmpdir = tmpdir();
+
+    // Create "file", a file.
+    check!(fs::File::create(tmpdir.join("file")));
+
+    // Create "symlink", a symlink to "file".
+    check!(symlink_file("file", tmpdir.join("symlink")));
+
+    // Create "hard_link", a hard link to "symlink".
+    check!(fs::hard_link(tmpdir.join("symlink"), tmpdir.join("hard_link")));
+
+    // "hard_link" should appear as a symlink.
+    assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
+
+    // We sould be able to open "file" via any of the above names.
+    let _ = check!(fs::File::open(tmpdir.join("file")));
+    assert!(fs::File::open(tmpdir.join("file.renamed")).is_err());
+    let _ = check!(fs::File::open(tmpdir.join("symlink")));
+    let _ = check!(fs::File::open(tmpdir.join("hard_link")));
+
+    // Rename "file" to "file.renamed".
+    check!(fs::rename(tmpdir.join("file"), tmpdir.join("file.renamed")));
+
+    // Now, the symlink and the hard link should be dangling.
+    assert!(fs::File::open(tmpdir.join("file")).is_err());
+    let _ = check!(fs::File::open(tmpdir.join("file.renamed")));
+    assert!(fs::File::open(tmpdir.join("symlink")).is_err());
+    assert!(fs::File::open(tmpdir.join("hard_link")).is_err());
+
+    // The symlink and the hard link should both still point to "file".
+    assert!(fs::read_link(tmpdir.join("file")).is_err());
+    assert!(fs::read_link(tmpdir.join("file.renamed")).is_err());
+    assert_eq!(check!(fs::read_link(tmpdir.join("symlink"))), Path::new("file"));
+    assert_eq!(check!(fs::read_link(tmpdir.join("hard_link"))), Path::new("file"));
+
+    // Remove "file.renamed".
+    check!(fs::remove_file(tmpdir.join("file.renamed")));
+
+    // Now, we can't open the file by any name.
+    assert!(fs::File::open(tmpdir.join("file")).is_err());
+    assert!(fs::File::open(tmpdir.join("file.renamed")).is_err());
+    assert!(fs::File::open(tmpdir.join("symlink")).is_err());
+    assert!(fs::File::open(tmpdir.join("hard_link")).is_err());
+
+    // "hard_link" should still appear as a symlink.
+    assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
+}
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index bc218b77c87..fa2608e6fb6 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -257,6 +257,7 @@
 #![feature(doc_spotlight)]
 #![feature(dropck_eyepatch)]
 #![feature(duration_constants)]
+#![feature(duration_zero)]
 #![feature(exact_size_is_empty)]
 #![feature(exhaustive_patterns)]
 #![feature(extend_one)]
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index d27d6e2c565..96594095cc3 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -1081,7 +1081,20 @@ pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
 pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
     let src = cstr(src)?;
     let dst = cstr(dst)?;
-    cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
+    cfg_if::cfg_if! {
+        if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android"))] {
+            // VxWorks, Redox, and old versions of Android lack `linkat`, so use
+            // `link` instead. POSIX leaves it implementation-defined whether
+            // `link` follows symlinks, so rely on the `symlink_hard_link` test
+            // in library/std/src/fs/tests.rs to check the behavior.
+            cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?;
+        } else {
+            // Use `linkat` with `AT_FDCWD` instead of `link` as `linkat` gives
+            // us a flag to specify how symlinks should be handled. Pass 0 as
+            // the flags argument, meaning don't follow symlinks.
+            cvt(unsafe { libc::linkat(libc::AT_FDCWD, src.as_ptr(), libc::AT_FDCWD, dst.as_ptr(), 0) })?;
+        }
+    }
     Ok(())
 }
 
diff --git a/library/std/src/sys/unix/process/process_common/tests.rs b/library/std/src/sys/unix/process/process_common/tests.rs
index e72fbf0beb4..10aa34e9443 100644
--- a/library/std/src/sys/unix/process/process_common/tests.rs
+++ b/library/std/src/sys/unix/process/process_common/tests.rs
@@ -14,17 +14,22 @@ macro_rules! t {
     };
 }
 
-// See #14232 for more information, but it appears that signal delivery to a
-// newly spawned process may just be raced in the macOS, so to prevent this
-// test from being flaky we ignore it on macOS.
 #[test]
-#[cfg_attr(target_os = "macos", ignore)]
-// When run under our current QEMU emulation test suite this test fails,
-// although the reason isn't very clear as to why. For now this test is
-// ignored there.
-#[cfg_attr(target_arch = "arm", ignore)]
-#[cfg_attr(target_arch = "aarch64", ignore)]
-#[cfg_attr(target_arch = "riscv64", ignore)]
+#[cfg_attr(
+    any(
+        // See #14232 for more information, but it appears that signal delivery to a
+        // newly spawned process may just be raced in the macOS, so to prevent this
+        // test from being flaky we ignore it on macOS.
+        target_os = "macos",
+        // When run under our current QEMU emulation test suite this test fails,
+        // although the reason isn't very clear as to why. For now this test is
+        // ignored there.
+        target_arch = "arm",
+        target_arch = "aarch64",
+        target_arch = "riscv64",
+    ),
+    ignore
+)]
 fn test_process_mask() {
     unsafe {
         // Test to make sure that a signal mask does not get inherited.
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 64d7898f030..e433f69a8b0 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -322,7 +322,7 @@ impl Instant {
     /// ```
     #[stable(feature = "checked_duration_since", since = "1.39.0")]
     pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
-        self.checked_duration_since(earlier).unwrap_or(Duration::new(0, 0))
+        self.checked_duration_since(earlier).unwrap_or_default()
     }
 
     /// Returns the amount of time elapsed since this instant was created.
diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs
index 783bf49f315..20c813fdc70 100644
--- a/library/std/src/time/tests.rs
+++ b/library/std/src/time/tests.rs
@@ -5,7 +5,7 @@ macro_rules! assert_almost_eq {
         let (a, b) = ($a, $b);
         if a != b {
             let (a, b) = if a > b { (a, b) } else { (b, a) };
-            assert!(a - Duration::new(0, 1000) <= b, "{:?} is not almost equal to {:?}", a, b);
+            assert!(a - Duration::from_micros(1) <= b, "{:?} is not almost equal to {:?}", a, b);
         }
     }};
 }
@@ -34,7 +34,7 @@ fn instant_math() {
     assert_almost_eq!(b - dur, a);
     assert_almost_eq!(a + dur, b);
 
-    let second = Duration::new(1, 0);
+    let second = Duration::SECOND;
     assert_almost_eq!(a - second + second, a);
     assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
 
@@ -65,24 +65,24 @@ fn instant_math_is_associative() {
 #[should_panic]
 fn instant_duration_since_panic() {
     let a = Instant::now();
-    (a - Duration::new(1, 0)).duration_since(a);
+    (a - Duration::SECOND).duration_since(a);
 }
 
 #[test]
 fn instant_checked_duration_since_nopanic() {
     let now = Instant::now();
-    let earlier = now - Duration::new(1, 0);
-    let later = now + Duration::new(1, 0);
+    let earlier = now - Duration::SECOND;
+    let later = now + Duration::SECOND;
     assert_eq!(earlier.checked_duration_since(now), None);
-    assert_eq!(later.checked_duration_since(now), Some(Duration::new(1, 0)));
-    assert_eq!(now.checked_duration_since(now), Some(Duration::new(0, 0)));
+    assert_eq!(later.checked_duration_since(now), Some(Duration::SECOND));
+    assert_eq!(now.checked_duration_since(now), Some(Duration::ZERO));
 }
 
 #[test]
 fn instant_saturating_duration_since_nopanic() {
     let a = Instant::now();
-    let ret = (a - Duration::new(1, 0)).saturating_duration_since(a);
-    assert_eq!(ret, Duration::new(0, 0));
+    let ret = (a - Duration::SECOND).saturating_duration_since(a);
+    assert_eq!(ret, Duration::ZERO);
 }
 
 #[test]
@@ -90,7 +90,7 @@ fn system_time_math() {
     let a = SystemTime::now();
     let b = SystemTime::now();
     match b.duration_since(a) {
-        Ok(dur) if dur == Duration::new(0, 0) => {
+        Ok(Duration::ZERO) => {
             assert_almost_eq!(a, b);
         }
         Ok(dur) => {
@@ -106,16 +106,16 @@ fn system_time_math() {
         }
     }
 
-    let second = Duration::new(1, 0);
+    let second = Duration::SECOND;
     assert_almost_eq!(a.duration_since(a - second).unwrap(), second);
     assert_almost_eq!(a.duration_since(a + second).unwrap_err().duration(), second);
 
     assert_almost_eq!(a - second + second, a);
     assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a);
 
-    let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0);
+    let one_second_from_epoch = UNIX_EPOCH + Duration::SECOND;
     let one_second_from_epoch2 =
-        UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000);
+        UNIX_EPOCH + Duration::from_millis(500) + Duration::from_millis(500);
     assert_eq!(one_second_from_epoch, one_second_from_epoch2);
 
     // checked_add_duration will not panic on overflow
@@ -141,12 +141,12 @@ fn system_time_elapsed() {
 #[test]
 fn since_epoch() {
     let ts = SystemTime::now();
-    let a = ts.duration_since(UNIX_EPOCH + Duration::new(1, 0)).unwrap();
+    let a = ts.duration_since(UNIX_EPOCH + Duration::SECOND).unwrap();
     let b = ts.duration_since(UNIX_EPOCH).unwrap();
     assert!(b > a);
-    assert_eq!(b - a, Duration::new(1, 0));
+    assert_eq!(b - a, Duration::SECOND);
 
-    let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30;
+    let thirty_years = Duration::SECOND * 60 * 60 * 24 * 365 * 30;
 
     // Right now for CI this test is run in an emulator, and apparently the
     // aarch64 emulator's sense of time is that we're still living in the
diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md
index 7bb4e504275..a103c9fb0b7 100644
--- a/src/bootstrap/CHANGELOG.md
+++ b/src/bootstrap/CHANGELOG.md
@@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 - `x.py check` needs opt-in to check tests (--all-targets) [#77473](https://github.com/rust-lang/rust/pull/77473)
 - The default bootstrap profiles are now located at `bootstrap/defaults/config.$PROFILE.toml` (previously they were located at `bootstrap/defaults/config.toml.$PROFILE`) [#77558](https://github.com/rust-lang/rust/pull/77558)
+- If you have Rust already installed, `x.py` will now infer the host target
+  from the default rust toolchain. [#78513](https://github.com/rust-lang/rust/pull/78513)
 
 
 ## [Version 2] - 2020-09-25
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 87e15363818..54d0a23dec5 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -187,8 +187,23 @@ def format_build_time(duration):
     return str(datetime.timedelta(seconds=int(duration)))
 
 
-def default_build_triple():
+def default_build_triple(verbose):
     """Build triple as in LLVM"""
+    # If the user already has a host build triple with an existing `rustc`
+    # install, use their preference. This fixes most issues with Windows builds
+    # being detected as GNU instead of MSVC.
+    try:
+        version = subprocess.check_output(["rustc", "--version", "--verbose"])
+        host = next(x for x in version.split('\n') if x.startswith("host: "))
+        triple = host.split("host: ")[1]
+        if verbose:
+            print("detected default triple {}".format(triple))
+        return triple
+    except Exception as e:
+        if verbose:
+            print("rustup not detected: {}".format(e))
+            print("falling back to auto-detect")
+
     default_encoding = sys.getdefaultencoding()
     required = sys.platform != 'win32'
     ostype = require(["uname", "-s"], exit=required)
@@ -831,7 +846,7 @@ class RustBuild(object):
         config = self.get_toml('build')
         if config:
             return config
-        return default_build_triple()
+        return default_build_triple(self.verbose)
 
     def check_submodule(self, module, slow_submodules):
         if not slow_submodules:
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index b48508f2c24..3d724c14842 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -264,7 +264,7 @@ impl<'a> ShouldRun<'a> {
     /// `all_krates` should probably be removed at some point.
     pub fn all_krates(mut self, name: &str) -> Self {
         let mut set = BTreeSet::new();
-        for krate in self.builder.in_tree_crates(name) {
+        for krate in self.builder.in_tree_crates(name, None) {
             let path = krate.local_path(self.builder);
             set.insert(path);
         }
@@ -277,7 +277,7 @@ impl<'a> ShouldRun<'a> {
     ///
     /// `make_run` will be called separately for each matching command-line path.
     pub fn krate(mut self, name: &str) -> Self {
-        for krate in self.builder.in_tree_crates(name) {
+        for krate in self.builder.in_tree_crates(name, None) {
             let path = krate.local_path(self.builder);
             self.paths.insert(PathSet::one(path));
         }
@@ -1178,6 +1178,14 @@ impl<'a> Builder<'a> {
             }
         }
 
+        // Compile everything except libraries and proc macros with the more
+        // efficient initial-exec TLS model. This doesn't work with `dlopen`,
+        // so we can't use it by default in general, but we can use it for tools
+        // and our own internal libraries.
+        if !mode.must_support_dlopen() {
+            rustflags.arg("-Ztls-model=initial-exec");
+        }
+
         if self.config.incremental {
             cargo.env("CARGO_INCREMENTAL", "1");
         } else {
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 2e3cfc98c8c..ecca12108b6 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -108,7 +108,7 @@ impl Step for Std {
             // Explicitly pass -p for all dependencies krates -- this will force cargo
             // to also check the tests/benches/examples for these crates, rather
             // than just the leaf crate.
-            for krate in builder.in_tree_crates("test") {
+            for krate in builder.in_tree_crates("test", Some(target)) {
                 cargo.arg("-p").arg(krate.name);
             }
 
@@ -172,7 +172,7 @@ impl Step for Rustc {
         // Explicitly pass -p for all compiler krates -- this will force cargo
         // to also check the tests/benches/examples for these crates, rather
         // than just the leaf crate.
-        for krate in builder.in_tree_crates("rustc-main") {
+        for krate in builder.in_tree_crates("rustc-main", Some(target)) {
             cargo.arg("-p").arg(krate.name);
         }
 
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index ed9b9108586..cdad1cb4d49 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -143,7 +143,7 @@ fn copy_third_party_objects(
         }
     }
 
-    if builder.config.sanitizers && compiler.stage != 0 {
+    if builder.config.sanitizers_enabled(target) && compiler.stage != 0 {
         // The sanitizers are only copied in stage1 or above,
         // to avoid creating dependency on LLVM.
         target_deps.extend(
@@ -251,7 +251,7 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
             .arg("--features")
             .arg(features);
     } else {
-        let mut features = builder.std_features();
+        let mut features = builder.std_features(target);
         features.push_str(compiler_builtins_c_feature);
 
         cargo
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 40ea9afb6f6..c0753d88504 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -99,6 +99,7 @@ pub struct Config {
     pub llvm_version_suffix: Option<String>,
     pub llvm_use_linker: Option<String>,
     pub llvm_allow_old_toolchain: Option<bool>,
+    pub llvm_polly: Option<bool>,
     pub llvm_from_ci: bool,
 
     pub use_lld: bool,
@@ -278,6 +279,8 @@ pub struct Target {
     pub ranlib: Option<PathBuf>,
     pub linker: Option<PathBuf>,
     pub ndk: Option<PathBuf>,
+    pub sanitizers: bool,
+    pub profiler: bool,
     pub crt_static: Option<bool>,
     pub musl_root: Option<PathBuf>,
     pub musl_libdir: Option<PathBuf>,
@@ -418,6 +421,7 @@ struct Llvm {
     use_libcxx: Option<bool>,
     use_linker: Option<String>,
     allow_old_toolchain: Option<bool>,
+    polly: Option<bool>,
     download_ci_llvm: Option<StringOrBool>,
 }
 
@@ -501,6 +505,8 @@ struct TomlTarget {
     llvm_config: Option<String>,
     llvm_filecheck: Option<String>,
     android_ndk: Option<String>,
+    sanitizers: Option<bool>,
+    profiler: Option<bool>,
     crt_static: Option<bool>,
     musl_root: Option<String>,
     musl_libdir: Option<String>,
@@ -762,6 +768,7 @@ impl Config {
             set(&mut config.llvm_use_libcxx, llvm.use_libcxx);
             config.llvm_use_linker = llvm.use_linker.clone();
             config.llvm_allow_old_toolchain = llvm.allow_old_toolchain;
+            config.llvm_polly = llvm.polly;
             config.llvm_from_ci = match llvm.download_ci_llvm {
                 Some(StringOrBool::String(s)) => {
                     assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
@@ -795,6 +802,7 @@ impl Config {
                 check_ci_llvm!(llvm.use_libcxx);
                 check_ci_llvm!(llvm.use_linker);
                 check_ci_llvm!(llvm.allow_old_toolchain);
+                check_ci_llvm!(llvm.polly);
 
                 // CI-built LLVM is shared
                 config.llvm_link_shared = true;
@@ -886,6 +894,8 @@ impl Config {
                 target.musl_libdir = cfg.musl_libdir.map(PathBuf::from);
                 target.wasi_root = cfg.wasi_root.map(PathBuf::from);
                 target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from);
+                target.sanitizers = cfg.sanitizers.unwrap_or(build.sanitizers.unwrap_or_default());
+                target.profiler = cfg.profiler.unwrap_or(build.profiler.unwrap_or_default());
 
                 config.target_config.insert(TargetSelection::from_user(&triple), target);
             }
@@ -995,6 +1005,22 @@ impl Config {
         self.verbose > 1
     }
 
+    pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool {
+        self.target_config.get(&target).map(|t| t.sanitizers).unwrap_or(self.sanitizers)
+    }
+
+    pub fn any_sanitizers_enabled(&self) -> bool {
+        self.target_config.values().any(|t| t.sanitizers) || self.sanitizers
+    }
+
+    pub fn profiler_enabled(&self, target: TargetSelection) -> bool {
+        self.target_config.get(&target).map(|t| t.profiler).unwrap_or(self.profiler)
+    }
+
+    pub fn any_profiler_enabled(&self) -> bool {
+        self.target_config.values().any(|t| t.profiler) || self.profiler
+    }
+
     pub fn llvm_enabled(&self) -> bool {
         self.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
     }
diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py
index e156952d56f..322e9d69232 100755
--- a/src/bootstrap/configure.py
+++ b/src/bootstrap/configure.py
@@ -266,7 +266,7 @@ config = {}
 def build():
     if 'build' in known_args:
         return known_args['build'][-1][1]
-    return bootstrap.default_build_triple()
+    return bootstrap.default_build_triple(verbose=False)
 
 
 def set(key, value):
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index bdab12db435..5ce5737f318 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1040,6 +1040,30 @@ impl Step for Src {
             builder.copy(&builder.src.join(file), &dst_src.join(file));
         }
 
+        // libtest includes std and everything else, so vendoring it
+        // creates exactly what's needed for `cargo -Zbuild-std` or any
+        // other analysis of the stdlib's source. Cargo also needs help
+        // finding the lock, so we copy it to libtest temporarily.
+        //
+        // Note that this requires std to only have one version of each
+        // crate. e.g. two versions of getopts won't be patchable.
+        let dst_libtest = dst_src.join("library/test");
+        let dst_vendor = dst_src.join("vendor");
+        let root_lock = dst_src.join("Cargo.lock");
+        let temp_lock = dst_libtest.join("Cargo.lock");
+
+        // `cargo vendor` will delete everything from the lockfile that
+        // isn't used by libtest, so we need to not use any links!
+        builder.really_copy(&root_lock, &temp_lock);
+
+        let mut cmd = Command::new(&builder.initial_cargo);
+        cmd.arg("vendor").arg(dst_vendor).current_dir(&dst_libtest);
+        builder.info("Dist src");
+        let _time = timeit(builder);
+        builder.run(&mut cmd);
+
+        builder.remove(&temp_lock);
+
         // Create source tarball in rust-installer format
         let mut cmd = rust_installer(builder);
         cmd.arg("generate")
@@ -1056,8 +1080,6 @@ impl Step for Src {
             .arg("--component-name=rust-src")
             .arg("--legacy-manifest-dirs=rustlib,cargo");
 
-        builder.info("Dist src");
-        let _time = timeit(builder);
         builder.run(&mut cmd);
 
         builder.remove_dir(&image);
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index aa670bd9a2e..af7f7eff894 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -535,8 +535,12 @@ impl Step for Rustc {
         // Find dependencies for top level crates.
         let mut compiler_crates = HashSet::new();
         for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] {
-            compiler_crates
-                .extend(builder.in_tree_crates(root_crate).into_iter().map(|krate| krate.name));
+            compiler_crates.extend(
+                builder
+                    .in_tree_crates(root_crate, Some(target))
+                    .into_iter()
+                    .map(|krate| krate.name),
+            );
         }
 
         for krate in &compiler_crates {
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 0878b0ff789..9f037890483 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -169,17 +169,18 @@ pub use crate::config::Config;
 pub use crate::flags::Subcommand;
 
 const LLVM_TOOLS: &[&str] = &[
-    "llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility
-    "llvm-objcopy", // used to transform ELFs into binary format which flashing tools consume
-    "llvm-objdump", // used to disassemble programs
+    "llvm-cov",      // used to generate coverage report
+    "llvm-nm",       // used to inspect binaries; it shows symbol names, their sizes and visibility
+    "llvm-objcopy",  // used to transform ELFs into binary format which flashing tools consume
+    "llvm-objdump",  // used to disassemble programs
     "llvm-profdata", // used to inspect and merge files generated by profiles
-    "llvm-readobj", // used to get information from ELFs/objects that the other tools don't provide
-    "llvm-size", // used to prints the size of the linker sections of a program
-    "llvm-strip", // used to discard symbols from binary files to reduce their size
-    "llvm-ar", // used for creating and modifying archive files
-    "llvm-dis", // used to disassemble LLVM bitcode
-    "llc",     // used to compile LLVM bytecode
-    "opt",     // used to optimize LLVM bytecode
+    "llvm-readobj",  // used to get information from ELFs/objects that the other tools don't provide
+    "llvm-size",     // used to prints the size of the linker sections of a program
+    "llvm-strip",    // used to discard symbols from binary files to reduce their size
+    "llvm-ar",       // used for creating and modifying archive files
+    "llvm-dis",      // used to disassemble LLVM bitcode
+    "llc",           // used to compile LLVM bytecode
+    "opt",           // used to optimize LLVM bytecode
 ];
 
 pub const VERSION: usize = 2;
@@ -332,6 +333,10 @@ impl Mode {
     pub fn is_tool(&self) -> bool {
         matches!(self, Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd)
     }
+
+    pub fn must_support_dlopen(&self) -> bool {
+        matches!(self, Mode::Std | Mode::Codegen)
+    }
 }
 
 impl Build {
@@ -537,7 +542,7 @@ impl Build {
 
     /// Gets the space-separated set of activated features for the standard
     /// library.
-    fn std_features(&self) -> String {
+    fn std_features(&self, target: TargetSelection) -> String {
         let mut features = "panic-unwind".to_string();
 
         match self.config.llvm_libunwind.unwrap_or_default() {
@@ -548,7 +553,7 @@ impl Build {
         if self.config.backtrace {
             features.push_str(" backtrace");
         }
-        if self.config.profiler {
+        if self.config.profiler_enabled(target) {
             features.push_str(" profiler");
         }
         features
@@ -1111,7 +1116,7 @@ impl Build {
     /// Returns a Vec of all the dependencies of the given root crate,
     /// including transitive dependencies and the root itself. Only includes
     /// "local" crates (those in the local source tree, not from a registry).
-    fn in_tree_crates(&self, root: &str) -> Vec<&Crate> {
+    fn in_tree_crates(&self, root: &str, target: Option<TargetSelection>) -> Vec<&Crate> {
         let mut ret = Vec::new();
         let mut list = vec![INTERNER.intern_str(root)];
         let mut visited = HashSet::new();
@@ -1132,7 +1137,10 @@ impl Build {
                 // metadata::build.
                 if visited.insert(dep)
                     && dep != "build_helper"
-                    && (dep != "profiler_builtins" || self.config.profiler)
+                    && (dep != "profiler_builtins"
+                        || target
+                            .map(|t| self.config.profiler_enabled(t))
+                            .unwrap_or(self.config.any_profiler_enabled()))
                     && (dep != "rustc_codegen_llvm" || self.config.llvm_enabled())
                 {
                     list.push(*dep);
@@ -1167,6 +1175,27 @@ impl Build {
         paths
     }
 
+    /// Copies a file from `src` to `dst` and doesn't use links, so
+    /// that the copy can be modified without affecting the original.
+    pub fn really_copy(&self, src: &Path, dst: &Path) {
+        if self.config.dry_run {
+            return;
+        }
+        self.verbose_than(1, &format!("Copy {:?} to {:?}", src, dst));
+        if src == dst {
+            return;
+        }
+        let _ = fs::remove_file(&dst);
+        let metadata = t!(src.symlink_metadata());
+        if let Err(e) = fs::copy(src, dst) {
+            panic!("failed to copy `{}` to `{}`: {}", src.display(), dst.display(), e)
+        }
+        t!(fs::set_permissions(dst, metadata.permissions()));
+        let atime = FileTime::from_last_access_time(&metadata);
+        let mtime = FileTime::from_last_modification_time(&metadata);
+        t!(filetime::set_file_times(dst, atime, mtime));
+    }
+
     /// Copies a file from `src` to `dst`
     pub fn copy(&self, src: &Path, dst: &Path) {
         if self.config.dry_run {
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 37d6fab070b..6dc83c7d70a 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -257,6 +257,10 @@ impl Step for Llvm {
             enabled_llvm_projects.push("compiler-rt");
         }
 
+        if let Some(true) = builder.config.llvm_polly {
+            enabled_llvm_projects.push("polly");
+        }
+
         // We want libxml to be disabled.
         // See https://github.com/rust-lang/rust/pull/50104
         cfg.define("LLVM_ENABLE_LIBXML2", "OFF");
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 6826d177a4a..4cfcf6ca407 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -91,7 +91,7 @@ pub fn check(build: &mut Build) {
                 .unwrap_or(true)
         })
         .any(|build_llvm_ourselves| build_llvm_ourselves);
-    if building_llvm || build.config.sanitizers {
+    if building_llvm || build.config.any_sanitizers_enabled() {
         cmd_finder.must_have("cmake");
     }
 
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 2b87c4b91af..60808dcba61 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1271,11 +1271,11 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         cmd.env("RUSTC_BOOTSTRAP", "1");
         builder.add_rust_test_threads(&mut cmd);
 
-        if builder.config.sanitizers {
+        if builder.config.sanitizers_enabled(target) {
             cmd.env("RUSTC_SANITIZER_SUPPORT", "1");
         }
 
-        if builder.config.profiler {
+        if builder.config.profiler_enabled(target) {
             cmd.env("RUSTC_PROFILER_SUPPORT", "1");
         }
 
@@ -1591,7 +1591,7 @@ impl Step for CrateLibrustc {
         let builder = run.builder;
         let compiler = builder.compiler(builder.top_stage, run.build_triple());
 
-        for krate in builder.in_tree_crates("rustc-main") {
+        for krate in builder.in_tree_crates("rustc-main", Some(run.target)) {
             if krate.path.ends_with(&run.path) {
                 let test_kind = builder.kind.into();
 
@@ -1698,7 +1698,7 @@ impl Step for Crate {
             });
         };
 
-        for krate in builder.in_tree_crates("test") {
+        for krate in builder.in_tree_crates("test", Some(run.target)) {
             if krate.path.ends_with(&run.path) {
                 make(Mode::Std, krate);
             }
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 df65f9df441..95c54ca1abc 100644
--- a/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
@@ -35,6 +35,5 @@ ENV HOSTS=aarch64-unknown-linux-gnu
 ENV RUST_CONFIGURE_ARGS \
       --enable-full-tools \
       --enable-profiler \
-      --enable-sanitizers \
-      --disable-docs
+      --enable-sanitizers
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile
deleted file mode 100644
index 7db6e58c4d6..00000000000
--- a/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile
+++ /dev/null
@@ -1,34 +0,0 @@
-FROM ubuntu:18.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  clang \
-  make \
-  ninja-build \
-  file \
-  curl \
-  ca-certificates \
-  python3 \
-  git \
-  cmake \
-  sudo \
-  bzip2 \
-  xz-utils \
-  wget \
-  libssl-dev \
-  pkg-config
-
-COPY scripts/freebsd-toolchain.sh /tmp/
-RUN /tmp/freebsd-toolchain.sh i686
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-ENV \
-    AR_i686_unknown_freebsd=i686-unknown-freebsd11-ar \
-    CC_i686_unknown_freebsd=i686-unknown-freebsd11-clang \
-    CXX_i686_unknown_freebsd=i686-unknown-freebsd11-clang++
-
-ENV HOSTS=i686-unknown-freebsd
-
-ENV RUST_CONFIGURE_ARGS --enable-extended --enable-profiler --disable-docs
-ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index 47a66f74808..b8b81ab327b 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -48,6 +48,9 @@ ENV \
     CFLAGS_x86_64_fortanix_unknown_sgx="-mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
     CXX_x86_64_fortanix_unknown_sgx=x86_64-fortanix-unknown-sgx-clang++-11 \
     CXXFLAGS_x86_64_fortanix_unknown_sgx="-mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \
+    AR_i686_unknown_freebsd=i686-unknown-freebsd11-ar \
+    CC_i686_unknown_freebsd=i686-unknown-freebsd11-clang \
+    CXX_i686_unknown_freebsd=i686-unknown-freebsd11-clang++ \
     CC=gcc-7 \
     CXX=g++-7
 
@@ -74,6 +77,9 @@ RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh
 COPY host-x86_64/dist-various-2/build-wasi-toolchain.sh /tmp/
 RUN /tmp/build-wasi-toolchain.sh
 
+COPY scripts/freebsd-toolchain.sh /tmp/
+RUN /tmp/freebsd-toolchain.sh i686
+
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
@@ -99,6 +105,7 @@ ENV TARGETS=$TARGETS,x86_64-fortanix-unknown-sgx
 ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda
 ENV TARGETS=$TARGETS,armv7-unknown-linux-gnueabi
 ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabi
+ENV TARGETS=$TARGETS,i686-unknown-freebsd
 
 # As per https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1300211
 # we need asm in the search path for gcc-7 (for gnux32) but not in the search path of the
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 9d7461ebee3..fcf869b68be 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
@@ -29,7 +29,8 @@ mkdir ../gcc-build
 cd ../gcc-build
 hide_output ../gcc-$GCC/configure \
     --prefix=/rustroot \
-    --enable-languages=c,c++
+    --enable-languages=c,c++ \
+    --disable-gnu-unique-object
 hide_output make -j10
 hide_output make install
 ln -s gcc /rustroot/bin/cc
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 4cbb7b62cd6..031000d147c 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -301,6 +301,9 @@ jobs:
           #   Linux/Docker builders   #
           #############################
 
+          - name: aarch64-gnu
+            <<: *job-aarch64-linux
+
           - name: arm-android
             <<: *job-linux-xl
 
@@ -325,9 +328,6 @@ jobs:
           - name: dist-i586-gnu-i586-i686-musl
             <<: *job-linux-xl
 
-          - name: dist-i686-freebsd
-            <<: *job-linux-xl
-
           - name: dist-i686-linux
             <<: *job-linux-xl
 
@@ -635,23 +635,6 @@ jobs:
               SCRIPT: python x.py dist
             <<: *job-windows-xl
 
-  auto-fallible:
-    <<: *base-ci-job
-    name: auto-fallible
-    env:
-      <<: [*shared-ci-variables, *dummy-variables]
-    if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'
-    strategy:
-      fail-fast: false
-      matrix:
-        include:
-          #############################
-          #   Linux/Docker builders   #
-          #############################
-
-          - name: aarch64-gnu
-            <<: *job-aarch64-linux
-
   try:
     <<: *base-ci-job
     name: try
diff --git a/src/ci/scripts/should-skip-this.sh b/src/ci/scripts/should-skip-this.sh
index f945db0ada2..36bf4368990 100755
--- a/src/ci/scripts/should-skip-this.sh
+++ b/src/ci/scripts/should-skip-this.sh
@@ -14,6 +14,10 @@ elif git diff HEAD^ | grep --quiet "^index .* 160000"; then
     # Submodules pseudo-files inside git have the 160000 permissions, so when
     # those files are present in the diff a submodule was updated.
     echo "Executing the job since submodules are updated"
+elif git diff --name-only HEAD^ | grep --quiet src/tools/clippy; then
+    # There is not an easy blanket search for subtrees. For now, manually list
+    # clippy.
+    echo "Executing the job since clippy subtree was updated"
 else
     echo "Not executing this job since no submodules were updated"
     ciCommandSetEnv SKIP_JOB 1
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 85c6f91f085..215e5d3d104 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -34,6 +34,7 @@ Specifically they will each satisfy the following requirements:
 
 target | std | host | notes
 -------|-----|------|-------
+`aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17+) [^missing-stack-probes]
 `i686-pc-windows-gnu` | ✓ | ✓ | 32-bit MinGW (Windows 7+)
 `i686-pc-windows-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+)
 `i686-unknown-linux-gnu` | ✓ | ✓ | 32-bit Linux (kernel 2.6.32+, glibc 2.11+)
@@ -42,6 +43,12 @@ target | std | host | notes
 `x86_64-pc-windows-msvc` | ✓ | ✓ | 64-bit MSVC (Windows 7+)
 `x86_64-unknown-linux-gnu` | ✓ | ✓ | 64-bit Linux (kernel 2.6.32+, glibc 2.11+)
 
+[^missing-stack-probes]: Stack probes support is missing on
+  `aarch64-unknown-linux-gnu`, but it's planned to be implemented in the near
+  future. The implementation is tracked on [issue #77071][77071].
+
+[77071]: https://github.com/rust-lang/rust/issues/77071
+
 ## Tier 2
 
 Tier 2 platforms can be thought of as "guaranteed to build". Automated tests
@@ -62,7 +69,6 @@ target | std | host | notes
 `aarch64-fuchsia` | ✓ |  | ARM64 Fuchsia
 `aarch64-linux-android` | ✓ |  | ARM64 Android
 `aarch64-pc-windows-msvc` | ✓ | ✓ | ARM64 Windows MSVC
-`aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17)
 `aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL
 `aarch64-unknown-none` | * |  | Bare ARM64, hardfloat
 `aarch64-unknown-none-softfloat` | * |  | Bare ARM64, softfloat
@@ -88,7 +94,7 @@ target | std | host | notes
 `i586-unknown-linux-gnu` | ✓ |  | 32-bit Linux w/o SSE (kernel 4.4, glibc 2.23)
 `i586-unknown-linux-musl` | ✓ |  | 32-bit Linux w/o SSE, MUSL
 `i686-linux-android` | ✓ |  | 32-bit x86 Android
-`i686-unknown-freebsd` | ✓ | ✓ | 32-bit FreeBSD
+`i686-unknown-freebsd` | ✓ |  | 32-bit FreeBSD
 `i686-unknown-linux-musl` | ✓ |  | 32-bit Linux with MUSL
 `mips-unknown-linux-gnu` | ✓ | ✓ | MIPS Linux (kernel 4.4, glibc 2.23)
 `mips-unknown-linux-musl` | ✓ |  | MIPS Linux with MUSL
diff --git a/src/doc/unstable-book/src/language-features/cfg-panic.md b/src/doc/unstable-book/src/language-features/cfg-panic.md
new file mode 100644
index 00000000000..f5b73128ad6
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/cfg-panic.md
@@ -0,0 +1,38 @@
+# `cfg_panic`
+
+The tracking issue for this feature is: [#77443]
+
+[#77443]: https://github.com/rust-lang/rust/issues/77443
+
+------------------------
+
+The `cfg_panic` feature makes it possible to execute different code
+depending on the panic strategy.
+
+Possible values at the moment are `"unwind"` or `"abort"`, although
+it is possible that new panic strategies may be added to Rust in the
+future.
+
+## Examples
+
+```rust
+#![feature(cfg_panic)]
+
+#[cfg(panic = "unwind")]
+fn a() {
+    // ...
+}
+
+#[cfg(not(panic = "unwind"))]
+fn a() {
+    // ...
+}
+
+fn b() {
+    if cfg!(panic = "abort") {
+        // ...
+    } else {
+        // ...
+    }
+}
+```
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index bfc74705818..366548d5b5f 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -935,8 +935,7 @@ impl<'a> Clean<Arguments> for (&'a [hir::Ty<'a>], &'a [Ident]) {
                 .iter()
                 .enumerate()
                 .map(|(i, ty)| {
-                    let mut name =
-                        self.1.get(i).map(|ident| ident.to_string()).unwrap_or(String::new());
+                    let mut name = self.1.get(i).map(|ident| ident.to_string()).unwrap_or_default();
                     if name.is_empty() {
                         name = "_".to_string();
                     }
@@ -1967,10 +1966,15 @@ impl Clean<Span> for rustc_span::Span {
             return Span::empty();
         }
 
+        // Get the macro invocation instead of the definition,
+        // in case the span is result of a macro expansion.
+        // (See rust-lang/rust#39726)
+        let span = self.source_callsite();
+
         let sm = cx.sess().source_map();
-        let filename = sm.span_to_filename(*self);
-        let lo = sm.lookup_char_pos(self.lo());
-        let hi = sm.lookup_char_pos(self.hi());
+        let filename = sm.span_to_filename(span);
+        let lo = sm.lookup_char_pos(span.lo());
+        let hi = sm.lookup_char_pos(span.hi());
         Span {
             filename,
             cnum: lo.file.cnum,
@@ -1978,7 +1982,7 @@ impl Clean<Span> for rustc_span::Span {
             locol: lo.col.to_usize(),
             hiline: hi.line,
             hicol: hi.col.to_usize(),
-            original: *self,
+            original: span,
         }
     }
 }
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 5eca54199d6..4cad6418d6a 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -322,7 +322,8 @@ pub fn run_core(
     let cpath = Some(input.clone());
     let input = Input::File(input);
 
-    let intra_link_resolution_failure_name = lint::builtin::BROKEN_INTRA_DOC_LINKS.name;
+    let broken_intra_doc_links = lint::builtin::BROKEN_INTRA_DOC_LINKS.name;
+    let private_intra_doc_links = lint::builtin::PRIVATE_INTRA_DOC_LINKS.name;
     let missing_docs = rustc_lint::builtin::MISSING_DOCS.name;
     let missing_doc_example = rustc_lint::builtin::MISSING_DOC_CODE_EXAMPLES.name;
     let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name;
@@ -336,7 +337,8 @@ pub fn run_core(
     // In addition to those specific lints, we also need to allow those given through
     // command line, otherwise they'll get ignored and we don't want that.
     let lints_to_show = vec![
-        intra_link_resolution_failure_name.to_owned(),
+        broken_intra_doc_links.to_owned(),
+        private_intra_doc_links.to_owned(),
         missing_docs.to_owned(),
         missing_doc_example.to_owned(),
         private_doc_tests.to_owned(),
@@ -349,9 +351,8 @@ pub fn run_core(
     ];
 
     let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| {
-        if lint.name == intra_link_resolution_failure_name
-            || lint.name == invalid_codeblock_attributes_name
-        {
+        // FIXME: why is this necessary?
+        if lint.name == broken_intra_doc_links || lint.name == invalid_codeblock_attributes_name {
             None
         } else {
             Some((lint.name_lower(), lint::Allow))
diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs
index cf785d362cd..add28de17ed 100644
--- a/src/librustdoc/html/render/cache.rs
+++ b/src/librustdoc/html/render/cache.rs
@@ -128,7 +128,7 @@ pub fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
         .module
         .as_ref()
         .map(|module| shorten(plain_text_summary(module.doc_value())))
-        .unwrap_or(String::new());
+        .unwrap_or_default();
 
     #[derive(Serialize)]
     struct CrateData<'a> {
diff --git a/src/librustdoc/html/static/settings.css b/src/librustdoc/html/static/settings.css
index 4bacd7b245b..fb8990b30e2 100644
--- a/src/librustdoc/html/static/settings.css
+++ b/src/librustdoc/html/static/settings.css
@@ -26,7 +26,8 @@
 }
 
 .toggle input {
-	display: none;
+	opacity: 0;
+	position: absolute;
 }
 
 .select-wrapper {
@@ -90,7 +91,7 @@ input:checked + .slider {
 }
 
 input:focus + .slider {
-	box-shadow: 0 0 1px #2196F3;
+	box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
 }
 
 input:checked + .slider:before {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 8be9482acff..c9d4f51cbf3 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -1,3 +1,7 @@
+//! This module implements [RFC 1946]: Intra-rustdoc-links
+//!
+//! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md
+
 use rustc_ast as ast;
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_errors::{Applicability, DiagnosticBuilder};
@@ -27,7 +31,7 @@ use std::cell::Cell;
 use std::mem;
 use std::ops::Range;
 
-use crate::clean::*;
+use crate::clean::{self, Crate, GetDefId, Import, Item, ItemLink, PrimitiveType};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::html::markdown::markdown_links;
@@ -42,10 +46,10 @@ pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
 };
 
 pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate {
-    let mut coll = LinkCollector::new(cx);
-    coll.fold_crate(krate)
+    LinkCollector::new(cx).fold_crate(krate)
 }
 
+/// Top-level errors emitted by this pass.
 enum ErrorKind<'a> {
     Resolve(Box<ResolutionFailure<'a>>),
     AnchorFailure(AnchorFailure),
@@ -58,18 +62,37 @@ impl<'a> From<ResolutionFailure<'a>> for ErrorKind<'a> {
 }
 
 #[derive(Debug)]
+/// A link failed to resolve.
 enum ResolutionFailure<'a> {
     /// This resolved, but with the wrong namespace.
-    /// `Namespace` is the expected namespace (as opposed to the actual).
-    WrongNamespace(Res, Namespace),
+    ///
+    /// `Namespace` is the namespace specified with a disambiguator
+    /// (as opposed to the actual namespace of the `Res`).
+    WrongNamespace(Res, /* disambiguated */ Namespace),
     /// The link failed to resolve. `resolution_failure` should look to see if there's
     /// a more helpful error that can be given.
-    NotResolved { module_id: DefId, partial_res: Option<Res>, unresolved: Cow<'a, str> },
-    /// should not ever happen
+    NotResolved {
+        /// The scope the link was resolved in.
+        module_id: DefId,
+        /// If part of the link resolved, this has the `Res`.
+        ///
+        /// In `[std::io::Error::x]`, `std::io::Error` would be a partial resolution.
+        partial_res: Option<Res>,
+        /// The remaining unresolved path segments.
+        ///
+        /// In `[std::io::Error::x]`, `x` would be unresolved.
+        unresolved: Cow<'a, str>,
+    },
+    /// This happens when rustdoc can't determine the parent scope for an item.
+    ///
+    /// It is always a bug in rustdoc.
     NoParentItem,
     /// This link has malformed generic parameters; e.g., the angle brackets are unbalanced.
     MalformedGenerics(MalformedGenerics),
-    /// used to communicate that this should be ignored, but shouldn't be reported to the user
+    /// Used to communicate that this should be ignored, but shouldn't be reported to the user
+    ///
+    /// This happens when there is no disambiguator and one of the namespaces
+    /// failed to resolve.
     Dummy,
 }
 
@@ -115,7 +138,9 @@ enum MalformedGenerics {
 }
 
 impl ResolutionFailure<'a> {
-    // This resolved fully (not just partially) but is erroneous for some other reason
+    /// This resolved fully (not just partially) but is erroneous for some other reason
+    ///
+    /// Returns the full resolution of the link, if present.
     fn full_res(&self) -> Option<Res> {
         match self {
             Self::WrongNamespace(res, _) => Some(*res),
@@ -125,13 +150,30 @@ impl ResolutionFailure<'a> {
 }
 
 enum AnchorFailure {
+    /// User error: `[std#x#y]` is not valid
     MultipleAnchors,
+    /// The anchor provided by the user conflicts with Rustdoc's generated anchor.
+    ///
+    /// This is an unfortunate state of affairs. Not every item that can be
+    /// linked to has its own page; sometimes it is a subheading within a page,
+    /// like for associated items. In those cases, rustdoc uses an anchor to
+    /// link to the subheading. Since you can't have two anchors for the same
+    /// link, Rustdoc disallows having a user-specified anchor.
+    ///
+    /// Most of the time this is fine, because you can just link to the page of
+    /// the item if you want to provide your own anchor. For primitives, though,
+    /// rustdoc uses the anchor as a side channel to know which page to link to;
+    /// it doesn't show up in the generated link. Ideally, rustdoc would remove
+    /// this limitation, allowing you to link to subheaders on primitives.
     RustdocAnchorConflict(Res),
 }
 
 struct LinkCollector<'a, 'tcx> {
     cx: &'a DocContext<'tcx>,
-    // NOTE: this may not necessarily be a module in the current crate
+    /// A stack of modules used to decide what scope to resolve in.
+    ///
+    /// The last module will be used if the parent scope of the current item is
+    /// unknown.
     mod_ids: Vec<DefId>,
     /// This is used to store the kind of associated items,
     /// because `clean` and the disambiguator code expect them to be different.
@@ -144,6 +186,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         LinkCollector { cx, mod_ids: Vec::new(), kind_side_channel: Cell::new(None) }
     }
 
+    /// Given a full link, parse it as an [enum struct variant].
+    ///
+    /// In particular, this will return an error whenever there aren't three
+    /// full path segments left in the link.
+    ///
+    /// [enum struct variant]: hir::VariantData::Struct
     fn variant_field(
         &self,
         path_str: &'path str,
@@ -235,6 +283,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         }
     }
 
+    /// Given a primitive type, try to resolve an associated item.
+    ///
+    /// HACK(jynelson): `item_str` is passed in instead of derived from `item_name` so the
+    /// lifetimes on `&'path` will work.
     fn resolve_primitive_associated_item(
         &self,
         prim_ty: hir::PrimTy,
@@ -286,7 +338,9 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     }
 
     /// Resolves a string as a macro.
-    fn macro_resolve(
+    ///
+    /// FIXME(jynelson): Can this be unified with `resolve()`?
+    fn resolve_macro(
         &self,
         path_str: &'a str,
         module_id: DefId,
@@ -294,6 +348,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         let cx = self.cx;
         let path = ast::Path::from_ident(Ident::from_str(path_str));
         cx.enter_resolver(|resolver| {
+            // FIXME(jynelson): does this really need 3 separate lookups?
             if let Ok((Some(ext), res)) = resolver.resolve_macro_path(
                 &path,
                 None,
@@ -326,6 +381,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         })
     }
 
+    /// Convenience wrapper around `resolve_str_path_error`.
+    ///
+    /// This also handles resolving `true` and `false` as booleans.
+    /// NOTE: `resolve_str_path_error` knows only about paths, not about types.
+    /// Associated items will never be resolved by this function.
     fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option<Res> {
         let result = self.cx.enter_resolver(|resolver| {
             resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
@@ -339,12 +399,13 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         }
     }
 
-    /// Resolves a string as a path within a particular namespace. Also returns an optional
-    /// URL fragment in the case of variants and methods.
+    /// Resolves a string as a path within a particular namespace. Returns an
+    /// optional URL fragment in the case of variants and methods.
     fn resolve<'path>(
         &self,
         path_str: &'path str,
         ns: Namespace,
+        // FIXME(#76467): This is for `Self`, and it's wrong.
         current_item: &Option<String>,
         module_id: DefId,
         extra_fragment: &Option<String>,
@@ -353,15 +414,13 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
 
         if let Some(res) = self.resolve_path(path_str, ns, module_id) {
             match res {
+                // FIXME(#76467): make this fallthrough to lookup the associated
+                // item a separate function.
                 Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => {
                     assert_eq!(ns, ValueNS);
-                    // Fall through: In case this is a trait item, skip the
-                    // early return and try looking for the trait.
                 }
                 Res::Def(DefKind::AssocTy, _) => {
                     assert_eq!(ns, TypeNS);
-                    // Fall through: In case this is a trait item, skip the
-                    // early return and try looking for the trait.
                 }
                 Res::Def(DefKind::Variant, _) => {
                     return handle_variant(cx, res, extra_fragment);
@@ -410,7 +469,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
             })?;
 
         // FIXME: are these both necessary?
-        let ty_res = if let Some(ty_res) = is_primitive(&path_root, TypeNS)
+        let ty_res = if let Some(ty_res) = resolve_primitive(&path_root, TypeNS)
             .map(|(_, res)| res)
             .or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
         {
@@ -452,8 +511,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     // There should only ever be one associated item that matches from any inherent impl
                     .next()
                     // Check if item_name belongs to `impl SomeTrait for SomeItem`
-                    // This gives precedence to `impl SomeItem`:
-                    // Although having both would be ambiguous, use impl version for compat. sake.
+                    // FIXME(#74563): This gives precedence to `impl SomeItem`:
+                    // Although having both would be ambiguous, use impl version for compatibility's sake.
                     // To handle that properly resolve() would have to support
                     // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
                     .or_else(|| {
@@ -480,6 +539,8 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     })
                 } else if ns == Namespace::ValueNS {
                     debug!("looking for variants or fields named {} for {:?}", item_name, did);
+                    // FIXME(jynelson): why is this different from
+                    // `variant_field`?
                     match cx.tcx.type_of(did).kind() {
                         ty::Adt(def, _) => {
                             let field = if def.is_enum() {
@@ -577,7 +638,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     ) -> Option<Res> {
         // resolve() can't be used for macro namespace
         let result = match ns {
-            Namespace::MacroNS => self.macro_resolve(path_str, module_id).map_err(ErrorKind::from),
+            Namespace::MacroNS => self.resolve_macro(path_str, module_id).map_err(ErrorKind::from),
             Namespace::TypeNS | Namespace::ValueNS => self
                 .resolve(path_str, ns, current_item, module_id, extra_fragment)
                 .map(|(res, _)| res),
@@ -593,6 +654,11 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     }
 }
 
+/// Look to see if a resolved item has an associated item named `item_name`.
+///
+/// Given `[std::io::Error::source]`, where `source` is unresolved, this would
+/// find `std::error::Error::source` and return
+/// `<io::Error as error::Error>::source`.
 fn resolve_associated_trait_item(
     did: DefId,
     module: DefId,
@@ -601,12 +667,12 @@ fn resolve_associated_trait_item(
     cx: &DocContext<'_>,
 ) -> Option<(ty::AssocKind, DefId)> {
     let ty = cx.tcx.type_of(did);
-    // First consider automatic impls: `impl From<T> for T`
+    // First consider blanket impls: `impl From<T> for T`
     let implicit_impls = crate::clean::get_auto_trait_and_blanket_impls(cx, ty, did);
     let mut candidates: Vec<_> = implicit_impls
         .flat_map(|impl_outer| {
             match impl_outer.inner {
-                ImplItem(impl_) => {
+                clean::ImplItem(impl_) => {
                     debug!("considering auto or blanket impl for trait {:?}", impl_.trait_);
                     // Give precedence to methods that were overridden
                     if !impl_.provided_trait_methods.contains(&*item_name.as_str()) {
@@ -669,7 +735,7 @@ fn resolve_associated_trait_item(
                 .map(|assoc| (assoc.kind, assoc.def_id))
         }));
     }
-    // FIXME: warn about ambiguity
+    // FIXME(#74563): warn about ambiguity
     debug!("the candidates were {:?}", candidates);
     candidates.pop()
 }
@@ -719,20 +785,15 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx
     iter.collect()
 }
 
-/// Check for resolve collisions between a trait and its derive
+/// Check for resolve collisions between a trait and its derive.
 ///
-/// These are common and we should just resolve to the trait in that case
+/// These are common and we should just resolve to the trait in that case.
 fn is_derive_trait_collision<T>(ns: &PerNS<Result<(Res, T), ResolutionFailure<'_>>>) -> bool {
-    if let PerNS {
+    matches!(*ns, PerNS {
         type_ns: Ok((Res::Def(DefKind::Trait, _), _)),
         macro_ns: Ok((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)),
         ..
-    } = *ns
-    {
-        true
-    } else {
-        false
-    }
+    })
 }
 
 impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
@@ -772,29 +833,30 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
         }
 
         let current_item = match item.inner {
-            ModuleItem(..) => {
+            clean::ModuleItem(..) => {
                 if item.attrs.inner_docs {
                     if item.def_id.is_top_level_module() { item.name.clone() } else { None }
                 } else {
                     match parent_node.or(self.mod_ids.last().copied()) {
                         Some(parent) if !parent.is_top_level_module() => {
-                            // FIXME: can we pull the parent module's name from elsewhere?
                             Some(self.cx.tcx.item_name(parent).to_string())
                         }
                         _ => None,
                     }
                 }
             }
-            ImplItem(Impl { ref for_, .. }) => {
+            clean::ImplItem(clean::Impl { ref for_, .. }) => {
                 for_.def_id().map(|did| self.cx.tcx.item_name(did).to_string())
             }
             // we don't display docs on `extern crate` items anyway, so don't process them.
-            ExternCrateItem(..) => {
+            clean::ExternCrateItem(..) => {
                 debug!("ignoring extern crate item {:?}", item.def_id);
                 return self.fold_item_recur(item);
             }
-            ImportItem(Import { kind: ImportKind::Simple(ref name, ..), .. }) => Some(name.clone()),
-            MacroItem(..) => None,
+            clean::ImportItem(Import { kind: clean::ImportKind::Simple(ref name, ..), .. }) => {
+                Some(name.clone())
+            }
+            clean::MacroItem(..) => None,
             _ => item.name.clone(),
         };
 
@@ -803,6 +865,8 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
         }
 
         // find item's parent to resolve `Self` in item's docs below
+        // FIXME(#76467, #75809): this is a mess and doesn't handle cross-crate
+        // re-exports
         let parent_name = self.cx.as_local_hir_id(item.def_id).and_then(|item_hir| {
             let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir);
             let item_parent = self.cx.tcx.hir().find(parent_hir);
@@ -870,7 +934,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
             };
             // NOTE: if there are links that start in one crate and end in another, this will not resolve them.
             // This is a degenerate case and it's not supported by rustdoc.
-            // FIXME: this will break links that start in `#[doc = ...]` and end as a sugared doc. Should this be supported?
             for (ori_link, link_range) in markdown_links(&combined_docs) {
                 let link = self.resolve_link(
                     &item,
@@ -888,15 +951,13 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
             }
         }
 
-        if item.is_mod() && !item.attrs.inner_docs {
-            self.mod_ids.push(item.def_id);
-        }
-
         if item.is_mod() {
-            let ret = self.fold_item_recur(item);
+            if !item.attrs.inner_docs {
+                self.mod_ids.push(item.def_id);
+            }
 
+            let ret = self.fold_item_recur(item);
             self.mod_ids.pop();
-
             ret
         } else {
             self.fold_item_recur(item)
@@ -905,6 +966,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
 }
 
 impl LinkCollector<'_, '_> {
+    /// This is the entry point for resolving an intra-doc link.
+    ///
+    /// FIXME(jynelson): this is way too many arguments
     fn resolve_link(
         &self,
         item: &Item,
@@ -943,129 +1007,120 @@ impl LinkCollector<'_, '_> {
         } else {
             (parts[0], None)
         };
-        let resolved_self;
-        let link_text;
-        let mut path_str;
-        let disambiguator;
-        let stripped_path_string;
-        let (mut res, mut fragment) = {
-            path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) {
-                disambiguator = Some(d);
-                path
-            } else {
-                disambiguator = None;
-                &link
-            }
-            .trim();
 
-            if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, ".contains(ch))) {
-                return None;
-            }
+        // Parse and strip the disambiguator from the link, if present.
+        let (mut path_str, disambiguator) = if let Ok((d, path)) = Disambiguator::from_str(&link) {
+            (path.trim(), Some(d))
+        } else {
+            (link.trim(), None)
+        };
 
-            // We stripped `()` and `!` when parsing the disambiguator.
-            // Add them back to be displayed, but not prefix disambiguators.
-            link_text = disambiguator
-                .map(|d| d.display_for(path_str))
-                .unwrap_or_else(|| path_str.to_owned());
-
-            // In order to correctly resolve intra-doc-links we need to
-            // pick a base AST node to work from.  If the documentation for
-            // this module came from an inner comment (//!) then we anchor
-            // our name resolution *inside* the module.  If, on the other
-            // hand it was an outer comment (///) then we anchor the name
-            // resolution in the parent module on the basis that the names
-            // used are more likely to be intended to be parent names.  For
-            // this, we set base_node to None for inner comments since
-            // we've already pushed this node onto the resolution stack but
-            // for outer comments we explicitly try and resolve against the
-            // parent_node first.
-            let base_node = if item.is_mod() && item.attrs.inner_docs {
-                self.mod_ids.last().copied()
-            } else {
-                parent_node
-            };
+        if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, ".contains(ch))) {
+            return None;
+        }
 
-            let mut module_id = if let Some(id) = base_node {
-                id
-            } else {
-                debug!("attempting to resolve item without parent module: {}", path_str);
-                let err_kind = ResolutionFailure::NoParentItem.into();
-                resolution_failure(
-                    self,
-                    &item,
-                    path_str,
-                    disambiguator,
-                    dox,
-                    link_range,
-                    smallvec![err_kind],
-                );
-                return None;
-            };
+        // We stripped `()` and `!` when parsing the disambiguator.
+        // Add them back to be displayed, but not prefix disambiguators.
+        let link_text =
+            disambiguator.map(|d| d.display_for(path_str)).unwrap_or_else(|| path_str.to_owned());
+
+        // In order to correctly resolve intra-doc-links we need to
+        // pick a base AST node to work from.  If the documentation for
+        // this module came from an inner comment (//!) then we anchor
+        // our name resolution *inside* the module.  If, on the other
+        // hand it was an outer comment (///) then we anchor the name
+        // resolution in the parent module on the basis that the names
+        // used are more likely to be intended to be parent names.  For
+        // this, we set base_node to None for inner comments since
+        // we've already pushed this node onto the resolution stack but
+        // for outer comments we explicitly try and resolve against the
+        // parent_node first.
+        let base_node = if item.is_mod() && item.attrs.inner_docs {
+            self.mod_ids.last().copied()
+        } else {
+            parent_node
+        };
 
-            // replace `Self` with suitable item's parent name
-            if path_str.starts_with("Self::") {
-                if let Some(ref name) = parent_name {
-                    resolved_self = format!("{}::{}", name, &path_str[6..]);
-                    path_str = &resolved_self;
-                }
-            } else if path_str.starts_with("crate::") {
-                use rustc_span::def_id::CRATE_DEF_INDEX;
-
-                // HACK(jynelson): rustc_resolve thinks that `crate` is the crate currently being documented.
-                // But rustdoc wants it to mean the crate this item was originally present in.
-                // To work around this, remove it and resolve relative to the crate root instead.
-                // HACK(jynelson)(2): If we just strip `crate::` then suddenly primitives become ambiguous
-                // (consider `crate::char`). Instead, change it to `self::`. This works because 'self' is now the crate root.
-                resolved_self = format!("self::{}", &path_str["crate::".len()..]);
-                path_str = &resolved_self;
-                module_id = DefId { krate, index: CRATE_DEF_INDEX };
-            }
+        let mut module_id = if let Some(id) = base_node {
+            id
+        } else {
+            // This is a bug.
+            debug!("attempting to resolve item without parent module: {}", path_str);
+            let err_kind = ResolutionFailure::NoParentItem.into();
+            resolution_failure(
+                self,
+                &item,
+                path_str,
+                disambiguator,
+                dox,
+                link_range,
+                smallvec![err_kind],
+            );
+            return None;
+        };
 
-            // Strip generics from the path.
-            if path_str.contains(['<', '>'].as_slice()) {
-                stripped_path_string = match strip_generics_from_path(path_str) {
-                    Ok(path) => path,
-                    Err(err_kind) => {
-                        debug!("link has malformed generics: {}", path_str);
-                        resolution_failure(
-                            self,
-                            &item,
-                            path_str,
-                            disambiguator,
-                            dox,
-                            link_range,
-                            smallvec![err_kind],
-                        );
-                        return None;
-                    }
-                };
-                path_str = &stripped_path_string;
+        let resolved_self;
+        // replace `Self` with suitable item's parent name
+        if path_str.starts_with("Self::") {
+            if let Some(ref name) = parent_name {
+                resolved_self = format!("{}::{}", name, &path_str[6..]);
+                path_str = &resolved_self;
             }
+        } else if path_str.starts_with("crate::") {
+            use rustc_span::def_id::CRATE_DEF_INDEX;
+
+            // HACK(jynelson): rustc_resolve thinks that `crate` is the crate currently being documented.
+            // But rustdoc wants it to mean the crate this item was originally present in.
+            // To work around this, remove it and resolve relative to the crate root instead.
+            // HACK(jynelson)(2): If we just strip `crate::` then suddenly primitives become ambiguous
+            // (consider `crate::char`). Instead, change it to `self::`. This works because 'self' is now the crate root.
+            // FIXME(#78696): This doesn't always work.
+            resolved_self = format!("self::{}", &path_str["crate::".len()..]);
+            path_str = &resolved_self;
+            module_id = DefId { krate, index: CRATE_DEF_INDEX };
+        }
 
-            // Sanity check to make sure we don't have any angle brackets after stripping generics.
-            assert!(!path_str.contains(['<', '>'].as_slice()));
+        // Strip generics from the path.
+        let stripped_path_string;
+        if path_str.contains(['<', '>'].as_slice()) {
+            stripped_path_string = match strip_generics_from_path(path_str) {
+                Ok(path) => path,
+                Err(err_kind) => {
+                    debug!("link has malformed generics: {}", path_str);
+                    resolution_failure(
+                        self,
+                        &item,
+                        path_str,
+                        disambiguator,
+                        dox,
+                        link_range,
+                        smallvec![err_kind],
+                    );
+                    return None;
+                }
+            };
+            path_str = &stripped_path_string;
+        }
+        // Sanity check to make sure we don't have any angle brackets after stripping generics.
+        assert!(!path_str.contains(['<', '>'].as_slice()));
 
-            // The link is not an intra-doc link if it still contains commas or spaces after
-            // stripping generics.
-            if path_str.contains([',', ' '].as_slice()) {
-                return None;
-            }
+        // The link is not an intra-doc link if it still contains commas or spaces after
+        // stripping generics.
+        if path_str.contains([',', ' '].as_slice()) {
+            return None;
+        }
 
-            match self.resolve_with_disambiguator(
-                disambiguator,
-                item,
-                dox,
-                path_str,
-                current_item,
-                module_id,
-                extra_fragment,
-                &ori_link,
-                link_range.clone(),
-            ) {
-                Some(x) => x,
-                None => return None,
-            }
-        };
+        let (mut res, mut fragment) = self.resolve_with_disambiguator(
+            disambiguator,
+            item,
+            dox,
+            path_str,
+            current_item,
+            module_id,
+            extra_fragment,
+            &ori_link,
+            link_range.clone(),
+        )?;
 
         // Check for a primitive which might conflict with a module
         // Report the ambiguity and require that the user specify which one they meant.
@@ -1075,7 +1130,7 @@ impl LinkCollector<'_, '_> {
             None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive)
         ) && !matches!(res, Res::PrimTy(_))
         {
-            if let Some((path, prim)) = is_primitive(path_str, TypeNS) {
+            if let Some((path, prim)) = resolve_primitive(path_str, TypeNS) {
                 // `prim@char`
                 if matches!(disambiguator, Some(Disambiguator::Primitive)) {
                     if fragment.is_some() {
@@ -1168,11 +1223,13 @@ impl LinkCollector<'_, '_> {
                     privacy_error(cx, &item, &path_str, dox, link_range);
                 }
             }
-            let id = register_res(cx, res);
+            let id = clean::register_res(cx, res);
             Some(ItemLink { link: ori_link, link_text, did: Some(id), fragment })
         }
     }
 
+    /// After parsing the disambiguator, resolve the main part of the link.
+    // FIXME(jynelson): wow this is just so much
     fn resolve_with_disambiguator(
         &self,
         disambiguator: Option<Disambiguator>,
@@ -1232,7 +1289,7 @@ impl LinkCollector<'_, '_> {
                 // Try everything!
                 let mut candidates = PerNS {
                     macro_ns: self
-                        .macro_resolve(path_str, base_node)
+                        .resolve_macro(path_str, base_node)
                         .map(|res| (res, extra_fragment.clone())),
                     type_ns: match self.resolve(
                         path_str,
@@ -1320,10 +1377,10 @@ impl LinkCollector<'_, '_> {
                 }
             }
             Some(MacroNS) => {
-                match self.macro_resolve(path_str, base_node) {
+                match self.resolve_macro(path_str, base_node) {
                     Ok(res) => Some((res, extra_fragment)),
                     Err(mut kind) => {
-                        // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible.
+                        // `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
                         for &ns in &[TypeNS, ValueNS] {
                             if let Some(res) = self.check_full_res(
                                 ns,
@@ -1354,9 +1411,15 @@ impl LinkCollector<'_, '_> {
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+/// Disambiguators for a link.
 enum Disambiguator {
+    /// `prim@`
+    ///
+    /// This is buggy, see <https://github.com/rust-lang/rust/pull/77875#discussion_r503583103>
     Primitive,
+    /// `struct@` or `f()`
     Kind(DefKind),
+    /// `type@`
     Namespace(Namespace),
 }
 
@@ -1373,7 +1436,7 @@ impl Disambiguator {
         }
     }
 
-    /// (disambiguator, path_str)
+    /// Given a link, parse and return `(disambiguator, path_str)`
     fn from_str(link: &str) -> Result<(Self, &str), ()> {
         use Disambiguator::{Kind, Namespace as NS, Primitive};
 
@@ -1424,6 +1487,7 @@ impl Disambiguator {
         }
     }
 
+    /// Used for error reporting.
     fn suggestion(self) -> Suggestion {
         let kind = match self {
             Disambiguator::Primitive => return Suggestion::Prefix("prim"),
@@ -1490,9 +1554,13 @@ impl Disambiguator {
     }
 }
 
+/// A suggestion to show in a diagnostic.
 enum Suggestion {
+    /// `struct@`
     Prefix(&'static str),
+    /// `f()`
     Function,
+    /// `m!`
     Macro,
 }
 
@@ -1582,6 +1650,11 @@ fn report_diagnostic(
     });
 }
 
+/// Reports a link that failed to resolve.
+///
+/// This also tries to resolve any intermediate path segments that weren't
+/// handled earlier. For example, if passed `Item::Crate(std)` and `path_str`
+/// `std::io::Error::x`, this will resolve `std::io::Error`.
 fn resolution_failure(
     collector: &LinkCollector<'_, '_>,
     item: &Item,
@@ -1816,6 +1889,7 @@ fn resolution_failure(
     );
 }
 
+/// Report an anchor failure.
 fn anchor_failure(
     cx: &DocContext<'_>,
     item: &Item,
@@ -1840,6 +1914,7 @@ fn anchor_failure(
     });
 }
 
+/// Report an ambiguity error, where there were multiple possible resolutions.
 fn ambiguity_error(
     cx: &DocContext<'_>,
     item: &Item,
@@ -1886,6 +1961,8 @@ fn ambiguity_error(
     });
 }
 
+/// In case of an ambiguity or mismatched disambiguator, suggest the correct
+/// disambiguator.
 fn suggest_disambiguator(
     disambiguator: Disambiguator,
     diag: &mut DiagnosticBuilder<'_>,
@@ -1911,6 +1988,7 @@ fn suggest_disambiguator(
     }
 }
 
+/// Report a link from a public item to a private one.
 fn privacy_error(
     cx: &DocContext<'_>,
     item: &Item,
@@ -1978,7 +2056,8 @@ const PRIMITIVES: &[(Symbol, Res)] = &[
     (sym::char, Res::PrimTy(hir::PrimTy::Char)),
 ];
 
-fn is_primitive(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> {
+/// Resolve a primitive type or value.
+fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> {
     is_bool_value(path_str, ns).or_else(|| {
         if ns == TypeNS {
             // FIXME: this should be replaced by a lookup in PrimitiveTypeTable
@@ -1990,6 +2069,7 @@ fn is_primitive(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> {
     })
 }
 
+/// Resolve a primitive value.
 fn is_bool_value(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> {
     if ns == TypeNS && (path_str == "true" || path_str == "false") {
         Some((sym::bool, Res::PrimTy(hir::PrimTy::Bool)))
diff --git a/src/test/mir-opt/inline/inline-cycle.rs b/src/test/mir-opt/inline/inline-cycle.rs
new file mode 100644
index 00000000000..63ad57de1d4
--- /dev/null
+++ b/src/test/mir-opt/inline/inline-cycle.rs
@@ -0,0 +1,60 @@
+// Check that inliner handles various forms of recursion and doesn't fall into
+// an infinite inlining cycle. The particular outcome of inlining is not
+// crucial otherwise.
+//
+// Regression test for issue #78573.
+
+fn main() {
+    one();
+    two();
+}
+
+// EMIT_MIR inline_cycle.one.Inline.diff
+fn one() {
+    <C as Call>::call();
+}
+
+pub trait Call {
+    fn call();
+}
+
+pub struct A<T>(T);
+pub struct B<T>(T);
+pub struct C;
+
+impl<T: Call> Call for A<T> {
+    #[inline]
+    fn call() {
+        <B<T> as Call>::call()
+    }
+}
+
+
+impl<T: Call> Call for B<T> {
+    #[inline]
+    fn call() {
+        <T as Call>::call()
+    }
+}
+
+impl Call for C {
+    #[inline]
+    fn call() {
+        A::<C>::call()
+    }
+}
+
+// EMIT_MIR inline_cycle.two.Inline.diff
+fn two() {
+    call(f);
+}
+
+#[inline]
+fn call<F: FnOnce()>(f: F) {
+    f();
+}
+
+#[inline]
+fn f() {
+    call(f);
+}
diff --git a/src/test/mir-opt/inline/inline-diverging.rs b/src/test/mir-opt/inline/inline-diverging.rs
new file mode 100644
index 00000000000..ae6f814c290
--- /dev/null
+++ b/src/test/mir-opt/inline/inline-diverging.rs
@@ -0,0 +1,40 @@
+// Tests inlining of diverging calls.
+//
+// ignore-wasm32-bare compiled with panic=abort by default
+#![crate_type = "lib"]
+
+// EMIT_MIR inline_diverging.f.Inline.diff
+pub fn f() {
+    sleep();
+}
+
+// EMIT_MIR inline_diverging.g.Inline.diff
+pub fn g(i: i32) -> u32 {
+    if i > 0 {
+        i as u32
+    } else {
+        panic();
+    }
+}
+
+// EMIT_MIR inline_diverging.h.Inline.diff
+pub fn h() {
+    call_twice(sleep);
+}
+
+#[inline(always)]
+pub fn call_twice<R, F: Fn() -> R>(f: F) -> (R, R) {
+    let a = f();
+    let b = f();
+    (a, b)
+}
+
+#[inline(always)]
+fn panic() -> ! {
+    panic!();
+}
+
+#[inline(always)]
+fn sleep() -> ! {
+    loop {}
+}
diff --git a/src/test/mir-opt/inline/inline-options.rs b/src/test/mir-opt/inline/inline-options.rs
new file mode 100644
index 00000000000..477f050b69e
--- /dev/null
+++ b/src/test/mir-opt/inline/inline-options.rs
@@ -0,0 +1,19 @@
+// Checks that inlining threshold can be controlled with
+// inline-mir-threshold and inline-hint-threshold options.
+//
+// compile-flags: -Zinline-mir-threshold=90
+// compile-flags: -Zinline-mir-hint-threshold=50
+
+// EMIT_MIR inline_options.main.Inline.after.mir
+fn main() {
+    not_inlined();
+    inlined::<u32>();
+}
+
+// Cost is approximately 3 * 25 + 5 = 80.
+#[inline]
+pub fn not_inlined() { g(); g(); g(); }
+pub fn inlined<T>() { g(); g(); g(); }
+
+#[inline(never)]
+fn g() {}
diff --git a/src/test/mir-opt/inline/inline-shims.rs b/src/test/mir-opt/inline/inline-shims.rs
new file mode 100644
index 00000000000..7c8618f71e5
--- /dev/null
+++ b/src/test/mir-opt/inline/inline-shims.rs
@@ -0,0 +1,13 @@
+// ignore-wasm32-bare compiled with panic=abort by default
+#![crate_type = "lib"]
+
+// EMIT_MIR inline_shims.clone.Inline.diff
+pub fn clone<A, B>(f: fn(A, B)) -> fn(A, B) {
+    f.clone()
+}
+
+// EMIT_MIR inline_shims.drop.Inline.diff
+pub fn drop<A, B>(a: *mut Vec<A>, b: *mut Option<B>) {
+    unsafe { std::ptr::drop_in_place(a) }
+    unsafe { std::ptr::drop_in_place(b) }
+}
diff --git a/src/test/mir-opt/inline/inline_cycle.one.Inline.diff b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff
new file mode 100644
index 00000000000..1b53c827885
--- /dev/null
+++ b/src/test/mir-opt/inline/inline_cycle.one.Inline.diff
@@ -0,0 +1,27 @@
+- // MIR for `one` before Inline
++ // MIR for `one` after Inline
+  
+  fn one() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/inline-cycle.rs:13:10: 13:10
+      let _1: ();                          // in scope 0 at $DIR/inline-cycle.rs:14:5: 14:24
++     scope 1 (inlined <C as Call>::call) { // at $DIR/inline-cycle.rs:14:5: 14:24
++     }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/inline-cycle.rs:14:5: 14:24
+-         _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle.rs:14:5: 14:24
++         _1 = <A<C> as Call>::call() -> bb1; // scope 1 at $DIR/inline-cycle.rs:14:5: 14:24
+                                           // mir::Constant
+-                                          // + span: $DIR/inline-cycle.rs:14:5: 14:22
+-                                          // + literal: Const { ty: fn() {<C as Call>::call}, val: Value(Scalar(<ZST>)) }
++                                          // + span: $DIR/inline-cycle.rs:14:5: 14:24
++                                          // + literal: Const { ty: fn() {<A<C> as Call>::call}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_1);                 // scope 0 at $DIR/inline-cycle.rs:14:24: 14:25
+          _0 = const ();                   // scope 0 at $DIR/inline-cycle.rs:13:10: 15:2
+          return;                          // scope 0 at $DIR/inline-cycle.rs:15:2: 15: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
new file mode 100644
index 00000000000..b44baca9bf4
--- /dev/null
+++ b/src/test/mir-opt/inline/inline_cycle.two.Inline.diff
@@ -0,0 +1,47 @@
+- // MIR for `two` before Inline
++ // MIR for `two` after Inline
+  
+  fn two() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/inline-cycle.rs:48:10: 48:10
+      let _1: ();                          // in scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
++     let mut _2: fn() {f};                // in scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
++     let mut _5: ();                      // in scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
++     scope 1 (inlined call::<fn() {f}>) { // at $DIR/inline-cycle.rs:49:5: 49:12
++         debug f => _2;                   // in scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
++         let _3: ();                      // in scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
++         let mut _4: fn() {f};            // in scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
++         scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline-cycle.rs:49:5: 49:12
++         }
++     }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
+-         _1 = call::<fn() {f}>(f) -> bb1; // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
++         StorageLive(_2);                 // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
++         _2 = f;                          // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
+                                           // mir::Constant
+-                                          // + span: $DIR/inline-cycle.rs:49:5: 49:9
+-                                          // + literal: Const { ty: fn(fn() {f}) {call::<fn() {f}>}, val: Value(Scalar(<ZST>)) }
+-                                          // mir::Constant
+                                           // + span: $DIR/inline-cycle.rs:49:10: 49:11
+                                           // + literal: Const { ty: fn() {f}, val: Value(Scalar(<ZST>)) }
++         StorageLive(_3);                 // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
++         StorageLive(_4);                 // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
++         _4 = move _2;                    // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
++         StorageLive(_5);                 // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
++         _5 = const ();                   // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
++         _3 = move _4() -> bb1;           // scope 2 at $DIR/inline-cycle.rs:49:5: 49:12
+      }
+  
+      bb1: {
++         StorageDead(_5);                 // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
++         StorageDead(_4);                 // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
++         StorageDead(_3);                 // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
++         _1 = const ();                   // scope 1 at $DIR/inline-cycle.rs:49:5: 49:12
++         StorageDead(_2);                 // scope 0 at $DIR/inline-cycle.rs:49:5: 49:12
+          StorageDead(_1);                 // scope 0 at $DIR/inline-cycle.rs:49:12: 49:13
+          _0 = const ();                   // scope 0 at $DIR/inline-cycle.rs:48:10: 50:2
+          return;                          // scope 0 at $DIR/inline-cycle.rs:50:2: 50: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
new file mode 100644
index 00000000000..6e36dc06a20
--- /dev/null
+++ b/src/test/mir-opt/inline/inline_diverging.f.Inline.diff
@@ -0,0 +1,26 @@
+- // MIR for `f` before Inline
++ // MIR for `f` after Inline
+  
+  fn f() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/inline-diverging.rs:7:12: 7:12
+      let mut _1: !;                       // in scope 0 at $DIR/inline-diverging.rs:7:12: 9:2
+      let _2: !;                           // in scope 0 at $DIR/inline-diverging.rs:8:5: 8:12
++     let mut _3: !;                       // in scope 0 at $DIR/inline-diverging.rs:8:5: 8:12
++     scope 1 (inlined sleep) {            // at $DIR/inline-diverging.rs:8:5: 8:12
++     }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/inline-diverging.rs:8:5: 8:12
+-         sleep();                         // scope 0 at $DIR/inline-diverging.rs:8:5: 8:12
+-                                          // mir::Constant
+-                                          // + span: $DIR/inline-diverging.rs:8:5: 8:10
+-                                          // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar(<ZST>)) }
++         StorageLive(_3);                 // scope 0 at $DIR/inline-diverging.rs:8:5: 8:12
++         goto -> bb1;                     // scope 0 at $DIR/inline-diverging.rs:8:5: 8:12
++     }
++ 
++     bb1: {
++         goto -> bb1;                     // scope 1 at $DIR/inline-diverging.rs:8:5: 8:12
+      }
+  }
+  
diff --git a/src/test/mir-opt/inline/inline_diverging.g.Inline.diff b/src/test/mir-opt/inline/inline_diverging.g.Inline.diff
new file mode 100644
index 00000000000..3dc33354a5a
--- /dev/null
+++ b/src/test/mir-opt/inline/inline_diverging.g.Inline.diff
@@ -0,0 +1,52 @@
+- // MIR for `g` before Inline
++ // MIR for `g` after Inline
+  
+  fn g(_1: i32) -> u32 {
+      debug i => _1;                       // in scope 0 at $DIR/inline-diverging.rs:12:10: 12:11
+      let mut _0: u32;                     // return place in scope 0 at $DIR/inline-diverging.rs:12:21: 12:24
+      let mut _2: bool;                    // in scope 0 at $DIR/inline-diverging.rs:13:8: 13:13
+      let mut _3: i32;                     // in scope 0 at $DIR/inline-diverging.rs:13:8: 13:9
+      let mut _4: i32;                     // in scope 0 at $DIR/inline-diverging.rs:14:9: 14:10
+      let mut _5: !;                       // in scope 0 at $DIR/inline-diverging.rs:15:12: 17:6
+      let _6: !;                           // in scope 0 at $DIR/inline-diverging.rs:16:9: 16:16
++     let mut _7: !;                       // in scope 0 at $DIR/inline-diverging.rs:16:9: 16:16
++     scope 1 (inlined panic) {            // at $DIR/inline-diverging.rs:16:9: 16:16
++     }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/inline-diverging.rs:13:8: 13:13
+          StorageLive(_3);                 // scope 0 at $DIR/inline-diverging.rs:13:8: 13:9
+          _3 = _1;                         // scope 0 at $DIR/inline-diverging.rs:13:8: 13:9
+          _2 = Gt(move _3, const 0_i32);   // scope 0 at $DIR/inline-diverging.rs:13:8: 13:13
+          StorageDead(_3);                 // scope 0 at $DIR/inline-diverging.rs:13:12: 13:13
+          switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/inline-diverging.rs:13:5: 17:6
+      }
+  
+      bb1: {
+          StorageLive(_6);                 // scope 0 at $DIR/inline-diverging.rs:16:9: 16:16
+-         panic();                         // scope 0 at $DIR/inline-diverging.rs:16:9: 16:16
++         StorageLive(_7);                 // scope 0 at $DIR/inline-diverging.rs:16:9: 16:16
++         begin_panic::<&str>(const "explicit panic"); // scope 1 at $DIR/inline-diverging.rs:16:9: 16:16
+                                           // mir::Constant
+-                                          // + span: $DIR/inline-diverging.rs:16:9: 16:14
+-                                          // + literal: Const { ty: fn() -> ! {panic}, val: Value(Scalar(<ZST>)) }
++                                          // + span: $DIR/inline-diverging.rs:16:9: 16:16
++                                          // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar(<ZST>)) }
++                                          // ty::Const
++                                          // + ty: &str
++                                          // + val: Value(Slice { data: Allocation { bytes: [101, 120, 112, 108, 105, 99, 105, 116, 32, 112, 97, 110, 105, 99], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [16383], len: Size { raw: 14 } }, size: Size { raw: 14 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 14 })
++                                          // mir::Constant
++                                          // + span: $DIR/inline-diverging.rs:16:9: 16:16
++                                          // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [101, 120, 112, 108, 105, 99, 105, 116, 32, 112, 97, 110, 105, 99], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [16383], len: Size { raw: 14 } }, size: Size { raw: 14 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 14 }) }
+      }
+  
+      bb2: {
+          StorageLive(_4);                 // scope 0 at $DIR/inline-diverging.rs:14:9: 14:10
+          _4 = _1;                         // scope 0 at $DIR/inline-diverging.rs:14:9: 14:10
+          _0 = move _4 as u32 (Misc);      // scope 0 at $DIR/inline-diverging.rs:14:9: 14:17
+          StorageDead(_4);                 // scope 0 at $DIR/inline-diverging.rs:14:16: 14:17
+          StorageDead(_2);                 // scope 0 at $DIR/inline-diverging.rs:18:1: 18:2
+          return;                          // scope 0 at $DIR/inline-diverging.rs:18:2: 18: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
new file mode 100644
index 00000000000..b728ad4b428
--- /dev/null
+++ b/src/test/mir-opt/inline/inline_diverging.h.Inline.diff
@@ -0,0 +1,58 @@
+- // MIR for `h` before Inline
++ // MIR for `h` after Inline
+  
+  fn h() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12
+      let _1: (!, !);                      // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++     let mut _2: fn() -> ! {sleep};       // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++     let mut _7: ();                      // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++     let mut _8: ();                      // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++     scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22
++         debug f => _2;                   // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
++         let _3: !;                       // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
++         let mut _4: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
++         let mut _5: &fn() -> ! {sleep};  // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
++         let mut _6: !;                   // in scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
++         scope 2 {
++             debug a => _3;               // in scope 2 at $DIR/inline-diverging.rs:22:5: 22:22
++             scope 3 {
++                 debug b => _6;           // in scope 3 at $DIR/inline-diverging.rs:22:5: 22:22
++             }
++             scope 6 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:22:5: 22:22
++                 scope 7 (inlined sleep) { // at $DIR/inline-diverging.rs:22:5: 22:22
++                 }
++             }
++         }
++         scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:22:5: 22:22
++             scope 5 (inlined sleep) {    // at $DIR/inline-diverging.rs:22:5: 22:22
++             }
++         }
++     }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+-         _1 = call_twice::<!, fn() -> ! {sleep}>(sleep) -> bb1; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++         StorageLive(_2);                 // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
++         _2 = sleep;                      // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+                                           // mir::Constant
+-                                          // + span: $DIR/inline-diverging.rs:22:5: 22:15
+-                                          // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice::<!, fn() -> ! {sleep}>}, val: Value(Scalar(<ZST>)) }
+-                                          // mir::Constant
+                                           // + span: $DIR/inline-diverging.rs:22:16: 22:21
+                                           // + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar(<ZST>)) }
++         StorageLive(_3);                 // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
++         StorageLive(_4);                 // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
++         _4 = &_2;                        // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
++         StorageLive(_7);                 // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
++         _7 = const ();                   // scope 1 at $DIR/inline-diverging.rs:22:5: 22:22
++         goto -> bb1;                     // scope 5 at $DIR/inline-diverging.rs:22:5: 22:22
+      }
+  
+      bb1: {
+-         StorageDead(_1);                 // scope 0 at $DIR/inline-diverging.rs:22:22: 22:23
+-         _0 = const ();                   // scope 0 at $DIR/inline-diverging.rs:21:12: 23:2
+-         return;                          // scope 0 at $DIR/inline-diverging.rs:23:2: 23:2
++         goto -> bb1;                     // scope 5 at $DIR/inline-diverging.rs:22:5: 22:22
+      }
+  }
+  
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
index 0fbafd76e20..3c0dfb4a77e 100644
--- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
+++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
@@ -18,6 +18,7 @@
           StorageLive(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
           _2 = Box(std::vec::Vec<u32>);    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
 -         (*_2) = Vec::<u32>::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         StorageLive(_4);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         _4 = &mut (*_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +                                          // ty::Const
@@ -34,6 +35,7 @@
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
 +         ((*_4).1: usize) = const 0_usize; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         StorageDead(_4);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
           _1 = move _2;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
           StorageDead(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
           _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
index 9277e57134e..a72db9cf1dc 100644
--- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
+++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
@@ -18,6 +18,7 @@
           StorageLive(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
           _2 = Box(std::vec::Vec<u32>);    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
 -         (*_2) = Vec::<u32>::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         StorageLive(_4);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         _4 = &mut (*_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +         ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +                                          // ty::Const
@@ -34,6 +35,7 @@
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, size: Size { raw: 16 }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
 +         ((*_4).1: usize) = const 0_usize; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         StorageDead(_4);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
           _1 = move _2;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
           StorageDead(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
           _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9: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
new file mode 100644
index 00000000000..4cbdde2ba07
--- /dev/null
+++ b/src/test/mir-opt/inline/inline_options.main.Inline.after.mir
@@ -0,0 +1,56 @@
+// MIR for `main` after Inline
+
+fn main() -> () {
+    let mut _0: ();                      // return place in scope 0 at $DIR/inline-options.rs:8:11: 8:11
+    let _1: ();                          // in scope 0 at $DIR/inline-options.rs:9:5: 9:18
+    let _2: ();                          // in scope 0 at $DIR/inline-options.rs:10:5: 10:21
+    scope 1 (inlined inlined::<u32>) {   // at $DIR/inline-options.rs:10:5: 10:21
+        let _3: ();                      // in scope 1 at $DIR/inline-options.rs:10:5: 10:21
+        let _4: ();                      // in scope 1 at $DIR/inline-options.rs:10:5: 10:21
+        let _5: ();                      // in scope 1 at $DIR/inline-options.rs:10:5: 10:21
+    }
+
+    bb0: {
+        StorageLive(_1);                 // scope 0 at $DIR/inline-options.rs:9:5: 9:18
+        _1 = not_inlined() -> bb1;       // scope 0 at $DIR/inline-options.rs:9:5: 9:18
+                                         // mir::Constant
+                                         // + span: $DIR/inline-options.rs:9:5: 9:16
+                                         // + literal: Const { ty: fn() {not_inlined}, val: Value(Scalar(<ZST>)) }
+    }
+
+    bb1: {
+        StorageDead(_1);                 // scope 0 at $DIR/inline-options.rs:9:18: 9:19
+        StorageLive(_2);                 // scope 0 at $DIR/inline-options.rs:10:5: 10:21
+        StorageLive(_3);                 // scope 1 at $DIR/inline-options.rs:10:5: 10:21
+        _3 = g() -> bb2;                 // scope 1 at $DIR/inline-options.rs:10:5: 10:21
+                                         // mir::Constant
+                                         // + span: $DIR/inline-options.rs:10:5: 10:21
+                                         // + literal: Const { ty: fn() {g}, val: Value(Scalar(<ZST>)) }
+    }
+
+    bb2: {
+        StorageDead(_3);                 // scope 1 at $DIR/inline-options.rs:10:5: 10:21
+        StorageLive(_4);                 // scope 1 at $DIR/inline-options.rs:10:5: 10:21
+        _4 = g() -> bb3;                 // scope 1 at $DIR/inline-options.rs:10:5: 10:21
+                                         // mir::Constant
+                                         // + span: $DIR/inline-options.rs:10:5: 10:21
+                                         // + literal: Const { ty: fn() {g}, val: Value(Scalar(<ZST>)) }
+    }
+
+    bb3: {
+        StorageDead(_4);                 // scope 1 at $DIR/inline-options.rs:10:5: 10:21
+        StorageLive(_5);                 // scope 1 at $DIR/inline-options.rs:10:5: 10:21
+        _5 = g() -> bb4;                 // scope 1 at $DIR/inline-options.rs:10:5: 10:21
+                                         // mir::Constant
+                                         // + span: $DIR/inline-options.rs:10:5: 10:21
+                                         // + literal: Const { ty: fn() {g}, val: Value(Scalar(<ZST>)) }
+    }
+
+    bb4: {
+        StorageDead(_5);                 // scope 1 at $DIR/inline-options.rs:10:5: 10:21
+        _2 = const ();                   // scope 1 at $DIR/inline-options.rs:10:5: 10:21
+        StorageDead(_2);                 // scope 0 at $DIR/inline-options.rs:10:21: 10:22
+        _0 = const ();                   // scope 0 at $DIR/inline-options.rs:8:11: 11:2
+        return;                          // scope 0 at $DIR/inline-options.rs:11:2: 11: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
new file mode 100644
index 00000000000..3bdd4f4ff56
--- /dev/null
+++ b/src/test/mir-opt/inline/inline_shims.clone.Inline.diff
@@ -0,0 +1,26 @@
+- // MIR for `clone` before Inline
++ // MIR for `clone` after Inline
+  
+  fn clone(_1: fn(A, B)) -> fn(A, B) {
+      debug f => _1;                       // in scope 0 at $DIR/inline-shims.rs:5:20: 5:21
+      let mut _0: fn(A, B);                // return place in scope 0 at $DIR/inline-shims.rs:5:36: 5:44
+      let mut _2: &fn(A, B);               // in scope 0 at $DIR/inline-shims.rs:6:5: 6:6
++     scope 1 (inlined <fn(A, B) as Clone>::clone - shim(fn(A, B))) { // at $DIR/inline-shims.rs:6:5: 6:14
++     }
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/inline-shims.rs:6:5: 6:6
+          _2 = &_1;                        // scope 0 at $DIR/inline-shims.rs:6:5: 6:6
+-         _0 = <fn(A, B) as Clone>::clone(move _2) -> bb1; // scope 0 at $DIR/inline-shims.rs:6:5: 6:14
+-                                          // mir::Constant
+-                                          // + span: $DIR/inline-shims.rs:6:7: 6:12
+-                                          // + literal: Const { ty: for<'r> fn(&'r fn(A, B)) -> fn(A, B) {<fn(A, B) as std::clone::Clone>::clone}, val: Value(Scalar(<ZST>)) }
+-     }
+- 
+-     bb1: {
++         _0 = (*_2);                      // scope 1 at $DIR/inline-shims.rs:6:5: 6:14
+          StorageDead(_2);                 // scope 0 at $DIR/inline-shims.rs:6:13: 6:14
+          return;                          // scope 0 at $DIR/inline-shims.rs:7:2: 7: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
new file mode 100644
index 00000000000..503d8bc6b7a
--- /dev/null
+++ b/src/test/mir-opt/inline/inline_shims.drop.Inline.diff
@@ -0,0 +1,52 @@
+- // MIR for `drop` before Inline
++ // MIR for `drop` after Inline
+  
+  fn drop(_1: *mut Vec<A>, _2: *mut Option<B>) -> () {
+      debug a => _1;                       // in scope 0 at $DIR/inline-shims.rs:10:19: 10:20
+      debug b => _2;                       // in scope 0 at $DIR/inline-shims.rs:10:35: 10:36
+      let mut _0: ();                      // return place in scope 0 at $DIR/inline-shims.rs:10:54: 10:54
+      let _3: ();                          // in scope 0 at $DIR/inline-shims.rs:11:14: 11:40
+      let mut _4: *mut std::vec::Vec<A>;   // in scope 0 at $DIR/inline-shims.rs:11:38: 11:39
+      let mut _5: *mut std::option::Option<B>; // in scope 0 at $DIR/inline-shims.rs:12:38: 12:39
+      scope 1 {
+      }
+      scope 2 {
++         scope 3 (inlined drop_in_place::<Option<B>> - shim(Some(Option<B>))) { // at $DIR/inline-shims.rs:12:14: 12:40
++             let mut _6: isize;           // in scope 3 at $DIR/inline-shims.rs:12:14: 12:40
++             let mut _7: isize;           // in scope 3 at $DIR/inline-shims.rs:12:14: 12:40
++         }
+      }
+  
+      bb0: {
+          StorageLive(_3);                 // scope 0 at $DIR/inline-shims.rs:11:5: 11:42
+          StorageLive(_4);                 // scope 1 at $DIR/inline-shims.rs:11:38: 11:39
+          _4 = _1;                         // scope 1 at $DIR/inline-shims.rs:11:38: 11:39
+          _3 = drop_in_place::<Vec<A>>(move _4) -> bb1; // scope 1 at $DIR/inline-shims.rs:11:14: 11:40
+                                           // mir::Constant
+                                           // + span: $DIR/inline-shims.rs:11:14: 11:37
+                                           // + literal: Const { ty: unsafe fn(*mut std::vec::Vec<A>) {std::intrinsics::drop_in_place::<std::vec::Vec<A>>}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageDead(_4);                 // scope 1 at $DIR/inline-shims.rs:11:39: 11:40
+          StorageDead(_3);                 // scope 0 at $DIR/inline-shims.rs:11:41: 11:42
+          StorageLive(_5);                 // scope 2 at $DIR/inline-shims.rs:12:38: 12:39
+          _5 = _2;                         // scope 2 at $DIR/inline-shims.rs:12:38: 12:39
+-         _0 = drop_in_place::<Option<B>>(move _5) -> bb2; // scope 2 at $DIR/inline-shims.rs:12:14: 12:40
+-                                          // mir::Constant
+-                                          // + span: $DIR/inline-shims.rs:12:14: 12:37
+-                                          // + literal: Const { ty: unsafe fn(*mut std::option::Option<B>) {std::intrinsics::drop_in_place::<std::option::Option<B>>}, val: Value(Scalar(<ZST>)) }
++         _6 = discriminant((*_5));        // scope 3 at $DIR/inline-shims.rs:12:14: 12:40
++         switchInt(move _6) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/inline-shims.rs:12:14: 12:40
+      }
+  
+      bb2: {
+          StorageDead(_5);                 // scope 2 at $DIR/inline-shims.rs:12:39: 12:40
+          return;                          // scope 0 at $DIR/inline-shims.rs:13:2: 13:2
++     }
++ 
++     bb3: {
++         drop((((*_5) as Some).0: B)) -> bb2; // scope 3 at $DIR/inline-shims.rs:12:14: 12:40
+      }
+  }
+  
diff --git a/src/test/rustdoc/external-macro-src.rs b/src/test/rustdoc/external-macro-src.rs
index 4394415e5c7..6a7dbb004a3 100644
--- a/src/test/rustdoc/external-macro-src.rs
+++ b/src/test/rustdoc/external-macro-src.rs
@@ -1,15 +1,12 @@
 // aux-build:external-macro-src.rs
-// ignore-tidy-linelength
 
 #![crate_name = "foo"]
 
 #[macro_use]
 extern crate external_macro_src;
 
-// @has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#4-15"]' '[src]'
+// @has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' '[src]'
 
 // @has foo/struct.Foo.html
-// @has - '//a[@href="https://example.com/src/external_macro_src/external-macro-src.rs.html#8"]' '[src]'
-// @has - '//a[@href="https://example.com/src/external_macro_src/external-macro-src.rs.html#9-13"]' '[src]'
-// @has - '//a[@href="https://example.com/src/external_macro_src/external-macro-src.rs.html#10-12"]' '[src]'
+// @has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' '[src]'
 make_foo!();
diff --git a/src/test/rustdoc/issue-26606.rs b/src/test/rustdoc/issue-26606.rs
index c8e9a63ea9f..bd6f38e9123 100644
--- a/src/test/rustdoc/issue-26606.rs
+++ b/src/test/rustdoc/issue-26606.rs
@@ -7,5 +7,5 @@
 extern crate issue_26606_macro;
 
 // @has issue_26606/constant.FOO.html
-// @has - '//a/@href' '../src/issue_26606_macro/issue-26606-macro.rs.html#3'
+// @has - '//a[@href="../src/issue_26606/issue-26606.rs.html#11"]' '[src]'
 make_item!(FOO);
diff --git a/src/test/rustdoc/thread-local-src.rs b/src/test/rustdoc/thread-local-src.rs
index 022d81a4dbf..5e56bb5819a 100644
--- a/src/test/rustdoc/thread-local-src.rs
+++ b/src/test/rustdoc/thread-local-src.rs
@@ -2,5 +2,5 @@
 
 // @has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' '[src]'
 
-// @has foo/constant.FOO.html '//a/@href' 'https://doc.rust-lang.org/nightly/src/std/'
+// @has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' '[src]'
 thread_local!(pub static FOO: bool = false);
diff --git a/src/test/ui/async-await/issue-74072-lifetime-name-annotations.rs b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.rs
new file mode 100644
index 00000000000..95683241aba
--- /dev/null
+++ b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.rs
@@ -0,0 +1,37 @@
+// edition:2018
+#![feature(async_closure)]
+use std::future::Future;
+
+// test the quality of annotations giving lifetimes names (`'1`) when async constructs are involved
+
+pub async fn async_fn(x: &mut i32) -> &i32 {
+    let y = &*x;
+    *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed
+    y
+}
+
+pub fn async_closure(x: &mut i32) -> impl Future<Output=&i32> {
+    (async move || {
+        let y = &*x;
+        *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed
+        y
+    })()
+}
+
+pub fn async_closure_explicit_return_type(x: &mut i32) -> impl Future<Output=&i32> {
+    (async move || -> &i32 {
+        let y = &*x;
+        *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed
+        y
+    })()
+}
+
+pub fn async_block(x: &mut i32) -> impl Future<Output=&i32> {
+    async move {
+        let y = &*x;
+        *x += 1; //~ ERROR cannot assign to `*x` because it is borrowed
+        y
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr
new file mode 100644
index 00000000000..123c3192cff
--- /dev/null
+++ b/src/test/ui/async-await/issue-74072-lifetime-name-annotations.stderr
@@ -0,0 +1,51 @@
+error[E0506]: cannot assign to `*x` because it is borrowed
+  --> $DIR/issue-74072-lifetime-name-annotations.rs:9:5
+   |
+LL | pub async fn async_fn(x: &mut i32) -> &i32 {
+   |                                       - let's call the lifetime of this reference `'1`
+LL |     let y = &*x;
+   |             --- borrow of `*x` occurs here
+LL |     *x += 1;
+   |     ^^^^^^^ assignment to borrowed `*x` occurs here
+LL |     y
+   |     - returning this value requires that `*x` is borrowed for `'1`
+
+error[E0506]: cannot assign to `*x` because it is borrowed
+  --> $DIR/issue-74072-lifetime-name-annotations.rs:16:9
+   |
+LL |         let y = &*x;
+   |                 --- borrow of `*x` occurs here
+LL |         *x += 1;
+   |         ^^^^^^^ assignment to borrowed `*x` occurs here
+LL |         y
+   |         - returning this value requires that `*x` is borrowed for `'1`
+LL |     })()
+   |     - return type of async closure is &'1 i32
+
+error[E0506]: cannot assign to `*x` because it is borrowed
+  --> $DIR/issue-74072-lifetime-name-annotations.rs:24:9
+   |
+LL |     (async move || -> &i32 {
+   |                       - let's call the lifetime of this reference `'1`
+LL |         let y = &*x;
+   |                 --- borrow of `*x` occurs here
+LL |         *x += 1;
+   |         ^^^^^^^ assignment to borrowed `*x` occurs here
+LL |         y
+   |         - returning this value requires that `*x` is borrowed for `'1`
+
+error[E0506]: cannot assign to `*x` because it is borrowed
+  --> $DIR/issue-74072-lifetime-name-annotations.rs:32:9
+   |
+LL |         let y = &*x;
+   |                 --- borrow of `*x` occurs here
+LL |         *x += 1;
+   |         ^^^^^^^ assignment to borrowed `*x` occurs here
+LL |         y
+   |         - returning this value requires that `*x` is borrowed for `'1`
+LL |     }
+   |     - return type of async block is &'1 i32
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0506`.
diff --git a/src/test/ui/async-await/issue-74497-lifetime-in-opaque.rs b/src/test/ui/async-await/issue-74497-lifetime-in-opaque.rs
new file mode 100644
index 00000000000..2d765eb41be
--- /dev/null
+++ b/src/test/ui/async-await/issue-74497-lifetime-in-opaque.rs
@@ -0,0 +1,19 @@
+// edition:2018
+
+// test that names give to anonymous lifetimes in opaque types like `impl Future` are correctly
+// introduced in error messages
+
+use std::future::Future;
+
+pub async fn foo<F, T>(_: F)
+where
+    F: Fn(&u8) -> T,
+    T: Future<Output = ()>,
+{
+}
+
+pub async fn bar(_: &u8) {}
+
+fn main() {
+    let _ = foo(|x| bar(x)); //~ ERROR lifetime may not live long enough
+}
diff --git a/src/test/ui/async-await/issue-74497-lifetime-in-opaque.stderr b/src/test/ui/async-await/issue-74497-lifetime-in-opaque.stderr
new file mode 100644
index 00000000000..89fe1abb365
--- /dev/null
+++ b/src/test/ui/async-await/issue-74497-lifetime-in-opaque.stderr
@@ -0,0 +1,11 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-74497-lifetime-in-opaque.rs:18:21
+   |
+LL |     let _ = foo(|x| bar(x));
+   |                  -- ^^^^^^ returning this value requires that `'1` must outlive `'2`
+   |                  ||
+   |                  |return type of closure `impl Future` contains a lifetime `'2`
+   |                  has type `&'1 u8`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/async-await/issues/issue-63388-1.stderr b/src/test/ui/async-await/issues/issue-63388-1.stderr
index 8813183312d..ac29cca9d3f 100644
--- a/src/test/ui/async-await/issues/issue-63388-1.stderr
+++ b/src/test/ui/async-await/issues/issue-63388-1.stderr
@@ -2,12 +2,14 @@ error[E0623]: lifetime mismatch
   --> $DIR/issue-63388-1.rs:14:9
    |
 LL |         &'a self, foo: &dyn Foo
-   |         -------- this parameter and the return type are declared with different lifetimes...
+   |         -------- this parameter and the returned future are declared with different lifetimes...
 LL |     ) -> &dyn Foo
    |          --------
+   |          |
+   |          this `async fn` implicitly returns an `impl Future<Output = &dyn Foo>`
 LL |     {
 LL |         foo
-   |         ^^^ ...but data from `foo` is returned here
+   |         ^^^ ...but data from `foo` is held across an await point here
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
index 7b8f290d6c2..5041b39a9e9 100644
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
+++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
@@ -4,8 +4,9 @@ error[E0623]: lifetime mismatch
 LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
    |                                           ------                ^^^^^^^^^^^^^^
    |                                           |                     |
-   |                                           |                     ...but data from `b` is returned here
-   |                                           this parameter and the return type are declared with different lifetimes...
+   |                                           |                     ...but data from `b` is held across an await point here
+   |                                           |                     this `async fn` implicitly returns an `impl Future<Output = impl Trait<'a>>`
+   |                                           this parameter and the returned future are declared with different lifetimes...
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/bad/bad-expr-lhs.rs b/src/test/ui/bad/bad-expr-lhs.rs
index d7cf1b77005..39536f12e3b 100644
--- a/src/test/ui/bad/bad-expr-lhs.rs
+++ b/src/test/ui/bad/bad-expr-lhs.rs
@@ -1,10 +1,12 @@
 fn main() {
     1 = 2; //~ ERROR invalid left-hand side of assignment
     1 += 2; //~ ERROR invalid left-hand side of assignment
-    (1, 2) = (3, 4); //~ ERROR invalid left-hand side of assignment
+    (1, 2) = (3, 4); //~ ERROR destructuring assignments are unstable
+    //~| ERROR invalid left-hand side of assignment
+    //~| ERROR invalid left-hand side of assignment
 
     let (a, b) = (1, 2);
-    (a, b) = (3, 4); //~ ERROR invalid left-hand side of assignment
+    (a, b) = (3, 4); //~ ERROR destructuring assignments are unstable
 
     None = Some(3); //~ ERROR invalid left-hand side of assignment
 }
diff --git a/src/test/ui/bad/bad-expr-lhs.stderr b/src/test/ui/bad/bad-expr-lhs.stderr
index a195e1054d0..d4b2193d09f 100644
--- a/src/test/ui/bad/bad-expr-lhs.stderr
+++ b/src/test/ui/bad/bad-expr-lhs.stderr
@@ -1,3 +1,25 @@
+error[E0658]: destructuring assignments are unstable
+  --> $DIR/bad-expr-lhs.rs:4:12
+   |
+LL |     (1, 2) = (3, 4);
+   |     ------ ^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+   = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+
+error[E0658]: destructuring assignments are unstable
+  --> $DIR/bad-expr-lhs.rs:9:12
+   |
+LL |     (a, b) = (3, 4);
+   |     ------ ^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+   = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+
 error[E0070]: invalid left-hand side of assignment
   --> $DIR/bad-expr-lhs.rs:2:7
    |
@@ -18,30 +40,27 @@ error[E0070]: invalid left-hand side of assignment
   --> $DIR/bad-expr-lhs.rs:4:12
    |
 LL |     (1, 2) = (3, 4);
-   |     ------ ^
-   |     |
-   |     cannot assign to this expression
+   |      -     ^
+   |      |
+   |      cannot assign to this expression
 
 error[E0070]: invalid left-hand side of assignment
-  --> $DIR/bad-expr-lhs.rs:7:12
-   |
-LL |     (a, b) = (3, 4);
-   |     ------ ^
-   |     |
-   |     cannot assign to this expression
+  --> $DIR/bad-expr-lhs.rs:4:12
    |
-   = note: destructuring assignments are not currently supported
-   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
+LL |     (1, 2) = (3, 4);
+   |         -  ^
+   |         |
+   |         cannot assign to this expression
 
 error[E0070]: invalid left-hand side of assignment
-  --> $DIR/bad-expr-lhs.rs:9:10
+  --> $DIR/bad-expr-lhs.rs:11:10
    |
 LL |     None = Some(3);
    |     ---- ^
    |     |
    |     cannot assign to this expression
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0067, E0070.
+Some errors have detailed explanations: E0067, E0070, E0658.
 For more information about an error, try `rustc --explain E0067`.
diff --git a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr
index e8a026cfab9..a7c3b9eec73 100644
--- a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr
+++ b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr
@@ -4,7 +4,7 @@ error: lifetime may not live long enough
 LL |     let _action = move || {
    |                   -------
    |                   |     |
-   |                   |     return type of closure is [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15]
+   |                   |     return type of closure `[closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15]` contains a lifetime `'2`
    |                   lifetime `'1` represents this closure's body
 LL |         || f() // The `nested` closure
    |         ^^^^^^ returning this value requires that `'1` must outlive `'2`
diff --git a/src/test/ui/cfg/cfg-panic-abort.rs b/src/test/ui/cfg/cfg-panic-abort.rs
new file mode 100644
index 00000000000..9b88eff12ed
--- /dev/null
+++ b/src/test/ui/cfg/cfg-panic-abort.rs
@@ -0,0 +1,16 @@
+// build-pass
+// compile-flags: -C panic=abort
+// no-prefer-dynamic
+#![feature(cfg_panic)]
+
+#[cfg(panic = "unwind")]
+pub fn bad() -> i32 { }
+
+#[cfg(not(panic = "abort"))]
+pub fn bad() -> i32 { }
+
+#[cfg(panic = "some_imaginary_future_panic_handler")]
+pub fn bad() -> i32 { }
+
+#[cfg(panic = "abort")]
+pub fn main() { }
diff --git a/src/test/ui/cfg/cfg-panic.rs b/src/test/ui/cfg/cfg-panic.rs
new file mode 100644
index 00000000000..dbb5932a9bb
--- /dev/null
+++ b/src/test/ui/cfg/cfg-panic.rs
@@ -0,0 +1,18 @@
+// build-pass
+// compile-flags: -C panic=unwind
+// ignore-emscripten no panic_unwind implementation
+// ignore-wasm32     no panic_unwind implementation
+// ignore-wasm64     no panic_unwind implementation
+#![feature(cfg_panic)]
+
+#[cfg(panic = "abort")]
+pub fn bad() -> i32 { }
+
+#[cfg(not(panic = "unwind"))]
+pub fn bad() -> i32 { }
+
+#[cfg(panic = "some_imaginary_future_panic_handler")]
+pub fn bad() -> i32 { }
+
+#[cfg(panic = "unwind")]
+pub fn main() { }
diff --git a/src/test/ui/chalkify/arithmetic.rs b/src/test/ui/chalkify/arithmetic.rs
new file mode 100644
index 00000000000..a20acce4c76
--- /dev/null
+++ b/src/test/ui/chalkify/arithmetic.rs
@@ -0,0 +1,20 @@
+// check-pass
+// compile-flags: -Z chalk
+
+fn main() {
+    1 + 2;
+    3 * 6;
+    2 - 5;
+    17 / 6;
+    23 % 11;
+    4 & 6;
+    7 | 15;
+    4 << 7;
+    123 >> 3;
+    1 == 2;
+    5 != 5;
+    6 < 2;
+    7 > 11;
+    3 <= 1;
+    9 >= 14;
+}
diff --git a/src/test/ui/chalkify/trait-objects.rs b/src/test/ui/chalkify/trait-objects.rs
new file mode 100644
index 00000000000..13d9e6a6578
--- /dev/null
+++ b/src/test/ui/chalkify/trait-objects.rs
@@ -0,0 +1,13 @@
+// check-pass
+// compile-flags: -Z chalk
+
+use std::fmt::Display;
+
+fn main() {
+    let d: &dyn Display = &mut 3;
+    // FIXME(chalk) should be able to call d.to_string() as well, but doing so
+    // requires Chalk to be able to prove trait object well-formed goals.
+    (&d).to_string();
+    let f: &dyn Fn(i32) -> _ = &|x| x + x;
+    f(2);
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/associated-consts.rs b/src/test/ui/const-generics/const_evaluatable_checked/associated-consts.rs
new file mode 100644
index 00000000000..533fe55b45b
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/associated-consts.rs
@@ -0,0 +1,31 @@
+// run-pass
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+pub trait BlockCipher {
+    const BLOCK_SIZE: usize;
+}
+
+struct FooCipher;
+impl BlockCipher for FooCipher {
+    const BLOCK_SIZE: usize = 64;
+}
+
+struct BarCipher;
+impl BlockCipher for BarCipher {
+    const BLOCK_SIZE: usize = 32;
+}
+
+pub struct Block<C>(C);
+
+pub fn test<C: BlockCipher, const M: usize>()
+where
+    [u8; M - C::BLOCK_SIZE]: Sized,
+{
+    let _ = [0; M - C::BLOCK_SIZE];
+}
+
+fn main() {
+    test::<FooCipher, 128>();
+    test::<BarCipher, 64>();
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs
new file mode 100644
index 00000000000..05049d9c2a6
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs
@@ -0,0 +1,16 @@
+#![feature(const_generics, const_evaluatable_checked)]
+#![allow(incomplete_features)]
+
+use std::mem::size_of;
+use std::marker::PhantomData;
+
+struct Foo<T>(PhantomData<T>);
+
+fn test<T>() -> [u8; size_of::<T>()] {
+    [0; size_of::<Foo<T>>()]
+    //~^ ERROR unconstrained generic constant
+}
+
+fn main() {
+    test::<u32>();
+}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr
new file mode 100644
index 00000000000..1f6dddb04e5
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr
@@ -0,0 +1,14 @@
+error: unconstrained generic constant
+  --> $DIR/different-fn.rs:10:9
+   |
+LL |     [0; size_of::<Foo<T>>()]
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+help: consider adding a `where` bound for this expression
+  --> $DIR/different-fn.rs:10:9
+   |
+LL |     [0; size_of::<Foo<T>>()]
+   |         ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/min_const_generics/macro-fail.rs b/src/test/ui/const-generics/min_const_generics/macro-fail.rs
new file mode 100644
index 00000000000..7f16f2f33de
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/macro-fail.rs
@@ -0,0 +1,48 @@
+#![feature(min_const_generics)]
+
+struct Example<const N: usize>;
+
+macro_rules! external_macro {
+  () => {{
+    //~^ ERROR expected type
+    const X: usize = 1337;
+    X
+  }}
+}
+
+trait Marker<const N: usize> {}
+impl<const N: usize> Marker<N> for Example<N> {}
+
+fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
+  //~^ ERROR wrong number of const
+  //~| ERROR wrong number of type
+  Example::<gimme_a_const!(marker)>
+  //~^ ERROR wrong number of const
+  //~| ERROR wrong number of type
+}
+
+fn from_marker(_: impl Marker<{
+    #[macro_export]
+    macro_rules! inline { () => {{ 3 }} }; inline!()
+}>) {}
+
+fn main() {
+  let _ok = Example::<{
+    #[macro_export]
+    macro_rules! gimme_a_const {
+      ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
+      //~^ ERROR expected type
+      //~| ERROR expected type
+    };
+    gimme_a_const!(run)
+  }>;
+
+  let _fail = Example::<external_macro!()>;
+  //~^ ERROR wrong number of const
+  //~| ERROR wrong number of type
+
+  let _fail = Example::<gimme_a_const!()>;
+  //~^ ERROR wrong number of const
+  //~| ERROR wrong number of type
+  //~| ERROR unexpected end of macro invocation
+}
diff --git a/src/test/ui/const-generics/min_const_generics/macro-fail.stderr b/src/test/ui/const-generics/min_const_generics/macro-fail.stderr
new file mode 100644
index 00000000000..fe7a4a5c382
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/macro-fail.stderr
@@ -0,0 +1,107 @@
+error: expected type, found `{`
+  --> $DIR/macro-fail.rs:33:27
+   |
+LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
+   |                                 ----------------------
+   |                                 |
+   |                                 this macro call doesn't expand to a type
+   |                                 in this macro invocation
+...
+LL |       ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected type, found `{`
+  --> $DIR/macro-fail.rs:33:27
+   |
+LL |   Example::<gimme_a_const!(marker)>
+   |             ----------------------
+   |             |
+   |             this macro call doesn't expand to a type
+   |             in this macro invocation
+...
+LL |       ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected type, found `{`
+  --> $DIR/macro-fail.rs:6:10
+   |
+LL |     () => {{
+   |  __________^
+LL | |
+LL | |     const X: usize = 1337;
+LL | |     X
+LL | |   }}
+   | |___^ expected type
+...
+LL |     let _fail = Example::<external_macro!()>;
+   |                           -----------------
+   |                           |
+   |                           this macro call doesn't expand to a type
+   |                           in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unexpected end of macro invocation
+  --> $DIR/macro-fail.rs:44:25
+   |
+LL |     macro_rules! gimme_a_const {
+   |     -------------------------- when calling this macro
+...
+LL |   let _fail = Example::<gimme_a_const!()>;
+   |                         ^^^^^^^^^^^^^^^^ missing tokens in macro arguments
+
+error[E0107]: wrong number of const arguments: expected 1, found 0
+  --> $DIR/macro-fail.rs:16:26
+   |
+LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument
+
+error[E0107]: wrong number of type arguments: expected 0, found 1
+  --> $DIR/macro-fail.rs:16:33
+   |
+LL | fn make_marker() -> impl Marker<gimme_a_const!(marker)> {
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^ unexpected type argument
+
+error[E0107]: wrong number of const arguments: expected 1, found 0
+  --> $DIR/macro-fail.rs:19:3
+   |
+LL |   Example::<gimme_a_const!(marker)>
+   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument
+
+error[E0107]: wrong number of type arguments: expected 0, found 1
+  --> $DIR/macro-fail.rs:19:13
+   |
+LL |   Example::<gimme_a_const!(marker)>
+   |             ^^^^^^^^^^^^^^^^^^^^^^ unexpected type argument
+
+error[E0107]: wrong number of const arguments: expected 1, found 0
+  --> $DIR/macro-fail.rs:40:15
+   |
+LL |   let _fail = Example::<external_macro!()>;
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument
+
+error[E0107]: wrong number of type arguments: expected 0, found 1
+  --> $DIR/macro-fail.rs:40:25
+   |
+LL |   let _fail = Example::<external_macro!()>;
+   |                         ^^^^^^^^^^^^^^^^^ unexpected type argument
+
+error[E0107]: wrong number of const arguments: expected 1, found 0
+  --> $DIR/macro-fail.rs:44:15
+   |
+LL |   let _fail = Example::<gimme_a_const!()>;
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument
+
+error[E0107]: wrong number of type arguments: expected 0, found 1
+  --> $DIR/macro-fail.rs:44:25
+   |
+LL |   let _fail = Example::<gimme_a_const!()>;
+   |                         ^^^^^^^^^^^^^^^^ unexpected type argument
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/const-generics/min_const_generics/macro.rs b/src/test/ui/const-generics/min_const_generics/macro.rs
new file mode 100644
index 00000000000..85ecce551d4
--- /dev/null
+++ b/src/test/ui/const-generics/min_const_generics/macro.rs
@@ -0,0 +1,57 @@
+// run-pass
+#![feature(min_const_generics)]
+
+struct Example<const N: usize>;
+
+macro_rules! external_macro {
+  () => {{
+    const X: usize = 1337;
+    X
+  }}
+}
+
+trait Marker<const N: usize> {}
+impl<const N: usize> Marker<N> for Example<N> {}
+
+fn make_marker() -> impl Marker<{
+    #[macro_export]
+    macro_rules! const_macro { () => {{ 3 }} }; inline!()
+}> {
+  Example::<{ const_macro!() }>
+}
+
+fn from_marker(_: impl Marker<{
+    #[macro_export]
+    macro_rules! inline { () => {{ 3 }} }; inline!()
+}>) {}
+
+fn main() {
+  let _ok = Example::<{
+    #[macro_export]
+    macro_rules! gimme_a_const {
+      ($rusty: ident) => {{ let $rusty = 3; *&$rusty }}
+    };
+    gimme_a_const!(run)
+  }>;
+
+  let _ok = Example::<{ external_macro!() }>;
+
+  let _ok: [_; gimme_a_const!(blah)] = [0,0,0];
+  let _ok: [[u8; gimme_a_const!(blah)]; gimme_a_const!(blah)];
+  let _ok: [u8; gimme_a_const!(blah)];
+
+  let _ok: [u8; {
+    #[macro_export]
+    macro_rules! const_two { () => {{ 2 }} };
+    const_two!()
+  }];
+
+  let _ok = [0; {
+    #[macro_export]
+    macro_rules! const_three { () => {{ 3 }} };
+    const_three!()
+  }];
+  let _ok = [0; const_three!()];
+
+  from_marker(make_marker());
+}
diff --git a/src/test/ui/consts/const-block-non-item-statement.rs b/src/test/ui/consts/const-block-non-item-statement.rs
index 9aec8552695..07970b457a3 100644
--- a/src/test/ui/consts/const-block-non-item-statement.rs
+++ b/src/test/ui/consts/const-block-non-item-statement.rs
@@ -1,4 +1,4 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 enum Foo {
     Bar = { let x = 1; 3 }
diff --git a/src/test/ui/consts/const-fn-destructuring-arg.rs b/src/test/ui/consts/const-fn-destructuring-arg.rs
index d2c89cb54a0..ea5c9ddc7ce 100644
--- a/src/test/ui/consts/const-fn-destructuring-arg.rs
+++ b/src/test/ui/consts/const-fn-destructuring-arg.rs
@@ -1,4 +1,4 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 const fn i((a, b): (u32, u32)) -> u32 {
     a + b
diff --git a/src/test/ui/consts/const_let_assign.rs b/src/test/ui/consts/const_let_assign.rs
index 343fcb4859b..b83acfb73cf 100644
--- a/src/test/ui/consts/const_let_assign.rs
+++ b/src/test/ui/consts/const_let_assign.rs
@@ -1,4 +1,4 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 struct S(i32);
 
diff --git a/src/test/ui/consts/const_let_assign2.rs b/src/test/ui/consts/const_let_assign2.rs
index 4787c1750d2..28265c85dd1 100644
--- a/src/test/ui/consts/const_let_assign2.rs
+++ b/src/test/ui/consts/const_let_assign2.rs
@@ -1,4 +1,4 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 pub struct AA {
     pub data: [u8; 10],
diff --git a/src/test/ui/consts/control-flow/assert.panic.stderr b/src/test/ui/consts/control-flow/assert.const_panic.stderr
index 03662a35209..03662a35209 100644
--- a/src/test/ui/consts/control-flow/assert.panic.stderr
+++ b/src/test/ui/consts/control-flow/assert.const_panic.stderr
diff --git a/src/test/ui/consts/control-flow/assert.rs b/src/test/ui/consts/control-flow/assert.rs
index 30cd31ee8a7..90017fee193 100644
--- a/src/test/ui/consts/control-flow/assert.rs
+++ b/src/test/ui/consts/control-flow/assert.rs
@@ -1,14 +1,14 @@
 // Test that `assert` works when `const_panic` is enabled.
 
-// revisions: stock panic
+// revisions: stock const_panic
 
-#![cfg_attr(panic, feature(const_panic))]
+#![cfg_attr(const_panic, feature(const_panic))]
 
 const _: () = assert!(true);
 //[stock]~^ ERROR panicking in constants is unstable
 
 const _: () = assert!(false);
 //[stock]~^ ERROR panicking in constants is unstable
-//[panic]~^^ ERROR any use of this value will cause an error
+//[const_panic]~^^ ERROR any use of this value will cause an error
 
 fn main() {}
diff --git a/src/test/ui/default-alloc-error-hook.rs b/src/test/ui/default-alloc-error-hook.rs
index 40f61c2b7d5..6871977c798 100644
--- a/src/test/ui/default-alloc-error-hook.rs
+++ b/src/test/ui/default-alloc-error-hook.rs
@@ -16,5 +16,5 @@ fn main() {
     let me = env::current_exe().unwrap();
     let output = Command::new(&me).arg("next").output().unwrap();
     assert!(!output.status.success(), "{:?} is a success", output.status);
-    assert_eq!(str::from_utf8(&output.stderr).unwrap(), "memory allocation of 42 bytes failed");
+    assert_eq!(str::from_utf8(&output.stderr).unwrap(), "memory allocation of 42 bytes failed\n");
 }
diff --git a/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs b/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs
new file mode 100644
index 00000000000..adecd0ff291
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs
@@ -0,0 +1,7 @@
+#![feature(destructuring_assignment)]
+
+fn main() {
+    let mut x = &0;
+    let mut y = &0;
+    (x, y) = &(1, 2); //~ ERROR mismatched types
+}
diff --git a/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr b/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr
new file mode 100644
index 00000000000..e6161fdfa24
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+  --> $DIR/default-match-bindings-forbidden.rs:6:5
+   |
+LL |     (x, y) = &(1, 2);
+   |     ^^^^^^   ------- this expression has type `&({integer}, {integer})`
+   |     |
+   |     expected reference, found tuple
+   |
+   = note: expected type `&({integer}, {integer})`
+             found tuple `(_, _)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/destructuring-assignment/note-unsupported.rs b/src/test/ui/destructuring-assignment/note-unsupported.rs
index 876c9efea26..e0cb9dc9158 100644
--- a/src/test/ui/destructuring-assignment/note-unsupported.rs
+++ b/src/test/ui/destructuring-assignment/note-unsupported.rs
@@ -3,23 +3,24 @@ struct S { x: u8, y: u8 }
 fn main() {
     let (a, b) = (1, 2);
 
-    (a, b) = (3, 4); //~ ERROR invalid left-hand side of assignment
+    (a, b) = (3, 4); //~ ERROR destructuring assignments are unstable
     (a, b) += (3, 4); //~ ERROR invalid left-hand side of assignment
-    //~^ ERROR binary assignment operation `+=` cannot be applied
+    //~| ERROR binary assignment operation `+=` cannot be applied
 
     [a, b] = [3, 4]; //~ ERROR invalid left-hand side of assignment
     [a, b] += [3, 4]; //~ ERROR invalid left-hand side of assignment
-    //~^ ERROR binary assignment operation `+=` cannot be applied
+    //~| ERROR binary assignment operation `+=` cannot be applied
 
     let s = S { x: 3, y: 4 };
 
     S { x: a, y: b } = s; //~ ERROR invalid left-hand side of assignment
     S { x: a, y: b } += s; //~ ERROR invalid left-hand side of assignment
-    //~^ ERROR binary assignment operation `+=` cannot be applied
+    //~| ERROR binary assignment operation `+=` cannot be applied
 
-    S { x: a, ..s } = S { x: 3, y: 4 }; //~ ERROR invalid left-hand side of assignment
+    S { x: a, ..s } = S { x: 3, y: 4 };
+    //~^ ERROR invalid left-hand side of assignment
 
     let c = 3;
 
-    ((a, b), c) = ((3, 4), 5); //~ ERROR invalid left-hand side of assignment
+    ((a, b), c) = ((3, 4), 5); //~ ERROR destructuring assignments are unstable
 }
diff --git a/src/test/ui/destructuring-assignment/note-unsupported.stderr b/src/test/ui/destructuring-assignment/note-unsupported.stderr
index d4e25930d22..c5543fab825 100644
--- a/src/test/ui/destructuring-assignment/note-unsupported.stderr
+++ b/src/test/ui/destructuring-assignment/note-unsupported.stderr
@@ -1,4 +1,4 @@
-error[E0070]: invalid left-hand side of assignment
+error[E0658]: destructuring assignments are unstable
   --> $DIR/note-unsupported.rs:6:12
    |
 LL |     (a, b) = (3, 4);
@@ -6,8 +6,19 @@ LL |     (a, b) = (3, 4);
    |     |
    |     cannot assign to this expression
    |
-   = note: destructuring assignments are not currently supported
-   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
+   = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+   = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+
+error[E0658]: destructuring assignments are unstable
+  --> $DIR/note-unsupported.rs:25:17
+   |
+LL |     ((a, b), c) = ((3, 4), 5);
+   |     ----------- ^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+   = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
 
 error[E0368]: binary assignment operation `+=` cannot be applied to type `({integer}, {integer})`
   --> $DIR/note-unsupported.rs:7:5
@@ -24,9 +35,6 @@ LL |     (a, b) += (3, 4);
    |     ------ ^^
    |     |
    |     cannot assign to this expression
-   |
-   = note: destructuring assignments are not currently supported
-   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
 
 error[E0070]: invalid left-hand side of assignment
   --> $DIR/note-unsupported.rs:10:12
@@ -35,9 +43,6 @@ LL |     [a, b] = [3, 4];
    |     ------ ^
    |     |
    |     cannot assign to this expression
-   |
-   = note: destructuring assignments are not currently supported
-   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
 
 error[E0368]: binary assignment operation `+=` cannot be applied to type `[{integer}; 2]`
   --> $DIR/note-unsupported.rs:11:5
@@ -54,9 +59,6 @@ LL |     [a, b] += [3, 4];
    |     ------ ^^
    |     |
    |     cannot assign to this expression
-   |
-   = note: destructuring assignments are not currently supported
-   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
 
 error[E0070]: invalid left-hand side of assignment
   --> $DIR/note-unsupported.rs:16:22
@@ -65,9 +67,6 @@ LL |     S { x: a, y: b } = s;
    |     ---------------- ^
    |     |
    |     cannot assign to this expression
-   |
-   = note: destructuring assignments are not currently supported
-   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
 
 error[E0368]: binary assignment operation `+=` cannot be applied to type `S`
   --> $DIR/note-unsupported.rs:17:5
@@ -86,9 +85,6 @@ LL |     S { x: a, y: b } += s;
    |     ---------------- ^^
    |     |
    |     cannot assign to this expression
-   |
-   = note: destructuring assignments are not currently supported
-   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
 
 error[E0070]: invalid left-hand side of assignment
   --> $DIR/note-unsupported.rs:20:21
@@ -97,22 +93,8 @@ LL |     S { x: a, ..s } = S { x: 3, y: 4 };
    |     --------------- ^
    |     |
    |     cannot assign to this expression
-   |
-   = note: destructuring assignments are not currently supported
-   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
-
-error[E0070]: invalid left-hand side of assignment
-  --> $DIR/note-unsupported.rs:24:17
-   |
-LL |     ((a, b), c) = ((3, 4), 5);
-   |     ----------- ^
-   |     |
-   |     cannot assign to this expression
-   |
-   = note: destructuring assignments are not currently supported
-   = note: for more information, see https://github.com/rust-lang/rfcs/issues/372
 
 error: aborting due to 11 previous errors
 
-Some errors have detailed explanations: E0067, E0070, E0368.
+Some errors have detailed explanations: E0067, E0070, E0368, E0658.
 For more information about an error, try `rustc --explain E0067`.
diff --git a/src/test/ui/destructuring-assignment/tuple_destructure.rs b/src/test/ui/destructuring-assignment/tuple_destructure.rs
new file mode 100644
index 00000000000..16aafc4693f
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/tuple_destructure.rs
@@ -0,0 +1,37 @@
+// run-pass
+
+#![feature(destructuring_assignment)]
+
+fn main() {
+    let (mut a, mut b);
+    (a, b) = (0, 1);
+    assert_eq!((a, b), (0, 1));
+    (b, a) = (a, b);
+    assert_eq!((a, b), (1, 0));
+    (a, .., b) = (1, 2);
+    assert_eq!((a, b), (1, 2));
+    (.., a) = (1, 2);
+    assert_eq!((a, b), (2, 2));
+    (..) = (3, 4);
+    assert_eq!((a, b), (2, 2));
+    (b, ..) = (5, 6, 7);
+    assert_eq!(b, 5);
+
+    // Test for a non-Copy type (String):
+    let (mut c, mut d);
+    (c, d) = ("c".to_owned(), "d".to_owned());
+    assert_eq!(c, "c");
+    assert_eq!(d, "d");
+    (d, c) = (c, d);
+    assert_eq!(c, "d");
+    assert_eq!(d, "c");
+
+    // Test nesting/parentheses:
+    ((a, b)) = (0, 1);
+    assert_eq!((a, b), (0, 1));
+    (((a, b)), (c)) = ((2, 3), d);
+    assert_eq!((a, b), (2, 3));
+    assert_eq!(c, "c");
+    ((a, .., b), .., (..)) = ((4, 5), ());
+    assert_eq!((a, b), (4, 5));
+}
diff --git a/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs b/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs
new file mode 100644
index 00000000000..b76f4968e62
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs
@@ -0,0 +1,10 @@
+#![feature(destructuring_assignment)]
+
+const C: i32 = 1;
+
+fn main() {
+    let (mut a, mut b);
+    (a, .., b, ..) = (0, 1); //~ ERROR `..` can only be used once per tuple pattern
+    (a, a, b) = (1, 2); //~ ERROR mismatched types
+    (C, ..) = (0,1); //~ ERROR invalid left-hand side of assignment
+}
diff --git a/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr
new file mode 100644
index 00000000000..a60e1cb1eec
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr
@@ -0,0 +1,31 @@
+error: `..` can only be used once per tuple pattern
+  --> $DIR/tuple_destructure_fail.rs:7:16
+   |
+LL |     (a, .., b, ..) = (0, 1);
+   |         --     ^^ can only be used once per tuple pattern
+   |         |
+   |         previously used here
+
+error[E0308]: mismatched types
+  --> $DIR/tuple_destructure_fail.rs:8:5
+   |
+LL |     (a, a, b) = (1, 2);
+   |     ^^^^^^^^^   ------ this expression has type `({integer}, {integer})`
+   |     |
+   |     expected a tuple with 2 elements, found one with 3 elements
+   |
+   = note: expected type `({integer}, {integer})`
+             found tuple `(_, _, _)`
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/tuple_destructure_fail.rs:9:13
+   |
+LL |     (C, ..) = (0,1);
+   |      -      ^
+   |      |
+   |      cannot assign to this expression
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0070, E0308.
+For more information about an error, try `rustc --explain E0070`.
diff --git a/src/test/ui/destructuring-assignment/warn-unused-duplication.rs b/src/test/ui/destructuring-assignment/warn-unused-duplication.rs
new file mode 100644
index 00000000000..c1c5c2cd3ce
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/warn-unused-duplication.rs
@@ -0,0 +1,23 @@
+// run-pass
+
+#![feature(destructuring_assignment)]
+
+#![warn(unused_assignments)]
+
+fn main() {
+    let mut a;
+    // Assignment occurs left-to-right.
+    // However, we emit warnings when this happens, so it is clear that this is happening.
+    (a, a) = (0, 1); //~ WARN value assigned to `a` is never read
+    assert_eq!(a, 1);
+
+    // We can't always tell when a variable is being assigned to twice, which is why we don't try
+    // to emit an error, which would be fallible.
+    let mut x = 1;
+    (*foo(&mut x), *foo(&mut x)) = (5, 6);
+    assert_eq!(x, 6);
+}
+
+fn foo<'a>(x: &'a mut u32) -> &'a mut u32 {
+    x
+}
diff --git a/src/test/ui/destructuring-assignment/warn-unused-duplication.stderr b/src/test/ui/destructuring-assignment/warn-unused-duplication.stderr
new file mode 100644
index 00000000000..b87ef6f1571
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/warn-unused-duplication.stderr
@@ -0,0 +1,15 @@
+warning: value assigned to `a` is never read
+  --> $DIR/warn-unused-duplication.rs:11:6
+   |
+LL |     (a, a) = (0, 1);
+   |      ^
+   |
+note: the lint level is defined here
+  --> $DIR/warn-unused-duplication.rs:5:9
+   |
+LL | #![warn(unused_assignments)]
+   |         ^^^^^^^^^^^^^^^^^^
+   = help: maybe it is overwritten before being read?
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-panic.rs b/src/test/ui/feature-gates/feature-gate-cfg-panic.rs
new file mode 100644
index 00000000000..1508374d942
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-cfg-panic.rs
@@ -0,0 +1,11 @@
+#[cfg(panic = "unwind")]
+//~^ ERROR `cfg(panic)` is experimental and subject to change
+fn foo() -> bool { true }
+#[cfg(not(panic = "unwind"))]
+//~^ ERROR `cfg(panic)` is experimental and subject to change
+fn foo() -> bool { false }
+
+
+fn main() {
+    assert!(foo());
+}
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-panic.stderr b/src/test/ui/feature-gates/feature-gate-cfg-panic.stderr
new file mode 100644
index 00000000000..ea5cd54fa90
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-cfg-panic.stderr
@@ -0,0 +1,21 @@
+error[E0658]: `cfg(panic)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-panic.rs:1:7
+   |
+LL | #[cfg(panic = "unwind")]
+   |       ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #77443 <https://github.com/rust-lang/rust/issues/77443> for more information
+   = help: add `#![feature(cfg_panic)]` to the crate attributes to enable
+
+error[E0658]: `cfg(panic)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-panic.rs:4:11
+   |
+LL | #[cfg(not(panic = "unwind"))]
+   |           ^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #77443 <https://github.com/rust-lang/rust/issues/77443> for more information
+   = help: add `#![feature(cfg_panic)]` 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/feature-gate-destructuring_assignment.rs b/src/test/ui/feature-gates/feature-gate-destructuring_assignment.rs
new file mode 100644
index 00000000000..e7801f0e8ec
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-destructuring_assignment.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let (a, b) = (0, 1);
+    (a, b) = (2, 3); //~ ERROR destructuring assignments are unstable
+}
diff --git a/src/test/ui/feature-gates/feature-gate-destructuring_assignment.stderr b/src/test/ui/feature-gates/feature-gate-destructuring_assignment.stderr
new file mode 100644
index 00000000000..62e71decb32
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-destructuring_assignment.stderr
@@ -0,0 +1,14 @@
+error[E0658]: destructuring assignments are unstable
+  --> $DIR/feature-gate-destructuring_assignment.rs:3:12
+   |
+LL |     (a, b) = (2, 3);
+   |     ------ ^
+   |     |
+   |     cannot assign to this expression
+   |
+   = note: see issue #71126 <https://github.com/rust-lang/rust/issues/71126> for more information
+   = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/fmt/format-args-capture.rs b/src/test/ui/fmt/format-args-capture.rs
index 7490632110c..9348bb46dfe 100644
--- a/src/test/ui/fmt/format-args-capture.rs
+++ b/src/test/ui/fmt/format-args-capture.rs
@@ -1,13 +1,16 @@
 // run-pass
-// ignore-wasm32
-// ignore-wasm64
 #![feature(format_args_capture)]
+#![feature(cfg_panic)]
 
 fn main() {
     named_argument_takes_precedence_to_captured();
-    panic_with_single_argument_does_not_get_formatted();
-    panic_with_multiple_arguments_is_formatted();
     formatting_parameters_can_be_captured();
+
+    #[cfg(panic = "unwind")]
+    {
+        panic_with_single_argument_does_not_get_formatted();
+        panic_with_multiple_arguments_is_formatted();
+    }
 }
 
 fn named_argument_takes_precedence_to_captured() {
@@ -22,6 +25,7 @@ fn named_argument_takes_precedence_to_captured() {
     assert_eq!(&s, "positional-named-captured");
 }
 
+#[cfg(panic = "unwind")]
 fn panic_with_single_argument_does_not_get_formatted() {
     // panic! with a single argument does not perform string formatting.
     // RFC #2795 suggests that this may need to change so that captured arguments are formatted.
@@ -34,6 +38,7 @@ fn panic_with_single_argument_does_not_get_formatted() {
     assert_eq!(msg.downcast_ref::<&str>(), Some(&"{foo}"))
 }
 
+#[cfg(panic = "unwind")]
 fn panic_with_multiple_arguments_is_formatted() {
     let foo = "captured";
 
diff --git a/src/test/ui/issues/issue-68696-catch-during-unwind.rs b/src/test/ui/issues/issue-68696-catch-during-unwind.rs
index d042bed225d..f25a78f59cd 100644
--- a/src/test/ui/issues/issue-68696-catch-during-unwind.rs
+++ b/src/test/ui/issues/issue-68696-catch-during-unwind.rs
@@ -4,8 +4,7 @@
 // entering the catch_unwind.
 //
 // run-pass
-// ignore-wasm       no panic support
-// ignore-emscripten no panic support
+#![feature(cfg_panic)]
 
 use std::panic::catch_unwind;
 
@@ -19,6 +18,7 @@ impl Drop for Guard {
 }
 
 fn main() {
+    #[cfg(panic = "unwind")]
     let _ = catch_unwind(|| {
         let _guard = Guard::default();
         panic!();
diff --git a/src/test/ui/issues/issue-76547.nll.stderr b/src/test/ui/issues/issue-76547.nll.stderr
new file mode 100644
index 00000000000..2456d6a1474
--- /dev/null
+++ b/src/test/ui/issues/issue-76547.nll.stderr
@@ -0,0 +1,20 @@
+error: lifetime may not live long enough
+  --> $DIR/issue-76547.rs:19:14
+   |
+LL | async fn fut(bufs: &mut [&mut [u8]]) {
+   |              ^^^^  -     - let's call the lifetime of this reference `'2`
+   |              |     |
+   |              |     let's call the lifetime of this reference `'1`
+   |              assignment requires that `'1` must outlive `'2`
+
+error: lifetime may not live long enough
+  --> $DIR/issue-76547.rs:33:15
+   |
+LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
+   |               ^^^^  -     - let's call the lifetime of this reference `'2`
+   |               |     |
+   |               |     let's call the lifetime of this reference `'1`
+   |               assignment requires that `'1` must outlive `'2`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/issues/issue-76547.rs b/src/test/ui/issues/issue-76547.rs
new file mode 100644
index 00000000000..5b3ee5b95c4
--- /dev/null
+++ b/src/test/ui/issues/issue-76547.rs
@@ -0,0 +1,38 @@
+// Test for diagnostic improvement issue #76547
+// edition:2018
+
+use std::{
+    future::Future,
+    task::{Context, Poll}
+};
+use std::pin::Pin;
+
+pub struct ListFut<'a>(&'a mut [&'a mut [u8]]);
+impl<'a> Future for ListFut<'a> {
+    type Output = ();
+
+    fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
+        unimplemented!()
+    }
+}
+
+async fn fut(bufs: &mut [&mut [u8]]) {
+    ListFut(bufs).await
+    //~^ ERROR lifetime mismatch
+}
+
+pub struct ListFut2<'a>(&'a mut [&'a mut [u8]]);
+impl<'a> Future for ListFut2<'a> {
+    type Output = i32;
+
+    fn poll(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
+        unimplemented!()
+    }
+}
+
+async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
+    ListFut2(bufs).await
+    //~^ ERROR lifetime mismatch
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-76547.stderr b/src/test/ui/issues/issue-76547.stderr
new file mode 100644
index 00000000000..9bfb0f28028
--- /dev/null
+++ b/src/test/ui/issues/issue-76547.stderr
@@ -0,0 +1,25 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/issue-76547.rs:20:13
+   |
+LL | async fn fut(bufs: &mut [&mut [u8]]) {
+   |                          ---------   -
+   |                          |           |
+   |                          |           this `async fn` implicitly returns an `impl Future<Output = ()>`
+   |                          this parameter and the returned future are declared with different lifetimes...
+LL |     ListFut(bufs).await
+   |             ^^^^ ...but data from `bufs` is held across an await point here
+
+error[E0623]: lifetime mismatch
+  --> $DIR/issue-76547.rs:34:14
+   |
+LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
+   |                           ---------      ---
+   |                           |              |
+   |                           |              this `async fn` implicitly returns an `impl Future<Output = i32>`
+   |                           this parameter and the returned future are declared with different lifetimes...
+LL |     ListFut2(bufs).await
+   |              ^^^^ ...but data from `bufs` is held across an await point here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/macros/issue-78892-substitution-in-statement-attr.rs b/src/test/ui/macros/issue-78892-substitution-in-statement-attr.rs
new file mode 100644
index 00000000000..9d1fae7a234
--- /dev/null
+++ b/src/test/ui/macros/issue-78892-substitution-in-statement-attr.rs
@@ -0,0 +1,14 @@
+// check-pass
+
+// regression test for #78892
+
+macro_rules! mac {
+    ($lint_name:ident) => {{
+        #[allow($lint_name)]
+        let _ = ();
+    }};
+}
+
+fn main() {
+    mac!(dead_code)
+}
diff --git a/src/test/ui/nll/issue-58053.stderr b/src/test/ui/nll/issue-58053.stderr
index 297681ff403..e41ee8a8970 100644
--- a/src/test/ui/nll/issue-58053.stderr
+++ b/src/test/ui/nll/issue-58053.stderr
@@ -2,9 +2,9 @@ error: lifetime may not live long enough
   --> $DIR/issue-58053.rs:6:33
    |
 LL |     let f = |x: &i32| -> &i32 { x };
-   |                 -        ----   ^ returning this value requires that `'1` must outlive `'2`
+   |                 -        -      ^ returning this value requires that `'1` must outlive `'2`
    |                 |        |
-   |                 |        return type of closure is &'2 i32
+   |                 |        let's call the lifetime of this reference `'2`
    |                 let's call the lifetime of this reference `'1`
 
 error: lifetime may not live long enough
diff --git a/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs b/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs
index 97a405b6999..30f3781bf77 100644
--- a/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs
+++ b/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.rs
@@ -1,4 +1,4 @@
-// Regression test; used to ICE with 'visit_mac disabled by default' due to a
+// Regression test; used to ICE with 'visit_mac_call disabled by default' due to a
 // `MutVisitor` in `fn make_all_value_bindings_mutable` (`parse/parser/pat.rs`).
 
 macro_rules! mac1 {
diff --git a/src/test/ui/regions/region-bound-extra-bound-in-inherent-impl.rs b/src/test/ui/regions/region-bound-extra-bound-in-inherent-impl.rs
index 49de70ae013..72d82da4534 100644
--- a/src/test/ui/regions/region-bound-extra-bound-in-inherent-impl.rs
+++ b/src/test/ui/regions/region-bound-extra-bound-in-inherent-impl.rs
@@ -1,7 +1,7 @@
 // Test related to #22779. In this case, the impl is an inherent impl,
 // so it doesn't have to match any trait, so no error results.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![allow(dead_code)]
 
 struct MySlice<'a, T:'a>(&'a mut [T]);
diff --git a/src/test/ui/regions/region-bound-same-bounds-in-trait-and-impl.rs b/src/test/ui/regions/region-bound-same-bounds-in-trait-and-impl.rs
index 4ce5daf3842..68056370c44 100644
--- a/src/test/ui/regions/region-bound-same-bounds-in-trait-and-impl.rs
+++ b/src/test/ui/regions/region-bound-same-bounds-in-trait-and-impl.rs
@@ -1,7 +1,7 @@
 // Test related to #22779, but where the `'a:'b` relation
 // appears in the trait too. No error here.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 trait Tr<'a, T> {
     fn renew<'b: 'a>(self) -> &'b mut [T] where 'a: 'b;
diff --git a/src/test/ui/regions/region-object-lifetime-1.rs b/src/test/ui/regions/region-object-lifetime-1.rs
index e58bd31d9cb..ddf3be690dd 100644
--- a/src/test/ui/regions/region-object-lifetime-1.rs
+++ b/src/test/ui/regions/region-object-lifetime-1.rs
@@ -1,7 +1,7 @@
 // Various tests related to testing how region inference works
 // with respect to the object receivers.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![allow(warnings)]
 
 trait Foo {
diff --git a/src/test/ui/regions/region-object-lifetime-3.rs b/src/test/ui/regions/region-object-lifetime-3.rs
index c3c7c51767d..0536fa2a20f 100644
--- a/src/test/ui/regions/region-object-lifetime-3.rs
+++ b/src/test/ui/regions/region-object-lifetime-3.rs
@@ -1,7 +1,7 @@
 // Various tests related to testing how region inference works
 // with respect to the object receivers.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![allow(warnings)]
 
 trait Foo {
diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-2.rs b/src/test/ui/regions/regions-implied-bounds-projection-gap-2.rs
index dcad2e81a54..a481a9cc5fe 100644
--- a/src/test/ui/regions/regions-implied-bounds-projection-gap-2.rs
+++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-2.rs
@@ -2,7 +2,7 @@
 // "projection gap": in this test, we know that `T: 'x`, and that is
 // enough to conclude that `T::Foo: 'x`.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-3.rs b/src/test/ui/regions/regions-implied-bounds-projection-gap-3.rs
index ff2e10804ae..a627cbbd88f 100644
--- a/src/test/ui/regions/regions-implied-bounds-projection-gap-3.rs
+++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-3.rs
@@ -2,7 +2,7 @@
 // "projection gap": in this test, we know that `T::Foo: 'x`, and that
 // is (naturally) enough to conclude that `T::Foo: 'x`.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-4.rs b/src/test/ui/regions/regions-implied-bounds-projection-gap-4.rs
index 3596bf7e8c2..5158c289340 100644
--- a/src/test/ui/regions/regions-implied-bounds-projection-gap-4.rs
+++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-4.rs
@@ -2,7 +2,7 @@
 // "projection gap": in this test, we know that `T: 'x`, and that
 // is (naturally) enough to conclude that `T: 'x`.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
diff --git a/src/test/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs b/src/test/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs
index fc4d1618401..15deaba5638 100644
--- a/src/test/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs
+++ b/src/test/ui/regions/regions-outlives-nominal-type-enum-region-rev.rs
@@ -3,7 +3,7 @@
 //
 // Rule OutlivesNominalType from RFC 1214.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
diff --git a/src/test/ui/regions/regions-outlives-nominal-type-enum-region.rs b/src/test/ui/regions/regions-outlives-nominal-type-enum-region.rs
index d716cb9c55b..7767c13c825 100644
--- a/src/test/ui/regions/regions-outlives-nominal-type-enum-region.rs
+++ b/src/test/ui/regions/regions-outlives-nominal-type-enum-region.rs
@@ -3,7 +3,7 @@
 //
 // Rule OutlivesNominalType from RFC 1214.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
diff --git a/src/test/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs b/src/test/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs
index 39eb0842d3f..37415994210 100644
--- a/src/test/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs
+++ b/src/test/ui/regions/regions-outlives-nominal-type-enum-type-rev.rs
@@ -3,7 +3,7 @@
 //
 // Rule OutlivesNominalType from RFC 1214.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
diff --git a/src/test/ui/regions/regions-outlives-nominal-type-enum-type.rs b/src/test/ui/regions/regions-outlives-nominal-type-enum-type.rs
index 561cad790f0..2e7f198d8c7 100644
--- a/src/test/ui/regions/regions-outlives-nominal-type-enum-type.rs
+++ b/src/test/ui/regions/regions-outlives-nominal-type-enum-type.rs
@@ -3,7 +3,7 @@
 //
 // Rule OutlivesNominalType from RFC 1214.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
diff --git a/src/test/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs b/src/test/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs
index e1287c34bac..45155c72166 100644
--- a/src/test/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs
+++ b/src/test/ui/regions/regions-outlives-nominal-type-struct-region-rev.rs
@@ -3,7 +3,7 @@
 //
 // Rule OutlivesNominalType from RFC 1214.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
diff --git a/src/test/ui/regions/regions-outlives-nominal-type-struct-region.rs b/src/test/ui/regions/regions-outlives-nominal-type-struct-region.rs
index 0d59f44584c..bba8b244524 100644
--- a/src/test/ui/regions/regions-outlives-nominal-type-struct-region.rs
+++ b/src/test/ui/regions/regions-outlives-nominal-type-struct-region.rs
@@ -3,7 +3,7 @@
 //
 // Rule OutlivesNominalType from RFC 1214.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
diff --git a/src/test/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs b/src/test/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs
index cf0d96ba7ed..220d2e83cc0 100644
--- a/src/test/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs
+++ b/src/test/ui/regions/regions-outlives-nominal-type-struct-type-rev.rs
@@ -3,7 +3,7 @@
 //
 // Rule OutlivesNominalType from RFC 1214.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
diff --git a/src/test/ui/regions/regions-outlives-nominal-type-struct-type.rs b/src/test/ui/regions/regions-outlives-nominal-type-struct-type.rs
index 069fc5dd008..9ddcdb649d8 100644
--- a/src/test/ui/regions/regions-outlives-nominal-type-struct-type.rs
+++ b/src/test/ui/regions/regions-outlives-nominal-type-struct-type.rs
@@ -3,7 +3,7 @@
 //
 // Rule OutlivesNominalType from RFC 1214.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
diff --git a/src/test/ui/regions/regions-outlives-projection-hrtype.rs b/src/test/ui/regions/regions-outlives-projection-hrtype.rs
index e7fe7b6c16d..5f9700df1cb 100644
--- a/src/test/ui/regions/regions-outlives-projection-hrtype.rs
+++ b/src/test/ui/regions/regions-outlives-projection-hrtype.rs
@@ -5,7 +5,7 @@
 // `'r` is bound, that leads to badness. This test checks that
 // everything works.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![allow(dead_code)]
 
 trait TheTrait {
diff --git a/src/test/ui/regions/regions-outlives-projection-trait-def.rs b/src/test/ui/regions/regions-outlives-projection-trait-def.rs
index 928ed4baaa0..5c37a585a40 100644
--- a/src/test/ui/regions/regions-outlives-projection-trait-def.rs
+++ b/src/test/ui/regions/regions-outlives-projection-trait-def.rs
@@ -1,7 +1,7 @@
 // Test that `<F as Foo<'a>>::Type: 'b`, where `trait Foo<'a> { Type:
 // 'a; }`, does not require that `F: 'b`.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![allow(dead_code)]
 
 trait SomeTrait<'a> {
diff --git a/src/test/ui/regions/regions-outlives-scalar.rs b/src/test/ui/regions/regions-outlives-scalar.rs
index 5d0ed999380..ce34ffcc858 100644
--- a/src/test/ui/regions/regions-outlives-scalar.rs
+++ b/src/test/ui/regions/regions-outlives-scalar.rs
@@ -1,7 +1,7 @@
 // Test that scalar values outlive all regions.
 // Rule OutlivesScalar from RFC 1214.
 
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 #![allow(dead_code)]
 
 struct Foo<'a> {
diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
index 37297032632..e6846fb4049 100644
--- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
+++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
@@ -2,25 +2,28 @@ error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
    |
 LL |     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
-   |                          ----               ----   ^ ...but data from `f` is returned here
-   |                          |
-   |                          this parameter and the return type are declared with different lifetimes...
+   |                          ----               ----   ^ ...but data from `f` is held across an await point here
+   |                          |                  |
+   |                          |                  this `async fn` implicitly returns an `impl Future<Output = &Foo>`
+   |                          this parameter and the returned future are declared with different lifetimes...
 
 error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:82
    |
 LL |     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-   |                          -----                        -----------------          ^ ...but data from `f` is returned here
-   |                          |
-   |                          this parameter and the return type are declared with different lifetimes...
+   |                          -----                        -----------------          ^ ...but data from `f` is held across an await point here
+   |                          |                            |
+   |                          |                            this `async fn` implicitly returns an `impl Future<Output = (Pin<&Foo>, &Foo)>`
+   |                          this parameter and the returned future are declared with different lifetimes...
 
 error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
    |
 LL |     async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
-   |                                  -----                   ---   ^^^ ...but data from `arg` is returned here
-   |                                  |
-   |                                  this parameter and the return type are declared with different lifetimes...
+   |                                  -----                   ---   ^^^ ...but data from `arg` is held across an await point here
+   |                                  |                       |
+   |                                  |                       this `async fn` implicitly returns an `impl Future<Output = &()>`
+   |                                  this parameter and the returned future are declared with different lifetimes...
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/self/elision/lt-ref-self-async.stderr b/src/test/ui/self/elision/lt-ref-self-async.stderr
index badd973c37f..3221d270850 100644
--- a/src/test/ui/self/elision/lt-ref-self-async.stderr
+++ b/src/test/ui/self/elision/lt-ref-self-async.stderr
@@ -3,60 +3,66 @@ error[E0623]: lifetime mismatch
    |
 LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                       -----              ----
-   |                       |
-   |                       this parameter and the return type are declared with different lifetimes...
+   |                       |                  |
+   |                       |                  this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                       this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:19:9
    |
 LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                             -----              ----
-   |                             |
-   |                             this parameter and the return type are declared with different lifetimes...
+   |                             |                  |
+   |                             |                  this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                             this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:23:9
    |
 LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                     -----               ----
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
+   |                                     |                   |
+   |                                     |                   this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                     this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:27:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                     -----               ----
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
+   |                                     |                   |
+   |                                     |                   this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                     this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:31:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                             -----                ----
-   |                                             |
-   |                                             this parameter and the return type are declared with different lifetimes...
+   |                                             |                    |
+   |                                             |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                             this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:35:9
    |
 LL |     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                         -----                ----
-   |                                         |
-   |                                         this parameter and the return type are declared with different lifetimes...
+   |                                         |                    |
+   |                                         |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                         this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/self/elision/ref-mut-self-async.stderr b/src/test/ui/self/elision/ref-mut-self-async.stderr
index 73d942a83f8..b6ca986923d 100644
--- a/src/test/ui/self/elision/ref-mut-self-async.stderr
+++ b/src/test/ui/self/elision/ref-mut-self-async.stderr
@@ -3,60 +3,66 @@ error[E0623]: lifetime mismatch
    |
 LL |     async fn ref_self(&mut self, f: &u32) -> &u32 {
    |                       ---------              ----
-   |                       |
-   |                       this parameter and the return type are declared with different lifetimes...
+   |                       |                      |
+   |                       |                      this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                       this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:19:9
    |
 LL |     async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
    |                             ---------              ----
-   |                             |
-   |                             this parameter and the return type are declared with different lifetimes...
+   |                             |                      |
+   |                             |                      this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                             this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:23:9
    |
 LL |     async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
    |                                     ---------               ----
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
+   |                                     |                       |
+   |                                     |                       this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                     this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:27:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
    |                                     ---------               ----
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
+   |                                     |                       |
+   |                                     |                       this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                     this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:31:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
    |                                             ---------                ----
-   |                                             |
-   |                                             this parameter and the return type are declared with different lifetimes...
+   |                                             |                        |
+   |                                             |                        this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                             this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:35:9
    |
 LL |     async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
    |                                             ---------                ----
-   |                                             |
-   |                                             this parameter and the return type are declared with different lifetimes...
+   |                                             |                        |
+   |                                             |                        this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                             this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/self/elision/ref-mut-struct-async.stderr b/src/test/ui/self/elision/ref-mut-struct-async.stderr
index 7d613c57448..eda15d76390 100644
--- a/src/test/ui/self/elision/ref-mut-struct-async.stderr
+++ b/src/test/ui/self/elision/ref-mut-struct-async.stderr
@@ -3,50 +3,55 @@ error[E0623]: lifetime mismatch
    |
 LL |     async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
    |                               -----------              ----
-   |                               |
-   |                               this parameter and the return type are declared with different lifetimes...
+   |                               |                        |
+   |                               |                        this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                               this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:17:9
    |
 LL |     async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
    |                                       -----------               ----
-   |                                       |
-   |                                       this parameter and the return type are declared with different lifetimes...
+   |                                       |                         |
+   |                                       |                         this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                       this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:21:9
    |
 LL |     async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
    |                                       -----------               ----
-   |                                       |
-   |                                       this parameter and the return type are declared with different lifetimes...
+   |                                       |                         |
+   |                                       |                         this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                       this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:25:9
    |
 LL |     async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
    |                                               -----------                ----
-   |                                               |
-   |                                               this parameter and the return type are declared with different lifetimes...
+   |                                               |                          |
+   |                                               |                          this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                               this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:29:9
    |
 LL |     async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
    |                                               -----------                ----
-   |                                               |
-   |                                               this parameter and the return type are declared with different lifetimes...
+   |                                               |                          |
+   |                                               |                          this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                               this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/self/elision/ref-self-async.stderr b/src/test/ui/self/elision/ref-self-async.stderr
index bda958241b6..b42caa88c6f 100644
--- a/src/test/ui/self/elision/ref-self-async.stderr
+++ b/src/test/ui/self/elision/ref-self-async.stderr
@@ -3,70 +3,77 @@ error[E0623]: lifetime mismatch
    |
 LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                       -----              ----
-   |                       |
-   |                       this parameter and the return type are declared with different lifetimes...
+   |                       |                  |
+   |                       |                  this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                       this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:29:9
    |
 LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                             -----              ----
-   |                             |
-   |                             this parameter and the return type are declared with different lifetimes...
+   |                             |                  |
+   |                             |                  this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                             this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:33:9
    |
 LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                     -----               ----
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
+   |                                     |                   |
+   |                                     |                   this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                     this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:37:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                     -----               ----
-   |                                     |
-   |                                     this parameter and the return type are declared with different lifetimes...
+   |                                     |                   |
+   |                                     |                   this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                     this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:41:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                             -----                ----
-   |                                             |
-   |                                             this parameter and the return type are declared with different lifetimes...
+   |                                             |                    |
+   |                                             |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                             this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:45:9
    |
 LL |     async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                             -----                ----
-   |                                             |
-   |                                             this parameter and the return type are declared with different lifetimes...
+   |                                             |                    |
+   |                                             |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                             this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:49:9
    |
 LL |     async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
    |                                            -----                    ---
-   |                                            |
-   |                                            this parameter and the return type are declared with different lifetimes...
+   |                                            |                        |
+   |                                            |                        this `async fn` implicitly returns an `impl Future<Output = &u8>`
+   |                                            this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/self/elision/ref-struct-async.stderr b/src/test/ui/self/elision/ref-struct-async.stderr
index fc85450c4a7..599becd3080 100644
--- a/src/test/ui/self/elision/ref-struct-async.stderr
+++ b/src/test/ui/self/elision/ref-struct-async.stderr
@@ -3,50 +3,55 @@ error[E0623]: lifetime mismatch
    |
 LL |     async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
    |                               -------              ----
-   |                               |
-   |                               this parameter and the return type are declared with different lifetimes...
+   |                               |                    |
+   |                               |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                               this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:17:9
    |
 LL |     async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
    |                                       -------               ----
-   |                                       |
-   |                                       this parameter and the return type are declared with different lifetimes...
+   |                                       |                     |
+   |                                       |                     this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                       this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:21:9
    |
 LL |     async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
    |                                       -------               ----
-   |                                       |
-   |                                       this parameter and the return type are declared with different lifetimes...
+   |                                       |                     |
+   |                                       |                     this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                       this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:25:9
    |
 LL |     async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
    |                                               -------                ----
-   |                                               |
-   |                                               this parameter and the return type are declared with different lifetimes...
+   |                                               |                      |
+   |                                               |                      this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                               this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:29:9
    |
 LL |     async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
    |                                           -------                ----
-   |                                           |
-   |                                           this parameter and the return type are declared with different lifetimes...
+   |                                           |                      |
+   |                                           |                      this `async fn` implicitly returns an `impl Future<Output = &u32>`
+   |                                           this parameter and the returned future are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is returned here
+   |         ^ ...but data from `f` is held across an await point here
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/test-attrs/test-allow-fail-attr.rs b/src/test/ui/test-attrs/test-allow-fail-attr.rs
index 1a478460efc..29ce9f7c2e9 100644
--- a/src/test/ui/test-attrs/test-allow-fail-attr.rs
+++ b/src/test/ui/test-attrs/test-allow-fail-attr.rs
@@ -1,11 +1,12 @@
 // run-pass
-// ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: --test
 #![feature(allow_fail)]
+#![feature(cfg_panic)]
 
 #[test]
 #[allow_fail]
 fn test1() {
+    #[cfg(not(panic = "abort"))]
     panic!();
 }
 
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 9a8f2404e4a..687354dc6ae 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -155,6 +155,7 @@ static TARGETS: &[&str] = &[
 ];
 
 static DOCS_TARGETS: &[&str] = &[
+    "aarch64-unknown-linux-gnu",
     "i686-apple-darwin",
     "i686-pc-windows-gnu",
     "i686-pc-windows-msvc",
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index 32c2562ee95..5a4264f9b5c 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -3089,7 +3089,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
     }
 }
 
-/// Detect the occurences of calls to `iter` or `into_iter` for the
+/// Detect the occurrences of calls to `iter` or `into_iter` for the
 /// given identifier
 fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident) -> Option<Vec<IterFunction>> {
     let mut visitor = IterFunctionVisitor {
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index 485888fa944..6b175490cc8 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -1,6 +1,6 @@
 use crate::utils::{span_lint, span_lint_and_then};
 use rustc_ast::ast::{
-    Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, MacCall, Pat, PatKind,
+    Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind,
 };
 use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
 use rustc_lint::{EarlyContext, EarlyLintPass};
@@ -150,9 +150,6 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> {
             _ => walk_pat(self, pat),
         }
     }
-    fn visit_mac(&mut self, _mac: &MacCall) {
-        // do not check macs
-    }
 }
 
 #[must_use]
@@ -357,9 +354,6 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> {
     fn visit_item(&mut self, _: &Item) {
         // do not recurse into inner items
     }
-    fn visit_mac(&mut self, _mac: &MacCall) {
-        // do not check macs
-    }
 }
 
 impl EarlyLintPass for NonExpressiveNames {