about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--.github/workflows/ci.yml130
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock123
-rw-r--r--Cargo.toml6
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs72
-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/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.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs14
-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.rs23
-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/hir.rs9
-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_macros/src/type_foldable.rs3
-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/traits/chalk.rs68
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs27
-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/interpret/eval_context.rs6
-rw-r--r--compiler/rustc_mir/src/monomorphize/collector.rs10
-rw-r--r--compiler/rustc_mir/src/transform/check_const_item_mutation.rs51
-rw-r--r--compiler/rustc_mir/src/transform/coverage/debug.rs8
-rw-r--r--compiler/rustc_mir/src/transform/inline.rs263
-rw-r--r--compiler/rustc_mir/src/transform/validate.rs99
-rw-r--r--compiler/rustc_mir/src/util/generic_graphviz.rs2
-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_resolve/src/diagnostics.rs48
-rw-r--r--compiler/rustc_resolve/src/imports.rs13
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/config.rs3
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_darwin.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_tvos.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_fuchsia.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_linux_android.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_none.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_redox.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs8
-rw-r--r--compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs8
-rw-r--r--compiler/rustc_target/src/spec/android_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/apple_sdk_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/arm_linux_androideabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/armebv7r_none_eabi.rs9
-rw-r--r--compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs9
-rw-r--r--compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs9
-rw-r--r--compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs9
-rw-r--r--compiler/rustc_target/src/spec/armv7_apple_ios.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7_linux_androideabi.rs6
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs9
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs9
-rw-r--r--compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv7a_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv7a_none_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv7r_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv7r_none_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/armv7s_apple_ios.rs10
-rw-r--r--compiler/rustc_target/src/spec/avr_gnu_base.rs8
-rw-r--r--compiler/rustc_target/src/spec/cloudabi_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/dragonfly_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/freebsd_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/fuchsia_base.rs3
-rw-r--r--compiler/rustc_target/src/spec/haiku_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/hermit_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/hermit_kernel_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/i386_apple_ios.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_apple_darwin.rs8
-rw-r--r--compiler/rustc_target/src/spec/i686_linux_android.rs8
-rw-r--r--compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs6
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs6
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_freebsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_haiku.rs6
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_netbsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_openbsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_uefi.rs8
-rw-r--r--compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs8
-rw-r--r--compiler/rustc_target/src/spec/i686_wrs_vxworks.rs6
-rw-r--r--compiler/rustc_target/src/spec/illumos_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/l4re_base.rs3
-rw-r--r--compiler/rustc_target/src/spec/linux_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/linux_kernel_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/linux_musl_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/linux_uclibc_base.rs5
-rw-r--r--compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs9
-rw-r--r--compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs14
-rw-r--r--compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs8
-rw-r--r--compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs8
-rw-r--r--compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs9
-rw-r--r--compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs14
-rw-r--r--compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs11
-rw-r--r--compiler/rustc_target/src/spec/mipsel_sony_psp.rs9
-rw-r--r--compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs10
-rw-r--r--compiler/rustc_target/src/spec/mipsel_unknown_none.rs8
-rw-r--r--compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs9
-rw-r--r--compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs9
-rw-r--r--compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs8
-rw-r--r--compiler/rustc_target/src/spec/mod.rs104
-rw-r--r--compiler/rustc_target/src/spec/msp430_none_elf.rs10
-rw-r--r--compiler/rustc_target/src/spec/msvc_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/netbsd_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs12
-rw-r--r--compiler/rustc_target/src/spec/openbsd_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs12
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs12
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs12
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs8
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs12
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs12
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs12
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs12
-rw-r--r--compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs12
-rw-r--r--compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs7
-rw-r--r--compiler/rustc_target/src/spec/redox_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs7
-rw-r--r--compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs7
-rw-r--r--compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs7
-rw-r--r--compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs7
-rw-r--r--compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs7
-rw-r--r--compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs9
-rw-r--r--compiler/rustc_target/src/spec/solaris_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs9
-rw-r--r--compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs12
-rw-r--r--compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs7
-rw-r--r--compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs7
-rw-r--r--compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs7
-rw-r--r--compiler/rustc_target/src/spec/thumb_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs7
-rw-r--r--compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs6
-rw-r--r--compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs8
-rw-r--r--compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs6
-rw-r--r--compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs8
-rw-r--r--compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs8
-rw-r--r--compiler/rustc_target/src/spec/uefi_msvc_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/vxworks_base.rs3
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs8
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs8
-rw-r--r--compiler/rustc_target/src/spec/wasm32_wasi.rs9
-rw-r--r--compiler/rustc_target/src/spec/windows_gnu_base.rs3
-rw-r--r--compiler/rustc_target/src/spec/windows_msvc_base.rs3
-rw-r--r--compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_darwin.rs8
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_ios.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_tvos.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_fuchsia.rs8
-rw-r--r--compiler/rustc_target/src/spec/x86_64_linux_android.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_linux_kernel.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs8
-rw-r--r--compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs7
-rw-r--r--compiler/rustc_target/src/spec/x86_64_sun_solaris.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs8
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs8
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs8
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_redox.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs8
-rw-r--r--compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs6
-rw-r--r--compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs8
-rw-r--r--compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.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/pat.rs5
-rw-r--r--compiler/rustc_typeck/src/check/regionck.rs2
-rw-r--r--compiler/rustc_typeck/src/collect/item_bounds.rs16
-rw-r--r--config.toml.example3
-rw-r--r--library/alloc/src/collections/btree/map/tests.rs26
-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/fmt.rs12
-rw-r--r--library/alloc/src/lib.rs2
-rw-r--r--library/core/src/cell.rs15
-rw-r--r--library/core/src/cmp.rs2
-rw-r--r--library/core/src/fmt/builders.rs44
-rw-r--r--library/core/src/hint.rs62
-rw-r--r--library/core/src/iter/adapters/flatten.rs2
-rw-r--r--library/core/src/iter/adapters/mod.rs38
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/core/src/num/error.rs17
-rw-r--r--library/core/src/num/mod.rs28
-rw-r--r--library/core/src/sync/atomic.rs25
-rw-r--r--library/core/src/task/poll.rs6
-rw-r--r--library/core/tests/cell.rs12
-rw-r--r--library/core/tests/lib.rs2
-rw-r--r--library/core/tests/nonzero.rs4
-rw-r--r--library/core/tests/num/mod.rs65
-rw-r--r--library/core/tests/task.rs14
-rw-r--r--library/std/src/collections/hash/map.rs4
-rw-r--r--library/std/src/fs.rs8
-rw-r--r--library/std/src/fs/tests.rs51
-rw-r--r--library/std/src/io/cursor.rs9
-rw-r--r--library/std/src/io/cursor/tests.rs7
-rw-r--r--library/std/src/io/util.rs9
-rw-r--r--library/std/src/io/util/tests.rs9
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--library/std/src/sync/mpsc/mod.rs3
-rw-r--r--library/std/src/sys/cloudabi/abi/cloudabi.rs12
-rw-r--r--library/std/src/sys/sgx/ext/io.rs2
-rw-r--r--library/std/src/sys/unix/fs.rs15
-rw-r--r--library/std/src/sys/unix/net.rs44
-rw-r--r--library/std/src/sys/unix/process/process_common/tests.rs25
-rw-r--r--library/std/src/thread/local.rs2
-rw-r--r--library/std/src/thread/mod.rs1
-rw-r--r--library/test/src/helpers/concurrency.rs18
-rw-r--r--src/bootstrap/CHANGELOG.md2
-rw-r--r--src/bootstrap/bootstrap.py19
-rw-r--r--src/bootstrap/builder.rs8
-rw-r--r--src/bootstrap/config.rs21
-rwxr-xr-xsrc/bootstrap/configure.py2
-rw-r--r--src/bootstrap/lib.rs4
-rw-r--r--src/bootstrap/native.rs4
-rw-r--r--src/bootstrap/test.rs26
-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
-rw-r--r--src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/i686-gnu/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile7
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile6
-rw-r--r--src/ci/github-actions/ci.yml41
-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/core.rs11
-rw-r--r--src/librustdoc/html/static/settings.css5
-rw-r--r--src/test/mir-opt/inline/inline-cycle.rs60
-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_shims.clone.Inline.diff26
-rw-r--r--src/test/mir-opt/inline/inline_shims.drop.Inline.diff52
-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/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/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/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/imports/issue-62767.rs8
-rw-r--r--src/test/ui/imports/issue-62767.stderr21
-rw-r--r--src/test/ui/issues/issue-68696-catch-during-unwind.rs4
-rw-r--r--src/test/ui/lint/lint-const-item-mutation.rs5
-rw-r--r--src/test/ui/lint/lint-const-item-mutation.stderr24
-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/print_type_sizes/anonymous.rs2
-rw-r--r--src/test/ui/print_type_sizes/generics.rs2
-rw-r--r--src/test/ui/print_type_sizes/multiple_types.rs2
-rw-r--r--src/test/ui/print_type_sizes/niche-filling.rs2
-rw-r--r--src/test/ui/print_type_sizes/no_duplicates.rs2
-rw-r--r--src/test/ui/print_type_sizes/packed.rs2
-rw-r--r--src/test/ui/print_type_sizes/padding.rs2
-rw-r--r--src/test/ui/print_type_sizes/repr-align.rs2
-rw-r--r--src/test/ui/print_type_sizes/repr_int_c.rs2
-rw-r--r--src/test/ui/print_type_sizes/uninhabited.rs2
-rw-r--r--src/test/ui/print_type_sizes/variants.rs2
-rw-r--r--src/test/ui/print_type_sizes/zero-sized-fields.rs2
-rw-r--r--src/test/ui/proc-macro/nonterminal-token-hygiene.rs33
-rw-r--r--src/test/ui/proc-macro/nonterminal-token-hygiene.stdout88
-rw-r--r--src/test/ui/test-attrs/test-allow-fail-attr.rs3
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-72793.rs27
-rw-r--r--src/tools/build-manifest/src/main.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs8
m---------src/tools/miri12
m---------src/tools/rls0
-rw-r--r--src/tools/rustc-workspace-hack/Cargo.toml1
m---------src/tools/rustfmt10
-rw-r--r--src/tools/x/Cargo.lock5
-rw-r--r--src/tools/x/Cargo.toml7
-rw-r--r--src/tools/x/README.md3
-rw-r--r--src/tools/x/src/main.rs92
371 files changed, 3297 insertions, 2881 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 91241d2b214..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: {}
@@ -321,8 +323,6 @@ jobs:
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
               SCRIPT: make ci-subset-1
-              NO_DEBUG_ASSERTIONS: 1
-              NO_LLVM_ASSERTIONS: 1
             os: windows-latest-xl
           - name: x86_64-msvc-2
             env:
@@ -333,23 +333,17 @@ jobs:
             env:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc"
               SCRIPT: make ci-subset-1
-              NO_DEBUG_ASSERTIONS: 1
-              NO_LLVM_ASSERTIONS: 1
             os: windows-latest-xl
           - name: i686-msvc-2
             env:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc"
               SCRIPT: make ci-subset-2
-              NO_DEBUG_ASSERTIONS: 1
-              NO_LLVM_ASSERTIONS: 1
             os: windows-latest-xl
           - name: x86_64-msvc-cargo
             env:
               SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-lld"
               VCVARS_BAT: vcvars64.bat
-              NO_DEBUG_ASSERTIONS: 1
-              NO_LLVM_ASSERTIONS: 1
             os: windows-latest-xl
           - name: x86_64-msvc-tools
             env:
@@ -361,8 +355,6 @@ jobs:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
               SCRIPT: make ci-mingw-subset-1
               CUSTOM_MINGW: 1
-              NO_DEBUG_ASSERTIONS: 1
-              NO_LLVM_ASSERTIONS: 1
             os: windows-latest-xl
           - name: i686-mingw-2
             env:
@@ -375,8 +367,6 @@ jobs:
               SCRIPT: make ci-mingw-subset-1
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
               CUSTOM_MINGW: 1
-              NO_DEBUG_ASSERTIONS: 1
-              NO_LLVM_ASSERTIONS: 1
             os: windows-latest-xl
           - name: x86_64-mingw-2
             env:
@@ -509,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/.gitignore b/.gitignore
index 1c50d9b054d..5f7135e38d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,7 @@ __pycache__/
 /inst/
 /llvm/
 /mingw-build/
+/src/tools/x/target
 # Created by default with `src/ci/docker/run.sh`:
 /obj/
 /unicode-downloads
diff --git a/Cargo.lock b/Cargo.lock
index b992552a521..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",
@@ -1968,18 +1968,6 @@ dependencies = [
 
 [[package]]
 name = "measureme"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fef709d3257013bba7cff14fc504e07e80631d3fe0f6d38ce63b8f6510ccb932"
-dependencies = [
- "byteorder",
- "memmap",
- "parking_lot 0.9.0",
- "rustc-hash",
-]
-
-[[package]]
-name = "measureme"
 version = "9.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "22bf8d885d073610aee20e7fa205c4341ed32a761dbde96da5fd96301a8d3e82"
@@ -2705,9 +2693,9 @@ dependencies = [
 
 [[package]]
 name = "racer"
-version = "2.1.39"
+version = "2.1.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9424b4650b9c1134d0a1b34dab82319691e1c95fa8af1658fc640deb1b6823c"
+checksum = "68c5fb83bc092c10e12ca863ab8922b1833382d5d248aaafca779886d3396a44"
 dependencies = [
  "bitflags",
  "clap",
@@ -3033,19 +3021,18 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_arena"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8e941a8fc3878a111d2bbfe78e39522d884136f0b412b12592195f26f653476"
+checksum = "477085eefed2f12085c68577cc3827c8c39a31a4a750978aacb9af10f7903174"
 dependencies = [
- "rustc-ap-rustc_data_structures",
  "smallvec 1.4.2",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_ast"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b58b6b035710df7f339a2bf86f6dafa876efd95439540970e24609e33598ca6"
+checksum = "4d4ad5ec25f6b3d122354595be0d1b513f37fca3299d9b448b1db28f4a9e4b12"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_data_structures",
@@ -3060,9 +3047,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_ast_passes"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d379a900d6a1f098490d92ab83e87487dcee2e4ec3f04c3ac4512b5117b64e2"
+checksum = "0c6d8635298d7736decdb3c6e92e784d3eccde557462a9c10ac11a34fec3d756"
 dependencies = [
  "itertools 0.9.0",
  "rustc-ap-rustc_ast",
@@ -3079,9 +3066,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_ast_pretty"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "658d925c0da9e3c5cddc5e54f4fa8c03b41aff1fc6dc5e41837c1118ad010ac0"
+checksum = "7a61bdb5252e1a95b7715038949e10f07ce770a436fcd497cdd9bc7255471de9"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_span",
@@ -3091,9 +3078,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_attr"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f387037534f34c148aed753622677500e42d190a095670e7ac3fffc09811a59"
+checksum = "84520a16cb61bd31e9c27e87eca5d933a9c94ac84f25649bddcc19989275ab2a"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_ast_pretty",
@@ -3110,10 +3097,11 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_data_structures"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14ffd17a37e00d77926a0713f191c59ff3aeb2b551a024c7cfffce14bab79be8"
+checksum = "b1cb2b6a38759cf7c0c1434c8b4cbfcab9cd24970d05f960f2ca01226ddb4d68"
 dependencies = [
+ "arrayvec",
  "bitflags",
  "cfg-if 0.1.10",
  "crossbeam-utils 0.7.2",
@@ -3121,7 +3109,7 @@ dependencies = [
  "indexmap",
  "jobserver",
  "libc",
- "measureme 0.7.1",
+ "measureme",
  "parking_lot 0.11.0",
  "rustc-ap-rustc_graphviz",
  "rustc-ap-rustc_index",
@@ -3140,9 +3128,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_errors"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b3263ddcfa9eb911e54a4e8088878dd9fd10e00d8b99b01033ba4a2733fe91d"
+checksum = "46cfb19536426bf9252827a78552d635be207a4be74f4e92832aad82d7f2135c"
 dependencies = [
  "annotate-snippets 0.8.0",
  "atty",
@@ -3159,9 +3147,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_expand"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1ab7e68cede8a2273fd8b8623002ce9dc832e061dfc3330e9bcc1fc2a722d73"
+checksum = "6273e60042a0ef31f6cfe783c519873993eb426f055be2bc058a48b6ca3934d0"
 dependencies = [
  "rustc-ap-rustc_ast",
  "rustc-ap-rustc_ast_passes",
@@ -3182,9 +3170,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_feature"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eea2dc95421bc19bbd4d939399833a882c46b684283b4267ad1fcf982fc043d9"
+checksum = "2936e8346157e2848305e509f38aa3ed4e97697975ef68027587f5db6a38703f"
 dependencies = [
  "rustc-ap-rustc_data_structures",
  "rustc-ap-rustc_span",
@@ -3192,21 +3180,21 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_fs_util"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e44c1804f09635f83f6cf1e04c2e92f8aeb7b4e850ac6c53d373dab02c13053"
+checksum = "9b4c3ae17776b5a5aa441ca510a650f75805e1f5569edd231caa8378552195a4"
 
 [[package]]
 name = "rustc-ap-rustc_graphviz"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc491f2b9be6e928f6df6b287549b8d50c48e8eff8638345155f40fa2cfb785d"
+checksum = "5611bf0ac0ac49c2a22c959c7d8b17f85f69959293f0e8c4f753eca832fe7ad0"
 
 [[package]]
 name = "rustc-ap-rustc_index"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa73f3fed413cdb6290738a10267da17b9ae8e02087334778b9a8c9491c5efc0"
+checksum = "ca67cf37c427057192e451c7f912e94ae9a8ca5ad69fd481c011fad3f86982cb"
 dependencies = [
  "arrayvec",
  "rustc-ap-rustc_macros",
@@ -3215,18 +3203,18 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_lexer"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e993881244a92f3b44cf43c8f22ae2ca5cefe4f55a34e2b65b72ee66fe5ad077"
+checksum = "a5b04cd2159495584d976d501c5394498470c2e94e4f0cebb8186562d407a678"
 dependencies = [
  "unicode-xid",
 ]
 
 [[package]]
 name = "rustc-ap-rustc_macros"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4effe366556e1d75344764adf4d54cba7c2fad33dbd07588e96d0853831ddc7c"
+checksum = "61ec6d623853449acd3c65050d249d3674edab5f6e4d9f074c7bac183269f9c8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3236,9 +3224,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_parse"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0342675835251571471d3dca9ea1576a853a8dfa1f4b0084db283c861223cb60"
+checksum = "ca524bafce4b04d2b49fee2d40b4b26c3ebab9f1a4f731fdf561f00617862f02"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_ast",
@@ -3256,9 +3244,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_serialize"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "438255ed968d73bf6573aa18d3b8d33c0a85ecdfd14160ef09ff813938e0606c"
+checksum = "c67920561e58f98c4de864407c92b2dd05ace5d5e5301e17444f10f742c005b7"
 dependencies = [
  "indexmap",
  "smallvec 1.4.2",
@@ -3266,9 +3254,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_session"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d61ff76dede8eb827f6805754900d1097a7046f938f950231b62b448f55bf78"
+checksum = "0762fd855792e06ef639327237898e4e092ad68150e6a8e19aeb7dc06276ad7a"
 dependencies = [
  "bitflags",
  "getopts",
@@ -3287,9 +3275,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_span"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c267f15c3cfc82a8a441d2bf86bcccf299d1eb625822468e3d8ee6f7c5a1c89"
+checksum = "0bf3db7b4ca5d21c14c45475df155e5e020c9a3760346945a662c9a9053b49c8"
 dependencies = [
  "cfg-if 0.1.10",
  "md-5 0.8.0",
@@ -3306,9 +3294,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_target"
-version = "679.0.0"
+version = "686.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b1b4b266c4d44aac0f7f83b6741d8f0545b03d1ce32f3b5254f2014225cb96c"
+checksum = "3aa6560bb9742b276064d67ab9edb5766ecb303f8ae3854835ad3fad4b432188"
 dependencies = [
  "bitflags",
  "rustc-ap-rustc_data_structures",
@@ -3393,6 +3381,7 @@ dependencies = [
 name = "rustc-workspace-hack"
 version = "1.0.0"
 dependencies = [
+ "byteorder",
  "crossbeam-utils 0.7.2",
  "proc-macro2",
  "quote",
@@ -3523,7 +3512,7 @@ version = "0.0.0"
 dependencies = [
  "bitflags",
  "libc",
- "measureme 9.0.0",
+ "measureme",
  "rustc-demangle",
  "rustc_ast",
  "rustc_attr",
@@ -3589,7 +3578,7 @@ dependencies = [
  "indexmap",
  "jobserver",
  "libc",
- "measureme 9.0.0",
+ "measureme",
  "parking_lot 0.11.0",
  "rustc-hash",
  "rustc-rayon",
@@ -3907,7 +3896,7 @@ version = "0.0.0"
 dependencies = [
  "bitflags",
  "chalk-ir",
- "measureme 9.0.0",
+ "measureme",
  "polonius-engine",
  "rustc-rayon-core",
  "rustc_apfloat",
@@ -4340,7 +4329,7 @@ dependencies = [
 
 [[package]]
 name = "rustfmt-nightly"
-version = "1.4.22"
+version = "1.4.24"
 dependencies = [
  "annotate-snippets 0.6.1",
  "anyhow",
@@ -5263,7 +5252,7 @@ dependencies = [
  "chrono",
  "lazy_static",
  "matchers",
- "parking_lot 0.11.0",
+ "parking_lot 0.9.0",
  "regex",
  "serde",
  "serde_json",
diff --git a/Cargo.toml b/Cargo.toml
index c27e5c469cf..e1a36d88086 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,11 +29,17 @@ members = [
   "src/tools/unicode-table-generator",
   "src/tools/expand-yaml-anchors",
 ]
+
 exclude = [
   "build",
   "compiler/rustc_codegen_cranelift",
   # HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`.
   "obj",
+  # The `x` binary is a thin wrapper that calls `x.py`, which initializes
+  # submodules, before which workspace members cannot be invoked because
+  # not all `Cargo.toml` files are available, so we exclude the `x` binary,
+  # so it can be invoked before the current checkout is set up.
+  "src/tools/x",
 ]
 
 [profile.release.package.compiler_builtins]
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index fe9ad58c9ac..7b85d28568b 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) {
@@ -461,7 +458,7 @@ pub fn noop_visit_ty_constraint<T: MutVisitor>(
 }
 
 pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
-    let Ty { id, kind, span, tokens: _ } = ty.deref_mut();
+    let Ty { id, kind, span, tokens } = ty.deref_mut();
     vis.visit_id(id);
     match kind {
         TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {}
@@ -494,9 +491,10 @@ 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);
 }
 
 pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
@@ -523,13 +521,14 @@ pub fn noop_visit_ident<T: MutVisitor>(Ident { name: _, span }: &mut Ident, vis:
     vis.visit_span(span);
 }
 
-pub fn noop_visit_path<T: MutVisitor>(Path { segments, span, tokens: _ }: &mut Path, vis: &mut T) {
+pub fn noop_visit_path<T: MutVisitor>(Path { segments, span, tokens }: &mut Path, vis: &mut T) {
     vis.visit_span(span);
     for PathSegment { ident, id, args } in segments {
         vis.visit_ident(ident);
         vis.visit_id(id);
         visit_opt(args, |args| vis.visit_generic_args(args));
     }
+    visit_lazy_tts(tokens, vis);
 }
 
 pub fn noop_visit_qself<T: MutVisitor>(qself: &mut Option<QSelf>, vis: &mut T) {
@@ -587,15 +586,17 @@ pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
 }
 
 pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
-    let Attribute { kind, id: _, style: _, span, tokens: _ } = attr;
+    let Attribute { kind, id: _, style: _, span, tokens } = attr;
     match kind {
-        AttrKind::Normal(AttrItem { path, args, tokens: _ }) => {
+        AttrKind::Normal(AttrItem { path, args, tokens }) => {
             vis.visit_path(path);
             visit_mac_args(args, vis);
+            visit_lazy_tts(tokens, vis);
         }
         AttrKind::DocComment(..) => {}
     }
     vis.visit_span(span);
+    visit_lazy_tts(tokens, vis);
 }
 
 pub fn noop_visit_mac<T: MutVisitor>(mac: &mut MacCall, vis: &mut T) {
@@ -652,12 +653,22 @@ pub fn visit_tt<T: MutVisitor>(tt: &mut TokenTree, vis: &mut T) {
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
 pub fn visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) {
-    if vis.token_visiting_enabled() {
+    if vis.token_visiting_enabled() && !tts.is_empty() {
         let tts = Lrc::make_mut(tts);
         visit_vec(tts, |(tree, _is_joint)| visit_tt(tree, vis));
     }
 }
 
+pub fn visit_lazy_tts<T: MutVisitor>(lazy_tts: &mut Option<LazyTokenStream>, vis: &mut T) {
+    if vis.token_visiting_enabled() {
+        visit_opt(lazy_tts, |lazy_tts| {
+            let mut tts = lazy_tts.create_token_stream();
+            visit_tts(&mut tts, vis);
+            *lazy_tts = LazyTokenStream::new(tts);
+        })
+    }
+}
+
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
 // Applies ident visitor if it's an ident; applies other visits to interpolated nodes.
 // In practice the ident part is not actually used by specific visitors right now,
@@ -725,9 +736,10 @@ pub fn visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut
         token::NtLifetime(ident) => vis.visit_ident(ident),
         token::NtLiteral(expr) => vis.visit_expr(expr),
         token::NtMeta(item) => {
-            let AttrItem { path, args, tokens: _ } = item.deref_mut();
+            let AttrItem { path, args, tokens } = item.deref_mut();
             vis.visit_path(path);
             visit_mac_args(args, vis);
+            visit_lazy_tts(tokens, vis);
         }
         token::NtPath(path) => vis.visit_path(path),
         token::NtTT(tt) => visit_tt(tt, vis),
@@ -887,10 +899,11 @@ pub fn noop_visit_mt<T: MutVisitor>(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mu
 }
 
 pub fn noop_visit_block<T: MutVisitor>(block: &mut P<Block>, vis: &mut T) {
-    let Block { id, stmts, rules: _, span, tokens: _ } = block.deref_mut();
+    let Block { id, stmts, rules: _, span, tokens } = block.deref_mut();
     vis.visit_id(id);
     stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt));
     vis.visit_span(span);
+    visit_lazy_tts(tokens, vis);
 }
 
 pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
@@ -946,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),
     }
 }
@@ -955,7 +968,7 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
     mut item: P<AssocItem>,
     visitor: &mut T,
 ) -> SmallVec<[P<AssocItem>; 1]> {
-    let Item { id, ident, vis, attrs, kind, span, tokens: _ } = item.deref_mut();
+    let Item { id, ident, vis, attrs, kind, span, tokens } = item.deref_mut();
     visitor.visit_id(id);
     visitor.visit_ident(ident);
     visitor.visit_vis(vis);
@@ -975,9 +988,10 @@ 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);
     smallvec![item]
 }
 
@@ -1028,16 +1042,14 @@ pub fn noop_flat_map_item<T: MutVisitor>(
     mut item: P<Item>,
     visitor: &mut T,
 ) -> SmallVec<[P<Item>; 1]> {
-    let Item { ident, attrs, id, kind, vis, span, tokens: _ } = item.deref_mut();
+    let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut();
     visitor.visit_ident(ident);
     visit_attrs(attrs, visitor);
     visitor.visit_id(id);
     visitor.visit_item_kind(kind);
     visitor.visit_vis(vis);
     visitor.visit_span(span);
-
-    // FIXME: if `tokens` is modified with a call to `vis.visit_tts` it causes
-    //        an ICE during resolve... odd!
+    visit_lazy_tts(tokens, visitor);
 
     smallvec![item]
 }
@@ -1046,7 +1058,7 @@ pub fn noop_flat_map_foreign_item<T: MutVisitor>(
     mut item: P<ForeignItem>,
     visitor: &mut T,
 ) -> SmallVec<[P<ForeignItem>; 1]> {
-    let Item { ident, attrs, id, kind, vis, span, tokens: _ } = item.deref_mut();
+    let Item { ident, attrs, id, kind, vis, span, tokens } = item.deref_mut();
     visitor.visit_id(id);
     visitor.visit_ident(ident);
     visitor.visit_vis(vis);
@@ -1066,14 +1078,15 @@ 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);
     smallvec![item]
 }
 
 pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
-    let Pat { id, kind, span, tokens: _ } = pat.deref_mut();
+    let Pat { id, kind, span, tokens } = pat.deref_mut();
     vis.visit_id(id);
     match kind {
         PatKind::Wild | PatKind::Rest => {}
@@ -1105,9 +1118,10 @@ 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);
 }
 
 pub fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonConst, vis: &mut T) {
@@ -1116,7 +1130,7 @@ pub fn noop_visit_anon_const<T: MutVisitor>(AnonConst { id, value }: &mut AnonCo
 }
 
 pub fn noop_visit_expr<T: MutVisitor>(
-    Expr { kind, id, span, attrs, tokens: _ }: &mut Expr,
+    Expr { kind, id, span, attrs, tokens }: &mut Expr,
     vis: &mut T,
 ) {
     match kind {
@@ -1270,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));
@@ -1295,6 +1309,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
     vis.visit_id(id);
     vis.visit_span(span);
     visit_thin_attrs(attrs, vis);
+    visit_lazy_tts(tokens, vis);
 }
 
 pub fn noop_filter_map_expr<T: MutVisitor>(mut e: P<Expr>, vis: &mut T) -> Option<P<Expr>> {
@@ -1305,11 +1320,12 @@ pub fn noop_filter_map_expr<T: MutVisitor>(mut e: P<Expr>, vis: &mut T) -> Optio
 }
 
 pub fn noop_flat_map_stmt<T: MutVisitor>(
-    Stmt { kind, mut span, mut id, tokens }: Stmt,
+    Stmt { kind, mut span, mut id, mut tokens }: Stmt,
     vis: &mut T,
 ) -> SmallVec<[Stmt; 1]> {
     vis.visit_id(&mut id);
     vis.visit_span(&mut span);
+    visit_lazy_tts(&mut tokens, vis);
     noop_flat_map_stmt_kind(kind, vis)
         .into_iter()
         .map(|kind| Stmt { id, kind, span, tokens: tokens.clone() })
@@ -1331,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 2ab6667ac3c..8751f09cfcb 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 599599f415f..af2f96d5e62 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -2531,6 +2531,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,
         )
@@ -2541,7 +2542,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/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..e68b626e22d 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -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
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_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_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index c124ab64218..a07dd8ede8b 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -547,11 +547,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 f6959591b56..8c7a4f06838 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 0cffca17271..f0e5826f403 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -313,25 +313,24 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
             // Implement the proposal described in
             // https://github.com/rust-lang/rust/issues/61733#issuecomment-509626449
             //
-            // The macro invocation expands to the list of statements.
-            // If the list of statements is empty, then 'parse'
-            // the trailing semicolon on the original invocation
-            // as an empty statement. That is:
+            // The macro invocation expands to the list of statements. If the
+            // list of statements is empty, then 'parse' the trailing semicolon
+            // on the original invocation as an empty statement. That is:
             //
             // `empty();` is parsed as a single `StmtKind::Empty`
             //
-            // If the list of statements is non-empty, see if the
-            // final statement alreayd has a trailing semicolon.
+            // If the list of statements is non-empty, see if the final
+            // statement already has a trailing semicolon.
             //
-            // If it doesn't have a semicolon, then 'parse' the trailing semicolon
-            // from the invocation as part of the final statement,
+            // If it doesn't have a semicolon, then 'parse' the trailing
+            // semicolon from the invocation as part of the final statement,
             // using `stmt.add_trailing_semicolon()`
             //
             // If it does have a semicolon, then 'parse' the trailing semicolon
             // from the invocation as a new StmtKind::Empty
 
-            // FIXME: We will need to preserve the original
-            // semicolon token and span as part of #15701
+            // FIXME: We will need to preserve the original semicolon token and
+            // span as part of #15701
             let empty_stmt = ast::Stmt {
                 id: ast::DUMMY_NODE_ID,
                 kind: ast::StmtKind::Empty,
@@ -386,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/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_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_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs
index b16e22e8d77..8fa6e6a7101 100644
--- a/compiler/rustc_macros/src/type_foldable.rs
+++ b/compiler/rustc_macros/src/type_foldable.rs
@@ -16,9 +16,8 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
         })
     });
 
-    let body_visit = s.fold(quote!(), |acc, bind| {
+    let body_visit = s.each(|bind| {
         quote! {
-            #acc
             ::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder)?;
         }
     });
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/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/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/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/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/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
index fb89b36060a..a8457043278 100644
--- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
+++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
@@ -61,22 +61,35 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
 
     fn lint_const_item_usage(
         &self,
+        place: &Place<'tcx>,
         const_item: DefId,
         location: Location,
         decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b>,
     ) {
-        let source_info = self.body.source_info(location);
-        let lint_root = self.body.source_scopes[source_info.scope]
-            .local_data
-            .as_ref()
-            .assert_crate_local()
-            .lint_root;
+        // Don't lint on borrowing/assigning to a dereference
+        // e.g:
+        //
+        // `unsafe { *FOO = 0; *BAR.field = 1; }`
+        // `unsafe { &mut *FOO }`
+        if !matches!(place.projection.last(), Some(PlaceElem::Deref)) {
+            let source_info = self.body.source_info(location);
+            let lint_root = self.body.source_scopes[source_info.scope]
+                .local_data
+                .as_ref()
+                .assert_crate_local()
+                .lint_root;
 
-        self.tcx.struct_span_lint_hir(CONST_ITEM_MUTATION, lint_root, source_info.span, |lint| {
-            decorate(lint)
-                .span_note(self.tcx.def_span(const_item), "`const` item defined here")
-                .emit()
-        });
+            self.tcx.struct_span_lint_hir(
+                CONST_ITEM_MUTATION,
+                lint_root,
+                source_info.span,
+                |lint| {
+                    decorate(lint)
+                        .span_note(self.tcx.def_span(const_item), "`const` item defined here")
+                        .emit()
+                },
+            );
+        }
     }
 }
 
@@ -88,15 +101,11 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> {
             // so emitting a lint would be redundant.
             if !lhs.projection.is_empty() {
                 if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
-                    // Don't lint on writes through a pointer
-                    // (e.g. `unsafe { *FOO = 0; *BAR.field = 1; }`)
-                    if !matches!(lhs.projection.last(), Some(PlaceElem::Deref)) {
-                        self.lint_const_item_usage(def_id, loc, |lint| {
-                            let mut lint = lint.build("attempting to modify a `const` item");
-                            lint.note("each usage of a `const` item creates a new temporary - the original `const` item will not be modified");
-                            lint
-                        })
-                    }
+                    self.lint_const_item_usage(&lhs, def_id, loc, |lint| {
+                        let mut lint = lint.build("attempting to modify a `const` item");
+                        lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified");
+                        lint
+                    })
                 }
             }
             // We are looking for MIR of the form:
@@ -127,7 +136,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> {
                 });
                 let lint_loc =
                     if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
-                self.lint_const_item_usage(def_id, lint_loc, |lint| {
+                self.lint_const_item_usage(place, def_id, lint_loc, |lint| {
                     let mut lint = lint.build("taking a mutable reference to a `const` item");
                     lint
                         .note("each usage of a `const` item creates a new temporary")
diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs
index cc697dfd7fe..ffa795134e2 100644
--- a/compiler/rustc_mir/src/transform/coverage/debug.rs
+++ b/compiler/rustc_mir/src/transform/coverage/debug.rs
@@ -147,8 +147,8 @@ impl DebugOptions {
         let mut counter_format = ExpressionFormat::default();
 
         if let Ok(env_debug_options) = std::env::var(RUSTC_COVERAGE_DEBUG_OPTIONS) {
-            for setting_str in env_debug_options.replace(" ", "").replace("-", "_").split(",") {
-                let mut setting = setting_str.splitn(2, "=");
+            for setting_str in env_debug_options.replace(" ", "").replace("-", "_").split(',') {
+                let mut setting = setting_str.splitn(2, '=');
                 match setting.next() {
                     Some(option) if option == "allow_unused_expressions" => {
                         allow_unused_expressions = bool_option_val(option, setting.next());
@@ -210,7 +210,7 @@ fn bool_option_val(option: &str, some_strval: Option<&str>) -> bool {
 
 fn counter_format_option_val(strval: &str) -> ExpressionFormat {
     let mut counter_format = ExpressionFormat { id: false, block: false, operation: false };
-    let components = strval.splitn(3, "+");
+    let components = strval.splitn(3, '+');
     for component in components {
         match component {
             "id" => counter_format.id = true,
@@ -695,7 +695,7 @@ pub(crate) fn dump_coverage_graphviz(
         let from_bcb_data = &basic_coverage_blocks[from_bcb];
         let from_terminator = from_bcb_data.terminator(mir_body);
         let mut edge_labels = from_terminator.kind.fmt_successor_labels();
-        edge_labels.retain(|label| label.to_string() != "unreachable");
+        edge_labels.retain(|label| label != "unreachable");
         let edge_counters = from_terminator
             .successors()
             .map(|&successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb));
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index 4de93739992..97b51344526 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -1,21 +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;
+use std::ops::{Range, RangeFrom};
 
 const DEFAULT_THRESHOLD: usize = 50;
 const HINT_THRESHOLD: usize = 100;
@@ -38,134 +37,128 @@ struct CallSite<'tcx> {
 
 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 +175,8 @@ impl Inliner<'tcx> {
 
         // Only consider direct calls to functions
         let terminator = bb_data.terminator();
-        if let TerminatorKind::Call { func: ref op, .. } = terminator.kind {
+        // FIXME: Handle inlining of diverging calls
+        if let TerminatorKind::Call { func: ref op, destination: Some(_), .. } = 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.
@@ -203,14 +197,6 @@ impl Inliner<'tcx> {
         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;
@@ -309,7 +295,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 +316,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 +368,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 +397,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();
         match terminator.kind {
-            // FIXME: Handle inlining of diverging calls
             TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => {
-                debug!("inlined {:?} into {:?}", callsite.callee, caller_body.source);
-
                 // 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`
@@ -425,7 +418,7 @@ impl Inliner<'tcx> {
                 }
 
                 let dest = if dest_needs_borrow(destination.0) {
-                    debug!("creating temp for return destination");
+                    trace!("creating temp for return destination");
                     let dest = Rvalue::Ref(
                         self.tcx.lifetimes.re_erased,
                         BorrowKind::Mut { allow_two_phase_borrow: false },
@@ -523,14 +516,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),
         }
     }
 
@@ -633,7 +620,7 @@ impl Inliner<'tcx> {
             }
         }
 
-        debug!("creating temp for argument {:?}", arg);
+        trace!("creating temp for argument {:?}", arg);
         // Otherwise, create a temporary for the arg
         let arg = Rvalue::Use(arg);
 
@@ -703,19 +690,19 @@ impl<'a, 'tcx> Integrator<'a, 'tcx> {
                 Local::new(self.new_locals.start.index() + (idx - self.args.len()))
             }
         };
-        debug!("mapping local `{:?}` to `{:?}`", local, new);
+        trace!("mapping local `{:?}` to `{:?}`", local, new);
         new
     }
 
     fn map_scope(&self, scope: SourceScope) -> SourceScope {
         let new = SourceScope::new(self.new_scopes.start.index() + scope.index());
-        debug!("mapping scope `{:?}` to `{:?}`", scope, new);
+        trace!("mapping scope `{:?}` to `{:?}`", scope, new);
         new
     }
 
     fn map_block(&self, block: BasicBlock) -> BasicBlock {
         let new = BasicBlock::new(self.new_blocks.start.index() + block.index());
-        debug!("mapping block `{:?}` to `{:?}`", block, new);
+        trace!("mapping block `{:?}` to `{:?}`", block, new);
         new
     }
 }
diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs
index 1868d3b47f2..e1e6e71acb5 100644
--- a/compiler/rustc_mir/src/transform/validate.rs
+++ b/compiler/rustc_mir/src/transform/validate.rs
@@ -6,6 +6,7 @@ use crate::util::storage::AlwaysLiveLocals;
 
 use super::MirPass;
 use rustc_index::bit_set::BitSet;
+use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
@@ -13,8 +14,8 @@ use rustc_middle::mir::{
     AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceRef,
     Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo,
 };
-use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::fold::BottomUpFolder;
+use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable};
 use rustc_target::abi::Size;
 
 #[derive(Copy, Clone, Debug)]
@@ -77,79 +78,27 @@ pub fn equal_up_to_regions(
         return true;
     }
 
-    struct LifetimeIgnoreRelation<'tcx> {
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    }
-
-    impl TypeRelation<'tcx> for LifetimeIgnoreRelation<'tcx> {
-        fn tcx(&self) -> TyCtxt<'tcx> {
-            self.tcx
-        }
-
-        fn param_env(&self) -> ty::ParamEnv<'tcx> {
-            self.param_env
-        }
-
-        fn tag(&self) -> &'static str {
-            "librustc_mir::transform::validate"
-        }
-
-        fn a_is_expected(&self) -> bool {
-            true
-        }
-
-        fn relate_with_variance<T: Relate<'tcx>>(
-            &mut self,
-            _: ty::Variance,
-            a: T,
-            b: T,
-        ) -> RelateResult<'tcx, T> {
-            // Ignore variance, require types to be exactly the same.
-            self.relate(a, b)
-        }
-
-        fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
-            if a == b {
-                // Short-circuit.
-                return Ok(a);
-            }
-            ty::relate::super_relate_tys(self, a, b)
-        }
-
-        fn regions(
-            &mut self,
-            a: ty::Region<'tcx>,
-            _b: ty::Region<'tcx>,
-        ) -> RelateResult<'tcx, ty::Region<'tcx>> {
-            // Ignore regions.
-            Ok(a)
-        }
-
-        fn consts(
-            &mut self,
-            a: &'tcx ty::Const<'tcx>,
-            b: &'tcx ty::Const<'tcx>,
-        ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
-            ty::relate::super_relate_consts(self, a, b)
-        }
-
-        fn binders<T>(
-            &mut self,
-            a: ty::Binder<T>,
-            b: ty::Binder<T>,
-        ) -> RelateResult<'tcx, ty::Binder<T>>
-        where
-            T: Relate<'tcx>,
-        {
-            self.relate(a.skip_binder(), b.skip_binder())?;
-            Ok(a)
-        }
-    }
-
-    // Instantiate and run relation.
-    let mut relator: LifetimeIgnoreRelation<'tcx> = LifetimeIgnoreRelation { tcx: tcx, param_env };
-    relator.relate(src, dest).is_ok()
+    // Normalize lifetimes away on both sides, then compare.
+    let param_env = param_env.with_reveal_all_normalized(tcx);
+    let normalize = |ty: Ty<'tcx>| {
+        tcx.normalize_erasing_regions(
+            param_env,
+            ty.fold_with(&mut BottomUpFolder {
+                tcx,
+                // FIXME: We erase all late-bound lifetimes, but this is not fully correct.
+                // If you have a type like `<for<'a> fn(&'a u32) as SomeTrait>::Assoc`,
+                // this is not necessarily equivalent to `<fn(&'static u32) as SomeTrait>::Assoc`,
+                // since one may have an `impl SomeTrait for fn(&32)` and
+                // `impl SomeTrait for fn(&'static u32)` at the same time which
+                // specify distinct values for Assoc. (See also #56105)
+                lt_op: |_| tcx.lifetimes.re_erased,
+                // Leave consts and types unchanged.
+                ct_op: |ct| ct,
+                ty_op: |ty| ty,
+            }),
+        )
+    };
+    tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok())
 }
 
 struct TypeChecker<'a, 'tcx> {
diff --git a/compiler/rustc_mir/src/util/generic_graphviz.rs b/compiler/rustc_mir/src/util/generic_graphviz.rs
index 91499bb61c2..8bd4a512bbb 100644
--- a/compiler/rustc_mir/src/util/generic_graphviz.rs
+++ b/compiler/rustc_mir/src/util/generic_graphviz.rs
@@ -174,7 +174,7 @@ impl<
     where
         W: Write,
     {
-        let lines = label.split("\n").map(|s| dot::escape_html(s)).collect::<Vec<_>>();
+        let lines = label.split('\n').map(|s| dot::escape_html(s)).collect::<Vec<_>>();
         let escaped_label = lines.join(r#"<br align="left"/>"#);
         writeln!(w, r#"    label=<<br/><br/>{}<br align="left"/><br/><br/><br/>>;"#, escaped_label)
     }
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_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 4e115c62c9e..5c7a7c1d0ae 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1021,17 +1021,11 @@ impl<'a> Resolver<'a> {
                 ("", "")
             };
 
-            let article = if built_in.is_empty() { res.article() } else { "a" };
-            format!(
-                "{a}{built_in} {thing}{from}",
-                a = article,
-                thing = res.descr(),
-                built_in = built_in,
-                from = from
-            )
+            let a = if built_in.is_empty() { res.article() } else { "a" };
+            format!("{a}{built_in} {thing}{from}", thing = res.descr())
         } else {
             let introduced = if b.is_import() { "imported" } else { "defined" };
-            format!("the {thing} {introduced} here", thing = res.descr(), introduced = introduced)
+            format!("the {thing} {introduced} here", thing = res.descr())
         }
     }
 
@@ -1049,19 +1043,13 @@ impl<'a> Resolver<'a> {
             ident.span,
             E0659,
             "`{ident}` is ambiguous ({why})",
-            ident = ident,
             why = kind.descr()
         );
         err.span_label(ident.span, "ambiguous name");
 
         let mut could_refer_to = |b: &NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
             let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
-            let note_msg = format!(
-                "`{ident}` could{also} refer to {what}",
-                ident = ident,
-                also = also,
-                what = what
-            );
+            let note_msg = format!("`{ident}` could{also} refer to {what}");
 
             let thing = b.res().descr();
             let mut help_msgs = Vec::new();
@@ -1071,30 +1059,18 @@ impl<'a> Resolver<'a> {
                     || kind == AmbiguityKind::GlobVsOuter && swapped != also.is_empty())
             {
                 help_msgs.push(format!(
-                    "consider adding an explicit import of \
-                     `{ident}` to disambiguate",
-                    ident = ident
+                    "consider adding an explicit import of `{ident}` to disambiguate"
                 ))
             }
             if b.is_extern_crate() && ident.span.rust_2018() {
-                help_msgs.push(format!(
-                    "use `::{ident}` to refer to this {thing} unambiguously",
-                    ident = ident,
-                    thing = thing,
-                ))
+                help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
             }
             if misc == AmbiguityErrorMisc::SuggestCrate {
-                help_msgs.push(format!(
-                    "use `crate::{ident}` to refer to this {thing} unambiguously",
-                    ident = ident,
-                    thing = thing,
-                ))
+                help_msgs
+                    .push(format!("use `crate::{ident}` to refer to this {thing} unambiguously"))
             } else if misc == AmbiguityErrorMisc::SuggestSelf {
-                help_msgs.push(format!(
-                    "use `self::{ident}` to refer to this {thing} unambiguously",
-                    ident = ident,
-                    thing = thing,
-                ))
+                help_msgs
+                    .push(format!("use `self::{ident}` to refer to this {thing} unambiguously"))
             }
 
             err.span_note(b.span, &note_msg);
@@ -1167,12 +1143,10 @@ impl<'a> Resolver<'a> {
             };
 
             let first = ptr::eq(binding, first_binding);
-            let descr = get_descr(binding);
             let msg = format!(
                 "{and_refers_to}the {item} `{name}`{which} is defined here{dots}",
                 and_refers_to = if first { "" } else { "...and refers to " },
-                item = descr,
-                name = name,
+                item = get_descr(binding),
                 which = if first { "" } else { " which" },
                 dots = if next_binding.is_some() { "..." } else { "" },
             );
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 269d25be0a5..026cf8be738 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -872,6 +872,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
     /// consolidate multiple unresolved import errors into a single diagnostic.
     fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImportError> {
         let orig_vis = import.vis.replace(ty::Visibility::Invisible);
+        let orig_unusable_binding = match &import.kind {
+            ImportKind::Single { target_bindings, .. } => {
+                Some(mem::replace(&mut self.r.unusable_binding, target_bindings[TypeNS].get()))
+            }
+            _ => None,
+        };
         let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
         let path_res = self.r.resolve_path(
             &import.module_path,
@@ -882,6 +888,9 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             import.crate_lint(),
         );
         let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
+        if let Some(orig_unusable_binding) = orig_unusable_binding {
+            self.r.unusable_binding = orig_unusable_binding;
+        }
         import.vis.set(orig_vis);
         if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res {
             // Consider erroneous imports used to avoid duplicate diagnostics.
@@ -892,8 +901,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 // Consistency checks, analogous to `finalize_macro_resolutions`.
                 if let Some(initial_module) = import.imported_module.get() {
                     if !ModuleOrUniformRoot::same_def(module, initial_module) && no_ambiguity {
-                        let msg = "inconsistent resolution for an import";
-                        self.r.session.span_err(import.span, msg);
+                        span_bug!(import.span, "inconsistent resolution for an import");
                     }
                 } else if self.r.privacy_errors.is_empty() {
                     let msg = "cannot determine resolution for the import";
@@ -913,6 +921,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             }
             PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => {
                 if no_ambiguity {
+                    assert!(import.imported_module.get().is_none());
                     let err = match self.make_path_suggestion(
                         span,
                         import.module_path.clone(),
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 14f8c7b09f8..00e6d5ca381 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -865,7 +865,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                     err.span_suggestion(
                         span,
                         &format!("use struct {} syntax instead", descr),
-                        format!("{} {{{pad}{}{pad}}}", path_str, fields, pad = pad),
+                        format!("{path_str} {{{pad}{fields}{pad}}}"),
                         applicability,
                     );
                 }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 30cd9944b1a..f1e30470f8e 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -11,6 +11,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
+#![feature(format_args_capture)]
 #![feature(nll)]
 #![feature(or_patterns)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index b632bfbed30..ab694ad4c5a 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -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_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/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
index c15bd9a08fc..098651614d0 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::apple_base::opts();
+    let mut base = super::apple_base::opts("macos");
     base.cpu = "apple-a12".to_string();
     base.max_atomic_width = Some(128);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]);
@@ -16,15 +16,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target,
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
         arch: arch.to_string(),
-        target_os: "macos".to_string(),
-        target_env: String::new(),
-        target_vendor: "apple".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
index 0019fc4492d..2218c6c6da7 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
@@ -1,19 +1,13 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts(Arch::Arm64);
+    let base = opts("ios", Arch::Arm64);
     Target {
         llvm_target: "arm64-apple-ios".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "ios".to_string(),
-        target_env: String::new(),
-        target_vendor: "apple".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".to_string(),
             eliminate_frame_pointer: false,
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
index 276682c591d..a83de77dc2a 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
@@ -1,19 +1,13 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts(Arch::Arm64);
+    let base = opts("tvos", Arch::Arm64);
     Target {
         llvm_target: "arm64-apple-tvos".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "tvos".to_string(),
-        target_env: String::new(),
-        target_vendor: "apple".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".to_string(),
             eliminate_frame_pointer: false,
diff --git a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
index 1f81a03c4a5..1252741f979 100644
--- a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::fuchsia_base::opts();
@@ -6,15 +6,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-fuchsia".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "fuchsia".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
index 1ed4f0da79c..fa6108df206 100644
--- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 // See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
 // for target ABI requirements.
@@ -11,15 +11,9 @@ pub fn target() -> Target {
     base.features = "+neon,+fp-armv8".to_string();
     Target {
         llvm_target: "aarch64-linux-android".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "android".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs
index 32fa2d69540..1369d9d0798 100644
--- a/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
@@ -8,15 +8,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-pc-windows-msvc".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "windows".to_string(),
-        target_env: "msvc".to_string(),
-        target_vendor: "pc".to_string(),
-        linker_flavor: LinkerFlavor::Msvc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs
index f9d62519bd9..67f69b40e55 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::cloudabi_base::opts();
@@ -8,15 +8,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-cloudabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "cloudabi".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
index 3d008290240..d48389d4a35 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
@@ -6,15 +6,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-freebsd".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "freebsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
index a7050cbee9e..44beb2f6ad8 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::hermit_base::opts();
@@ -6,15 +6,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-hermit".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "hermit".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: 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 10255012e41..9d9698a440d 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_base::opts();
@@ -6,15 +6,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
-        target_env: "gnu".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "linux".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             unsupported_abis: super::arm_base::unsupported_abis(),
             target_mcount: "\u{1}_mcount".to_string(),
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 f530163faf7..2dd703b66ff 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -6,15 +6,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-linux-musl".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
-        target_env: "musl".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "linux".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             unsupported_abis: super::arm_base::unsupported_abis(),
             target_mcount: "\u{1}_mcount".to_string(),
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
index dcb157d7aab..81e383ca5f1 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
@@ -7,15 +7,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-netbsd".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "netbsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_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 6d3e72906d5..1088807f2c2 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
@@ -10,6 +10,8 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOp
 
 pub fn target() -> Target {
     let opts = TargetOptions {
+        target_vendor: String::new(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         features: "+strict-align,+neon,+fp-armv8".to_string(),
         executables: true,
@@ -23,15 +25,9 @@ pub fn target() -> Target {
     };
     Target {
         llvm_target: "aarch64-unknown-none".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: opts,
     }
 }
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 784cd7eb3c9..044c9fa1de8 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
@@ -10,6 +10,8 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOp
 
 pub fn target() -> Target {
     let opts = TargetOptions {
+        target_vendor: String::new(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         features: "+strict-align,-neon,-fp-armv8".to_string(),
         executables: true,
@@ -23,15 +25,9 @@ pub fn target() -> Target {
     };
     Target {
         llvm_target: "aarch64-unknown-none".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: opts,
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
index e03690e86b8..83ba1ecd1d3 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
@@ -7,15 +7,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-openbsd".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "openbsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs b/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs
index 13adec9d4c4..b9c9325831d 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::redox_base::opts();
@@ -6,15 +6,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-redox".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "redox".to_string(),
-        target_env: "relibc".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs
index d6af5dd3628..e0a81df2b0d 100644
--- a/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::windows_uwp_msvc_base::opts();
@@ -7,15 +7,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-pc-windows-msvc".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "windows".to_string(),
-        target_env: "msvc".to_string(),
-        target_vendor: "uwp".to_string(),
-        linker_flavor: LinkerFlavor::Msvc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
index 6fce200a96e..beb8ce30cc9 100644
--- a/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
@@ -6,15 +6,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
         arch: "aarch64".to_string(),
-        target_os: "vxworks".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "wrs".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs
index 0824bc30358..1bd5eb6988c 100644
--- a/compiler/rustc_target/src/spec/android_base.rs
+++ b/compiler/rustc_target/src/spec/android_base.rs
@@ -2,6 +2,7 @@ use crate::spec::{LinkerFlavor, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     let mut base = super::linux_base::opts();
+    base.target_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
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 2e3c835c0e5..045d9967f30 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -2,7 +2,7 @@ use std::env;
 
 use crate::spec::{LinkArgs, TargetOptions};
 
-pub fn opts() -> TargetOptions {
+pub fn opts(os: &str) -> TargetOptions {
     // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
     // either the linker will complain if it is used or the binary will end up
     // segfaulting at runtime when run on 10.6. Rust by default supports macOS
@@ -17,6 +17,8 @@ pub fn opts() -> TargetOptions {
     let version = macos_deployment_target();
 
     TargetOptions {
+        target_os: os.to_string(),
+        target_vendor: "apple".to_string(),
         // macOS has -dead_strip, which doesn't rely on function_sections
         function_sections: false,
         dynamic_linking: true,
diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs
index 1b17c2c278f..092401f1146 100644
--- a/compiler/rustc_target/src/spec/apple_sdk_base.rs
+++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs
@@ -31,7 +31,7 @@ fn link_env_remove(arch: Arch) -> Vec<String> {
     }
 }
 
-pub fn opts(arch: Arch) -> TargetOptions {
+pub fn opts(os: &str, arch: Arch) -> TargetOptions {
     TargetOptions {
         cpu: target_cpu(arch),
         dynamic_linking: false,
@@ -39,6 +39,6 @@ pub fn opts(arch: Arch) -> TargetOptions {
         link_env_remove: link_env_remove(arch),
         has_elf_tls: false,
         eliminate_frame_pointer: false,
-        ..super::apple_base::opts()
+        ..super::apple_base::opts(os)
     }
 }
diff --git a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
index f9c69217460..43537569e7d 100644
--- a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::android_base::opts();
@@ -8,15 +8,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "arm-linux-androideabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "android".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
     }
 }
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 96a444fc465..dca0b1ec2e4 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
@@ -1,19 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.max_atomic_width = Some(64);
     Target {
         llvm_target: "arm-unknown-linux-gnueabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             features: "+strict-align,+v6".to_string(),
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 534b98cc607..ee71ae61972 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
@@ -1,19 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.max_atomic_width = Some(64);
     Target {
         llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             features: "+strict-align,+v6,+vfp2,-d32".to_string(),
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 e5fa3e3a1cb..6938a043602 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -12,15 +12,9 @@ pub fn target() -> Target {
         // to determine the calling convention and float ABI, and it doesn't
         // support the "musleabi" value.
         llvm_target: "arm-unknown-linux-gnueabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             unsupported_abis: super::arm_base::unsupported_abis(),
             target_mcount: "\u{1}mcount".to_string(),
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 b631a0010a0..4adf3a33893 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -12,15 +12,9 @@ pub fn target() -> Target {
         // uses it to determine the calling convention and float ABI, and it
         // doesn't support the "musleabihf" value.
         llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             unsupported_abis: super::arm_base::unsupported_abis(),
             target_mcount: "\u{1}mcount".to_string(),
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
index 86d0cd57af3..7bfa5baecb5 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
@@ -6,17 +6,14 @@ use crate::spec::{Target, TargetOptions};
 pub fn target() -> Target {
     Target {
         llvm_target: "armebv7r-unknown-none-eabi".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "none".to_string(),
-        target_env: "".to_string(),
-        target_vendor: "".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
+            target_endian: "big".to_string(),
+            target_vendor: String::new(),
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             executables: true,
             linker: Some("rust-lld".to_owned()),
             relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
index 9ea44b3b25e..7afc933a28f 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
@@ -6,17 +6,14 @@ use crate::spec::{Target, TargetOptions};
 pub fn target() -> Target {
     Target {
         llvm_target: "armebv7r-unknown-none-eabihf".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
+            target_endian: "big".to_string(),
+            target_vendor: String::new(),
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             executables: true,
             linker: Some("rust-lld".to_owned()),
             relocation_model: RelocModel::Static,
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 be32731a869..c58fa7407b4 100644
--- a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
@@ -1,18 +1,12 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = super::linux_base::opts();
     Target {
         llvm_target: "armv4t-unknown-linux-gnueabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             features: "+soft-float,+strict-align".to_string(),
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 4ea4b650623..049a031398a 100644
--- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
@@ -1,18 +1,12 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = super::linux_base::opts();
     Target {
         llvm_target: "armv5te-unknown-linux-gnueabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             features: "+soft-float,+strict-align".to_string(),
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 a41a5409ac9..77cf8bb76d3 100644
--- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = super::linux_musl_base::opts();
@@ -7,15 +7,9 @@ pub fn target() -> Target {
         // uses it to determine the calling convention and float ABI, and LLVM
         // doesn't support the "musleabihf" value.
         llvm_target: "armv5te-unknown-linux-gnueabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             features: "+soft-float,+strict-align".to_string(),
diff --git a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
index 68f6502133a..981d615f684 100644
--- a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
@@ -1,20 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = super::freebsd_base::opts();
     Target {
         llvm_target: "armv6-unknown-freebsd-gnueabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "freebsd".to_string(),
-        target_env: "gnueabihf".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
+            target_env: "gnueabihf".to_string(),
             features: "+v6,+vfp2,-d32".to_string(),
             max_atomic_width: Some(64),
             unsupported_abis: super::arm_base::unsupported_abis(),
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 23a20ca1c9f..8417a8f2801 100644
--- a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
@@ -1,21 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.max_atomic_width = Some(64);
     Target {
         llvm_target: "armv6-unknown-netbsdelf-eabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "netbsd".to_string(),
-        target_env: "eabihf".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
+            target_env: "eabihf".to_string(),
             features: "+v6,+vfp2,-d32".to_string(),
             unsupported_abis: super::arm_base::unsupported_abis(),
             target_mcount: "__mcount".to_string(),
diff --git a/compiler/rustc_target/src/spec/armv7_apple_ios.rs b/compiler/rustc_target/src/spec/armv7_apple_ios.rs
index 24a47dd56a9..051a394657c 100644
--- a/compiler/rustc_target/src/spec/armv7_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/armv7_apple_ios.rs
@@ -1,19 +1,13 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts(Arch::Armv7);
+    let base = opts("ios", Arch::Armv7);
     Target {
         llvm_target: "armv7-apple-ios".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(),
         arch: "arm".to_string(),
-        target_os: "ios".to_string(),
-        target_env: String::new(),
-        target_vendor: "apple".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             features: "+v7,+vfp3,+neon".to_string(),
             max_atomic_width: Some(64),
diff --git a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
index 342959883cb..9aa378a8018 100644
--- a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
@@ -16,15 +16,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "armv7-none-linux-android".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "android".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..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 d4bb4e963fb..921640d0aa6 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::cloudabi_base::opts();
@@ -10,15 +10,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "cloudabi".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_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 c32e2d4376e..88d5c86cfab 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
@@ -1,20 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = super::freebsd_base::opts();
     Target {
         llvm_target: "armv7-unknown-freebsd-gnueabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "freebsd".to_string(),
-        target_env: "gnueabihf".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
+            target_env: "gnueabihf".to_string(),
             features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
             max_atomic_width: Some(64),
             unsupported_abis: super::arm_base::unsupported_abis(),
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 66d3b3e5d07..2a31bf4e332 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 // This target is for glibc Linux on ARMv7 without thumb-mode, NEON or
 // hardfloat.
@@ -7,15 +7,9 @@ pub fn target() -> Target {
     let base = super::linux_base::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             features: "+v7,+thumb2,+soft-float,-neon".to_string(),
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 c1ef540a01d..d04400b79df 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 // This target is for glibc Linux on ARMv7 without NEON or
 // thumb-mode. See the thumbv7neon variant for enabling both.
@@ -7,15 +7,9 @@ pub fn target() -> Target {
     let base = super::linux_base::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             // Info about features at https://wiki.debian.org/ArmHardFloatPort
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 d4d26b14556..ebbbd61fc11 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 // This target is for musl Linux on ARMv7 without thumb-mode, NEON or
 // hardfloat.
@@ -12,15 +12,9 @@ pub fn target() -> Target {
         // to determine the calling convention and float ABI, and it doesn't
         // support the "musleabi" value.
         llvm_target: "armv7-unknown-linux-gnueabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             features: "+v7,+thumb2,+soft-float,-neon".to_string(),
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 88db04a74e2..ee603aa0684 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 // This target is for musl Linux on ARMv7 without thumb-mode or NEON.
 
@@ -9,15 +9,9 @@ pub fn target() -> Target {
         // uses it to determine the calling convention and float ABI, and LLVM
         // doesn't support the "musleabihf" value.
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         // Most of these settings are copied from the armv7_unknown_linux_gnueabihf
         // target.
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 fe2471ab0d0..09c531ebc8a 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
@@ -1,20 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = super::netbsd_base::opts();
     Target {
         llvm_target: "armv7-unknown-netbsdelf-eabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "netbsd".to_string(),
-        target_env: "eabihf".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
+            target_env: "eabihf".to_string(),
             features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
             cpu: "generic".to_string(),
             max_atomic_width: Some(64),
diff --git a/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
index 9b8cefdfa9e..6a43054067f 100644
--- a/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
@@ -1,18 +1,12 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let base = super::vxworks_base::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "vxworks".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "wrs".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             // Info about features at https://wiki.debian.org/ArmHardFloatPort
             features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
index 4199ac4569a..b6b34e27562 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
@@ -21,6 +21,8 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOp
 
 pub fn target() -> Target {
     let opts = TargetOptions {
+        target_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(),
         executables: true,
@@ -34,15 +36,9 @@ pub fn target() -> Target {
     };
     Target {
         llvm_target: "armv7a-none-eabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
         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(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: opts,
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
index 99a06590097..8b9df361844 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
@@ -9,6 +9,8 @@ use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOp
 
 pub fn target() -> Target {
     let opts = TargetOptions {
+        target_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(),
         executables: true,
@@ -22,15 +24,9 @@ pub fn target() -> Target {
     };
     Target {
         llvm_target: "armv7a-none-eabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
         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(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: opts,
     }
 }
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
index f0e79072bc1..fdd74d27619 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
@@ -6,17 +6,13 @@ use crate::spec::{Target, TargetOptions};
 pub fn target() -> Target {
     Target {
         llvm_target: "armv7r-unknown-none-eabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "none".to_string(),
-        target_env: "".to_string(),
-        target_vendor: "".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
+            target_vendor: String::new(),
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             executables: true,
             linker: Some("rust-lld".to_owned()),
             relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
index 4c464d2b256..7baafea90b9 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
@@ -6,17 +6,13 @@ use crate::spec::{Target, TargetOptions};
 pub fn target() -> Target {
     Target {
         llvm_target: "armv7r-unknown-none-eabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "none".to_string(),
-        target_env: "".to_string(),
-        target_vendor: "".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
+            target_vendor: String::new(),
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             executables: true,
             linker: Some("rust-lld".to_owned()),
             relocation_model: RelocModel::Static,
diff --git a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
index 4c2d70ae34b..be74136a2d6 100644
--- a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
@@ -1,19 +1,13 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts(Arch::Armv7s);
+    let base = opts("ios", Arch::Armv7s);
     Target {
         llvm_target: "armv7s-apple-ios".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(),
         arch: "arm".to_string(),
-        target_os: "ios".to_string(),
-        target_env: String::new(),
-        target_vendor: "apple".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             features: "+v7,+vfp4,+neon".to_string(),
             max_atomic_width: Some(64),
diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs
index 01445dc3898..268af87cfe9 100644
--- a/compiler/rustc_target/src/spec/avr_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs
@@ -8,14 +8,10 @@ pub fn target(target_cpu: String) -> Target {
         arch: "avr".to_string(),
         data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(),
         llvm_target: "avr-unknown-unknown".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 16,
-        linker_flavor: LinkerFlavor::Gcc,
-        target_os: "unknown".to_string(),
-        target_env: "".to_string(),
-        target_vendor: "unknown".to_string(),
-        target_c_int_width: 16.to_string(),
         options: TargetOptions {
+            target_c_int_width: "16".to_string(),
+            target_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 39039435f58..0053adb8552 100644
--- a/compiler/rustc_target/src/spec/cloudabi_base.rs
+++ b/compiler/rustc_target/src/spec/cloudabi_base.rs
@@ -12,6 +12,7 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_os: "cloudabi".to_string(),
         executables: true,
         target_family: None,
         linker_is_gnu: true,
diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs
index 82dc5f54659..a182e37dd80 100644
--- a/compiler/rustc_target/src/spec/dragonfly_base.rs
+++ b/compiler/rustc_target/src/spec/dragonfly_base.rs
@@ -16,6 +16,7 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_os: "dragonfly".to_string(),
         dynamic_linking: true,
         executables: true,
         target_family: Some("unix".to_string()),
diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs
index 051325a8df6..25535117743 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -16,6 +16,7 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_os: "freebsd".to_string(),
         dynamic_linking: true,
         executables: true,
         target_family: Some("unix".to_string()),
diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs
index 6f432dc1171..97998eed886 100644
--- a/compiler/rustc_target/src/spec/fuchsia_base.rs
+++ b/compiler/rustc_target/src/spec/fuchsia_base.rs
@@ -20,6 +20,9 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_os: "fuchsia".to_string(),
+        target_vendor: String::new(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         lld_flavor: LldFlavor::Ld,
         dynamic_linking: true,
diff --git a/compiler/rustc_target/src/spec/haiku_base.rs b/compiler/rustc_target/src/spec/haiku_base.rs
index 3d7ae6c302d..3d9dd44e786 100644
--- a/compiler/rustc_target/src/spec/haiku_base.rs
+++ b/compiler/rustc_target/src/spec/haiku_base.rs
@@ -2,6 +2,7 @@ use crate::spec::{RelroLevel, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
+        target_os: "haiku".to_string(),
         dynamic_linking: true,
         executables: true,
         has_rpath: false,
diff --git a/compiler/rustc_target/src/spec/hermit_base.rs b/compiler/rustc_target/src/spec/hermit_base.rs
index e063c94cf2c..2953646afd0 100644
--- a/compiler/rustc_target/src/spec/hermit_base.rs
+++ b/compiler/rustc_target/src/spec/hermit_base.rs
@@ -9,6 +9,8 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_os: "hermit".to_string(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         linker: Some("rust-lld".to_owned()),
         executables: true,
         has_elf_tls: true,
diff --git a/compiler/rustc_target/src/spec/hermit_kernel_base.rs b/compiler/rustc_target/src/spec/hermit_kernel_base.rs
index 01b9f75637f..7d06cbd62f5 100644
--- a/compiler/rustc_target/src/spec/hermit_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/hermit_kernel_base.rs
@@ -9,6 +9,8 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_os: "hermit".to_string(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         disable_redzone: true,
         linker: Some("rust-lld".to_owned()),
         executables: true,
diff --git a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
index 143b93dfeef..73d5e2057f9 100644
--- a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkArgs, LinkerFlavor, Target};
+use crate::spec::{LinkArgs, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -19,9 +19,7 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "hexagon-unknown-linux-musl".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: concat!(
             "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32",
             ":32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-v32",
@@ -30,10 +28,6 @@ pub fn target() -> Target {
         )
         .to_string(),
         arch: "hexagon".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs
index 21421497965..302306ee579 100644
--- a/compiler/rustc_target/src/spec/i386_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs
@@ -1,21 +1,15 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts(Arch::I386);
+    let base = opts("ios", Arch::I386);
     Target {
         llvm_target: "i386-apple-ios".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:128-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "ios".to_string(),
-        target_env: String::new(),
-        target_vendor: "apple".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
index 9c7e7241b57..ac295aa3587 100644
--- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::apple_base::opts();
+    let mut base = super::apple_base::opts("macos");
     base.cpu = "yonah".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
@@ -17,17 +17,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target,
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:128-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "macos".to_string(),
-        target_env: String::new(),
-        target_vendor: "apple".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs
index d116ae62e0f..52059b930d1 100644
--- a/compiler/rustc_target/src/spec/i686_linux_android.rs
+++ b/compiler/rustc_target/src/spec/i686_linux_android.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::Target;
 
 // See https://developer.android.com/ndk/guides/abis.html#x86
 // for target ABI requirements.
@@ -15,17 +15,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-linux-android".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "android".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
index 84585bd515a..4979a5b3bc8 100644
--- a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
@@ -18,17 +18,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-pc-windows-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             i64:64-f80:32-n8:16:32-a:0:32-S32"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "windows".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "pc".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
index db20b6094b7..e7a5643eaaa 100644
--- a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
@@ -22,17 +22,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-pc-windows-msvc".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             i64:64-f80:32-n8:16:32-a:0:32-S32"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "windows".to_string(),
-        target_env: "msvc".to_string(),
-        target_vendor: "pc".to_string(),
-        linker_flavor: LinkerFlavor::Msvc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs
index d9365d59e0e..0cdb9f9de56 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs
@@ -10,17 +10,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-cloudabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "cloudabi".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
index ba379a40f50..fc1c8607d65 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
@@ -11,17 +11,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-freebsd".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "freebsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
index 02754b39fa7..22c8ba54753 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
@@ -9,17 +9,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-haiku".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "haiku".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: 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 b7ceaefef93..62b02d841c2 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
@@ -9,17 +9,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
index 9240b56aeaf..1673b2a1802 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
@@ -24,17 +24,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-linux-musl".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
index a4421924a7b..2568fabfb05 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
@@ -9,17 +9,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-netbsdelf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "netbsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
index fe5030f661b..87642efdee8 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
@@ -10,17 +10,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-openbsd".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "openbsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/i686_unknown_uefi.rs
index 676a8ca0acc..5af3a6b41e2 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_uefi.rs
@@ -5,7 +5,7 @@
 // The cdecl ABI is used. It differs from the stdcall or fastcall ABI.
 // "i686-unknown-windows" is used to get the minimal subset of windows-specific features.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::uefi_msvc_base::opts();
@@ -78,17 +78,11 @@ pub fn target() -> Target {
     // remove -gnu and use the default one.
     Target {
         llvm_target: "i686-unknown-windows-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             i64:64-f80:32-n8:16:32-a:0:32-S32"
             .to_string(),
-        target_os: "uefi".to_string(),
-        target_env: "".to_string(),
-        target_vendor: "unknown".to_string(),
         arch: "x86".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
 
         options: base,
     }
diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
index ec5a9cc68ce..a3de93efb78 100644
--- a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
@@ -17,17 +17,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-pc-windows-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             i64:64-f80:32-n8:16:32-a:0:32-S32"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "windows".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "uwp".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs
index d960a130351..ce6200be81f 100644
--- a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::windows_uwp_msvc_base::opts();
@@ -8,17 +8,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-pc-windows-msvc".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             i64:64-f80:32-n8:16:32-a:0:32-S32"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "windows".to_string(),
-        target_env: "msvc".to_string(),
-        target_vendor: "uwp".to_string(),
-        linker_flavor: LinkerFlavor::Msvc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
index 0e5c7b6143e..c0825358cab 100644
--- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
@@ -9,17 +9,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
             f64:32:64-f80:32-n8:16:32-S128"
             .to_string(),
         arch: "x86".to_string(),
-        target_os: "vxworks".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "wrs".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs
index 214142b88fc..625f7b18b25 100644
--- a/compiler/rustc_target/src/spec/illumos_base.rs
+++ b/compiler/rustc_target/src/spec/illumos_base.rs
@@ -16,6 +16,7 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_os: "illumos".to_string(),
         dynamic_linking: true,
         executables: true,
         has_rpath: true,
diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs
index 5caad10161d..6d1e610d0e9 100644
--- a/compiler/rustc_target/src/spec/l4re_base.rs
+++ b/compiler/rustc_target/src/spec/l4re_base.rs
@@ -17,6 +17,9 @@ pub fn opts() -> TargetOptions {
     args.insert(LinkerFlavor::Gcc, vec![]);
 
     TargetOptions {
+        target_os: "l4re".to_string(),
+        target_env: "uclibc".to_string(),
+        linker_flavor: LinkerFlavor::Ld,
         executables: true,
         has_elf_tls: false,
         panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs
index 7ad972b0692..b3a850591fd 100644
--- a/compiler/rustc_target/src/spec/linux_base.rs
+++ b/compiler/rustc_target/src/spec/linux_base.rs
@@ -19,6 +19,8 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_os: "linux".to_string(),
+        target_env: "gnu".to_string(),
         dynamic_linking: true,
         executables: true,
         target_family: Some("unix".to_string()),
diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs
index 6d929d12447..9c883f9a188 100644
--- a/compiler/rustc_target/src/spec/linux_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs
@@ -8,6 +8,7 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_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 16cc3b762f6..3a44d3326eb 100644
--- a/compiler/rustc_target/src/spec/linux_musl_base.rs
+++ b/compiler/rustc_target/src/spec/linux_musl_base.rs
@@ -4,6 +4,7 @@ use crate::spec::TargetOptions;
 pub fn opts() -> TargetOptions {
     let mut base = super::linux_base::opts();
 
+    base.target_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
new file mode 100644
index 00000000000..ce7c79c1644
--- /dev/null
+++ b/compiler/rustc_target/src/spec/linux_uclibc_base.rs
@@ -0,0 +1,5 @@
+use crate::spec::TargetOptions;
+
+pub fn opts() -> TargetOptions {
+    TargetOptions { target_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 5cbd6bcd3d8..f0a266a63af 100644
--- a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
@@ -1,18 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "mips64-unknown-linux-gnuabi64".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
+            target_endian: "big".to_string(),
             // NOTE(mips64r2) matches C toolchain
             cpu: "mips64r2".to_string(),
             features: "+mips64r2".to_string(),
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 3ca92dd1d04..805a965bc0f 100644
--- a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -8,15 +8,13 @@ pub fn target() -> Target {
     Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64-unknown-linux-musl".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions {
+            target_endian: "big".to_string(),
+            target_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 4761be5b7ef..f47b058bd08 100644
--- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
@@ -1,17 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "mips64el-unknown-linux-gnuabi64".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             // NOTE(mips64r2) matches C toolchain
             cpu: "mips64r2".to_string(),
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 d87170b6868..5c985eb842c 100644
--- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -8,15 +8,9 @@ pub fn target() -> Target {
     Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64el-unknown-linux-musl".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_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 e51cf3c59f6..1fc66861364 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
@@ -1,18 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "mips-unknown-linux-gnu".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
+            target_endian: "big".to_string(),
             cpu: "mips32r2".to_string(),
             features: "+mips32r2,+fpxx,+nooddspreg".to_string(),
             max_atomic_width: Some(32),
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 44d136ee7e9..ed03f5d990e 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -8,15 +8,13 @@ pub fn target() -> Target {
     base.crt_static_default = false;
     Target {
         llvm_target: "mips-unknown-linux-musl".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions {
+            target_endian: "big".to_string(),
+            target_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 7e168836dc7..fa1d789bfa8 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
@@ -1,24 +1,19 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "mips-unknown-linux-uclibc".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "uclibc".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
+            target_endian: "big".to_string(),
             cpu: "mips32r2".to_string(),
             features: "+mips32r2,+soft-float".to_string(),
             max_atomic_width: Some(32),
             target_mcount: "_mcount".to_string(),
 
-            ..super::linux_base::opts()
+            ..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 9897b0093fc..3f426e2e5fe 100644
--- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
+++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
@@ -10,17 +10,14 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "mipsel-sony-psp".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
-        target_os: "psp".to_string(),
-        target_env: "".to_string(),
-        target_vendor: "sony".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
+            target_os: "psp".to_string(),
+            target_vendor: "sony".to_string(),
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             cpu: "mips2".to_string(),
             executables: true,
             linker: Some("rust-lld".to_owned()),
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 509f3e04ba7..16fbab58140 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs
@@ -1,17 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "mipsel-unknown-linux-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             cpu: "mips32r2".to_string(),
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 0d3691dd5b9..d1b603cd9de 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
@@ -8,15 +8,9 @@ pub fn target() -> Target {
     base.crt_static_default = false;
     Target {
         llvm_target: "mipsel-unknown-linux-musl".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_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 6d50d9ba81e..a09f7ad0121 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs
@@ -1,17 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "mipsel-unknown-linux-uclibc".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "uclibc".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             cpu: "mips32r2".to_string(),
@@ -19,7 +13,7 @@ pub fn target() -> Target {
             max_atomic_width: Some(32),
             target_mcount: "_mcount".to_string(),
 
-            ..super::linux_base::opts()
+            ..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 1651ff9c2d6..60c4c3bb051 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_none.rs
@@ -9,17 +9,13 @@ use crate::spec::{PanicStrategy, Target, TargetOptions};
 pub fn target() -> Target {
     Target {
         llvm_target: "mipsel-unknown-none".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
+            target_vendor: String::new(),
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             cpu: "mips32r2".to_string(),
             features: "+mips32r2,+soft-float,+noabicalls".to_string(),
             max_atomic_width: Some(32),
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 d6e71d2922f..417ee6e043b 100644
--- a/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
@@ -1,18 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "mipsisa32r6-unknown-linux-gnu".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
+            target_endian: "big".to_string(),
             cpu: "mips32r6".to_string(),
             features: "+mips32r6".to_string(),
             max_atomic_width: Some(32),
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 67e97fd2f0f..cf273c6ab2b 100644
--- a/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs
@@ -1,17 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "mipsisa32r6el-unknown-linux-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(),
         arch: "mips".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             cpu: "mips32r6".to_string(),
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 c3a7ae8b11f..1d82395f536 100644
--- a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
@@ -1,18 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "mipsisa64r6-unknown-linux-gnuabi64".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
+            target_endian: "big".to_string(),
             // NOTE(mips64r6) matches C toolchain
             cpu: "mips64r6".to_string(),
             features: "+mips64r6".to_string(),
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 467e05a00d4..aadd36235bf 100644
--- a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
@@ -1,17 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "mipsisa64r6el-unknown-linux-gnuabi64".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
         arch: "mips64".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             // NOTE(mips64r6) matches C toolchain
             cpu: "mips64r6".to_string(),
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index d3c5a9433d0..55d27fd8698 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -37,7 +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::path::{Path, PathBuf};
 use std::str::FromStr;
 use std::{fmt, io};
@@ -64,6 +66,7 @@ mod l4re_base;
 mod linux_base;
 mod linux_kernel_base;
 mod linux_musl_base;
+mod linux_uclibc_base;
 mod msvc_base;
 mod netbsd_base;
 mod openbsd_base;
@@ -174,6 +177,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 {
@@ -664,26 +674,13 @@ supported_targets! {
 pub struct Target {
     /// Target triple to pass to LLVM.
     pub llvm_target: String,
-    /// String to use as the `target_endian` `cfg` variable.
-    pub target_endian: String,
     /// Number of bits in a pointer. Influences the `target_pointer_width` `cfg` variable.
     pub pointer_width: u32,
-    /// Width of c_int type
-    pub target_c_int_width: String,
-    /// OS name to use for conditional compilation.
-    pub target_os: String,
-    /// Environment name to use for conditional compilation.
-    pub target_env: String,
-    /// Vendor name to use for conditional compilation.
-    pub target_vendor: String,
     /// Architecture to use for ABI considerations. Valid options include: "x86",
     /// "x86_64", "arm", "aarch64", "mips", "powerpc", "powerpc64", and others.
     pub arch: String,
     /// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
     pub data_layout: String,
-    /// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
-    /// on the command line.
-    pub linker_flavor: LinkerFlavor,
     /// Optional settings with defaults.
     pub options: TargetOptions,
 }
@@ -707,6 +704,20 @@ 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,
+    /// Width of c_int type. Defaults to "32".
+    pub target_c_int_width: String,
+    /// OS name to use for conditional compilation. Defaults to "none".
+    pub target_os: String,
+    /// Environment name to use for conditional compilation. Defaults to "".
+    pub target_env: String,
+    /// Vendor name to use for conditional compilation. Defaults to "unknown".
+    pub target_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,
+
     /// Linker to invoke
     pub linker: Option<String>,
 
@@ -985,6 +996,12 @@ 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(),
+            linker_flavor: LinkerFlavor::Gcc,
             linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
             lld_flavor: LldFlavor::Ld,
             pre_link_args: LinkArgs::new(),
@@ -1075,6 +1092,17 @@ impl Default for TargetOptions {
     }
 }
 
+/// `TargetOptions` being a separate type is basically an implementation detail of `Target` that is
+/// used for providing defaults. Perhaps there's a way to merge `TargetOptions` into `Target` so
+/// this `Deref` implementation is no longer necessary.
+impl Deref for Target {
+    type Target = TargetOptions;
+
+    fn deref(&self) -> &Self::Target {
+        &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 {
@@ -1135,27 +1163,13 @@ impl Target {
                 .ok_or_else(|| format!("Field {} in target specification is required", name))
         };
 
-        let get_opt_field = |name: &str, default: &str| {
-            obj.find(name)
-                .and_then(|s| s.as_string())
-                .map(|s| s.to_string())
-                .unwrap_or_else(|| default.to_string())
-        };
-
         let mut base = Target {
             llvm_target: get_req_field("llvm-target")?,
-            target_endian: get_req_field("target-endian")?,
             pointer_width: get_req_field("target-pointer-width")?
                 .parse::<u32>()
                 .map_err(|_| "target-pointer-width must be an integer".to_string())?,
-            target_c_int_width: get_req_field("target-c-int-width")?,
             data_layout: get_req_field("data-layout")?,
             arch: get_req_field("arch")?,
-            target_os: get_req_field("os")?,
-            target_env: get_opt_field("env", ""),
-            target_vendor: get_opt_field("vendor", "unknown"),
-            linker_flavor: LinkerFlavor::from_str(&*get_req_field("linker-flavor")?)
-                .ok_or_else(|| format!("linker flavor must be {}", LinkerFlavor::one_of()))?,
             options: Default::default(),
         };
 
@@ -1166,6 +1180,12 @@ impl Target {
                     base.options.$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();
+                }
+            } );
             ($key_name:ident, bool) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(s) = obj.find(&name).and_then(Json::as_boolean) {
@@ -1301,11 +1321,13 @@ impl Target {
             } );
             ($key_name:ident, LinkerFlavor) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
-                obj.find(&name[..]).and_then(|o| o.as_string().map(|s| {
-                    LinkerFlavor::from_str(&s).ok_or_else(|| {
-                        Err(format!("'{}' is not a valid value for linker-flavor. \
-                                     Use 'em', 'gcc', 'ld' or 'msvc.", s))
-                    })
+                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,
+                        _ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
+                                                      Use {}", s, LinkerFlavor::one_of()))),
+                    }
+                    Some(Ok(()))
                 })).unwrap_or(Ok(()))
             } );
             ($key_name:ident, crt_objects_fallback) => ( {
@@ -1392,6 +1414,12 @@ 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!(linker_flavor, LinkerFlavor)?;
         key!(linker, optional);
         key!(lld_flavor, LldFlavor)?;
         key!(pre_link_objects, link_objects);
@@ -1619,17 +1647,17 @@ impl ToJson for Target {
         }
 
         target_val!(llvm_target);
-        target_val!(target_endian);
         d.insert("target-pointer-width".to_string(), self.pointer_width.to_string().to_json());
-        target_val!(target_c_int_width);
         target_val!(arch);
-        target_val!(target_os, "os");
-        target_val!(target_env, "env");
-        target_val!(target_vendor, "vendor");
         target_val!(data_layout);
-        target_val!(linker_flavor);
 
         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!(linker_flavor);
         target_option_val!(linker);
         target_option_val!(lld_flavor);
         target_option_val!(pre_link_objects);
diff --git a/compiler/rustc_target/src/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs
index 5bb8109ce26..48b6d1be9ce 100644
--- a/compiler/rustc_target/src/spec/msp430_none_elf.rs
+++ b/compiler/rustc_target/src/spec/msp430_none_elf.rs
@@ -1,19 +1,15 @@
-use crate::spec::{LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{PanicStrategy, RelocModel, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "msp430-none-elf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 16,
-        target_c_int_width: "16".to_string(),
         data_layout: "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16".to_string(),
         arch: "msp430".to_string(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
+            target_c_int_width: "16".to_string(),
+            target_vendor: String::new(),
             executables: true,
 
             // The LLVM backend currently can't generate object files. To
diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs
index f57ef87cf12..8cd6735a8c1 100644
--- a/compiler/rustc_target/src/spec/msvc_base.rs
+++ b/compiler/rustc_target/src/spec/msvc_base.rs
@@ -18,6 +18,7 @@ pub fn opts() -> TargetOptions {
     pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Link), pre_link_args_msvc);
 
     TargetOptions {
+        linker_flavor: LinkerFlavor::Msvc,
         executables: true,
         is_like_windows: true,
         is_like_msvc: true,
diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs
index d7baf81fce3..437b50b6f11 100644
--- a/compiler/rustc_target/src/spec/netbsd_base.rs
+++ b/compiler/rustc_target/src/spec/netbsd_base.rs
@@ -14,6 +14,7 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_os: "netbsd".to_string(),
         dynamic_linking: true,
         executables: true,
         target_family: Some("unix".to_string()),
diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
index 86360c181d1..f759724445e 100644
--- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
@@ -6,18 +6,12 @@ pub fn target() -> Target {
         arch: "nvptx64".to_string(),
         data_layout: "e-i64:64-i128:128-v16:16-v32:32-n16:32:64".to_string(),
         llvm_target: "nvptx64-nvidia-cuda".to_string(),
-
-        target_os: "cuda".to_string(),
-        target_vendor: "nvidia".to_string(),
-        target_env: String::new(),
-
-        linker_flavor: LinkerFlavor::PtxLinker,
-
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
 
         options: TargetOptions {
+            target_os: "cuda".to_string(),
+            target_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 92a382e826b..5e83e79d9ed 100644
--- a/compiler/rustc_target/src/spec/openbsd_base.rs
+++ b/compiler/rustc_target/src/spec/openbsd_base.rs
@@ -16,6 +16,7 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_os: "openbsd".to_string(),
         dynamic_linking: true,
         executables: true,
         target_family: Some("unix".to_string()),
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
index 563ff96a403..3d20f15b391 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
@@ -8,15 +8,13 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64-unknown-freebsd".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
-        target_os: "freebsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions {
+            target_endian: "big".to_string(),
+            target_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 7d37670e5b0..e52643eb893 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
@@ -12,15 +12,13 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions {
+            target_endian: "big".to_string(),
+            target_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 e108d75f337..315192929ac 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
@@ -8,15 +8,13 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64-unknown-linux-musl".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions {
+            target_endian: "big".to_string(),
+            target_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 9784c637c7e..a31256761a4 100644
--- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
@@ -8,15 +8,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
-        target_os: "vxworks".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "wrs".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions { ..base },
+        options: TargetOptions { target_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 46d847f6e5f..4cf296c3fa7 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
@@ -8,15 +8,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_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 e04ee013701..41756028cbe 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
@@ -8,15 +8,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "powerpc64le-unknown-linux-musl".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-i64:64-n32:64".to_string(),
         arch: "powerpc64".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_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 80fc63e78e4..f3ec02c10d2 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
@@ -7,15 +7,13 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnu".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions {
+            target_endian: "big".to_string(),
+            target_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 612d2967ee0..4e3ffca0a08 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
@@ -7,15 +7,13 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions {
+            target_endian: "big".to_string(),
+            target_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 fd89262e464..1d5c19b5420 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
@@ -7,15 +7,13 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-linux-musl".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions { target_mcount: "_mcount".to_string(), ..base },
+        options: TargetOptions {
+            target_endian: "big".to_string(),
+            target_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 d33258d1859..4d7eb8d0100 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
@@ -7,15 +7,13 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-netbsd".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
-        target_os: "netbsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
+        options: TargetOptions {
+            target_endian: "big".to_string(),
+            target_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 6a12f4c59f6..dc6a4e28a3d 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
@@ -8,15 +8,13 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnu".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
-        target_os: "vxworks".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "wrs".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions { features: "+secure-plt".to_string(), ..base },
+        options: TargetOptions {
+            target_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 5fee61fa0bd..1ce3fa21918 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
@@ -8,16 +8,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(),
         arch: "powerpc".to_string(),
-        target_os: "vxworks".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "wrs".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
+            target_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 18cafe654d1..04409a1cd04 100644
--- a/compiler/rustc_target/src/spec/redox_base.rs
+++ b/compiler/rustc_target/src/spec/redox_base.rs
@@ -19,6 +19,8 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_os: "redox".to_string(),
+        target_env: "relibc".to_string(),
         dynamic_linking: true,
         executables: true,
         target_family: Some("unix".to_string()),
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 415d7c5607d..f9405d9dfb6 100644
--- a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
@@ -1,17 +1,11 @@
-use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions};
+use crate::spec::{CodeModel, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "riscv32-unknown-linux-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
-        target_env: "gnu".to_string(),
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
         arch: "riscv32".to_string(),
-        target_os: "linux".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             unsupported_abis: super::riscv_base::unsupported_abis(),
             code_model: Some(CodeModel::Medium),
diff --git a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
index 022768f6ab8..a31a08a8cf9 100644
--- a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
@@ -5,16 +5,11 @@ pub fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
         llvm_target: "riscv32".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
         arch: "riscv32".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             linker: Some("rust-lld".to_string()),
             cpu: "generic-rv32".to_string(),
             max_atomic_width: Some(0),
diff --git a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
index 13f0d42d6fd..2ee53fdc401 100644
--- a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
@@ -5,16 +5,11 @@ pub fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
         llvm_target: "riscv32".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
         arch: "riscv32".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             linker: Some("rust-lld".to_string()),
             cpu: "generic-rv32".to_string(),
             max_atomic_width: Some(32),
diff --git a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
index 86189c27bbd..89d760e082f 100644
--- a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
@@ -5,16 +5,11 @@ pub fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
         llvm_target: "riscv32".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
         arch: "riscv32".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             linker: Some("rust-lld".to_string()),
             cpu: "generic-rv32".to_string(),
             max_atomic_width: Some(0),
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 808d7159f82..3b7ff47a540 100644
--- a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
@@ -1,17 +1,11 @@
-use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions};
+use crate::spec::{CodeModel, Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "riscv64-unknown-linux-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
-        target_env: "gnu".to_string(),
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
         arch: "riscv64".to_string(),
-        target_os: "linux".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions {
             unsupported_abis: super::riscv_base::unsupported_abis(),
             code_model: Some(CodeModel::Medium),
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
index 0211bc02d2d..33a785fdfee 100644
--- a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
@@ -5,16 +5,11 @@ pub fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
         llvm_target: "riscv64".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
         arch: "riscv64".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             linker: Some("rust-lld".to_string()),
             cpu: "generic-rv64".to_string(),
             max_atomic_width: Some(64),
diff --git a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
index 1050ce5ba74..908367ee200 100644
--- a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
@@ -5,16 +5,11 @@ pub fn target() -> Target {
     Target {
         data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
         llvm_target: "riscv64".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
         arch: "riscv64".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
+            linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
             linker: Some("rust-lld".to_string()),
             cpu: "generic-rv64".to_string(),
             max_atomic_width: Some(64),
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 653b83646ce..69b880cdb81 100644
--- a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
@@ -1,7 +1,8 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::linux_base::opts();
+    base.target_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
@@ -13,15 +14,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "s390x-unknown-linux-gnu".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64".to_string(),
         arch: "s390x".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/solaris_base.rs b/compiler/rustc_target/src/spec/solaris_base.rs
index 3d7f0034b8b..1454d83e936 100644
--- a/compiler/rustc_target/src/spec/solaris_base.rs
+++ b/compiler/rustc_target/src/spec/solaris_base.rs
@@ -2,6 +2,8 @@ use crate::spec::TargetOptions;
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
+        target_os: "solaris".to_string(),
+        target_vendor: "sun".to_string(),
         dynamic_linking: true,
         executables: true,
         has_rpath: true,
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 e50c114fcfa..f02b01a514b 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
@@ -1,21 +1,16 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::linux_base::opts();
+    base.target_endian = "big".to_string();
     base.cpu = "v9".to_string();
     base.max_atomic_width = Some(64);
 
     Target {
         llvm_target: "sparc64-unknown-linux-gnu".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
         arch: "sparc64".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
index 6d8e433949b..de35bb8fe14 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
@@ -8,15 +8,13 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "sparc64-unknown-netbsd".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
         arch: "sparc64".to_string(),
-        target_os: "netbsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
-        options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
+        options: TargetOptions {
+            target_endian: "big".to_string(),
+            target_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 45700e14c53..301c91e432c 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
@@ -2,21 +2,16 @@ use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
+    base.target_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);
 
     Target {
         llvm_target: "sparc64-unknown-openbsd".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
         arch: "sparc64".to_string(),
-        target_os: "openbsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
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 fc400dd3446..071175819f4 100644
--- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
@@ -2,21 +2,16 @@ use crate::spec::{LinkerFlavor, Target};
 
 pub fn target() -> Target {
     let mut base = super::linux_base::opts();
+    base.target_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());
 
     Target {
         llvm_target: "sparc-unknown-linux-gnu".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".to_string(),
         arch: "sparc".to_string(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
index 0878e7fd21e..e8c30dcbf85 100644
--- a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
@@ -2,6 +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.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
     // llvm calls this "v9"
     base.cpu = "v9".to_string();
@@ -9,19 +10,13 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "sparcv9-sun-solaris".to_string(),
-        target_endian: "big".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
         // Use "sparc64" instead of "sparcv9" here, since the former is already
         // used widely in the source base.  If we ever needed ABI
         // differentiation from the sparc64, we could, but that would probably
         // just be confusing.
         arch: "sparc64".to_string(),
-        target_os: "solaris".to_string(),
-        target_env: String::new(),
-        target_vendor: "sun".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/thumb_base.rs b/compiler/rustc_target/src/spec/thumb_base.rs
index 2f7d15d5856..cc955799d2f 100644
--- a/compiler/rustc_target/src/spec/thumb_base.rs
+++ b/compiler/rustc_target/src/spec/thumb_base.rs
@@ -27,11 +27,13 @@
 // differentiate these targets from our other `arm(v7)-*-*-gnueabi(hf)` targets in the context of
 // build scripts / gcc flags.
 
-use crate::spec::{PanicStrategy, RelocModel, TargetOptions};
+use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions};
 
 pub fn opts() -> TargetOptions {
     // See rust-lang/rfcs#1645 for a discussion about these defaults
     TargetOptions {
+        target_vendor: String::new(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         executables: true,
         // In most cases, LLD is good enough
         linker: Some("rust-lld".to_string()),
diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
index d5ce62d8c1c..d87c06d49cb 100644
--- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
@@ -13,12 +13,7 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions};
 pub fn target() -> Target {
     Target {
         llvm_target: "thumbv4t-none-eabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
-        target_os: "none".to_string(),
-        target_env: "".to_string(),
-        target_vendor: "".to_string(),
         arch: "arm".to_string(),
         /* Data layout args are '-' separated:
          * little endian
@@ -30,8 +25,8 @@ pub fn target() -> Target {
          * All other elements are default
          */
         data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
-        linker_flavor: LinkerFlavor::Ld,
         options: TargetOptions {
+            linker_flavor: LinkerFlavor::Ld,
             linker: Some("arm-none-eabi-ld".to_string()),
             linker_is_gnu: true,
 
diff --git a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
index 407fa6116c5..11c8bf46348 100644
--- a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
@@ -1,19 +1,13 @@
 // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture)
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "thumbv6m-none-eabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
             // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
diff --git a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
index d34f42cdc61..8131a6e2ea4 100644
--- a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
@@ -23,15 +23,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "thumbv7a-pc-windows-msvc".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-        target_os: "windows".to_string(),
-        target_env: "msvc".to_string(),
-        target_vendor: "pc".to_string(),
-        linker_flavor: LinkerFlavor::Msvc,
 
         options: TargetOptions {
             features: "+vfp3,+neon".to_string(),
diff --git a/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs
index 143a9a48a4a..a2c1b6bb90c 100644
--- a/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions};
+use crate::spec::{PanicStrategy, Target, TargetOptions};
 
 pub fn target() -> Target {
     let mut base = super::windows_uwp_msvc_base::opts();
@@ -11,15 +11,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "thumbv7a-pc-windows-msvc".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
         arch: "arm".to_string(),
-        target_os: "windows".to_string(),
-        target_env: "msvc".to_string(),
-        target_vendor: "uwp".to_string(),
-        linker_flavor: LinkerFlavor::Msvc,
         options: TargetOptions {
             features: "+vfp3,+neon".to_string(),
             cpu: "generic".to_string(),
diff --git a/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs
index e0b00460e08..141eb7e78b9 100644
--- a/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs
@@ -9,20 +9,14 @@
 // To opt-in to hardware accelerated floating point operations, you can use, for example,
 // `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "thumbv7em-none-eabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions { max_atomic_width: Some(32), ..super::thumb_base::opts() },
     }
diff --git a/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs
index eecd75e4614..f5bd054f859 100644
--- a/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs
@@ -8,20 +8,14 @@
 //
 // To opt into double precision hardware support, use the `-C target-feature=+fp64` flag.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "thumbv7em-none-eabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
             // `+vfp4` is the lowest common denominator between the Cortex-M4 (vfp4-16) and the
diff --git a/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs
index a02100ee199..7af28cd9c9f 100644
--- a/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs
@@ -1,19 +1,13 @@
 // Targets the Cortex-M3 processor (ARMv7-M)
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "thumbv7m-none-eabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions { max_atomic_width: Some(32), ..super::thumb_base::opts() },
     }
diff --git a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
index 35e7d480f3f..41fdbc2f0a0 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
@@ -16,15 +16,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "armv7-none-linux-android".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "android".to_string(),
-        target_env: "".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { unsupported_abis: super::arm_base::unsupported_abis(), ..base },
     }
 }
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 946b0db4c22..561da4d15cd 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 // This target is for glibc Linux on ARMv7 with thumb mode enabled
 // (for consistency with Android and Debian-based distributions)
@@ -10,15 +10,9 @@ pub fn target() -> Target {
     let base = super::linux_base::opts();
     Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: TargetOptions {
             // Info about features at https://wiki.debian.org/ArmHardFloatPort
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 91945f9dcdc..5b1fc74bdd0 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 // This target is for musl Linux on ARMv7 with thumb mode enabled
 // (for consistency with Android and Debian-based distributions)
@@ -13,15 +13,9 @@ pub fn target() -> Target {
         // uses it to determine the calling convention and float ABI, and LLVM
         // doesn't support the "musleabihf" value.
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         // Most of these settings are copied from the thumbv7neon_unknown_linux_gnueabihf
         // target.
diff --git a/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs
index 383346400b5..a2200bc64e7 100644
--- a/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs
@@ -1,19 +1,13 @@
 // Targets the Cortex-M23 processor (Baseline ARMv8-M)
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "thumbv8m.base-none-eabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
             // ARMv8-M baseline doesn't support unaligned loads/stores so we disable them
diff --git a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs
index 3d0fb664cf6..67cdbab4860 100644
--- a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs
@@ -1,20 +1,14 @@
 // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile),
 // without the Floating Point extension.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "thumbv8m.main-none-eabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions { max_atomic_width: Some(32), ..super::thumb_base::opts() },
     }
diff --git a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs
index 82368cb59b2..49748f5ec6d 100644
--- a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs
@@ -1,20 +1,14 @@
 // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile),
 // with the Floating Point extension.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     Target {
         llvm_target: "thumbv8m.main-none-eabihf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "none".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
 
         options: TargetOptions {
             // If the Floating Point extension is implemented in the Cortex-M33
diff --git a/compiler/rustc_target/src/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs
index 3f7c78c8e7d..91a39f7b9b4 100644
--- a/compiler/rustc_target/src/spec/uefi_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/uefi_msvc_base.rs
@@ -37,6 +37,8 @@ pub fn opts() -> TargetOptions {
         .extend(pre_link_args_msvc);
 
     TargetOptions {
+        target_os: "uefi".to_string(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
         disable_redzone: true,
         exe_suffix: ".efi".to_string(),
         allows_weak_linkage: false,
diff --git a/compiler/rustc_target/src/spec/vxworks_base.rs b/compiler/rustc_target/src/spec/vxworks_base.rs
index 777bb58d7db..e8044e4dc1a 100644
--- a/compiler/rustc_target/src/spec/vxworks_base.rs
+++ b/compiler/rustc_target/src/spec/vxworks_base.rs
@@ -17,6 +17,9 @@ pub fn opts() -> TargetOptions {
     );
 
     TargetOptions {
+        target_os: "vxworks".to_string(),
+        target_env: "gnu".to_string(),
+        target_vendor: "wrs".to_string(),
         linker: Some("wr-c++".to_string()),
         exe_suffix: ".vxe".to_string(),
         dynamic_linking: true,
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index aea06412aa2..dbafe362f2a 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -17,6 +17,8 @@ pub fn target() -> Target {
     );
 
     let opts = TargetOptions {
+        target_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.
         exe_suffix: ".js".to_string(),
@@ -30,15 +32,9 @@ pub fn target() -> Target {
     };
     Target {
         llvm_target: "wasm32-unknown-emscripten".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
-        target_os: "emscripten".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
         data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
         arch: "wasm32".to_string(),
-        linker_flavor: LinkerFlavor::Em,
         options: opts,
     }
 }
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
index 1ef0a819378..4401772788b 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
@@ -15,6 +15,8 @@ use super::{LinkerFlavor, LldFlavor, Target};
 
 pub fn target() -> Target {
     let mut options = wasm32_base::options();
+    options.target_os = "unknown".to_string();
+    options.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm);
     let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
 
     // Make sure clang uses LLD as its linker and is configured appropriately
@@ -32,15 +34,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "wasm32-unknown-unknown".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
-        target_os: "unknown".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
         data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
         arch: "wasm32".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm),
         options,
     }
 }
diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs
index 8c2bb920829..6f5316e30f6 100644
--- a/compiler/rustc_target/src/spec/wasm32_wasi.rs
+++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs
@@ -78,6 +78,9 @@ 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.linker_flavor = LinkerFlavor::Lld(LldFlavor::Wasm);
     options
         .pre_link_args
         .entry(LinkerFlavor::Gcc)
@@ -106,15 +109,9 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "wasm32-wasi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
-        target_os: "wasi".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
         data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(),
         arch: "wasm32".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm),
         options,
     }
 }
diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs
index 98e42f6c37c..37188a59eb5 100644
--- a/compiler/rustc_target/src/spec/windows_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs
@@ -62,6 +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(),
         // FIXME(#13846) this should be enabled for windows
         function_sections: false,
         linker: Some("gcc".to_string()),
diff --git a/compiler/rustc_target/src/spec/windows_msvc_base.rs b/compiler/rustc_target/src/spec/windows_msvc_base.rs
index 77171f8672e..c1101623867 100644
--- a/compiler/rustc_target/src/spec/windows_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/windows_msvc_base.rs
@@ -4,6 +4,9 @@ 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(),
         dynamic_linking: true,
         dll_prefix: String::new(),
         dll_suffix: ".dll".to_string(),
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 fcb2af0005f..225b94c3755 100644
--- a/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs
@@ -25,6 +25,7 @@ pub fn opts() -> TargetOptions {
     late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs);
 
     TargetOptions {
+        target_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 04ffa1a0add..380d685dacf 100644
--- a/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs
+++ b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs
@@ -3,6 +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();
     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 2b39fec594a..6cd4daa7a74 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -1,7 +1,7 @@
 use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::apple_base::opts();
+    let mut base = super::apple_base::opts("macos");
     base.cpu = "core2".to_string();
     base.max_atomic_width = Some(128); // core2 support cmpxchg16b
     base.eliminate_frame_pointer = false;
@@ -20,16 +20,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target,
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "macos".to_string(),
-        target_env: String::new(),
-        target_vendor: "apple".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
index 685e046b64b..c9c7eeb7231 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
@@ -1,20 +1,14 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts(Arch::X86_64);
+    let base = opts("ios", Arch::X86_64);
     Target {
         llvm_target: "x86_64-apple-ios".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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: "x86_64".to_string(),
-        target_os: "ios".to_string(),
-        target_env: String::new(),
-        target_vendor: "apple".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
index ff7331560ed..6b360e5495b 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
@@ -1,20 +1,14 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts(Arch::X86_64_macabi);
+    let base = opts("ios", Arch::X86_64_macabi);
     Target {
         llvm_target: "x86_64-apple-ios13.0-macabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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: "x86_64".to_string(),
-        target_os: "ios".to_string(),
-        target_env: String::new(),
-        target_vendor: "apple".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
index 7c0a819f5dd..5b2a62a23fd 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
@@ -1,19 +1,13 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions};
+use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts(Arch::X86_64);
+    let base = opts("tvos", Arch::X86_64);
     Target {
         llvm_target: "x86_64-apple-tvos".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(),
         arch: "x86_64".to_string(),
-        target_os: "tvos".to_string(),
-        target_env: String::new(),
-        target_vendor: "apple".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { max_atomic_width: Some(64), stack_probes: true, ..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 8f1627d4a29..550d308ed8f 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,6 +55,10 @@ pub fn target() -> Target {
         "TEXT_SIZE",
     ];
     let opts = TargetOptions {
+        target_os: "unknown".into(),
+        target_env: "sgx".into(),
+        target_vendor: "fortanix".into(),
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         dynamic_linking: false,
         executables: true,
         linker_is_gnu: true,
@@ -76,16 +80,10 @@ pub fn target() -> Target {
     };
     Target {
         llvm_target: "x86_64-elf".into(),
-        target_endian: "little".into(),
         pointer_width: 64,
-        target_c_int_width: "32".into(),
-        target_os: "unknown".into(),
-        target_env: "sgx".into(),
-        target_vendor: "fortanix".into(),
         data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .into(),
         arch: "x86_64".into(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: opts,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
index 71add0a6c0a..6c049c2635c 100644
--- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::fuchsia_base::opts();
@@ -8,16 +8,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-fuchsia".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "fuchsia".to_string(),
-        target_env: String::new(),
-        target_vendor: String::new(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
index aa5e48cee07..27327160178 100644
--- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
@@ -11,16 +11,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-linux-android".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "android".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs b/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs
index 243167558be..43e683ddbcc 100644
--- a/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs
+++ b/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs
@@ -16,16 +16,10 @@ pub fn target() -> Target {
     Target {
         // FIXME: Some dispute, the linux-on-clang folks think this should use "Linux"
         llvm_target: "x86_64-elf".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "none".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
         arch: "x86_64".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
 
         options: base,
     }
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs
index 3b2edc91bc2..36726ab4aed 100644
--- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs
@@ -14,16 +14,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-windows-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-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(),
-        target_os: "windows".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "pc".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs
index f21b059551d..72bbb10323c 100644
--- a/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
@@ -8,16 +8,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-windows-msvc".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-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(),
-        target_os: "windows".to_string(),
-        target_env: "msvc".to_string(),
-        target_vendor: "pc".to_string(),
-        linker_flavor: LinkerFlavor::Msvc,
         options: base,
     }
 }
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 2e009d7abbf..511a4559935 100644
--- a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
@@ -2,6 +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.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());
@@ -15,16 +16,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-rumprun-netbsd".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "netbsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "rumprun".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
index aef06157cdd..6ccf78402e1 100644
--- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
@@ -9,16 +9,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-solaris".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "solaris".to_string(),
-        target_env: String::new(),
-        target_vendor: "sun".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs
index bdaab883d90..cf57f4ec624 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs
@@ -10,16 +10,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-cloudabi".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "cloudabi".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
index 13a62d5081c..30aa2909873 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
@@ -9,16 +9,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-dragonfly".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "dragonfly".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
index 145983022e8..ee904d76242 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
@@ -9,16 +9,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-freebsd".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "freebsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
index d88812e4248..ea7e068e516 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
@@ -11,16 +11,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-haiku".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "haiku".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
index a5002091d07..4005aaf58b1 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::hermit_base::opts();
@@ -9,16 +9,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-hermit".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "hermit".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs
index 91d7b0eaefc..b72d529363a 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::hermit_kernel_base::opts();
@@ -11,16 +11,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-hermit".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "hermit".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
index e49f009be0f..d3f9349d99b 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
@@ -10,16 +10,10 @@ pub fn target() -> Target {
         // LLVM does not currently have a separate illumos target,
         // so we still pass Solaris to it
         llvm_target: "x86_64-pc-solaris".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "illumos".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
index fc5b1ba60ec..1fbd0bb4cec 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::l4re_base::opts();
@@ -7,16 +7,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-l4re-uclibc".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "l4re".to_string(),
-        target_env: "uclibc".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Ld,
         options: 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 9d9f99c9b59..1f368ff1611 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
@@ -9,16 +9,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-linux-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
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 e4a0d913bab..375b22fd92b 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
@@ -13,17 +13,11 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-linux-gnux32".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 32,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:e-p:32:32-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(),
-        target_os: "linux".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
index a7d3324b2c7..3669c10981e 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs
@@ -10,16 +10,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-linux-musl".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "linux".to_string(),
-        target_env: "musl".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
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 a8106c0c770..656ef90892c 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
@@ -9,16 +9,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-netbsd".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "netbsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { target_mcount: "__mcount".to_string(), ..base },
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
index 5afe73ea713..0fe01f09c2e 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
@@ -9,16 +9,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-openbsd".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "openbsd".to_string(),
-        target_env: String::new(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
index e21148887d9..cdd445b2614 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
@@ -9,16 +9,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-redox".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "redox".to_string(),
-        target_env: "relibc".to_string(),
-        target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
index 894bd334169..b7dcce5f895 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
@@ -5,7 +5,7 @@
 // The win64 ABI is used. It differs from the sysv64 ABI, so we must use a windows target with
 // LLVM. "x86_64-unknown-windows" is used to get the minimal subset of windows-specific features.
 
-use crate::spec::{CodeModel, LinkerFlavor, LldFlavor, Target};
+use crate::spec::{CodeModel, Target};
 
 pub fn target() -> Target {
     let mut base = super::uefi_msvc_base::opts();
@@ -30,16 +30,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-windows".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
             .to_string(),
-        target_os: "uefi".to_string(),
-        target_env: "".to_string(),
-        target_vendor: "unknown".to_string(),
         arch: "x86_64".to_string(),
-        linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
 
         options: base,
     }
diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs
index a4fa0d03546..57913ba0dab 100644
--- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs
@@ -13,16 +13,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-windows-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-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(),
-        target_os: "windows".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "uwp".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs
index aaf85bbce81..27c579ed5bc 100644
--- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target};
+use crate::spec::Target;
 
 pub fn target() -> Target {
     let mut base = super::windows_uwp_msvc_base::opts();
@@ -8,16 +8,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-pc-windows-msvc".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         data_layout: "e-m:w-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(),
-        target_os: "windows".to_string(),
-        target_env: "msvc".to_string(),
-        target_vendor: "uwp".to_string(),
-        linker_flavor: LinkerFlavor::Msvc,
         options: base,
     }
 }
diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
index 5edf7e7af51..163af6fd8e1 100644
--- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
@@ -10,16 +10,10 @@ pub fn target() -> Target {
 
     Target {
         llvm_target: "x86_64-unknown-linux-gnu".to_string(),
-        target_endian: "little".to_string(),
         pointer_width: 64,
-        target_c_int_width: "32".to_string(),
         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(),
-        target_os: "vxworks".to_string(),
-        target_env: "gnu".to_string(),
-        target_vendor: "wrs".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
         options: base,
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 827b1d35f1c..a85ffd3c961 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -338,7 +338,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
 
         let ty = ty.super_fold_with(self);
         match *ty.kind() {
-            ty::Opaque(def_id, substs) => {
+            ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
                 // Only normalize `impl Trait` after type-checking, usually in codegen.
                 match self.param_env.reveal() {
                     Reveal::UserFacing => ty,
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index d748fc8235e..42a598ce3a0 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -108,7 +108,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
 
         let ty = ty.super_fold_with(self);
         let res = (|| match *ty.kind() {
-            ty::Opaque(def_id, substs) => {
+            ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
                 // Only normalize `impl Trait` after type-checking, usually in codegen.
                 match self.param_env.reveal() {
                     Reveal::UserFacing => ty,
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/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/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..1dcc5f13415 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
 # =============================================================================
diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs
index d5b1c600d93..4fea6adf541 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() {
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/fmt.rs b/library/alloc/src/fmt.rs
index a886e17f5a9..5ebc4d6c4c1 100644
--- a/library/alloc/src/fmt.rs
+++ b/library/alloc/src/fmt.rs
@@ -309,13 +309,13 @@
 //! * `?` ⇒ [`Debug`]
 //! * `x?` ⇒ [`Debug`] with lower-case hexadecimal integers
 //! * `X?` ⇒ [`Debug`] with upper-case hexadecimal integers
-//! * `o` ⇒ [`Octal`](trait.Octal.html)
-//! * `x` ⇒ [`LowerHex`](trait.LowerHex.html)
-//! * `X` ⇒ [`UpperHex`](trait.UpperHex.html)
-//! * `p` ⇒ [`Pointer`](trait.Pointer.html)
+//! * `o` ⇒ [`Octal`]
+//! * `x` ⇒ [`LowerHex`]
+//! * `X` ⇒ [`UpperHex`]
+//! * `p` ⇒ [`Pointer`]
 //! * `b` ⇒ [`Binary`]
-//! * `e` ⇒ [`LowerExp`](trait.LowerExp.html)
-//! * `E` ⇒ [`UpperExp`](trait.UpperExp.html)
+//! * `e` ⇒ [`LowerExp`]
+//! * `E` ⇒ [`UpperExp`]
 //!
 //! What this means is that any type of argument which implements the
 //! [`fmt::Binary`][`Binary`] trait can then be formatted with `{:b}`. Implementations
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 405667e0b2a..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)]
@@ -119,7 +120,6 @@
 #![feature(raw_ref_op)]
 #![feature(rustc_attrs)]
 #![feature(receiver_trait)]
-#![feature(renamed_spin_loop)]
 #![feature(min_specialization)]
 #![feature(slice_ptr_get)]
 #![feature(slice_ptr_len)]
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index ef2a5dd570f..b2afb702eeb 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -406,7 +406,8 @@ impl<T> Cell<T> {
     /// assert_eq!(five, 5);
     /// ```
     #[stable(feature = "move_cell", since = "1.17.0")]
-    pub fn into_inner(self) -> T {
+    #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
+    pub const fn into_inner(self) -> T {
         self.value.into_inner()
     }
 }
@@ -573,7 +574,7 @@ pub struct RefCell<T: ?Sized> {
     value: UnsafeCell<T>,
 }
 
-/// An error returned by [`RefCell::try_borrow`](struct.RefCell.html#method.try_borrow).
+/// An error returned by [`RefCell::try_borrow`].
 #[stable(feature = "try_borrow", since = "1.13.0")]
 pub struct BorrowError {
     _private: (),
@@ -593,7 +594,7 @@ impl Display for BorrowError {
     }
 }
 
-/// An error returned by [`RefCell::try_borrow_mut`](struct.RefCell.html#method.try_borrow_mut).
+/// An error returned by [`RefCell::try_borrow_mut`].
 #[stable(feature = "try_borrow", since = "1.13.0")]
 pub struct BorrowMutError {
     _private: (),
@@ -668,12 +669,11 @@ impl<T> RefCell<T> {
     /// let five = c.into_inner();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
     #[inline]
-    pub fn into_inner(self) -> T {
+    pub const fn into_inner(self) -> T {
         // Since this function takes `self` (the `RefCell`) by value, the
         // compiler statically verifies that it is not currently borrowed.
-        // Therefore the following assertion is just a `debug_assert!`.
-        debug_assert!(self.borrow.get() == UNUSED);
         self.value.into_inner()
     }
 
@@ -1682,7 +1682,8 @@ impl<T> UnsafeCell<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_inner(self) -> T {
+    #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
+    pub const fn into_inner(self) -> T {
         self.value
     }
 }
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index a048f65a149..bbb3a3dea43 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -29,7 +29,7 @@ use self::Ordering::*;
 ///
 /// This trait allows for partial equality, for types that do not have a full
 /// equivalence relation. For example, in floating point numbers `NaN != NaN`,
-/// so floating point types implement `PartialEq` but not [`Eq`](Eq).
+/// so floating point types implement `PartialEq` but not [`Eq`].
 ///
 /// Formally, the equality must be (for all `a`, `b` and `c`):
 ///
diff --git a/library/core/src/fmt/builders.rs b/library/core/src/fmt/builders.rs
index 63866a5d110..d95d43f0854 100644
--- a/library/core/src/fmt/builders.rs
+++ b/library/core/src/fmt/builders.rs
@@ -1,4 +1,6 @@
-use crate::fmt;
+#![allow(unused_imports)]
+
+use crate::fmt::{self, Debug, Formatter};
 
 struct PadAdapter<'buf, 'state> {
     buf: &'buf mut (dyn fmt::Write + 'buf),
@@ -53,14 +55,12 @@ impl fmt::Write for PadAdapter<'_, '_> {
     }
 }
 
-/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
+/// A struct to help with [`fmt::Debug`](Debug) implementations.
 ///
 /// This is useful when you wish to output a formatted struct as a part of your
-/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
+/// [`Debug::fmt`] implementation.
 ///
-/// This can be constructed by the
-/// [`Formatter::debug_struct`](struct.Formatter.html#method.debug_struct)
-/// method.
+/// This can be constructed by the [`Formatter::debug_struct`] method.
 ///
 /// # Examples
 ///
@@ -257,14 +257,12 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
     }
 }
 
-/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
+/// A struct to help with [`fmt::Debug`](Debug) implementations.
 ///
 /// This is useful when you wish to output a formatted tuple as a part of your
-/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
+/// [`Debug::fmt`] implementation.
 ///
-/// This can be constructed by the
-/// [`Formatter::debug_tuple`](struct.Formatter.html#method.debug_tuple)
-/// method.
+/// This can be constructed by the [`Formatter::debug_tuple`] method.
 ///
 /// # Examples
 ///
@@ -428,14 +426,12 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
     }
 }
 
-/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
+/// A struct to help with [`fmt::Debug`](Debug) implementations.
 ///
 /// This is useful when you wish to output a formatted set of items as a part
-/// of your [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
+/// of your [`Debug::fmt`] implementation.
 ///
-/// This can be constructed by the
-/// [`Formatter::debug_set`](struct.Formatter.html#method.debug_set)
-/// method.
+/// This can be constructed by the [`Formatter::debug_set`] method.
 ///
 /// # Examples
 ///
@@ -560,14 +556,12 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> {
     }
 }
 
-/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
+/// A struct to help with [`fmt::Debug`](Debug) implementations.
 ///
 /// This is useful when you wish to output a formatted list of items as a part
-/// of your [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
+/// of your [`Debug::fmt`] implementation.
 ///
-/// This can be constructed by the
-/// [`Formatter::debug_list`](struct.Formatter.html#method.debug_list)
-/// method.
+/// This can be constructed by the [`Formatter::debug_list`] method.
 ///
 /// # Examples
 ///
@@ -692,14 +686,12 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> {
     }
 }
 
-/// A struct to help with [`fmt::Debug`](trait.Debug.html) implementations.
+/// A struct to help with [`fmt::Debug`](Debug) implementations.
 ///
 /// This is useful when you wish to output a formatted map as a part of your
-/// [`Debug::fmt`](trait.Debug.html#tymethod.fmt) implementation.
+/// [`Debug::fmt`] implementation.
 ///
-/// This can be constructed by the
-/// [`Formatter::debug_map`](struct.Formatter.html#method.debug_map)
-/// method.
+/// This can be constructed by the [`Formatter::debug_map`] method.
 ///
 /// # Examples
 ///
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 454fb34e77e..979a5f8cf50 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -1,6 +1,7 @@
 #![stable(feature = "core_hint", since = "1.27.0")]
 
 //! Hints to compiler that affects how code should be emitted or optimized.
+//! Hints may be compile time or runtime.
 
 use crate::intrinsics;
 
@@ -24,7 +25,6 @@ use crate::intrinsics;
 /// Otherwise, consider using the [`unreachable!`] macro, which does not allow
 /// optimizations but will panic when executed.
 ///
-///
 /// # Example
 ///
 /// ```
@@ -51,18 +51,62 @@ pub const unsafe fn unreachable_unchecked() -> ! {
     unsafe { intrinsics::unreachable() }
 }
 
-/// Emits a machine instruction hinting to the processor that it is running in busy-wait
-/// spin-loop ("spin lock").
+/// Emits a machine instruction to signal the processor that it is running in
+/// a busy-wait spin-loop ("spin lock").
+///
+/// Upon receiving the spin-loop signal the processor can optimize its behavior by,
+/// for example, saving power or switching hyper-threads.
+///
+/// This function is different from [`thread::yield_now`] which directly
+/// yields to the system's scheduler, whereas `spin_loop` does not interact
+/// with the operating system.
+///
+/// A common use case for `spin_loop` is implementing bounded optimistic
+/// spinning in a CAS loop in synchronization primitives. To avoid problems
+/// like priority inversion, it is strongly recommended that the spin loop is
+/// terminated after a finite amount of iterations and an appropriate blocking
+/// syscall is made.
+///
+/// **Note**: On platforms that do not support receiving spin-loop hints this
+/// function does not do anything at all.
+///
+/// # Examples
 ///
-/// For a discussion of different locking strategies and their trade-offs, see
-/// [`core::sync::atomic::spin_loop_hint`].
+/// ```
+/// use std::sync::atomic::{AtomicBool, Ordering};
+/// use std::sync::Arc;
+/// use std::{hint, thread};
+///
+/// // A shared atomic value that threads will use to coordinate
+/// let live = Arc::new(AtomicBool::new(false));
+///
+/// // In a background thread we'll eventually set the value
+/// let bg_work = {
+///     let live = live.clone();
+///     thread::spawn(move || {
+///         // Do some work, then make the value live
+///         do_some_work();
+///         live.store(true, Ordering::Release);
+///     })
+/// };
 ///
-/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
-/// do anything at all.
+/// // Back on our current thread, we wait for the value to be set
+/// while live.load(Ordering::Acquire) {
+///     // The spin loop is a hint to the CPU that we're waiting, but probably
+///     // not for very long
+///     hint::spin_loop();
+/// }
+///
+/// // The value is now set
+/// # fn do_some_work() {}
+/// do_some_work();
+/// bg_work.join()?;
+/// # Ok::<(), Box<dyn core::any::Any + Send + 'static>>(())
+/// ```
 ///
-/// [`core::sync::atomic::spin_loop_hint`]: crate::sync::atomic::spin_loop_hint
+/// [`thread::yield_now`]: ../../std/thread/fn.yield_now.html
 #[inline]
-#[unstable(feature = "renamed_spin_loop", issue = "55002")]
+#[stable(feature = "renamed_spin_loop", since = "1.49.0")]
 pub fn spin_loop() {
     #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
     {
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 35adb4f69d8..96d0a60a327 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -121,7 +121,7 @@ where
 /// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`flatten`]: trait.Iterator.html#method.flatten
+/// [`flatten`]: Iterator::flatten
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "iterator_flatten", since = "1.29.0")]
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 9c8e639c2d8..9586284e1d7 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -85,7 +85,7 @@ pub unsafe trait SourceIter {
     /// * whatever remains in the source after iteration has stopped
     /// * the memory that has become unused by advancing a consuming iterator
     ///
-    /// [`next()`]: trait.Iterator.html#method.next
+    /// [`next()`]: Iterator::next
     unsafe fn as_inner(&mut self) -> &mut Self::Source;
 }
 
@@ -94,7 +94,7 @@ pub unsafe trait SourceIter {
 /// This `struct` is created by the [`rev`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`rev`]: trait.Iterator.html#method.rev
+/// [`rev`]: Iterator::rev
 /// [`Iterator`]: trait.Iterator.html
 #[derive(Clone, Debug)]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
@@ -228,7 +228,7 @@ unsafe impl<I> TrustedLen for Rev<I> where I: TrustedLen + DoubleEndedIterator {
 /// This `struct` is created by the [`copied`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`copied`]: trait.Iterator.html#method.copied
+/// [`copied`]: Iterator::copied
 /// [`Iterator`]: trait.Iterator.html
 #[stable(feature = "iter_copied", since = "1.36.0")]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
@@ -380,7 +380,7 @@ where
 /// This `struct` is created by the [`cloned`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`cloned`]: trait.Iterator.html#method.cloned
+/// [`cloned`]: Iterator::cloned
 /// [`Iterator`]: trait.Iterator.html
 #[stable(feature = "iter_cloned", since = "1.1.0")]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
@@ -515,7 +515,7 @@ where
 /// This `struct` is created by the [`cycle`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`cycle`]: trait.Iterator.html#method.cycle
+/// [`cycle`]: Iterator::cycle
 /// [`Iterator`]: trait.Iterator.html
 #[derive(Clone, Debug)]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
@@ -600,7 +600,7 @@ impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}
 /// This `struct` is created by the [`step_by`] method on [`Iterator`]. See
 /// its documentation for more.
 ///
-/// [`step_by`]: trait.Iterator.html#method.step_by
+/// [`step_by`]: Iterator::step_by
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "iterator_step_by", since = "1.28.0")]
@@ -833,7 +833,7 @@ impl<I> ExactSizeIterator for StepBy<I> where I: ExactSizeIterator {}
 /// This `struct` is created by the [`map`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`map`]: trait.Iterator.html#method.map
+/// [`map`]: Iterator::map
 /// [`Iterator`]: trait.Iterator.html
 ///
 /// # Notes about side effects
@@ -1042,7 +1042,7 @@ unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for Map<I, F> where F: FnM
 /// This `struct` is created by the [`filter`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`filter`]: trait.Iterator.html#method.filter
+/// [`filter`]: Iterator::filter
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1191,7 +1191,7 @@ unsafe impl<I: InPlaceIterable, P> InPlaceIterable for Filter<I, P> where P: FnM
 /// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`filter_map`]: trait.Iterator.html#method.filter_map
+/// [`filter_map`]: Iterator::filter_map
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1338,7 +1338,7 @@ unsafe impl<B, I: InPlaceIterable, F> InPlaceIterable for FilterMap<I, F> where
 /// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`enumerate`]: trait.Iterator.html#method.enumerate
+/// [`enumerate`]: Iterator::enumerate
 /// [`Iterator`]: trait.Iterator.html
 #[derive(Clone, Debug)]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
@@ -1574,7 +1574,7 @@ unsafe impl<I: InPlaceIterable> InPlaceIterable for Enumerate<I> {}
 /// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`peekable`]: trait.Iterator.html#method.peekable
+/// [`peekable`]: Iterator::peekable
 /// [`Iterator`]: trait.Iterator.html
 #[derive(Clone, Debug)]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
@@ -1743,7 +1743,7 @@ impl<I: Iterator> Peekable<I> {
     /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`.
     /// But if the iteration is over, `None` is returned.
     ///
-    /// [`next`]: trait.Iterator.html#tymethod.next
+    /// [`next`]: Iterator::next
     ///
     /// Because `peek()` returns a reference, and many iterators iterate over
     /// references, there can be a possibly confusing situation where the
@@ -1871,7 +1871,7 @@ unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}
 /// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`skip_while`]: trait.Iterator.html#method.skip_while
+/// [`skip_while`]: Iterator::skip_while
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1993,7 +1993,7 @@ unsafe impl<I: InPlaceIterable, F> InPlaceIterable for SkipWhile<I, F> where
 /// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`take_while`]: trait.Iterator.html#method.take_while
+/// [`take_while`]: Iterator::take_while
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -2128,7 +2128,7 @@ unsafe impl<I: InPlaceIterable, F> InPlaceIterable for TakeWhile<I, F> where
 /// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`map_while`]: trait.Iterator.html#method.map_while
+/// [`map_while`]: Iterator::map_while
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
@@ -2226,7 +2226,7 @@ unsafe impl<B, I: InPlaceIterable, P> InPlaceIterable for MapWhile<I, P> where
 /// This `struct` is created by the [`skip`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`skip`]: trait.Iterator.html#method.skip
+/// [`skip`]: Iterator::skip
 /// [`Iterator`]: trait.Iterator.html
 #[derive(Clone, Debug)]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
@@ -2422,7 +2422,7 @@ unsafe impl<I: InPlaceIterable> InPlaceIterable for Skip<I> {}
 /// This `struct` is created by the [`take`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`take`]: trait.Iterator.html#method.take
+/// [`take`]: Iterator::take
 /// [`Iterator`]: trait.Iterator.html
 #[derive(Clone, Debug)]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
@@ -2627,7 +2627,7 @@ unsafe impl<I: TrustedLen> TrustedLen for Take<I> {}
 /// This `struct` is created by the [`scan`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`scan`]: trait.Iterator.html#method.scan
+/// [`scan`]: Iterator::scan
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -2735,7 +2735,7 @@ unsafe impl<St, F, B, I: InPlaceIterable> InPlaceIterable for Scan<I, St, F> whe
 /// This `struct` is created by the [`inspect`] method on [`Iterator`]. See its
 /// documentation for more.
 ///
-/// [`inspect`]: trait.Iterator.html#method.inspect
+/// [`inspect`]: Iterator::inspect
 /// [`Iterator`]: trait.Iterator.html
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 069e6e7e718..41202546566 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -70,6 +70,7 @@
 #![feature(cfg_target_has_atomic)]
 #![feature(const_alloc_layout)]
 #![feature(const_discriminant)]
+#![feature(const_cell_into_inner)]
 #![feature(const_checked_int_methods)]
 #![feature(const_euclidean_int_methods)]
 #![feature(const_float_classify)]
@@ -158,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/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 4f64e30ccf8..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 {
@@ -130,7 +135,7 @@ impl i128 {
 #[cfg(target_pointer_width = "16")]
 #[lang = "isize"]
 impl isize {
-    int_impl! { isize, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234",
+    int_impl! { isize, i16, usize, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234",
     "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
 }
@@ -138,7 +143,7 @@ impl isize {
 #[cfg(target_pointer_width = "32")]
 #[lang = "isize"]
 impl isize {
-    int_impl! { isize, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301",
+    int_impl! { isize, i32, usize, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301",
     "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
@@ -147,7 +152,7 @@ impl isize {
 #[cfg(target_pointer_width = "64")]
 #[lang = "isize"]
 impl isize {
-    int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "",
+    int_impl! { isize, i64, usize, 64, -9223372036854775808, 9223372036854775807, "", "",
     12, "0xaa00000000006e1", "0x6e10aa",  "0x1234567890123456", "0x5634129078563412",
      "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
      "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
@@ -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/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 2edeb81011a..d48c02bf59c 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -115,23 +115,13 @@ use crate::hint::spin_loop;
 
 /// Signals the processor that it is inside a busy-wait spin-loop ("spin lock").
 ///
-/// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving
-/// power or switching hyper-threads.
-///
-/// This function is different from [`std::thread::yield_now`] which directly yields to the
-/// system's scheduler, whereas `spin_loop_hint` does not interact with the operating system.
-///
-/// A common use case for `spin_loop_hint` is implementing bounded optimistic spinning in a CAS
-/// loop in synchronization primitives. To avoid problems like priority inversion, it is strongly
-/// recommended that the spin loop is terminated after a finite amount of iterations and an
-/// appropriate blocking syscall is made.
+/// This function is expected to be deprecated in favor of
+/// [`hint::spin_loop`].
 ///
 /// **Note**: On platforms that do not support receiving spin-loop hints this function does not
 /// do anything at all.
 ///
-/// [`std::thread::yield_now`]: ../../../std/thread/fn.yield_now.html
-/// [`std::thread::sleep`]: ../../../std/thread/fn.sleep.html
-/// [`std::sync::Mutex`]: ../../../std/sync/struct.Mutex.html
+/// [`hint::spin_loop`]: crate::hint::spin_loop
 #[inline]
 #[stable(feature = "spin_loop_hint", since = "1.24.0")]
 pub fn spin_loop_hint() {
@@ -365,7 +355,8 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "atomic_access", since = "1.15.0")]
-    pub fn into_inner(self) -> bool {
+    #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
+    pub const fn into_inner(self) -> bool {
         self.v.into_inner() != 0
     }
 
@@ -941,7 +932,8 @@ impl<T> AtomicPtr<T> {
     /// ```
     #[inline]
     #[stable(feature = "atomic_access", since = "1.15.0")]
-    pub fn into_inner(self) -> *mut T {
+    #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
+    pub const fn into_inner(self) -> *mut T {
         self.p.into_inner()
     }
 
@@ -1462,7 +1454,8 @@ assert_eq!(some_var.into_inner(), 5);
 ```"),
                 #[inline]
                 #[$stable_access]
-                pub fn into_inner(self) -> $int_type {
+                #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")]
+                pub const fn into_inner(self) -> $int_type {
                     self.v.into_inner()
                 }
             }
diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs
index 4e987a53b2c..6851f3fcd2f 100644
--- a/library/core/src/task/poll.rs
+++ b/library/core/src/task/poll.rs
@@ -39,15 +39,17 @@ impl<T> Poll<T> {
 
     /// Returns `true` if this is `Poll::Ready`
     #[inline]
+    #[rustc_const_stable(feature = "const_poll", since = "1.49.0")]
     #[stable(feature = "futures_api", since = "1.36.0")]
-    pub fn is_ready(&self) -> bool {
+    pub const fn is_ready(&self) -> bool {
         matches!(*self, Poll::Ready(_))
     }
 
     /// Returns `true` if this is `Poll::Pending`
     #[inline]
+    #[rustc_const_stable(feature = "const_poll", since = "1.49.0")]
     #[stable(feature = "futures_api", since = "1.36.0")]
-    pub fn is_pending(&self) -> bool {
+    pub const fn is_pending(&self) -> bool {
         !self.is_ready()
     }
 }
diff --git a/library/core/tests/cell.rs b/library/core/tests/cell.rs
index 40be01f4439..77517879dd2 100644
--- a/library/core/tests/cell.rs
+++ b/library/core/tests/cell.rs
@@ -422,3 +422,15 @@ fn refcell_format() {
     let msg = format!("{name} {}", &*what.borrow(), name = &*name.borrow());
     assert_eq!(msg, "rust rocks".to_string());
 }
+
+#[allow(dead_code)]
+fn const_cells() {
+    const UNSAFE_CELL: UnsafeCell<i32> = UnsafeCell::new(3);
+    const _: i32 = UNSAFE_CELL.into_inner();
+
+    const REF_CELL: RefCell<i32> = RefCell::new(3);
+    const _: i32 = REF_CELL.into_inner();
+
+    const CELL: Cell<i32> = Cell::new(3);
+    const _: i32 = CELL.into_inner();
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 0c4ce867f54..c9f9b890c39 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -9,6 +9,7 @@
 #![feature(box_syntax)]
 #![feature(cell_update)]
 #![feature(const_assume)]
+#![feature(const_cell_into_inner)]
 #![feature(core_intrinsics)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
@@ -91,5 +92,6 @@ mod result;
 mod slice;
 mod str;
 mod str_lossy;
+mod task;
 mod time;
 mod tuple;
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/task.rs b/library/core/tests/task.rs
new file mode 100644
index 00000000000..d71fef9e5c8
--- /dev/null
+++ b/library/core/tests/task.rs
@@ -0,0 +1,14 @@
+use core::task::Poll;
+
+#[test]
+fn poll_const() {
+    // test that the methods of `Poll` are usable in a const context
+
+    const POLL: Poll<usize> = Poll::Pending;
+
+    const IS_READY: bool = POLL.is_ready();
+    assert!(!IS_READY);
+
+    const IS_PENDING: bool = POLL.is_pending();
+    assert!(IS_PENDING);
+}
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index d1244c2ca53..fa229251703 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -1390,8 +1390,6 @@ pub struct IntoValues<K, V> {
 /// A builder for computing where in a HashMap a key-value pair would be stored.
 ///
 /// See the [`HashMap::raw_entry_mut`] docs for usage examples.
-///
-/// [`HashMap::raw_entry_mut`]: HashMap::raw_entry_mut
 #[unstable(feature = "hash_raw_entry", issue = "56167")]
 pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> {
     map: &'a mut HashMap<K, V, S>,
@@ -1430,8 +1428,6 @@ pub struct RawVacantEntryMut<'a, K: 'a, V: 'a, S: 'a> {
 /// A builder for computing where in a HashMap a key-value pair would be stored.
 ///
 /// See the [`HashMap::raw_entry`] docs for usage examples.
-///
-/// [`HashMap::raw_entry`]: HashMap::raw_entry
 #[unstable(feature = "hash_raw_entry", issue = "56167")]
 pub struct RawEntryBuilder<'a, K: 'a, V: 'a, S: 'a> {
     map: &'a HashMap<K, V, S>,
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/io/cursor.rs b/library/std/src/io/cursor.rs
index 5733735dc4a..bbee2cc9842 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -94,7 +94,8 @@ impl<T> Cursor<T> {
     /// # force_inference(&buff);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn new(inner: T) -> Cursor<T> {
+    #[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
+    pub const fn new(inner: T) -> Cursor<T> {
         Cursor { pos: 0, inner }
     }
 
@@ -130,7 +131,8 @@ impl<T> Cursor<T> {
     /// let reference = buff.get_ref();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_ref(&self) -> &T {
+    #[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
+    pub const fn get_ref(&self) -> &T {
         &self.inner
     }
 
@@ -175,7 +177,8 @@ impl<T> Cursor<T> {
     /// assert_eq!(buff.position(), 1);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn position(&self) -> u64 {
+    #[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
+    pub const fn position(&self) -> u64 {
         self.pos
     }
 
diff --git a/library/std/src/io/cursor/tests.rs b/library/std/src/io/cursor/tests.rs
index 80d88ca66f6..5da31ce0ba7 100644
--- a/library/std/src/io/cursor/tests.rs
+++ b/library/std/src/io/cursor/tests.rs
@@ -514,3 +514,10 @@ fn test_eq() {
 
     let _: AssertEq<Cursor<Vec<u8>>> = AssertEq(Cursor::new(Vec::new()));
 }
+
+#[allow(dead_code)]
+fn const_cursor() {
+    const CURSOR: Cursor<&[u8]> = Cursor::new(&[0]);
+    const _: &&[u8] = CURSOR.get_ref();
+    const _: u64 = CURSOR.position();
+}
diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs
index dc05b9648fd..2b1f371129e 100644
--- a/library/std/src/io/util.rs
+++ b/library/std/src/io/util.rs
@@ -102,7 +102,8 @@ pub struct Empty {
 /// assert!(buffer.is_empty());
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn empty() -> Empty {
+#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
+pub const fn empty() -> Empty {
     Empty { _priv: () }
 }
 
@@ -159,7 +160,8 @@ pub struct Repeat {
 /// assert_eq!(buffer, [0b101, 0b101, 0b101]);
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn repeat(byte: u8) -> Repeat {
+#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
+pub const fn repeat(byte: u8) -> Repeat {
     Repeat { byte }
 }
 
@@ -226,7 +228,8 @@ pub struct Sink {
 /// assert_eq!(num_bytes, 5);
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-pub fn sink() -> Sink {
+#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
+pub const fn sink() -> Sink {
     Sink { _priv: () }
 }
 
diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs
index e5e32ecb405..9450b1ee124 100644
--- a/library/std/src/io/util/tests.rs
+++ b/library/std/src/io/util/tests.rs
@@ -1,5 +1,5 @@
 use crate::io::prelude::*;
-use crate::io::{copy, empty, repeat, sink};
+use crate::io::{copy, empty, repeat, sink, Empty, Repeat, Sink};
 
 #[test]
 fn copy_copies() {
@@ -43,3 +43,10 @@ fn take_some_bytes() {
     assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4);
     assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
 }
+
+#[allow(dead_code)]
+fn const_utils() {
+    const _: Empty = empty();
+    const _: Repeat = repeat(b'c');
+    const _: Sink = sink();
+}
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 96a7755c688..bc218b77c87 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -242,6 +242,7 @@
 #![feature(const_fn_transmute)]
 #![feature(const_fn)]
 #![feature(const_fn_fn_ptr_basics)]
+#![feature(const_io_structs)]
 #![feature(const_ip)]
 #![feature(const_ipv6)]
 #![feature(const_raw_ptr_deref)]
@@ -296,7 +297,6 @@
 #![feature(raw)]
 #![feature(raw_ref_macros)]
 #![feature(ready_macro)]
-#![feature(renamed_spin_loop)]
 #![feature(rustc_attrs)]
 #![feature(rustc_private)]
 #![feature(shrink_to)]
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index dc13c9433f1..db0777ee9f0 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -535,9 +535,6 @@ unsafe impl<T: Send> Send for SyncSender<T> {}
 /// A **send** operation can only fail if the receiving end of a channel is
 /// disconnected, implying that the data could never be received. The error
 /// contains the data being sent as a payload so it can be recovered.
-///
-/// [`Sender::send`]: Sender::send
-/// [`SyncSender::send`]: SyncSender::send
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(PartialEq, Eq, Clone, Copy)]
 pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
diff --git a/library/std/src/sys/cloudabi/abi/cloudabi.rs b/library/std/src/sys/cloudabi/abi/cloudabi.rs
index 5c4e3fd85c4..d67f0f81a9f 100644
--- a/library/std/src/sys/cloudabi/abi/cloudabi.rs
+++ b/library/std/src/sys/cloudabi/abi/cloudabi.rs
@@ -143,7 +143,7 @@ pub enum advice {
     WILLNEED = 6,
 }
 
-/// Enumeration describing the kind of value stored in [`auxv`](struct.auxv.html).
+/// Enumeration describing the kind of value stored in [`auxv`].
 #[repr(u32)]
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
 #[non_exhaustive]
@@ -246,7 +246,7 @@ pub struct condvar(pub u32);
 pub const CONDVAR_HAS_NO_WAITERS: condvar = condvar(0);
 
 /// Identifier for a device containing a file system. Can be used
-/// in combination with [`inode`](struct.inode.html) to uniquely identify a file on the
+/// in combination with [`inode`] to uniquely identify a file on the
 /// local system.
 #[repr(C)]
 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
@@ -808,7 +808,7 @@ bitflags! {
     const FILE_SYMLINK          = 0x0000000001000000;
     /// The right to invoke [`file_unlink()`](fn.file_unlink.html).
     const FILE_UNLINK           = 0x0000000002000000;
-    /// The right to invoke [`mem_map()`](fn.mem_map.html) with [`mprot`](struct.mprot.html) set to
+    /// The right to invoke [`mem_map()`](fn.mem_map.html) with [`mprot`] set to
     /// zero.
     const MEM_MAP               = 0x0000000004000000;
     /// If [`MEM_MAP`](struct.rights.html#associatedconstant.MEM_MAP) is set, the right to invoke
@@ -1020,7 +1020,7 @@ bitflags! {
 /// written it into locks when acquiring them for writing. It is
 /// not advised to use these identifiers for any other purpose.
 ///
-/// As the thread identifier is also stored in [`lock`](struct.lock.html) when
+/// As the thread identifier is also stored in [`lock`] when
 /// [`LOCK_WRLOCKED`](constant.LOCK_WRLOCKED.html) is set, the top two bits of the thread
 /// must always be set to zero.
 #[repr(C)]
@@ -1373,7 +1373,7 @@ fn lookup_layout_test() {
 /// Entry point for a process (`_start`).
 ///
 /// **auxv**:
-/// The auxiliary vector. See [`auxv`](struct.auxv.html).
+/// The auxiliary vector. See [`auxv`].
 pub type processentry = unsafe extern "C" fn(auxv: *const auxv) -> ();
 
 /// Arguments of [`sock_recv()`](fn.sock_recv.html).
@@ -2372,7 +2372,7 @@ pub unsafe fn file_open(
 ///
 /// When successful, the contents of the output buffer consist of
 /// a sequence of directory entries. Each directory entry consists
-/// of a [`dirent`](struct.dirent.html) object, followed by [`dirent.d_namlen`](struct.dirent.html#structfield.d_namlen) bytes
+/// of a [`dirent`] object, followed by [`dirent.d_namlen`](struct.dirent.html#structfield.d_namlen) bytes
 /// holding the name of the directory entry.
 ///
 /// This system call fills the output buffer as much as possible,
diff --git a/library/std/src/sys/sgx/ext/io.rs b/library/std/src/sys/sgx/ext/io.rs
index 8aa84a550d2..f79874a4aec 100644
--- a/library/std/src/sys/sgx/ext/io.rs
+++ b/library/std/src/sys/sgx/ext/io.rs
@@ -1,7 +1,7 @@
 //! SGX-specific extensions to general I/O primitives
 //!
 //! SGX file descriptors behave differently from Unix file descriptors. See the
-//! description of [`TryIntoRawFd`](trait.TryIntoRawFd.html) for more details.
+//! description of [`TryIntoRawFd`] for more details.
 #![unstable(feature = "sgx_platform", issue = "56975")]
 
 use crate::net;
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/net.rs b/library/std/src/sys/unix/net.rs
index 74c7db27226..378d690f8bf 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -55,9 +55,18 @@ impl Socket {
     pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
         unsafe {
             cfg_if::cfg_if! {
-                if #[cfg(target_os = "linux")] {
-                    // On Linux we pass the SOCK_CLOEXEC flag to atomically create
-                    // the socket and set it as CLOEXEC, added in 2.6.27.
+                if #[cfg(any(
+                    target_os = "android",
+                    target_os = "dragonfly",
+                    target_os = "freebsd",
+                    target_os = "illumos",
+                    target_os = "linux",
+                    target_os = "netbsd",
+                    target_os = "opensbd",
+                ))] {
+                    // On platforms that support it we pass the SOCK_CLOEXEC
+                    // flag to atomically create the socket and set it as
+                    // CLOEXEC. On Linux this was added in 2.6.27.
                     let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?;
                     Ok(Socket(FileDesc::new(fd)))
                 } else {
@@ -83,7 +92,15 @@ impl Socket {
             let mut fds = [0, 0];
 
             cfg_if::cfg_if! {
-                if #[cfg(target_os = "linux")] {
+                if #[cfg(any(
+                    target_os = "android",
+                    target_os = "dragonfly",
+                    target_os = "freebsd",
+                    target_os = "illumos",
+                    target_os = "linux",
+                    target_os = "netbsd",
+                    target_os = "opensbd",
+                ))] {
                     // Like above, set cloexec atomically
                     cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
                     Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))))
@@ -174,13 +191,28 @@ impl Socket {
     pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> {
         // Unfortunately the only known way right now to accept a socket and
         // atomically set the CLOEXEC flag is to use the `accept4` syscall on
-        // Linux. This was added in 2.6.28, glibc 2.10 and musl 0.9.5.
+        // platforms that support it. On Linux, this was added in 2.6.28,
+        // glibc 2.10 and musl 0.9.5.
         cfg_if::cfg_if! {
-            if #[cfg(target_os = "linux")] {
+            if #[cfg(any(
+                target_os = "dragonfly",
+                target_os = "freebsd",
+                target_os = "illumos",
+                target_os = "linux",
+                target_os = "netbsd",
+                target_os = "opensbd",
+            ))] {
                 let fd = cvt_r(|| unsafe {
                     libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
                 })?;
                 Ok(Socket(FileDesc::new(fd)))
+            // While the Android kernel supports the syscall,
+            // it is not included in all versions of Android's libc.
+            } else if #[cfg(target_os = "android")] {
+                let fd = cvt_r(|| unsafe {
+                    libc::syscall(libc::SYS_accept4, self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
+                })?;
+                Ok(Socket(FileDesc::new(fd as c_int)))
             } else {
                 let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?;
                 let fd = FileDesc::new(fd);
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/thread/local.rs b/library/std/src/thread/local.rs
index d8db5d1aa69..dd438858c37 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -255,7 +255,7 @@ impl<T: 'static> LocalKey<T> {
     ///
     /// This will lazily initialize the value if this thread has not referenced
     /// this key yet. If the key has been destroyed (which may happen if this is called
-    /// in a destructor), this function will return an [`AccessError`](struct.AccessError.html).
+    /// in a destructor), this function will return an [`AccessError`].
     ///
     /// # Panics
     ///
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index bdb8fc7807b..fefaa77a2a1 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -137,7 +137,6 @@
 //! [`thread::current`]: current
 //! [`thread::Result`]: Result
 //! [`unpark`]: Thread::unpark
-//! [`Thread::name`]: Thread::name
 //! [`thread::park_timeout`]: park_timeout
 //! [`Cell`]: crate::cell::Cell
 //! [`RefCell`]: crate::cell::RefCell
diff --git a/library/test/src/helpers/concurrency.rs b/library/test/src/helpers/concurrency.rs
index 7e9bd50f556..c39a9b0ec02 100644
--- a/library/test/src/helpers/concurrency.rs
+++ b/library/test/src/helpers/concurrency.rs
@@ -1,18 +1,14 @@
 //! Helper module which helps to determine amount of threads to be used
 //! during tests execution.
-use std::env;
-use std::thread;
+use std::{env, num::NonZeroUsize, thread};
 
-#[allow(deprecated)]
 pub fn get_concurrency() -> usize {
-    match env::var("RUST_TEST_THREADS") {
-        Ok(s) => {
-            let opt_n: Option<usize> = s.parse().ok();
-            match opt_n {
-                Some(n) if n > 0 => n,
-                _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", s),
-            }
+    if let Ok(value) = env::var("RUST_TEST_THREADS") {
+        match value.parse::<NonZeroUsize>().ok() {
+            Some(n) => n.get(),
+            _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", value),
         }
-        Err(..) => thread::available_concurrency().map(|n| n.get()).unwrap_or(1),
+    } else {
+        thread::available_concurrency().map(|n| n.get()).unwrap_or(1)
     }
 }
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..db671c5fe65 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -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/config.rs b/src/bootstrap/config.rs
index 7698ff62880..2fc121a2e86 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,
@@ -418,6 +419,7 @@ struct Llvm {
     use_libcxx: Option<bool>,
     use_linker: Option<String>,
     allow_old_toolchain: Option<bool>,
+    polly: Option<bool>,
     download_ci_llvm: Option<StringOrBool>,
 }
 
@@ -762,6 +764,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 +798,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;
@@ -913,11 +917,18 @@ impl Config {
             set(&mut config.missing_tools, t.missing_tools);
         }
 
-        // Cargo does not provide a RUSTFMT environment variable, so we
-        // synthesize it manually. Note that we also later check the config.toml
-        // and set this to that path if necessary.
-        let rustfmt = config.initial_rustc.with_file_name(exe("rustfmt", config.build));
-        config.initial_rustfmt = if rustfmt.exists() { Some(rustfmt) } else { None };
+        config.initial_rustfmt = config.initial_rustfmt.or_else({
+            let build = config.build;
+            let initial_rustc = &config.initial_rustc;
+
+            move || {
+                // Cargo does not provide a RUSTFMT environment variable, so we
+                // synthesize it manually.
+                let rustfmt = initial_rustc.with_file_name(exe("rustfmt", build));
+
+                if rustfmt.exists() { Some(rustfmt) } else { None }
+            }
+        });
 
         // Now that we've reached the end of our configuration, infer the
         // default values for all options that we haven't otherwise stored yet.
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/lib.rs b/src/bootstrap/lib.rs
index 0878b0ff789..3d111839dc7 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -332,6 +332,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 {
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/test.rs b/src/bootstrap/test.rs
index b48e9696c9a..2b87c4b91af 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1205,17 +1205,6 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             // Only pass correct values for these flags for the `run-make` suite as it
             // requires that a C++ compiler was configured which isn't always the case.
             if !builder.config.dry_run && matches!(suite, "run-make" | "run-make-fulldeps") {
-                cmd.arg("--cc")
-                    .arg(builder.cc(target))
-                    .arg("--cxx")
-                    .arg(builder.cxx(target).unwrap())
-                    .arg("--cflags")
-                    .arg(builder.cflags(target, GitRepo::Rustc).join(" "));
-                copts_passed = true;
-                if let Some(ar) = builder.ar(target) {
-                    cmd.arg("--ar").arg(ar);
-                }
-
                 // The llvm/bin directory contains many useful cross-platform
                 // tools. Pass the path to run-make tests so they can use them.
                 let llvm_bin_path = llvm_config
@@ -1241,6 +1230,21 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             }
         }
 
+        // Only pass correct values for these flags for the `run-make` suite as it
+        // requires that a C++ compiler was configured which isn't always the case.
+        if !builder.config.dry_run && matches!(suite, "run-make" | "run-make-fulldeps") {
+            cmd.arg("--cc")
+                .arg(builder.cc(target))
+                .arg("--cxx")
+                .arg(builder.cxx(target).unwrap())
+                .arg("--cflags")
+                .arg(builder.cflags(target, GitRepo::Rustc).join(" "));
+            copts_passed = true;
+            if let Some(ar) = builder.ar(target) {
+                cmd.arg("--ar").arg(ar);
+            }
+        }
+
         if !llvm_components_passed {
             cmd.arg("--llvm-components").arg("");
         }
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/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
index 930061fca6f..0e28ea9668f 100644
--- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
+++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
@@ -27,6 +27,3 @@ RUN echo "optimize = false" >> /config/nopt-std-config.toml
 ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
 ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \
   && python3 ../x.py --stage 2 test
-
-# FIXME(#59637) takes too long on CI right now
-ENV NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1
diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile
index ea178bcf4f2..195601755f3 100644
--- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile
+++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile
@@ -28,6 +28,3 @@ ENV SCRIPT python3 ../x.py --stage 2 test \
   --exclude src/test/rustdoc-js \
   --exclude src/tools/error_index_generator \
   --exclude src/tools/linkchecker
-
-# FIXME(#59637) takes too long on CI right now
-ENV NO_LLVM_ASSERTIONS=1 NO_DEBUG_ASSERTIONS=1
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile
index 5f98edf6171..5faa0ccab56 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile
@@ -22,10 +22,3 @@ RUN sh /scripts/sccache.sh
 ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false
 ENV SCRIPT python3 ../x.py --stage 2 test distcheck
 ENV DIST_SRC 1
-
-# The purpose of this builder is to test that we can `./x.py --stage 2 test` successfully
-# from a tarball, not to test LLVM/rustc's own set of assertions. These cause a
-# significant hit to CI compile time (over a half hour as observed in #61185),
-# so disable assertions for this builder.
-ENV NO_LLVM_ASSERTIONS=1
-ENV NO_DEBUG_ASSERTIONS=1
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile
index 34c6396b7b5..bd046f802c8 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile
@@ -57,9 +57,3 @@ ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \
            python2.7 ../x.py --stage 2 test src/test/ui --pass=check && \
            # Run tidy at the very end, after all the other tests.
            python2.7 ../x.py --stage 2 test src/tools/tidy
-
-# The purpose of this container isn't to test with debug assertions and
-# this is run on all PRs, so let's get speedier builds by disabling these extra
-# checks.
-ENV NO_DEBUG_ASSERTIONS=1
-ENV NO_LLVM_ASSERTIONS=1
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 0df191f8f74..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
 
@@ -500,9 +500,6 @@ jobs:
             env:
               RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
               SCRIPT: make ci-subset-1
-              # FIXME(#59637)
-              NO_DEBUG_ASSERTIONS: 1
-              NO_LLVM_ASSERTIONS: 1
             <<: *job-windows-xl
 
           - name: x86_64-msvc-2
@@ -515,18 +512,12 @@ jobs:
             env:
               RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
               SCRIPT: make ci-subset-1
-              # FIXME(#59637)
-              NO_DEBUG_ASSERTIONS: 1
-              NO_LLVM_ASSERTIONS: 1
             <<: *job-windows-xl
 
           - name: i686-msvc-2
             env:
               RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
               SCRIPT: make ci-subset-2
-              # FIXME(#59637)
-              NO_DEBUG_ASSERTIONS: 1
-              NO_LLVM_ASSERTIONS: 1
             <<: *job-windows-xl
 
           - name: x86_64-msvc-cargo
@@ -534,9 +525,6 @@ jobs:
               SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo
               RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld
               VCVARS_BAT: vcvars64.bat
-              # FIXME(#59637)
-              NO_DEBUG_ASSERTIONS: 1
-              NO_LLVM_ASSERTIONS: 1
             <<: *job-windows-xl
 
           - name: x86_64-msvc-tools
@@ -566,9 +554,6 @@ jobs:
               RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
               SCRIPT: make ci-mingw-subset-1
               CUSTOM_MINGW: 1
-              # FIXME(#59637)
-              NO_DEBUG_ASSERTIONS: 1
-              NO_LLVM_ASSERTIONS: 1
             <<: *job-windows-xl
 
           - name: i686-mingw-2
@@ -583,9 +568,6 @@ jobs:
               SCRIPT: make ci-mingw-subset-1
               RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler
               CUSTOM_MINGW: 1
-              # FIXME(#59637)
-              NO_DEBUG_ASSERTIONS: 1
-              NO_LLVM_ASSERTIONS: 1
             <<: *job-windows-xl
 
           - name: x86_64-mingw-2
@@ -653,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/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/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/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-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_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/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/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/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/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/imports/issue-62767.rs b/src/test/ui/imports/issue-62767.rs
index 0e0f915ea53..01184eea9b4 100644
--- a/src/test/ui/imports/issue-62767.rs
+++ b/src/test/ui/imports/issue-62767.rs
@@ -1,3 +1,5 @@
+// check-pass
+
 // Minimized case from #62767.
 mod m {
     pub enum Same {
@@ -9,7 +11,7 @@ use m::*;
 
 // The variant `Same` introduced by this import is also considered when resolving the prefix
 // `Same::` during import validation to avoid effects similar to time travel (#74556).
-use Same::Same; //~ ERROR unresolved import `Same`
+use Same::Same;
 
 // Case from #74556.
 mod foo {
@@ -21,8 +23,8 @@ mod foo {
 }
 
 use foo::*;
-use bar::bar; //~ ERROR unresolved import `bar::bar`
-              //~| ERROR inconsistent resolution for an import
+use bar::bar;
+
 use bar::foobar;
 
 fn main() {}
diff --git a/src/test/ui/imports/issue-62767.stderr b/src/test/ui/imports/issue-62767.stderr
deleted file mode 100644
index a4334bda6dd..00000000000
--- a/src/test/ui/imports/issue-62767.stderr
+++ /dev/null
@@ -1,21 +0,0 @@
-error: inconsistent resolution for an import
-  --> $DIR/issue-62767.rs:24:5
-   |
-LL | use bar::bar;
-   |     ^^^^^^^^
-
-error[E0432]: unresolved import `Same`
-  --> $DIR/issue-62767.rs:12:5
-   |
-LL | use Same::Same;
-   |     ^^^^ `Same` is a variant, not a module
-
-error[E0432]: unresolved import `bar::bar`
-  --> $DIR/issue-62767.rs:24:5
-   |
-LL | use bar::bar;
-   |     ^^^^^^^^ no `bar` in `foo::bar::bar`
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0432`.
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/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs
index c49a13f1065..ef55f31593b 100644
--- a/src/test/ui/lint/lint-const-item-mutation.rs
+++ b/src/test/ui/lint/lint-const-item-mutation.rs
@@ -29,6 +29,7 @@ const RAW_PTR: *mut u8 = 1 as *mut u8;
 const MUTABLE: Mutable = Mutable { msg: "" };
 const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() };
 const VEC: Vec<i32> = Vec::new();
+const PTR: *mut () = 1 as *mut _;
 
 fn main() {
     ARRAY[0] = 5; //~ WARN attempting to modify
@@ -50,4 +51,8 @@ fn main() {
     MUTABLE.msg = "wow"; // no warning, because Drop observes the mutation
     MUTABLE2.msg = "wow"; //~ WARN attempting to modify
     VEC.push(0); //~ WARN taking a mutable reference to a `const` item
+
+    // Test that we don't warn when converting a raw pointer
+    // into a mutable reference
+    unsafe { &mut *PTR };
 }
diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr
index 11b5124b2d2..ae95abc72f3 100644
--- a/src/test/ui/lint/lint-const-item-mutation.stderr
+++ b/src/test/ui/lint/lint-const-item-mutation.stderr
@@ -1,11 +1,11 @@
 warning: attempting to modify a `const` item
-  --> $DIR/lint-const-item-mutation.rs:34:5
+  --> $DIR/lint-const-item-mutation.rs:35:5
    |
 LL |     ARRAY[0] = 5;
    |     ^^^^^^^^^^^^
    |
    = note: `#[warn(const_item_mutation)]` on by default
-   = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
+   = note: each usage of a `const` item creates a new temporary; the original `const` item will not be modified
 note: `const` item defined here
   --> $DIR/lint-const-item-mutation.rs:26:1
    |
@@ -13,12 +13,12 @@ LL | const ARRAY: [u8; 1] = [25];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attempting to modify a `const` item
-  --> $DIR/lint-const-item-mutation.rs:35:5
+  --> $DIR/lint-const-item-mutation.rs:36:5
    |
 LL |     MY_STRUCT.field = false;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
+   = note: each usage of a `const` item creates a new temporary; the original `const` item will not be modified
 note: `const` item defined here
   --> $DIR/lint-const-item-mutation.rs:27:1
    |
@@ -26,12 +26,12 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attempting to modify a `const` item
-  --> $DIR/lint-const-item-mutation.rs:36:5
+  --> $DIR/lint-const-item-mutation.rs:37:5
    |
 LL |     MY_STRUCT.inner_array[0] = 'b';
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
+   = note: each usage of a `const` item creates a new temporary; the original `const` item will not be modified
 note: `const` item defined here
   --> $DIR/lint-const-item-mutation.rs:27:1
    |
@@ -39,7 +39,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/lint-const-item-mutation.rs:37:5
+  --> $DIR/lint-const-item-mutation.rs:38:5
    |
 LL |     MY_STRUCT.use_mut();
    |     ^^^^^^^^^^^^^^^^^^^
@@ -58,7 +58,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/lint-const-item-mutation.rs:38:5
+  --> $DIR/lint-const-item-mutation.rs:39:5
    |
 LL |     &mut MY_STRUCT;
    |     ^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/lint-const-item-mutation.rs:39:5
+  --> $DIR/lint-const-item-mutation.rs:40:5
    |
 LL |     (&mut MY_STRUCT).use_mut();
    |     ^^^^^^^^^^^^^^^^
@@ -86,12 +86,12 @@ LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attempting to modify a `const` item
-  --> $DIR/lint-const-item-mutation.rs:51:5
+  --> $DIR/lint-const-item-mutation.rs:52:5
    |
 LL |     MUTABLE2.msg = "wow";
    |     ^^^^^^^^^^^^^^^^^^^^
    |
-   = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
+   = note: each usage of a `const` item creates a new temporary; the original `const` item will not be modified
 note: `const` item defined here
   --> $DIR/lint-const-item-mutation.rs:30:1
    |
@@ -99,7 +99,7 @@ LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/lint-const-item-mutation.rs:52:5
+  --> $DIR/lint-const-item-mutation.rs:53:5
    |
 LL |     VEC.push(0);
    |     ^^^^^^^^^^^
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/print_type_sizes/anonymous.rs b/src/test/ui/print_type_sizes/anonymous.rs
index b96348640fa..2b008ca3b3a 100644
--- a/src/test/ui/print_type_sizes/anonymous.rs
+++ b/src/test/ui/print_type_sizes/anonymous.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 
 // All of the types that occur in this function are uninteresting, in
 // that one cannot control the sizes of these types with the same sort
diff --git a/src/test/ui/print_type_sizes/generics.rs b/src/test/ui/print_type_sizes/generics.rs
index f165526dffa..3ef7b60db2c 100644
--- a/src/test/ui/print_type_sizes/generics.rs
+++ b/src/test/ui/print_type_sizes/generics.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
diff --git a/src/test/ui/print_type_sizes/multiple_types.rs b/src/test/ui/print_type_sizes/multiple_types.rs
index 4cb7ae03b54..f1ad27ec131 100644
--- a/src/test/ui/print_type_sizes/multiple_types.rs
+++ b/src/test/ui/print_type_sizes/multiple_types.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 
 // This file illustrates that when multiple structural types occur in
 // a function, every one of them is included in the output.
diff --git a/src/test/ui/print_type_sizes/niche-filling.rs b/src/test/ui/print_type_sizes/niche-filling.rs
index d9845fd6d70..37ac45f7e05 100644
--- a/src/test/ui/print_type_sizes/niche-filling.rs
+++ b/src/test/ui/print_type_sizes/niche-filling.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
diff --git a/src/test/ui/print_type_sizes/no_duplicates.rs b/src/test/ui/print_type_sizes/no_duplicates.rs
index 4495a7770a7..e45e4794a35 100644
--- a/src/test/ui/print_type_sizes/no_duplicates.rs
+++ b/src/test/ui/print_type_sizes/no_duplicates.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
diff --git a/src/test/ui/print_type_sizes/packed.rs b/src/test/ui/print_type_sizes/packed.rs
index dce4a61ef33..269cc3cc282 100644
--- a/src/test/ui/print_type_sizes/packed.rs
+++ b/src/test/ui/print_type_sizes/packed.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
diff --git a/src/test/ui/print_type_sizes/padding.rs b/src/test/ui/print_type_sizes/padding.rs
index 1f894c5e252..d1acad16d7e 100644
--- a/src/test/ui/print_type_sizes/padding.rs
+++ b/src/test/ui/print_type_sizes/padding.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 
 // This file illustrates how padding is handled: alignment
 // requirements can lead to the introduction of padding, either before
diff --git a/src/test/ui/print_type_sizes/repr-align.rs b/src/test/ui/print_type_sizes/repr-align.rs
index 1e6f7ccca40..07544935b2f 100644
--- a/src/test/ui/print_type_sizes/repr-align.rs
+++ b/src/test/ui/print_type_sizes/repr-align.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
diff --git a/src/test/ui/print_type_sizes/repr_int_c.rs b/src/test/ui/print_type_sizes/repr_int_c.rs
index 7aad2715bc0..b8067c112ee 100644
--- a/src/test/ui/print_type_sizes/repr_int_c.rs
+++ b/src/test/ui/print_type_sizes/repr_int_c.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 
 // This test makes sure that the tag is not grown for `repr(C)` or `repr(u8)`
 // variants (see https://github.com/rust-lang/rust/issues/50098 for the original bug).
diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs
index ae4e492456a..c234547bd14 100644
--- a/src/test/ui/print_type_sizes/uninhabited.rs
+++ b/src/test/ui/print_type_sizes/uninhabited.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 // ^-- needed because `--pass check` does not emit the output needed.
 //     FIXME: consider using an attribute instead of side-effects.
diff --git a/src/test/ui/print_type_sizes/variants.rs b/src/test/ui/print_type_sizes/variants.rs
index 77e2b4befba..6c8553cc23d 100644
--- a/src/test/ui/print_type_sizes/variants.rs
+++ b/src/test/ui/print_type_sizes/variants.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 
 // This file illustrates two things:
 //
diff --git a/src/test/ui/print_type_sizes/zero-sized-fields.rs b/src/test/ui/print_type_sizes/zero-sized-fields.rs
index 71d09167747..e02a33109e5 100644
--- a/src/test/ui/print_type_sizes/zero-sized-fields.rs
+++ b/src/test/ui/print_type_sizes/zero-sized-fields.rs
@@ -1,5 +1,5 @@
 // compile-flags: -Z print-type-sizes
-// build-pass (FIXME(62277): could be check-pass?)
+// build-pass
 // ignore-pass
 
 // At one point, zero-sized fields such as those in this file were causing
diff --git a/src/test/ui/proc-macro/nonterminal-token-hygiene.rs b/src/test/ui/proc-macro/nonterminal-token-hygiene.rs
new file mode 100644
index 00000000000..98fd4306004
--- /dev/null
+++ b/src/test/ui/proc-macro/nonterminal-token-hygiene.rs
@@ -0,0 +1,33 @@
+// Make sure that marks from declarative macros are applied to tokens in nonterminal.
+
+// check-pass
+// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene
+// compile-flags: -Z trim-diagnostic-paths=no
+// normalize-stdout-test "\d+#" -> "0#"
+// aux-build:test-macros.rs
+
+#![feature(decl_macro)]
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[macro_use]
+extern crate test_macros;
+
+macro_rules! outer {
+    ($item:item) => {
+        macro inner() {
+            print_bang! { $item }
+        }
+
+        inner!();
+    };
+}
+
+struct S;
+
+outer! {
+    struct S; // OK, not a duplicate definition of `S`
+}
+
+fn main() {}
diff --git a/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
new file mode 100644
index 00000000000..1623d677726
--- /dev/null
+++ b/src/test/ui/proc-macro/nonterminal-token-hygiene.stdout
@@ -0,0 +1,88 @@
+PRINT-BANG INPUT (DISPLAY): struct S;
+PRINT-BANG RE-COLLECTED (DISPLAY): struct S ;
+PRINT-BANG INPUT (DEBUG): TokenStream [
+    Group {
+        delimiter: None,
+        stream: TokenStream [
+            Ident {
+                ident: "struct",
+                span: $DIR/nonterminal-token-hygiene.rs:30:5: 30:11 (#5),
+            },
+            Ident {
+                ident: "S",
+                span: $DIR/nonterminal-token-hygiene.rs:30:12: 30:13 (#5),
+            },
+            Punct {
+                ch: ';',
+                spacing: Alone,
+                span: $DIR/nonterminal-token-hygiene.rs:30:13: 30:14 (#5),
+            },
+        ],
+        span: $DIR/nonterminal-token-hygiene.rs:20:27: 20:32 (#6),
+    },
+]
+#![feature /* 0#0 */(prelude_import)]
+#![no_std /* 0#0 */]
+// Make sure that marks from declarative macros are applied to tokens in nonterminal.
+
+// check-pass
+// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene
+// compile-flags: -Z trim-diagnostic-paths=no
+// normalize-stdout-test "\d+#" -> "0#"
+// aux-build:test-macros.rs
+
+#![feature /* 0#0 */(decl_macro)]
+
+#![no_std /* 0#0 */]
+#[prelude_import /* 0#1 */]
+use ::core /* 0#1 */::prelude /* 0#1 */::v1 /* 0#1 */::*;
+#[macro_use /* 0#1 */]
+extern crate core /* 0#2 */;
+#[macro_use /* 0#1 */]
+extern crate compiler_builtins /* 0#2 */;
+// Don't load unnecessary hygiene information from std
+extern crate std /* 0#0 */;
+
+#[macro_use /* 0#0 */]
+extern crate test_macros /* 0#0 */;
+
+macro_rules! outer
+    /*
+    0#0
+    */ {
+    ($ item : item) =>
+    {
+        macro inner() { print_bang ! { $ item } } inner ! () ;
+
+    } ;
+}
+
+struct S /* 0#0 */;
+macro inner /* 0#4 */ { () => { print_bang ! { struct S; } } }
+
+struct S /* 0#5 */;
+// OK, not a duplicate definition of `S`
+
+fn main /* 0#0 */() { }
+
+/*
+Expansions:
+0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root
+1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
+2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer")
+3: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
+4: parent: ExpnId(2), call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner")
+5: parent: ExpnId(4), call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang")
+
+SyntaxContexts:
+#0: parent: #0, outer_mark: (ExpnId(0), Opaque)
+#1: parent: #0, outer_mark: (ExpnId(1), Opaque)
+#2: parent: #0, outer_mark: (ExpnId(1), Transparent)
+#3: parent: #0, outer_mark: (ExpnId(3), Opaque)
+#4: parent: #0, outer_mark: (ExpnId(2), SemiTransparent)
+#5: parent: #0, outer_mark: (ExpnId(4), Opaque)
+#6: parent: #4, outer_mark: (ExpnId(4), Opaque)
+#7: parent: #0, outer_mark: (ExpnId(5), Opaque)
+#8: parent: #6, outer_mark: (ExpnId(5), Transparent)
+#9: parent: #5, outer_mark: (ExpnId(5), SemiTransparent)
+*/
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/test/ui/type-alias-impl-trait/issue-72793.rs b/src/test/ui/type-alias-impl-trait/issue-72793.rs
deleted file mode 100644
index e643a8cab5b..00000000000
--- a/src/test/ui/type-alias-impl-trait/issue-72793.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// build-pass
-
-// Regression test for #72793.
-// FIXME: This still shows ICE with `-Zmir-opt-level=2`.
-
-#![feature(type_alias_impl_trait)]
-
-trait T { type Item; }
-
-type Alias<'a> = impl T<Item = &'a ()>;
-
-struct S;
-impl<'a> T for &'a S {
-    type Item = &'a ();
-}
-
-fn filter_positive<'a>() -> Alias<'a> {
-    &S
-}
-
-fn with_positive(fun: impl Fn(Alias<'_>)) {
-    fun(filter_positive());
-}
-
-fn main() {
-    with_positive(|_| ());
-}
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/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 {
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 6359b1b0eb724f2432fd4776c3fc5f5cad9e67d
+Subproject 30e0c303a019737cb0e22db464c774ac66b14e0
diff --git a/src/tools/rls b/src/tools/rls
-Subproject 1f686d5f707269b1086f6afcdced36225c0c5ff
+Subproject dab1468d6aeed0e49f7d0569c1d2128b5a7751e
diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml
index 213cb07fddf..337d65e4da4 100644
--- a/src/tools/rustc-workspace-hack/Cargo.toml
+++ b/src/tools/rustc-workspace-hack/Cargo.toml
@@ -61,6 +61,7 @@ features = [
 ]
 
 [dependencies]
+byteorder = { version = "1", features = ['default', 'std'] }
 curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true }
 crossbeam-utils = { version = "0.7.2", features = ["nightly"] }
 proc-macro2 = { version = "1", features = ["default"] }
diff --git a/src/tools/rustfmt b/src/tools/rustfmt
-Subproject 97d0301011533e1c131c0edd660d77b4bd476c8
+Subproject eb894d53708122a67762de9489881c11aa8ce25
diff --git a/src/tools/x/Cargo.lock b/src/tools/x/Cargo.lock
new file mode 100644
index 00000000000..723d6cb25ed
--- /dev/null
+++ b/src/tools/x/Cargo.lock
@@ -0,0 +1,5 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "x"
+version = "0.1.0"
diff --git a/src/tools/x/Cargo.toml b/src/tools/x/Cargo.toml
new file mode 100644
index 00000000000..72c4948c617
--- /dev/null
+++ b/src/tools/x/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "x"
+version = "0.1.0"
+description = "Run x.py slightly more conveniently"
+authors = ["Casey Rodarmor <casey@rodarmor.com>"]
+edition = "2018"
+publish = false
diff --git a/src/tools/x/README.md b/src/tools/x/README.md
new file mode 100644
index 00000000000..3b3cf2847c2
--- /dev/null
+++ b/src/tools/x/README.md
@@ -0,0 +1,3 @@
+# x
+
+`x` invokes `x.py` from any subdirectory.
diff --git a/src/tools/x/src/main.rs b/src/tools/x/src/main.rs
new file mode 100644
index 00000000000..6c0311433d6
--- /dev/null
+++ b/src/tools/x/src/main.rs
@@ -0,0 +1,92 @@
+//! Run `x.py` from any subdirectory of a rust compiler checkout.
+//!
+//! We prefer `exec`, to avoid adding an extra process in the process tree.
+//! However, since `exec` isn't available on Windows, we indirect through
+//! `exec_or_status`, which will call `exec` on unix and `status` on Windows.
+//!
+//! We use `python`, `python3`, or `python2` as the python interpreter to run
+//! `x.py`, in that order of preference.
+
+use std::{
+    env, io,
+    process::{self, Command, ExitStatus},
+};
+
+const PYTHON: &str = "python";
+const PYTHON2: &str = "python2";
+const PYTHON3: &str = "python3";
+
+fn python() -> &'static str {
+    let val = match env::var_os("PATH") {
+        Some(val) => val,
+        None => return PYTHON,
+    };
+
+    let mut python2 = false;
+    let mut python3 = false;
+
+    for dir in env::split_paths(&val) {
+        if dir.join(PYTHON).exists() {
+            return PYTHON;
+        }
+
+        python2 |= dir.join(PYTHON2).exists();
+        python3 |= dir.join(PYTHON3).exists();
+    }
+
+    if python3 {
+        PYTHON3
+    } else if python2 {
+        PYTHON2
+    } else {
+        PYTHON
+    }
+}
+
+#[cfg(unix)]
+fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
+    use std::os::unix::process::CommandExt;
+    Err(command.exec())
+}
+
+#[cfg(not(unix))]
+fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
+    command.status()
+}
+
+fn main() {
+    let current = match env::current_dir() {
+        Ok(dir) => dir,
+        Err(err) => {
+            eprintln!("Failed to get current directory: {}", err);
+            process::exit(1);
+        }
+    };
+
+    for dir in current.ancestors() {
+        let candidate = dir.join("x.py");
+
+        if candidate.exists() {
+            let mut python = Command::new(python());
+
+            python.arg(&candidate).args(env::args().skip(1)).current_dir(dir);
+
+            let result = exec_or_status(&mut python);
+
+            match result {
+                Err(error) => {
+                    eprintln!("Failed to invoke `{}`: {}", candidate.display(), error);
+                }
+                Ok(status) => {
+                    process::exit(status.code().unwrap_or(1));
+                }
+            }
+        }
+    }
+
+    eprintln!(
+        "x.py not found. Please run inside of a checkout of `https://github.com/rust-lang/rust`."
+    );
+
+    process::exit(1);
+}