about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTim Diekmann <21277928+TimDiekmann@users.noreply.github.com>2020-10-16 08:54:38 +0200
committerGitHub <noreply@github.com>2020-10-16 08:54:38 +0200
commit955b37b3059a7e06842559af54e1685e33b0cf6c (patch)
treef11d1e90021475b287dcef9ab05f3f3bfc004ea8
parentd5720bba8f5b278616a2fbd0da39478879a3f68b (diff)
parent8e6f69afc9b0943003ce51a53d1f59611e6601a3 (diff)
downloadrust-955b37b3059a7e06842559af54e1685e33b0cf6c.tar.gz
rust-955b37b3059a7e06842559af54e1685e33b0cf6c.zip
Merge branch 'master' into box-alloc
-rw-r--r--.github/ISSUE_TEMPLATE/regression.md68
-rw-r--r--.github/workflows/ci.yml34
-rw-r--r--.gitmodules2
-rw-r--r--Cargo.lock160
-rw-r--r--compiler/rustc_arena/Cargo.toml1
-rw-r--r--compiler/rustc_arena/src/lib.rs7
-rw-r--r--compiler/rustc_ast/src/ast.rs62
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs9
-rw-r--r--compiler/rustc_ast/src/token.rs31
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs6
-rw-r--r--compiler/rustc_ast/src/util/parser.rs1
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs2
-rw-r--r--compiler/rustc_ast_pretty/src/pp.rs19
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/mod.rs104
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs (renamed from compiler/rustc_ast_pretty/src/pprust.rs)403
-rw-r--r--compiler/rustc_attr/src/builtin.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs35
-rw-r--r--compiler/rustc_builtin_macros/src/assert.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs22
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs33
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs51
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs261
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs16
-rw-r--r--compiler/rustc_codegen_llvm/src/base.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs21
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs58
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/mod.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs36
-rw-r--r--compiler/rustc_codegen_llvm/src/va_arg.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs117
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs48
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs38
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs47
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/mod.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs2
-rw-r--r--compiler/rustc_data_structures/src/fingerprint.rs4
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs2
-rw-r--r--compiler/rustc_data_structures/src/sorted_map.rs6
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs2
-rw-r--r--compiler/rustc_data_structures/src/work_queue.rs6
-rw-r--r--compiler/rustc_driver/Cargo.toml2
-rw-r--r--compiler/rustc_driver/src/lib.rs65
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0007.md8
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0424.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0723.md16
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0778.md35
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0779.md32
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs13
-rw-r--r--compiler/rustc_errors/src/emitter.rs2
-rw-r--r--compiler/rustc_expand/src/base.rs14
-rw-r--r--compiler/rustc_expand/src/build.rs97
-rw-r--r--compiler/rustc_expand/src/expand.rs4
-rw-r--r--compiler/rustc_feature/src/accepted.rs3
-rw-r--r--compiler/rustc_feature/src/active.rs10
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_fs_util/src/lib.rs27
-rw-r--r--compiler/rustc_hir/src/definitions.rs6
-rw-r--r--compiler/rustc_hir/src/hir.rs24
-rw-r--r--compiler/rustc_hir/src/hir_id.rs2
-rw-r--r--compiler/rustc_hir/src/pat_util.rs28
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs9
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs31
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs13
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs2
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs2
-rw-r--r--compiler/rustc_interface/src/passes.rs4
-rw-r--r--compiler/rustc_interface/src/queries.rs38
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_interface/src/util.rs2
-rw-r--r--compiler/rustc_lexer/src/lib.rs34
-rw-r--r--compiler/rustc_lint/src/context.rs4
-rw-r--r--compiler/rustc_lint/src/lib.rs7
-rw-r--r--compiler/rustc_lint/src/types.rs4
-rw-r--r--compiler/rustc_llvm/build.rs9
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp39
-rw-r--r--compiler/rustc_metadata/src/dependency_format.rs2
-rw-r--r--compiler/rustc_metadata/src/locator.rs2
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs21
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs2
-rw-r--r--compiler/rustc_middle/Cargo.toml2
-rw-r--r--compiler/rustc_middle/src/ich/impls_hir.rs6
-rw-r--r--compiler/rustc_middle/src/ich/impls_syntax.rs22
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs7
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs5
-rw-r--r--compiler/rustc_middle/src/middle/region.rs10
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs11
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs60
-rw-r--r--compiler/rustc_middle/src/mir/query.rs46
-rw-r--r--compiler/rustc_middle/src/mir/terminator/mod.rs113
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs3
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs11
-rw-r--r--compiler/rustc_middle/src/query/mod.rs16
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs8
-rw-r--r--compiler/rustc_middle/src/ty/context.rs8
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs51
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs8
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs12
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs10
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs40
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs2
-rw-r--r--compiler/rustc_middle/src/ty/outlives.rs10
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs48
-rw-r--r--compiler/rustc_middle/src/ty/query/on_disk_cache.rs27
-rw-r--r--compiler/rustc_middle/src/ty/query/plumbing.rs13
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs8
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs3
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs28
-rw-r--r--compiler/rustc_middle/src/ty/util.rs30
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs68
-rw-r--r--compiler/rustc_mir/src/borrow_check/invalidation.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/mod.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/mod.rs2
-rw-r--r--compiler/rustc_mir/src/const_eval/eval_queries.rs2
-rw-r--r--compiler/rustc_mir/src/const_eval/mod.rs2
-rw-r--r--compiler/rustc_mir/src/dataflow/framework/direction.rs18
-rw-r--r--compiler/rustc_mir/src/dataflow/framework/engine.rs57
-rw-r--r--compiler/rustc_mir/src/interpret/eval_context.rs8
-rw-r--r--compiler/rustc_mir/src/interpret/machine.rs7
-rw-r--r--compiler/rustc_mir/src/interpret/operand.rs6
-rw-r--r--compiler/rustc_mir/src/interpret/place.rs13
-rw-r--r--compiler/rustc_mir/src/interpret/terminator.rs10
-rw-r--r--compiler/rustc_mir/src/monomorphize/collector.rs18
-rw-r--r--compiler/rustc_mir/src/monomorphize/partitioning/default.rs2
-rw-r--r--compiler/rustc_mir/src/transform/check_const_item_mutation.rs3
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/ops.rs11
-rw-r--r--compiler/rustc_mir/src/transform/early_otherwise_branch.rs35
-rw-r--r--compiler/rustc_mir/src/transform/generator.rs6
-rw-r--r--compiler/rustc_mir/src/transform/inline.rs2
-rw-r--r--compiler/rustc_mir/src/transform/match_branches.rs9
-rw-r--r--compiler/rustc_mir/src/transform/mod.rs8
-rw-r--r--compiler/rustc_mir/src/transform/promote_consts.rs17
-rw-r--r--compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs2
-rw-r--r--compiler/rustc_mir/src/transform/simplify_branches.rs9
-rw-r--r--compiler/rustc_mir/src/transform/simplify_comparison_integral.rs48
-rw-r--r--compiler/rustc_mir/src/transform/simplify_try.rs14
-rw-r--r--compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs32
-rw-r--r--compiler/rustc_mir/src/transform/unreachable_prop.rs20
-rw-r--r--compiler/rustc_mir/src/transform/validate.rs34
-rw-r--r--compiler/rustc_mir/src/util/elaborate_drops.rs14
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs5
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs60
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs74
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs8
-rw-r--r--compiler/rustc_parse/src/lib.rs94
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs87
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs80
-rw-r--r--compiler/rustc_parse/src/parser/item.rs2
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs3
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs36
-rw-r--r--compiler/rustc_passes/src/check_attr.rs15
-rw-r--r--compiler/rustc_passes/src/intrinsicck.rs4
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs2
-rw-r--r--compiler/rustc_query_system/src/dep_graph/dep_node.rs4
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs5
-rw-r--r--compiler/rustc_query_system/src/dep_graph/query.rs19
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs21
-rw-r--r--compiler/rustc_resolve/src/late.rs20
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs364
-rw-r--r--compiler/rustc_resolve/src/lib.rs2
-rw-r--r--compiler/rustc_serialize/src/opaque.rs6
-rw-r--r--compiler/rustc_session/src/config.rs50
-rw-r--r--compiler/rustc_session/src/lint/builtin.rs11
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_session/src/output.rs26
-rw-r--r--compiler/rustc_session/src/session.rs45
-rw-r--r--compiler/rustc_span/src/hygiene.rs8
-rw-r--r--compiler/rustc_span/src/lib.rs18
-rw-r--r--compiler/rustc_span/src/source_map.rs9
-rw-r--r--compiler/rustc_span/src/symbol.rs7
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs9
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs67
-rw-r--r--compiler/rustc_target/src/abi/mod.rs4
-rw-r--r--compiler/rustc_target/src/asm/mips.rs73
-rw-r--r--compiler/rustc_target/src/asm/mod.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_darwin.rs10
-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.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_linux_android.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs10
-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.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_redox.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs10
-rw-r--r--compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs10
-rw-r--r--compiler/rustc_target/src/spec/android_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/arm_linux_androideabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/armebv7r_none_eabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs11
-rw-r--r--compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs11
-rw-r--r--compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs11
-rw-r--r--compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7_apple_ios.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7_linux_androideabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs10
-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.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7r_none_eabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/armv7s_apple_ios.rs10
-rw-r--r--compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs6
-rw-r--r--compiler/rustc_target/src/spec/avr_gnu_base.rs10
-rw-r--r--compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs4
-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/hexagon_unknown_linux_musl.rs10
-rw-r--r--compiler/rustc_target/src/spec/i386_apple_ios.rs10
-rw-r--r--compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs8
-rw-r--r--compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs8
-rw-r--r--compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs8
-rw-r--r--compiler/rustc_target/src/spec/i686_apple_darwin.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_linux_android.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_freebsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_haiku.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_netbsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_openbsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_unknown_uefi.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs10
-rw-r--r--compiler/rustc_target/src/spec/i686_wrs_vxworks.rs10
-rw-r--r--compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs10
-rw-r--r--compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs10
-rw-r--r--compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs10
-rw-r--r--compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs10
-rw-r--r--compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs10
-rw-r--r--compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs10
-rw-r--r--compiler/rustc_target/src/spec/mipsel_sony_psp.rs10
-rw-r--r--compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs10
-rw-r--r--compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs10
-rw-r--r--compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs10
-rw-r--r--compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs10
-rw-r--r--compiler/rustc_target/src/spec/mod.rs89
-rw-r--r--compiler/rustc_target/src/spec/msp430_none_elf.rs10
-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.rs10
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs10
-rw-r--r--compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs10
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs10
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs10
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs10
-rw-r--r--compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs10
-rw-r--r--compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs10
-rw-r--r--compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs10
-rw-r--r--compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs10
-rw-r--r--compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs10
-rw-r--r--compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs10
-rw-r--r--compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs10
-rw-r--r--compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs10
-rw-r--r--compiler/rustc_target/src/spec/tests/tests_impl.rs15
-rw-r--r--compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs11
-rw-r--r--compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs10
-rw-r--r--compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs10
-rw-r--r--compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs10
-rw-r--r--compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs10
-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.rs8
-rw-r--r--compiler/rustc_target/src/spec/windows_gnu_base.rs4
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_darwin.rs10
-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.rs8
-rw-r--r--compiler/rustc_target/src/spec/x86_64_fuchsia.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_linux_android.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_linux_kernel.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs15
-rw-r--r--compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_sun_solaris.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_redox.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs15
-rw-r--r--compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs10
-rw-r--r--compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs10
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs41
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs33
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs145
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs51
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs59
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs188
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs6
-rw-r--r--compiler/rustc_traits/Cargo.toml6
-rw-r--r--compiler/rustc_traits/src/dropck_outlives.rs33
-rw-r--r--compiler/rustc_typeck/src/bounds.rs2
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs8
-rw-r--r--compiler/rustc_typeck/src/check/check.rs2
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs17
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs23
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt.rs3200
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs1469
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs996
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/mod.rs295
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs528
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior.rs95
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs4
-rw-r--r--compiler/rustc_typeck/src/check/op.rs25
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs8
-rw-r--r--compiler/rustc_typeck/src/collect.rs75
-rw-r--r--config.toml.example12
-rw-r--r--library/alloc/src/alloc.rs21
-rw-r--r--library/alloc/src/boxed.rs2
-rw-r--r--library/alloc/src/collections/btree/map.rs4
-rw-r--r--library/alloc/src/collections/btree/node.rs88
-rw-r--r--library/alloc/src/collections/btree/node/tests.rs33
-rw-r--r--library/alloc/src/vec.rs5
-rw-r--r--library/alloc/tests/vec.rs3
m---------library/backtrace0
-rw-r--r--library/core/src/cell.rs8
-rw-r--r--library/core/src/ffi.rs2
-rw-r--r--library/core/src/fmt/mod.rs16
-rw-r--r--library/core/src/intrinsics.rs4
-rw-r--r--library/core/src/iter/sources.rs4
-rw-r--r--library/core/src/iter/traits/collect.rs6
-rw-r--r--library/core/src/iter/traits/exact_size.rs6
-rw-r--r--library/core/src/lib.rs9
-rw-r--r--library/core/src/option.rs3
-rw-r--r--library/core/src/result.rs2
-rw-r--r--library/core/src/slice/iter.rs29
-rw-r--r--library/core/src/slice/mod.rs98
-rw-r--r--library/core/src/str/iter.rs164
-rw-r--r--library/core/src/task/wake.rs3
-rw-r--r--library/core/tests/num/int_macros.rs4
-rw-r--r--library/core/tests/slice.rs32
-rw-r--r--library/proc_macro/src/lib.rs2
-rw-r--r--library/std/src/backtrace.rs6
-rw-r--r--library/std/src/ffi/os_str.rs4
-rw-r--r--library/std/src/io/buffered.rs1438
-rw-r--r--library/std/src/io/buffered/bufreader.rs423
-rw-r--r--library/std/src/io/buffered/bufwriter.rs387
-rw-r--r--library/std/src/io/buffered/linewriter.rs232
-rw-r--r--library/std/src/io/buffered/linewritershim.rs270
-rw-r--r--library/std/src/io/buffered/mod.rs151
-rw-r--r--library/std/src/lib.rs7
-rw-r--r--library/std/src/net/parser.rs34
-rw-r--r--library/std/src/net/parser/tests.rs6
-rw-r--r--library/std/src/os/linux/fs.rs2
-rw-r--r--library/std/src/path.rs4
-rw-r--r--library/std/src/primitive_docs.rs2
-rw-r--r--library/std/src/sync/mutex.rs2
-rw-r--r--library/std/src/sys/cloudabi/condvar.rs41
-rw-r--r--library/std/src/sys/cloudabi/mutex.rs54
-rw-r--r--library/std/src/sys/cloudabi/rwlock.rs47
-rw-r--r--library/std/src/sys/sgx/abi/mod.rs2
-rw-r--r--library/std/src/sys/sgx/abi/tls.rs9
-rw-r--r--library/std/src/sys/sgx/abi/usercalls/alloc.rs71
-rw-r--r--library/std/src/sys/sgx/abi/usercalls/mod.rs3
-rw-r--r--library/std/src/sys/sgx/abi/usercalls/raw.rs70
-rw-r--r--library/std/src/sys/sgx/alloc.rs20
-rw-r--r--library/std/src/sys/sgx/args.rs2
-rw-r--r--library/std/src/sys/sgx/condvar.rs8
-rw-r--r--library/std/src/sys/sgx/mod.rs5
-rw-r--r--library/std/src/sys/sgx/rwlock.rs19
-rw-r--r--library/std/src/sys/sgx/stdio.rs2
-rw-r--r--library/std/src/sys/sgx/thread.rs2
-rw-r--r--library/std/src/sys/sgx/waitqueue/unsafe_list.rs72
-rw-r--r--library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs4
-rw-r--r--library/std/src/sys/unix/fs.rs28
-rw-r--r--library/std/src/sys/unix/os.rs2
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs42
-rw-r--r--library/std/src/sys/unix/time.rs56
-rw-r--r--library/std/src/sys/unsupported/common.rs13
-rw-r--r--library/std/src/sys/unsupported/mod.rs2
-rw-r--r--library/std/src/sys/unsupported/mutex.rs22
-rw-r--r--library/std/src/sys/unsupported/rwlock.rs33
-rw-r--r--library/std/src/sys/vxworks/fs.rs7
-rw-r--r--library/std/src/sys/vxworks/os.rs2
-rw-r--r--library/std/src/sys/wasi/ext/io.rs18
-rw-r--r--library/std/src/sys/wasi/mod.rs1
-rw-r--r--library/std/src/sys/wasm/futex_atomics.rs17
-rw-r--r--library/std/src/sys/wasm/mod.rs3
-rw-r--r--library/std/src/sys/windows/c.rs11
-rw-r--r--library/std/src/sys/windows/mod.rs53
-rw-r--r--library/std/src/sys/windows/time.rs36
-rw-r--r--library/std/src/sys_common/backtrace.rs22
-rw-r--r--library/std/src/sys_common/mutex.rs19
-rw-r--r--library/std/src/sys_common/thread_parker/mod.rs6
-rw-r--r--library/test/src/formatters/json.rs4
-rw-r--r--library/unwind/src/libunwind.rs2
-rw-r--r--src/bootstrap/CHANGELOG.md6
-rw-r--r--src/bootstrap/README.md6
-rw-r--r--src/bootstrap/bin/main.rs8
-rw-r--r--src/bootstrap/bootstrap.py15
-rw-r--r--src/bootstrap/builder.rs43
-rw-r--r--src/bootstrap/compile.rs10
-rw-r--r--src/bootstrap/config.rs13
-rw-r--r--src/bootstrap/defaults/config.compiler.toml5
-rw-r--r--src/bootstrap/defaults/config.library.toml5
-rw-r--r--src/bootstrap/dist.rs87
-rw-r--r--src/bootstrap/flags.rs24
-rw-r--r--src/bootstrap/lib.rs39
-rw-r--r--src/bootstrap/run.rs1
-rw-r--r--src/bootstrap/setup.rs77
-rw-r--r--src/bootstrap/test.rs9
-rw-r--r--src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile6
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile4
-rw-r--r--src/ci/github-actions/ci.yml49
-rwxr-xr-xsrc/ci/scripts/install-clang.sh14
-rwxr-xr-xsrc/ci/scripts/install-mingw.sh7
-rwxr-xr-xsrc/ci/scripts/select-xcode.sh13
m---------src/doc/book0
m---------src/doc/embedded-book0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustc/src/codegen-options/index.md20
-rw-r--r--src/doc/rustc/src/platform-support.md8
-rw-r--r--src/doc/rustdoc/src/SUMMARY.md2
-rw-r--r--src/doc/rustdoc/src/advanced-features.md2
-rw-r--r--src/doc/rustdoc/src/linking-to-items-by-name.md41
-rw-r--r--src/doc/rustdoc/src/lints.md45
-rw-r--r--src/doc/unstable-book/src/compiler-flags/codegen-backend.md31
-rw-r--r--src/doc/unstable-book/src/library-features/asm.md27
-rw-r--r--src/etc/gdb_providers.py63
-rw-r--r--src/etc/lldb_commands34
-rwxr-xr-xsrc/etc/pre-commit.sh10
-rw-r--r--src/librustdoc/clean/cfg.rs31
-rw-r--r--src/librustdoc/clean/cfg/tests.rs36
-rw-r--r--src/librustdoc/clean/inline.rs68
-rw-r--r--src/librustdoc/clean/mod.rs98
-rw-r--r--src/librustdoc/clean/types.rs174
-rw-r--r--src/librustdoc/clean/utils.rs15
-rw-r--r--src/librustdoc/core.rs2
-rw-r--r--src/librustdoc/doctest.rs2
-rw-r--r--src/librustdoc/doctree.rs3
-rw-r--r--src/librustdoc/html/format.rs16
-rw-r--r--src/librustdoc/html/markdown.rs2
-rw-r--r--src/librustdoc/html/render/mod.rs163
-rw-r--r--src/librustdoc/html/static/rustdoc.css22
-rw-r--r--src/librustdoc/lib.rs2
-rw-r--r--src/librustdoc/passes/calculate_doc_coverage.rs36
-rw-r--r--src/librustdoc/passes/collapse_docs.rs5
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs630
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs6
-rw-r--r--src/librustdoc/passes/doc_test_lints.rs15
-rw-r--r--src/librustdoc/passes/html_tags.rs226
-rw-r--r--src/librustdoc/passes/mod.rs179
-rw-r--r--src/librustdoc/passes/stripper.rs172
-rw-r--r--src/librustdoc/visit_ast.rs1
m---------src/llvm-project0
-rw-r--r--src/stage0.txt4
-rw-r--r--src/test/assembly/asm/mips-types.rs154
-rw-r--r--src/test/codegen/len-is-bounded.rs24
-rw-r--r--src/test/codegen/slice-windows-no-bounds-check.rs35
-rw-r--r--src/test/codegen/tune-cpu-on-functions.rs21
-rw-r--r--src/test/compile-fail/issue-27675-unchecked-bounds.rs19
-rw-r--r--src/test/debuginfo/pretty-std-collections.rs16
-rw-r--r--src/test/incremental/thinlto/cgu_invalidated_via_import.rs4
-rw-r--r--src/test/incremental/thinlto/cgu_keeps_identical_fn.rs47
-rw-r--r--src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs4
-rw-r--r--src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir2
-rw-r--r--src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs58
-rw-r--r--src/test/rustdoc-js/doc-alias-whitespace.js19
-rw-r--r--src/test/rustdoc-js/doc-alias-whitespace.rs4
-rw-r--r--src/test/rustdoc-ui/auxiliary/intra-doc-broken.rs4
-rw-r--r--src/test/rustdoc-ui/check-doc-alias-attr.rs3
-rw-r--r--src/test/rustdoc-ui/check-doc-alias-attr.stderr20
-rw-r--r--src/test/rustdoc-ui/coverage/allow_missing_docs.rs41
-rw-r--r--src/test/rustdoc-ui/coverage/allow_missing_docs.stderr20
-rw-r--r--src/test/rustdoc-ui/coverage/allow_missing_docs.stdout7
-rw-r--r--src/test/rustdoc-ui/intra-doc-broken-reexport.rs8
-rw-r--r--src/test/rustdoc-ui/intra-link-errors.rs2
-rw-r--r--src/test/rustdoc-ui/intra-link-malformed-generics.rs19
-rw-r--r--src/test/rustdoc-ui/intra-link-malformed-generics.stderr102
-rw-r--r--src/test/rustdoc-ui/intra-links-ambiguity.rs4
-rw-r--r--src/test/rustdoc-ui/intra-links-ambiguity.stderr17
-rw-r--r--src/test/rustdoc-ui/invalid-html-tags.rs89
-rw-r--r--src/test/rustdoc-ui/invalid-html-tags.stderr86
-rw-r--r--src/test/rustdoc-ui/lint-group.rs5
-rw-r--r--src/test/rustdoc-ui/lint-group.stderr21
-rw-r--r--src/test/rustdoc-ui/pub-export-lint.rs5
-rw-r--r--src/test/rustdoc-ui/pub-export-lint.stderr15
-rw-r--r--src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs6
-rw-r--r--src/test/rustdoc/auxiliary/reexport-check.rs2
-rw-r--r--src/test/rustdoc/doc-cfg-simplification.rs182
-rw-r--r--src/test/rustdoc/doc-cfg.rs7
-rw-r--r--src/test/rustdoc/duplicate-cfg.rs26
-rw-r--r--src/test/rustdoc/intra-doc-link-generic-params.rs59
-rw-r--r--src/test/rustdoc/intra-link-reexport-additional-docs.rs23
-rw-r--r--src/test/rustdoc/primitive-link.rs3
-rw-r--r--src/test/rustdoc/reexport-check.rs17
-rw-r--r--src/test/ui-fulldeps/compiler-calls.rs11
-rw-r--r--src/test/ui/arg-count-mismatch.stderr9
-rw-r--r--src/test/ui/asm/interpolated-idents.rs24
-rw-r--r--src/test/ui/asm/interpolated-idents.stderr51
-rw-r--r--src/test/ui/associated-type-bounds/issue-70292.rs21
-rw-r--r--src/test/ui/associated-type-bounds/issue-71443-1.rs9
-rw-r--r--src/test/ui/associated-type-bounds/issue-71443-1.stderr11
-rw-r--r--src/test/ui/associated-type-bounds/issue-71443-2.rs11
-rw-r--r--src/test/ui/associated-types/issue-54108.rs41
-rw-r--r--src/test/ui/associated-types/issue-54108.stderr18
-rw-r--r--src/test/ui/associated-types/issue-65934.rs17
-rw-r--r--src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs2
-rw-r--r--src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr34
-rw-r--r--src/test/ui/borrowck/mut-borrow-of-mut-ref.rs14
-rw-r--r--src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr22
-rw-r--r--src/test/ui/c-variadic/variadic-ffi-1.stderr18
-rw-r--r--src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr2
-rw-r--r--src/test/ui/check-doc-alias-attr.rs3
-rw-r--r--src/test/ui/check-doc-alias-attr.stderr20
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr12
-rw-r--r--src/test/ui/const-generics/array-size-in-generic-struct-param.rs4
-rw-r--r--src/test/ui/const-generics/const-argument-if-length.min.stderr6
-rw-r--r--src/test/ui/const-generics/const-argument-if-length.rs2
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr6
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs2
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr12
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr6
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs2
-rw-r--r--src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr12
-rw-r--r--src/test/ui/const-generics/generic-function-call-in-array-length.rs4
-rw-r--r--src/test/ui/const-generics/generic-sum-in-array-length.min.stderr12
-rw-r--r--src/test/ui/const-generics/generic-sum-in-array-length.rs4
-rw-r--r--src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr6
-rw-r--r--src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs2
-rw-r--r--src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr12
-rw-r--r--src/test/ui/const-generics/issue-61522-array-len-succ.rs4
-rw-r--r--src/test/ui/const-generics/issue-67375.min.stderr6
-rw-r--r--src/test/ui/const-generics/issue-67375.rs2
-rw-r--r--src/test/ui/const-generics/issue-67945-1.min.stderr12
-rw-r--r--src/test/ui/const-generics/issue-67945-1.rs4
-rw-r--r--src/test/ui/const-generics/issue-67945-2.min.stderr12
-rw-r--r--src/test/ui/const-generics/issue-67945-2.rs4
-rw-r--r--src/test/ui/const-generics/issues/issue-61747.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-61747.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-61935.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-61935.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-62220.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-62220.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-62456.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-64494.min.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-64494.rs4
-rw-r--r--src/test/ui/const-generics/issues/issue-66205.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-66205.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-67739.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-67739.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-68366.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-68366.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-68977.min.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-68977.rs4
-rw-r--r--src/test/ui/const-generics/issues/issue-72787.min.stderr24
-rw-r--r--src/test/ui/const-generics/issues/issue-72787.rs8
-rw-r--r--src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs2
-rw-r--r--src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs4
-rw-r--r--src/test/ui/const-generics/min_const_generics/complex-expression.rs8
-rw-r--r--src/test/ui/const-generics/min_const_generics/complex-expression.stderr24
-rw-r--r--src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr6
-rw-r--r--src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr6
-rw-r--r--src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs2
-rw-r--r--src/test/ui/const-generics/wf-misc.min.stderr12
-rw-r--r--src/test/ui/const-generics/wf-misc.rs4
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs7
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr18
-rw-r--r--src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr42
-rw-r--r--src/test/ui/drop/dynamic-drop-async.rs2
-rw-r--r--src/test/ui/drop/dynamic-drop.rs1
-rw-r--r--src/test/ui/error-codes/E0007.rs11
-rw-r--r--src/test/ui/error-codes/E0007.stderr22
-rw-r--r--src/test/ui/error-codes/E0060.stderr9
-rw-r--r--src/test/ui/error-codes/E0061.stderr18
-rw-r--r--src/test/ui/error-codes/E0778.rs8
-rw-r--r--src/test/ui/error-codes/E0778.stderr9
-rw-r--r--src/test/ui/error-codes/E0779.rs6
-rw-r--r--src/test/ui/error-codes/E0779.stderr9
-rw-r--r--src/test/ui/feature-gate-isa_attribute.rs6
-rw-r--r--src/test/ui/feature-gate-isa_attribute.stderr25
-rw-r--r--src/test/ui/feature-gates/feature-gate-negate-unsigned.stderr5
-rw-r--r--src/test/ui/generator/generator-yielding-or-returning-itself.stderr4
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-2.stderr2
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-3.stderr2
-rw-r--r--src/test/ui/generator/static-not-unpin.stderr4
-rw-r--r--src/test/ui/generator/type-mismatch-signature-deduction.stderr2
-rw-r--r--src/test/ui/generator/yielding-in-match-guards.rs24
-rw-r--r--src/test/ui/hrtb/issue-58451.stderr20
-rw-r--r--src/test/ui/impl-trait/issues/issue-65581.rs33
-rw-r--r--src/test/ui/issues/issue-18075.rs7
-rw-r--r--src/test/ui/issues/issue-18819.stderr9
-rw-r--r--src/test/ui/issues/issue-26094.stderr9
-rw-r--r--src/test/ui/issues/issue-4935.stderr9
-rw-r--r--src/test/ui/issues/issue-73427.rs44
-rw-r--r--src/test/ui/issues/issue-73427.stderr72
-rw-r--r--src/test/ui/lto-opt-level-s.rs7
-rw-r--r--src/test/ui/lto-opt-level-z.rs7
-rw-r--r--src/test/ui/methods/method-call-err-msg.stderr36
-rw-r--r--src/test/ui/mismatched_types/issue-36053-2.stderr16
-rw-r--r--src/test/ui/mismatched_types/issue-38371.stderr2
-rw-r--r--src/test/ui/not-enough-arguments.rs19
-rw-r--r--src/test/ui/not-enough-arguments.stderr39
-rw-r--r--src/test/ui/parser/bare-struct-body.rs15
-rw-r--r--src/test/ui/parser/bare-struct-body.stderr41
-rw-r--r--src/test/ui/parser/float-field.stderr10
-rw-r--r--src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr68
-rw-r--r--src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs1
-rw-r--r--src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr12
-rw-r--r--src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs1
-rw-r--r--src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr2
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs1
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr16
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs1
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs1
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr34
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs1
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr2
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs1
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr96
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs1
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr50
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs1
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr94
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs1
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr68
-rw-r--r--src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs1
-rw-r--r--src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr6
-rw-r--r--src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs1
-rw-r--r--src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr12
-rw-r--r--src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs2
-rw-r--r--src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs2
-rw-r--r--src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr36
-rw-r--r--src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs1
-rw-r--r--src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs23
-rw-r--r--src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr66
-rw-r--r--src/test/ui/pattern/move-ref-patterns/issue-53840.rs2
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs2
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr54
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs2
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs2
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr6
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs2
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr4
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs2
-rw-r--r--src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs7
-rw-r--r--src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs7
-rw-r--r--src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs7
-rw-r--r--src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs7
-rw-r--r--src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs28
-rw-r--r--src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout4
-rw-r--r--src/test/ui/proc-macro/invalid-punct-ident-1.rs3
-rw-r--r--src/test/ui/proc-macro/invalid-punct-ident-1.stderr2
-rw-r--r--src/test/ui/proc-macro/invalid-punct-ident-2.rs3
-rw-r--r--src/test/ui/proc-macro/invalid-punct-ident-2.stderr2
-rw-r--r--src/test/ui/proc-macro/invalid-punct-ident-3.rs3
-rw-r--r--src/test/ui/proc-macro/invalid-punct-ident-3.stderr2
-rw-r--r--src/test/ui/proc-macro/issue-75734-pp-paren.rs26
-rw-r--r--src/test/ui/proc-macro/issue-75734-pp-paren.stdout134
-rw-r--r--src/test/ui/proc-macro/load-panic-backtrace.rs3
-rw-r--r--src/test/ui/proc-macro/load-panic-backtrace.stderr2
-rw-r--r--src/test/ui/resolve/privacy-enum-ctor.stderr43
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/for.rs2
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/for.stderr2
-rw-r--r--src/test/ui/span/issue-34264.stderr18
-rw-r--r--src/test/ui/span/missing-unit-argument.stderr42
-rw-r--r--src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr6
-rw-r--r--src/test/ui/symbol-names/issue-75326.legacy.stderr20
-rw-r--r--src/test/ui/symbol-names/issue-75326.rs58
-rw-r--r--src/test/ui/symbol-names/issue-75326.v0.stderr20
-rw-r--r--src/test/ui/traits/assoc_type_bound_with_struct.rs19
-rw-r--r--src/test/ui/traits/assoc_type_bound_with_struct.stderr83
-rw-r--r--src/test/ui/traits/trait-bounds-not-on-struct.rs33
-rw-r--r--src/test/ui/traits/trait-bounds-not-on-struct.stderr165
-rw-r--r--src/test/ui/tuple/index-invalid.stderr8
-rw-r--r--src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr9
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-52843.rs15
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-52843.stderr14
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53096.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs2
-rw-r--r--src/test/ui/type-alias-impl-trait/structural-match.rs2
-rw-r--r--src/test/ui/unboxed-closures/issue-53448.rs15
-rw-r--r--src/test/ui/unboxed-closures/issue-53448.stderr20
-rw-r--r--src/test/ui/union/union-deref.stderr6
-rw-r--r--src/test/ui/unsigned-literal-negation.rs5
-rw-r--r--src/test/ui/unsigned-literal-negation.stderr36
-rw-r--r--src/tools/build-manifest/Cargo.toml1
-rw-r--r--src/tools/build-manifest/README.md4
-rw-r--r--src/tools/build-manifest/src/main.rs38
-rw-r--r--src/tools/build-manifest/src/versions.rs87
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/CHANGELOG.md129
-rw-r--r--src/tools/clippy/README.md2
-rw-r--r--src/tools/clippy/clippy_dev/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs43
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs20
-rw-r--r--src/tools/clippy/clippy_dev/src/serve.rs64
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml1
-rw-r--r--src/tools/clippy/clippy_lints/src/asm_syntax.rs125
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_method.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs169
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/loops.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/types.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/unicode.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/paths.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs192
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs17
-rw-r--r--src/tools/clippy/clippy_workspace_tests/build.rs7
-rw-r--r--src/tools/clippy/doc/adding_lints.md3
-rw-r--r--src/tools/clippy/doc/basics.md6
-rw-r--r--src/tools/clippy/src/driver.rs10
-rw-r--r--src/tools/clippy/src/lintlist/mod.rs43
-rw-r--r--src/tools/clippy/tests/cargo/mod.rs37
-rw-r--r--src/tools/clippy/tests/compile-test.rs3
-rw-r--r--src/tools/clippy/tests/dogfood.rs7
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs13
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr16
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--src/tools/clippy/tests/ui/asm_syntax.rs31
-rw-r--r--src/tools/clippy/tests/ui/asm_syntax.stderr44
-rw-r--r--src/tools/clippy/tests/ui/attrs.rs3
-rw-r--r--src/tools/clippy/tests/ui/attrs.stderr25
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs62
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs1
-rw-r--r--src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs8
-rw-r--r--src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr27
-rw-r--r--src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs1
-rw-r--r--src/tools/clippy/tests/ui/crashes/cc_seme.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-1588.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-1782.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-1969.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2499.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2594.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2727.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2760.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2774.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2774.stderr10
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2862.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2865.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3151.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3462.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3741.rs1
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3747.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-4727.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-4760.rs1
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-700.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/if_same_then_else.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/issue-825.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr14
-rw-r--r--src/tools/clippy/tests/ui/crashes/procedural_macro.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/regressions.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/returns.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/single-match-else.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/trivial_bounds.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs2
-rw-r--r--src/tools/clippy/tests/ui/custom_ice_message.stderr2
-rw-r--r--src/tools/clippy/tests/ui/escape_analysis.rs8
-rw-r--r--src/tools/clippy/tests/ui/explicit_counter_loop.rs29
-rw-r--r--src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed4
-rw-r--r--src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs4
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed11
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.rs11
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr36
-rw-r--r--src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs45
-rw-r--r--src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr10
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.rs98
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.stderr50
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop2.rs14
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.fixed25
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.rs25
-rw-r--r--src/tools/clippy/tests/ui/or_fun_call.stderr20
-rw-r--r--src/tools/clippy/tests/ui/print_stdout_build_script.rs12
-rw-r--r--src/tools/clippy/tests/ui/regex.rs3
-rw-r--r--src/tools/clippy/tests/ui/unicode.rs6
-rw-r--r--src/tools/clippy/tests/ui/unicode.stderr22
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_sort_by.fixed30
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_sort_by.rs10
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_sort_by.stderr52
m---------src/tools/miri24
-rwxr-xr-xsrc/tools/publish_toolstate.py2
m---------src/tools/rls0
-rw-r--r--src/tools/rust-demangler/main.rs66
-rw-r--r--triagebot.toml1
895 files changed, 16032 insertions, 11284 deletions
diff --git a/.github/ISSUE_TEMPLATE/regression.md b/.github/ISSUE_TEMPLATE/regression.md
new file mode 100644
index 00000000000..ffab883987c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/regression.md
@@ -0,0 +1,68 @@
+---
+name: Regression
+about: Report something that unexpectedly changed between Rust versions.
+labels: C-bug regression-untriaged
+---
+<!--
+Thank you for filing a regression report! 🐛 A regression is something that changed between versions of Rust but was not supposed to.
+
+Please provide a short summary of the regression, along with any information you feel is relevant to replicate it.
+-->
+
+### Code
+
+I tried this code:
+
+```rust
+<code>
+```
+
+I expected to see this happen: *explanation*
+
+Instead, this happened: *explanation*
+
+### Version it worked on
+
+<!--
+Provide the most recent version this worked on, for example:
+
+It most recently worked on: Rust 1.47
+-->
+
+It most recently worked on: <!-- version -->
+
+### Version with regression
+
+<!--
+Provide the version you are using that has the regression.
+-->
+
+`rustc --version --verbose`:
+```
+<version>
+```
+
+<!--
+Did the compiler crash? If so, please provide a backtrace.
+-->
+
+### Backtrace
+<!--
+Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your
+environment. E.g. `RUST_BACKTRACE=1 cargo build`.
+-->
+<details><summary>Backtrace</summary>
+<p>
+
+```
+<backtrace>
+```
+
+</p>
+</details>
+
+<!--
+If you know when this regression occurred, please add a line like below, replacing `{channel}` with one of stable, beta, or nightly.
+
+@rustbot modify labels: +regression-from-stable-to-{channel} -regression-untriaged
+-->
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 23058b7a808..6025808eb61 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -89,6 +89,9 @@ jobs:
       - 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
@@ -300,6 +303,20 @@ jobs:
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
             os: macos-latest
+          - name: dist-aarch64-apple
+            env:
+              SCRIPT: "./x.py dist --stage 2"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              SELECT_XCODE: /Applications/Xcode_12.2.app
+              USE_XCODE_CLANG: 1
+              MACOSX_DEPLOYMENT_TARGET: 11.0
+              MACOSX_STD_DEPLOYMENT_TARGET: 11.0
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+              DIST_REQUIRE_ALL_TOOLS: 1
+              JEMALLOC_SYS_WITH_LG_PAGE: 14
+            os: macos-latest
           - name: x86_64-msvc-1
             env:
               RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
@@ -369,7 +386,7 @@ jobs:
             os: windows-latest-xl
           - name: dist-x86_64-msvc
             env:
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc --enable-full-tools --enable-profiler"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler"
               SCRIPT: python x.py dist
               DIST_REQUIRE_ALL_TOOLS: 1
             os: windows-latest-xl
@@ -379,6 +396,12 @@ jobs:
               SCRIPT: python x.py dist
               DIST_REQUIRE_ALL_TOOLS: 1
             os: windows-latest-xl
+          - name: dist-aarch64-msvc
+            env:
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=aarch64-pc-windows-msvc --enable-full-tools --enable-profiler"
+              SCRIPT: python x.py dist
+              DIST_REQUIRE_ALL_TOOLS: 0
+            os: windows-latest-xl
           - name: dist-i686-mingw
             env:
               RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler"
@@ -437,6 +460,9 @@ jobs:
       - 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
@@ -544,6 +570,9 @@ jobs:
       - 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
@@ -648,6 +677,9 @@ jobs:
       - 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
diff --git a/.gitmodules b/.gitmodules
index d460b6508f6..984113151de 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -37,7 +37,7 @@
 [submodule "src/llvm-project"]
 	path = src/llvm-project
 	url = https://github.com/rust-lang/llvm-project.git
-	branch = rustc/11.0-2020-09-22
+	branch = rustc/11.0-2020-10-12
 [submodule "src/doc/embedded-book"]
 	path = src/doc/embedded-book
 	url = https://github.com/rust-embedded/book.git
diff --git a/Cargo.lock b/Cargo.lock
index 6fa6d97ab54..5ca804cb739 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -132,13 +132,13 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
 
 [[package]]
 name = "backtrace"
-version = "0.3.50"
+version = "0.3.53"
 dependencies = [
  "addr2line",
- "cfg-if",
+ "cfg-if 1.0.0",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.21.1",
  "rustc-demangle",
 ]
 
@@ -243,6 +243,7 @@ dependencies = [
  "anyhow",
  "flate2",
  "hex 0.4.2",
+ "num_cpus",
  "rayon",
  "serde",
  "serde_json",
@@ -294,7 +295,7 @@ checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da"
 
 [[package]]
 name = "cargo"
-version = "0.49.0"
+version = "0.50.0"
 dependencies = [
  "anyhow",
  "atty",
@@ -305,7 +306,7 @@ dependencies = [
  "clap",
  "core-foundation",
  "crates-io",
- "crossbeam-utils 0.7.2",
+ "crossbeam-utils 0.8.0",
  "crypto-hash",
  "curl",
  "curl-sys",
@@ -441,10 +442,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
 name = "chalk-derive"
-version = "0.31.0"
+version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca40c97e20f43e4aac2282d342103d45fafad74ad9bfcbaaf0b5d386f9ce1f39"
+checksum = "2d072b2ba723f0bada7c515d8b3725224bc4f5052d2a92dcbeb0b118ff37084a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -454,9 +461,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-engine"
-version = "0.31.0"
+version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88e3d545394fbc4f7d8fe203c6a78d2b73f82bb119f21af98de1f924c2518e34"
+checksum = "6fb5475f6083d6d6c509e1c335c4f69ad04144ac090faa1afb134a53c3695841"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -467,9 +474,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.31.0"
+version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c4183955e084fcc387b515f867ed0e17e9e7301f5eee29c0338d5e63315bb41"
+checksum = "f60cdb0e18c5455cb6a85e8464aad3622b70476018edfa8845691df66f7e9a05"
 dependencies = [
  "chalk-derive",
  "lazy_static",
@@ -477,9 +484,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.31.0"
+version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50e8407bba06d9e760011a28060e8f3b3f87b82ea53fb8bfaa43614c19c14dcc"
+checksum = "981534d499a8476ecc0b520be4d3864757f96211826a75360fbf2cb6fae362ab"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -548,7 +555,6 @@ dependencies = [
  "cargo_metadata 0.11.1",
  "if_chain",
  "itertools 0.9.0",
- "lazy_static",
  "pulldown-cmark 0.8.0",
  "quine-mc_cluskey",
  "quote",
@@ -671,6 +677,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "const_fn"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce90df4c658c62f12d78f7508cf92f9173e5184a539c10bfe54a3107b3ffd0f2"
+
+[[package]]
 name = "constant_time_eq"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -723,17 +735,17 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
 ]
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.4.3"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6"
+checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
 dependencies = [
- "cfg-if",
  "crossbeam-utils 0.7.2",
+ "maybe-uninit",
 ]
 
 [[package]]
@@ -754,7 +766,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
 dependencies = [
  "autocfg",
- "cfg-if",
+ "cfg-if 0.1.10",
  "crossbeam-utils 0.7.2",
  "lazy_static",
  "maybe-uninit",
@@ -777,7 +789,7 @@ version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "crossbeam-utils 0.7.2",
  "maybe-uninit",
 ]
@@ -788,7 +800,7 @@ version = "0.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "lazy_static",
 ]
 
@@ -799,7 +811,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
 dependencies = [
  "autocfg",
- "cfg-if",
+ "cfg-if 0.1.10",
+ "lazy_static",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5"
+dependencies = [
+ "autocfg",
+ "cfg-if 1.0.0",
+ "const_fn",
  "lazy_static",
 ]
 
@@ -929,7 +953,7 @@ version = "2.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "dirs-sys",
 ]
 
@@ -1071,7 +1095,7 @@ version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "redox_syscall",
  "winapi 0.3.9",
@@ -1089,7 +1113,7 @@ version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "crc32fast",
  "libc",
  "libz-sys",
@@ -1220,7 +1244,7 @@ version = "0.1.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "wasi",
 ]
@@ -1231,7 +1255,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "wasi",
 ]
@@ -1249,9 +1273,9 @@ dependencies = [
 
 [[package]]
 name = "git2"
-version = "0.13.8"
+version = "0.13.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6ac22e49b7d886b6802c66662b12609452248b1bc9e87d6d83ecea3db96f557"
+checksum = "ca6f1a0238d7f8f8fd5ee642f4ebac4dbc03e03d1f78fbe7a3ede35dcf7e2224"
 dependencies = [
  "bitflags",
  "libc",
@@ -1669,9 +1693,9 @@ dependencies = [
 
 [[package]]
 name = "libgit2-sys"
-version = "0.12.9+1.0.1"
+version = "0.12.14+1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b33bf3d9d4c45b48ae1ea7c334be69994624dc0a69f833d5d9f7605f24b552b"
+checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549"
 dependencies = [
  "cc",
  "libc",
@@ -1693,9 +1717,9 @@ dependencies = [
 
 [[package]]
 name = "libssh2-sys"
-version = "0.2.18"
+version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eafa907407504b0e683786d4aba47acf250f114d37357d56608333fd167dd0fc"
+checksum = "ca46220853ba1c512fc82826d0834d87b06bcd3c2a42241b7de72f3d2fe17056"
 dependencies = [
  "cc",
  "libc",
@@ -1760,7 +1784,7 @@ version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
 ]
 
 [[package]]
@@ -1990,7 +2014,7 @@ version = "0.6.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "fuchsia-zircon",
  "fuchsia-zircon-sys",
  "iovec",
@@ -2071,7 +2095,7 @@ version = "0.2.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "winapi 0.3.9",
 ]
@@ -2123,6 +2147,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "object"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37fd5004feb2ce328a52b0b3d01dbf4ffff72583493900ed15f22d4111c51693"
+
+[[package]]
 name = "once_cell"
 version = "1.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2165,7 +2195,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4"
 dependencies = [
  "bitflags",
- "cfg-if",
+ "cfg-if 0.1.10",
  "foreign-types",
  "lazy_static",
  "libc",
@@ -2180,9 +2210,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
 
 [[package]]
 name = "openssl-src"
-version = "111.10.2+1.1.1g"
+version = "111.12.0+1.1.1h"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a287fdb22e32b5b60624d4a5a7a02dbe82777f730ec0dbc42a0554326fef5a70"
+checksum = "858a4132194f8570a7ee9eb8629e85b23cbc4565f2d4a162e87556e5956abf61"
 dependencies = [
  "cc",
 ]
@@ -2222,14 +2252,14 @@ version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
 ]
 
 [[package]]
 name = "panic_abort"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "libc",
@@ -2240,7 +2270,7 @@ name = "panic_unwind"
 version = "0.0.0"
 dependencies = [
  "alloc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "libc",
@@ -2303,7 +2333,7 @@ version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "cloudabi 0.0.3",
  "libc",
  "redox_syscall",
@@ -2318,7 +2348,7 @@ version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "cloudabi 0.0.3",
  "libc",
  "redox_syscall",
@@ -2332,7 +2362,7 @@ version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "cloudabi 0.1.0",
  "instant",
  "libc",
@@ -3036,7 +3066,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "14ffd17a37e00d77926a0713f191c59ff3aeb2b551a024c7cfffce14bab79be8"
 dependencies = [
  "bitflags",
- "cfg-if",
+ "cfg-if 0.1.10",
  "crossbeam-utils 0.7.2",
  "ena",
  "indexmap",
@@ -3212,7 +3242,7 @@ version = "679.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1c267f15c3cfc82a8a441d2bf86bcccf299d1eb625822468e3d8ee6f7c5a1c89"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "md-5",
  "rustc-ap-rustc_arena",
  "rustc-ap-rustc_data_structures",
@@ -3338,7 +3368,6 @@ dependencies = [
 name = "rustc_arena"
 version = "0.0.0"
 dependencies = [
- "rustc_data_structures",
  "smallvec 1.4.2",
 ]
 
@@ -3505,7 +3534,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "bitflags",
- "cfg-if",
+ "cfg-if 0.1.10",
  "crossbeam-utils 0.7.2",
  "ena",
  "indexmap",
@@ -4056,7 +4085,7 @@ dependencies = [
 name = "rustc_span"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "md-5",
  "rustc_arena",
  "rustc_data_structures",
@@ -4417,7 +4446,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1"
 dependencies = [
  "block-buffer 0.9.0",
- "cfg-if",
+ "cfg-if 0.1.10",
  "cpuid-bool",
  "digest 0.9.0",
  "opaque-debug 0.3.0",
@@ -4503,7 +4532,7 @@ version = "0.3.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "redox_syscall",
  "winapi 0.3.9",
@@ -4522,7 +4551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "21ccb4c06ec57bc82d0f610f1a2963d7648700e43a6f513e564b9c89f7991786"
 dependencies = [
  "cc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "psm",
  "winapi 0.3.9",
@@ -4534,7 +4563,7 @@ version = "0.0.0"
 dependencies = [
  "addr2line",
  "alloc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "dlmalloc",
@@ -4543,7 +4572,7 @@ dependencies = [
  "hermit-abi",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.20.0",
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
@@ -4676,7 +4705,7 @@ version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "libc",
  "rand",
  "redox_syscall",
@@ -4736,7 +4765,7 @@ dependencies = [
 name = "test"
 version = "0.0.0"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "core",
  "getopts",
  "libc",
@@ -5068,9 +5097,9 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.5.6"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"
+checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645"
 dependencies = [
  "serde",
 ]
@@ -5081,7 +5110,7 @@ version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c"
 dependencies = [
- "cfg-if",
+ "cfg-if 0.1.10",
  "tracing-attributes",
  "tracing-core",
 ]
@@ -5099,9 +5128,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-core"
-version = "0.1.15"
+version = "0.1.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f0e00789804e99b20f12bc7003ca416309d28a6f495d6af58d1e2c2842461b5"
+checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f"
 dependencies = [
  "lazy_static",
 ]
@@ -5129,9 +5158,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-subscriber"
-version = "0.2.11"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "abd165311cc4d7a555ad11cc77a37756df836182db0d81aac908c8184c584f40"
+checksum = "4ef0a5e15477aa303afbfac3a44cba9b6430fdaad52423b1e6c0dbbe28c3eedd"
 dependencies = [
  "ansi_term 0.12.1",
  "chrono",
@@ -5144,6 +5173,7 @@ dependencies = [
  "sharded-slab",
  "smallvec 1.4.2",
  "thread_local",
+ "tracing",
  "tracing-core",
  "tracing-log",
  "tracing-serde",
@@ -5277,7 +5307,7 @@ name = "unwind"
 version = "0.0.0"
 dependencies = [
  "cc",
- "cfg-if",
+ "cfg-if 0.1.10",
  "compiler_builtins",
  "core",
  "libc",
diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml
index 41701f3255f..29caa852ed4 100644
--- a/compiler/rustc_arena/Cargo.toml
+++ b/compiler/rustc_arena/Cargo.toml
@@ -5,5 +5,4 @@ version = "0.0.0"
 edition = "2018"
 
 [dependencies]
-rustc_data_structures = { path = "../rustc_data_structures" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 166f7f53c41..c051c607ff2 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -16,7 +16,6 @@
 #![feature(maybe_uninit_slice)]
 #![cfg_attr(test, feature(test))]
 
-use rustc_data_structures::cold_path;
 use smallvec::SmallVec;
 
 use std::alloc::Layout;
@@ -27,6 +26,12 @@ use std::mem::{self, MaybeUninit};
 use std::ptr;
 use std::slice;
 
+#[inline(never)]
+#[cold]
+pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
+    f()
+}
+
 /// An arena that can hold objects of only one type.
 pub struct TypedArena<T> {
     /// A pointer to the next object to be allocated.
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 492d5788fc0..8f156aea2ff 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -27,6 +27,7 @@ use crate::token::{self, CommentKind, DelimToken};
 use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_macros::HashStable_Generic;
@@ -166,13 +167,6 @@ pub enum GenericArgs {
 }
 
 impl GenericArgs {
-    pub fn is_parenthesized(&self) -> bool {
-        match *self {
-            Parenthesized(..) => true,
-            _ => false,
-        }
-    }
-
     pub fn is_angle_bracketed(&self) -> bool {
         match *self {
             AngleBracketed(..) => true,
@@ -856,13 +850,6 @@ impl BinOpKind {
         }
     }
 
-    pub fn is_shift(&self) -> bool {
-        match *self {
-            BinOpKind::Shl | BinOpKind::Shr => true,
-            _ => false,
-        }
-    }
-
     pub fn is_comparison(&self) -> bool {
         use BinOpKind::*;
         // Note for developers: please keep this as is;
@@ -872,11 +859,6 @@ impl BinOpKind {
             And | Or | Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr => false,
         }
     }
-
-    /// Returns `true` if the binary operator takes its arguments by value
-    pub fn is_by_value(&self) -> bool {
-        !self.is_comparison()
-    }
 }
 
 pub type BinOp = Spanned<BinOpKind>;
@@ -895,14 +877,6 @@ pub enum UnOp {
 }
 
 impl UnOp {
-    /// Returns `true` if the unary operator takes its argument by value
-    pub fn is_by_value(u: UnOp) -> bool {
-        match u {
-            UnOp::Neg | UnOp::Not => true,
-            _ => false,
-        }
-    }
-
     pub fn to_string(op: UnOp) -> &'static str {
         match op {
             UnOp::Deref => "*",
@@ -1752,13 +1726,6 @@ impl IntTy {
         }
     }
 
-    pub fn val_to_string(&self, val: i128) -> String {
-        // Cast to a `u128` so we can correctly print `INT128_MIN`. All integral types
-        // are parsed as `u128`, so we wouldn't want to print an extra negative
-        // sign.
-        format!("{}{}", val as u128, self.name_str())
-    }
-
     pub fn bit_width(&self) -> Option<u64> {
         Some(match *self {
             IntTy::Isize => return None,
@@ -1817,10 +1784,6 @@ impl UintTy {
         }
     }
 
-    pub fn val_to_string(&self, val: u128) -> String {
-        format!("{}{}", val, self.name_str())
-    }
-
     pub fn bit_width(&self) -> Option<u64> {
         Some(match *self {
             UintTy::Usize => return None,
@@ -1864,7 +1827,7 @@ pub enum AssocTyConstraintKind {
     Bound { bounds: GenericBounds },
 }
 
-#[derive(Clone, Encodable, Decodable, Debug)]
+#[derive(Encodable, Decodable, Debug)]
 pub struct Ty {
     pub id: NodeId,
     pub kind: TyKind,
@@ -1872,6 +1835,27 @@ pub struct Ty {
     pub tokens: Option<TokenStream>,
 }
 
+impl Clone for Ty {
+    fn clone(&self) -> Self {
+        ensure_sufficient_stack(|| Self {
+            id: self.id,
+            kind: self.kind.clone(),
+            span: self.span,
+            tokens: self.tokens.clone(),
+        })
+    }
+}
+
+impl Ty {
+    pub fn peel_refs(&self) -> &Self {
+        let mut final_ty = self;
+        while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind {
+            final_ty = &ty;
+        }
+        final_ty
+    }
+}
+
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct BareFnTy {
     pub unsafety: Unsafe,
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 2782869fb88..8351be222f6 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -101,11 +101,6 @@ impl NestedMetaItem {
         self.meta_item().is_some()
     }
 
-    /// Returns `true` if the variant is `Literal`.
-    pub fn is_literal(&self) -> bool {
-        self.literal().is_some()
-    }
-
     /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
     pub fn is_word(&self) -> bool {
         self.meta_item().map_or(false, |meta_item| meta_item.is_word())
@@ -232,10 +227,6 @@ impl MetaItem {
     pub fn is_value_str(&self) -> bool {
         self.value_str().is_some()
     }
-
-    pub fn is_meta_item_list(&self) -> bool {
-        self.meta_item_list().is_some()
-    }
 }
 
 impl AttrItem {
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index d5b3e87adc3..ad9c7391939 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -54,16 +54,6 @@ pub enum DelimToken {
     NoDelim,
 }
 
-impl DelimToken {
-    pub fn len(self) -> usize {
-        if self == NoDelim { 0 } else { 1 }
-    }
-
-    pub fn is_empty(self) -> bool {
-        self == NoDelim
-    }
-}
-
 #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum LitKind {
     Bool, // AST only, must never appear in a `Token`
@@ -810,10 +800,10 @@ impl Nonterminal {
             if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind {
                 let filename = source_map.span_to_filename(orig_span);
                 if let FileName::Real(RealFileName::Named(path)) = filename {
-                    let matches_prefix = |prefix| {
-                        // Check for a path that ends with 'prefix*/src/lib.rs'
+                    let matches_prefix = |prefix, filename| {
+                        // Check for a path that ends with 'prefix*/src/<filename>'
                         let mut iter = path.components().rev();
-                        iter.next().and_then(|p| p.as_os_str().to_str()) == Some("lib.rs")
+                        iter.next().and_then(|p| p.as_os_str().to_str()) == Some(filename)
                             && iter.next().and_then(|p| p.as_os_str().to_str()) == Some("src")
                             && iter
                                 .next()
@@ -821,14 +811,25 @@ impl Nonterminal {
                                 .map_or(false, |p| p.starts_with(prefix))
                     };
 
-                    if (macro_name == sym::impl_macros && matches_prefix("time-macros-impl"))
-                        || (macro_name == sym::arrays && matches_prefix("js-sys"))
+                    if (macro_name == sym::impl_macros
+                        && matches_prefix("time-macros-impl", "lib.rs"))
+                        || (macro_name == sym::arrays && matches_prefix("js-sys", "lib.rs"))
                     {
                         let snippet = source_map.span_to_snippet(orig_span);
                         if snippet.as_deref() == Ok("$name") {
                             return Some((*ident, *is_raw));
                         }
                     }
+
+                    if macro_name == sym::tuple_from_req
+                        && (matches_prefix("actix-web", "extract.rs")
+                            || matches_prefix("actori-web", "extract.rs"))
+                    {
+                        let snippet = source_map.span_to_snippet(orig_span);
+                        if snippet.as_deref() == Ok("$T") {
+                            return Some((*ident, *is_raw));
+                        }
+                    }
                 }
             }
         }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index f201f0b5c66..8acb6b2f375 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -295,12 +295,6 @@ impl TokenStream {
                 .collect(),
         ))
     }
-
-    pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
-        TokenStream(Lrc::new(
-            self.0.iter().map(|(tree, is_joint)| (f(tree.clone()), *is_joint)).collect(),
-        ))
-    }
 }
 
 // 99.5%+ of the time we have 1 or 2 elements in this vector.
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 2ee94965756..be5516ef471 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -231,7 +231,6 @@ impl AssocOp {
     }
 }
 
-pub const PREC_RESET: i8 = -100;
 pub const PREC_CLOSURE: i8 = -40;
 pub const PREC_JUMP: i8 = -30;
 pub const PREC_RANGE: i8 = -10;
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 4676ad5c31f..2d2caa7a808 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -985,7 +985,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             asm::InlineAsmReg::parse(
                                 sess.asm_arch?,
                                 |feature| sess.target_features.contains(&Symbol::intern(feature)),
-                                &sess.target.target,
+                                &sess.target,
                                 s,
                             )
                             .map_err(|e| {
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 232ee35c4f7..d9791fe743c 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -796,7 +796,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
     fn visit_expr(&mut self, expr: &'a Expr) {
         match &expr.kind {
-            ExprKind::LlvmInlineAsm(..) if !self.session.target.target.options.allow_asm => {
+            ExprKind::LlvmInlineAsm(..) if !self.session.target.options.allow_asm => {
                 struct_span_err!(
                     self.session,
                     expr.span,
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index ca7f127ced6..95f969d7691 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -170,17 +170,11 @@ pub enum Token {
 
 impl Token {
     crate fn is_eof(&self) -> bool {
-        match *self {
-            Token::Eof => true,
-            _ => false,
-        }
+        matches!(self, Token::Eof)
     }
 
     pub fn is_hardbreak_tok(&self) -> bool {
-        match *self {
-            Token::Break(BreakToken { offset: 0, blank_space: bs }) if bs == SIZE_INFINITY => true,
-            _ => false,
-        }
+        matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY }))
     }
 }
 
@@ -491,12 +485,9 @@ impl Printer {
     }
 
     fn get_top(&mut self) -> PrintStackElem {
-        match self.print_stack.last() {
-            Some(el) => *el,
-            None => {
-                PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) }
-            }
-        }
+        *self.print_stack.last().unwrap_or({
+            &PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) }
+        })
     }
 
     fn print_begin(&mut self, b: BeginToken, l: isize) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs
new file mode 100644
index 00000000000..b34ea41ab55
--- /dev/null
+++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs
@@ -0,0 +1,104 @@
+#[cfg(test)]
+mod tests;
+
+pub mod state;
+pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State};
+
+use rustc_ast as ast;
+use rustc_ast::token::{Nonterminal, Token, TokenKind};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
+
+pub fn nonterminal_to_string_no_extra_parens(nt: &Nonterminal) -> String {
+    let state = State::without_insert_extra_parens();
+    state.nonterminal_to_string(nt)
+}
+
+pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
+    State::new().nonterminal_to_string(nt)
+}
+
+/// Print the token kind precisely, without converting `$crate` into its respective crate name.
+pub fn token_kind_to_string(tok: &TokenKind) -> String {
+    State::new().token_kind_to_string(tok)
+}
+
+/// Print the token precisely, without converting `$crate` into its respective crate name.
+pub fn token_to_string(token: &Token) -> String {
+    State::new().token_to_string(token)
+}
+
+pub fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String {
+    State::new().token_to_string_ext(token, convert_dollar_crate)
+}
+
+pub fn ty_to_string(ty: &ast::Ty) -> String {
+    State::new().ty_to_string(ty)
+}
+
+pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String {
+    State::new().bounds_to_string(bounds)
+}
+
+pub fn pat_to_string(pat: &ast::Pat) -> String {
+    State::new().pat_to_string(pat)
+}
+
+pub fn expr_to_string(e: &ast::Expr) -> String {
+    State::new().expr_to_string(e)
+}
+
+pub fn tt_to_string(tt: &TokenTree) -> String {
+    State::new().tt_to_string(tt)
+}
+
+pub fn tts_to_string(tokens: &TokenStream) -> String {
+    State::new().tts_to_string(tokens)
+}
+
+pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
+    State::new().stmt_to_string(stmt)
+}
+
+pub fn item_to_string(i: &ast::Item) -> String {
+    State::new().item_to_string(i)
+}
+
+pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String {
+    State::new().generic_params_to_string(generic_params)
+}
+
+pub fn path_to_string(p: &ast::Path) -> String {
+    State::new().path_to_string(p)
+}
+
+pub fn path_segment_to_string(p: &ast::PathSegment) -> String {
+    State::new().path_segment_to_string(p)
+}
+
+pub fn vis_to_string(v: &ast::Visibility) -> String {
+    State::new().vis_to_string(v)
+}
+
+pub fn block_to_string(blk: &ast::Block) -> String {
+    State::new().block_to_string(blk)
+}
+
+pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String {
+    State::new().meta_list_item_to_string(li)
+}
+
+pub fn attr_item_to_string(ai: &ast::AttrItem) -> String {
+    State::new().attr_item_to_string(ai)
+}
+
+pub fn attribute_to_string(attr: &ast::Attribute) -> String {
+    State::new().attribute_to_string(attr)
+}
+
+pub fn param_to_string(arg: &ast::Param) -> String {
+    State::new().param_to_string(arg)
+}
+
+pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
+    State::new().to_string(f)
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index d16b541c699..9aa066370bb 100644
--- a/compiler/rustc_ast_pretty/src/pprust.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -20,9 +20,6 @@ use rustc_span::{BytePos, FileName, Span};
 
 use std::borrow::Cow;
 
-#[cfg(test)]
-mod tests;
-
 pub enum MacHeader<'a> {
     Path(&'a ast::Path),
     Keyword(&'static str),
@@ -91,6 +88,13 @@ pub struct State<'a> {
     comments: Option<Comments<'a>>,
     ann: &'a (dyn PpAnn + 'a),
     is_expanded: bool,
+    // If `true`, additional parenthesis (separate from `ExprKind::Paren`)
+    // are inserted to ensure that proper precedence is preserved
+    // in the pretty-printed output.
+    //
+    // This is usually `true`, except when performing the pretty-print/reparse
+    // check in `nt_to_tokenstream`
+    insert_extra_parens: bool,
 }
 
 crate const INDENT_UNIT: usize = 4;
@@ -112,6 +116,7 @@ pub fn print_crate<'a>(
         comments: Some(Comments::new(sm, filename, input)),
         ann,
         is_expanded,
+        insert_extra_parens: true,
     };
 
     if is_expanded && has_injected_crate {
@@ -142,13 +147,6 @@ pub fn print_crate<'a>(
     s.s.eof()
 }
 
-pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
-    let mut printer =
-        State { s: pp::mk_printer(), comments: None, ann: &NoAnn, is_expanded: false };
-    f(&mut printer);
-    printer.s.eof()
-}
-
 // This makes printed token streams look slightly nicer,
 // and also addresses some specific regressions described in #63896 and #73345.
 fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
@@ -231,173 +229,8 @@ pub fn literal_to_string(lit: token::Lit) -> String {
     out
 }
 
-/// Print the token kind precisely, without converting `$crate` into its respective crate name.
-pub fn token_kind_to_string(tok: &TokenKind) -> String {
-    token_kind_to_string_ext(tok, None)
-}
-
-fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>) -> String {
-    match *tok {
-        token::Eq => "=".to_string(),
-        token::Lt => "<".to_string(),
-        token::Le => "<=".to_string(),
-        token::EqEq => "==".to_string(),
-        token::Ne => "!=".to_string(),
-        token::Ge => ">=".to_string(),
-        token::Gt => ">".to_string(),
-        token::Not => "!".to_string(),
-        token::Tilde => "~".to_string(),
-        token::OrOr => "||".to_string(),
-        token::AndAnd => "&&".to_string(),
-        token::BinOp(op) => binop_to_string(op).to_string(),
-        token::BinOpEq(op) => format!("{}=", binop_to_string(op)),
-
-        /* Structural symbols */
-        token::At => "@".to_string(),
-        token::Dot => ".".to_string(),
-        token::DotDot => "..".to_string(),
-        token::DotDotDot => "...".to_string(),
-        token::DotDotEq => "..=".to_string(),
-        token::Comma => ",".to_string(),
-        token::Semi => ";".to_string(),
-        token::Colon => ":".to_string(),
-        token::ModSep => "::".to_string(),
-        token::RArrow => "->".to_string(),
-        token::LArrow => "<-".to_string(),
-        token::FatArrow => "=>".to_string(),
-        token::OpenDelim(token::Paren) => "(".to_string(),
-        token::CloseDelim(token::Paren) => ")".to_string(),
-        token::OpenDelim(token::Bracket) => "[".to_string(),
-        token::CloseDelim(token::Bracket) => "]".to_string(),
-        token::OpenDelim(token::Brace) => "{".to_string(),
-        token::CloseDelim(token::Brace) => "}".to_string(),
-        token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".to_string(),
-        token::Pound => "#".to_string(),
-        token::Dollar => "$".to_string(),
-        token::Question => "?".to_string(),
-        token::SingleQuote => "'".to_string(),
-
-        /* Literals */
-        token::Literal(lit) => literal_to_string(lit),
-
-        /* Name components */
-        token::Ident(s, is_raw) => IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string(),
-        token::Lifetime(s) => s.to_string(),
-
-        /* Other */
-        token::DocComment(comment_kind, attr_style, data) => {
-            doc_comment_to_string(comment_kind, attr_style, data)
-        }
-        token::Eof => "<eof>".to_string(),
-
-        token::Interpolated(ref nt) => nonterminal_to_string(nt),
-    }
-}
-
-/// Print the token precisely, without converting `$crate` into its respective crate name.
-pub fn token_to_string(token: &Token) -> String {
-    token_to_string_ext(token, false)
-}
-
-fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String {
-    let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
-    token_kind_to_string_ext(&token.kind, convert_dollar_crate)
-}
-
-pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
-    match *nt {
-        token::NtExpr(ref e) => expr_to_string(e),
-        token::NtMeta(ref e) => attr_item_to_string(e),
-        token::NtTy(ref e) => ty_to_string(e),
-        token::NtPath(ref e) => path_to_string(e),
-        token::NtItem(ref e) => item_to_string(e),
-        token::NtBlock(ref e) => block_to_string(e),
-        token::NtStmt(ref e) => stmt_to_string(e),
-        token::NtPat(ref e) => pat_to_string(e),
-        token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(),
-        token::NtLifetime(e) => e.to_string(),
-        token::NtLiteral(ref e) => expr_to_string(e),
-        token::NtTT(ref tree) => tt_to_string(tree),
-        token::NtVis(ref e) => vis_to_string(e),
-    }
-}
-
-pub fn ty_to_string(ty: &ast::Ty) -> String {
-    to_string(|s| s.print_type(ty))
-}
-
-pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String {
-    to_string(|s| s.print_type_bounds("", bounds))
-}
-
-pub fn pat_to_string(pat: &ast::Pat) -> String {
-    to_string(|s| s.print_pat(pat))
-}
-
-pub fn expr_to_string(e: &ast::Expr) -> String {
-    to_string(|s| s.print_expr(e))
-}
-
-pub fn tt_to_string(tt: &TokenTree) -> String {
-    to_string(|s| s.print_tt(tt, false))
-}
-
-pub fn tts_to_string(tokens: &TokenStream) -> String {
-    to_string(|s| s.print_tts(tokens, false))
-}
-
-pub fn stmt_to_string(stmt: &ast::Stmt) -> String {
-    to_string(|s| s.print_stmt(stmt))
-}
-
-pub fn item_to_string(i: &ast::Item) -> String {
-    to_string(|s| s.print_item(i))
-}
-
-pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String {
-    to_string(|s| s.print_generic_params(generic_params))
-}
-
-pub fn path_to_string(p: &ast::Path) -> String {
-    to_string(|s| s.print_path(p, false, 0))
-}
-
-pub fn path_segment_to_string(p: &ast::PathSegment) -> String {
-    to_string(|s| s.print_path_segment(p, false))
-}
-
-pub fn vis_to_string(v: &ast::Visibility) -> String {
-    to_string(|s| s.print_visibility(v))
-}
-
-fn block_to_string(blk: &ast::Block) -> String {
-    to_string(|s| {
-        // Containing cbox, will be closed by `print_block` at `}`.
-        s.cbox(INDENT_UNIT);
-        // Head-ibox, will be closed by `print_block` after `{`.
-        s.ibox(0);
-        s.print_block(blk)
-    })
-}
-
-pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String {
-    to_string(|s| s.print_meta_list_item(li))
-}
-
-fn attr_item_to_string(ai: &ast::AttrItem) -> String {
-    to_string(|s| s.print_attr_item(ai, ai.path.span))
-}
-
-pub fn attribute_to_string(attr: &ast::Attribute) -> String {
-    to_string(|s| s.print_attribute(attr))
-}
-
-pub fn param_to_string(arg: &ast::Param) -> String {
-    to_string(|s| s.print_param(arg, false))
-}
-
 fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
-    format!("{}{}", to_string(|s| s.print_visibility(vis)), s)
+    format!("{}{}", State::new().to_string(|s| s.print_visibility(vis)), s)
 }
 
 impl std::ops::Deref for State<'_> {
@@ -414,6 +247,7 @@ impl std::ops::DerefMut for State<'_> {
 }
 
 pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
+    fn insert_extra_parens(&self) -> bool;
     fn comments(&mut self) -> &mut Option<Comments<'a>>;
     fn print_ident(&mut self, ident: Ident);
     fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
@@ -679,7 +513,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
     fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) {
         match tt {
             TokenTree::Token(token) => {
-                self.word(token_to_string_ext(&token, convert_dollar_crate));
+                let token_str = self.token_to_string_ext(&token, convert_dollar_crate);
+                self.word(token_str);
                 if let token::DocComment(..) = token.kind {
                     self.hardbreak()
                 }
@@ -745,14 +580,20 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
                     self.space();
                 }
             }
-            _ => self.word(token_kind_to_string(&token::OpenDelim(delim))),
+            _ => {
+                let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
+                self.word(token_str)
+            }
         }
         self.ibox(0);
         self.print_tts(tts, convert_dollar_crate);
         self.end();
         match delim {
             DelimToken::Brace => self.bclose(span),
-            _ => self.word(token_kind_to_string(&token::CloseDelim(delim))),
+            _ => {
+                let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
+                self.word(token_str)
+            }
         }
     }
 
@@ -818,9 +659,190 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
             }
         }
     }
+
+    fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
+        match *nt {
+            token::NtExpr(ref e) => self.expr_to_string(e),
+            token::NtMeta(ref e) => self.attr_item_to_string(e),
+            token::NtTy(ref e) => self.ty_to_string(e),
+            token::NtPath(ref e) => self.path_to_string(e),
+            token::NtItem(ref e) => self.item_to_string(e),
+            token::NtBlock(ref e) => self.block_to_string(e),
+            token::NtStmt(ref e) => self.stmt_to_string(e),
+            token::NtPat(ref e) => self.pat_to_string(e),
+            token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(),
+            token::NtLifetime(e) => e.to_string(),
+            token::NtLiteral(ref e) => self.expr_to_string(e),
+            token::NtTT(ref tree) => self.tt_to_string(tree),
+            token::NtVis(ref e) => self.vis_to_string(e),
+        }
+    }
+
+    /// Print the token kind precisely, without converting `$crate` into its respective crate name.
+    fn token_kind_to_string(&self, tok: &TokenKind) -> String {
+        self.token_kind_to_string_ext(tok, None)
+    }
+
+    fn token_kind_to_string_ext(
+        &self,
+        tok: &TokenKind,
+        convert_dollar_crate: Option<Span>,
+    ) -> String {
+        match *tok {
+            token::Eq => "=".to_string(),
+            token::Lt => "<".to_string(),
+            token::Le => "<=".to_string(),
+            token::EqEq => "==".to_string(),
+            token::Ne => "!=".to_string(),
+            token::Ge => ">=".to_string(),
+            token::Gt => ">".to_string(),
+            token::Not => "!".to_string(),
+            token::Tilde => "~".to_string(),
+            token::OrOr => "||".to_string(),
+            token::AndAnd => "&&".to_string(),
+            token::BinOp(op) => binop_to_string(op).to_string(),
+            token::BinOpEq(op) => format!("{}=", binop_to_string(op)),
+
+            /* Structural symbols */
+            token::At => "@".to_string(),
+            token::Dot => ".".to_string(),
+            token::DotDot => "..".to_string(),
+            token::DotDotDot => "...".to_string(),
+            token::DotDotEq => "..=".to_string(),
+            token::Comma => ",".to_string(),
+            token::Semi => ";".to_string(),
+            token::Colon => ":".to_string(),
+            token::ModSep => "::".to_string(),
+            token::RArrow => "->".to_string(),
+            token::LArrow => "<-".to_string(),
+            token::FatArrow => "=>".to_string(),
+            token::OpenDelim(token::Paren) => "(".to_string(),
+            token::CloseDelim(token::Paren) => ")".to_string(),
+            token::OpenDelim(token::Bracket) => "[".to_string(),
+            token::CloseDelim(token::Bracket) => "]".to_string(),
+            token::OpenDelim(token::Brace) => "{".to_string(),
+            token::CloseDelim(token::Brace) => "}".to_string(),
+            token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".to_string(),
+            token::Pound => "#".to_string(),
+            token::Dollar => "$".to_string(),
+            token::Question => "?".to_string(),
+            token::SingleQuote => "'".to_string(),
+
+            /* Literals */
+            token::Literal(lit) => literal_to_string(lit),
+
+            /* Name components */
+            token::Ident(s, is_raw) => {
+                IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string()
+            }
+            token::Lifetime(s) => s.to_string(),
+
+            /* Other */
+            token::DocComment(comment_kind, attr_style, data) => {
+                doc_comment_to_string(comment_kind, attr_style, data)
+            }
+            token::Eof => "<eof>".to_string(),
+
+            token::Interpolated(ref nt) => self.nonterminal_to_string(nt),
+        }
+    }
+
+    /// Print the token precisely, without converting `$crate` into its respective crate name.
+    fn token_to_string(&self, token: &Token) -> String {
+        self.token_to_string_ext(token, false)
+    }
+
+    fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> String {
+        let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
+        self.token_kind_to_string_ext(&token.kind, convert_dollar_crate)
+    }
+
+    fn ty_to_string(&self, ty: &ast::Ty) -> String {
+        self.to_string(|s| s.print_type(ty))
+    }
+
+    fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
+        self.to_string(|s| s.print_type_bounds("", bounds))
+    }
+
+    fn pat_to_string(&self, pat: &ast::Pat) -> String {
+        self.to_string(|s| s.print_pat(pat))
+    }
+
+    fn expr_to_string(&self, e: &ast::Expr) -> String {
+        self.to_string(|s| s.print_expr(e))
+    }
+
+    fn tt_to_string(&self, tt: &TokenTree) -> String {
+        self.to_string(|s| s.print_tt(tt, false))
+    }
+
+    fn tts_to_string(&self, tokens: &TokenStream) -> String {
+        self.to_string(|s| s.print_tts(tokens, false))
+    }
+
+    fn stmt_to_string(&self, stmt: &ast::Stmt) -> String {
+        self.to_string(|s| s.print_stmt(stmt))
+    }
+
+    fn item_to_string(&self, i: &ast::Item) -> String {
+        self.to_string(|s| s.print_item(i))
+    }
+
+    fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String {
+        self.to_string(|s| s.print_generic_params(generic_params))
+    }
+
+    fn path_to_string(&self, p: &ast::Path) -> String {
+        self.to_string(|s| s.print_path(p, false, 0))
+    }
+
+    fn path_segment_to_string(&self, p: &ast::PathSegment) -> String {
+        self.to_string(|s| s.print_path_segment(p, false))
+    }
+
+    fn vis_to_string(&self, v: &ast::Visibility) -> String {
+        self.to_string(|s| s.print_visibility(v))
+    }
+
+    fn block_to_string(&self, blk: &ast::Block) -> String {
+        self.to_string(|s| {
+            // Containing cbox, will be closed by `print_block` at `}`.
+            s.cbox(INDENT_UNIT);
+            // Head-ibox, will be closed by `print_block` after `{`.
+            s.ibox(0);
+            s.print_block(blk)
+        })
+    }
+
+    fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String {
+        self.to_string(|s| s.print_meta_list_item(li))
+    }
+
+    fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String {
+        self.to_string(|s| s.print_attr_item(ai, ai.path.span))
+    }
+
+    fn attribute_to_string(&self, attr: &ast::Attribute) -> String {
+        self.to_string(|s| s.print_attribute(attr))
+    }
+
+    fn param_to_string(&self, arg: &ast::Param) -> String {
+        self.to_string(|s| s.print_param(arg, false))
+    }
+
+    fn to_string(&self, f: impl FnOnce(&mut State<'_>)) -> String {
+        let mut printer = State::new();
+        printer.insert_extra_parens = self.insert_extra_parens();
+        f(&mut printer);
+        printer.s.eof()
+    }
 }
 
 impl<'a> PrintState<'a> for State<'a> {
+    fn insert_extra_parens(&self) -> bool {
+        self.insert_extra_parens
+    }
     fn comments(&mut self) -> &mut Option<Comments<'a>> {
         &mut self.comments
     }
@@ -856,6 +878,20 @@ impl<'a> PrintState<'a> for State<'a> {
 }
 
 impl<'a> State<'a> {
+    pub fn new() -> State<'a> {
+        State {
+            s: pp::mk_printer(),
+            comments: None,
+            ann: &NoAnn,
+            is_expanded: false,
+            insert_extra_parens: true,
+        }
+    }
+
+    pub(super) fn without_insert_extra_parens() -> State<'a> {
+        State { insert_extra_parens: false, ..State::new() }
+    }
+
     // Synthesizes a comment that was not textually present in the original source
     // file.
     pub fn synth_comment(&mut self, text: String) {
@@ -1139,7 +1175,7 @@ impl<'a> State<'a> {
                 self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
             }
             ast::ItemKind::Mod(ref _mod) => {
-                self.head(to_string(|s| {
+                self.head(self.to_string(|s| {
                     s.print_visibility(&item.vis);
                     s.print_unsafety(_mod.unsafety);
                     s.word("mod");
@@ -1158,7 +1194,7 @@ impl<'a> State<'a> {
                 }
             }
             ast::ItemKind::ForeignMod(ref nmod) => {
-                self.head(to_string(|s| {
+                self.head(self.to_string(|s| {
                     s.print_unsafety(nmod.unsafety);
                     s.word("extern");
                 }));
@@ -1366,7 +1402,7 @@ impl<'a> State<'a> {
                 ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
             },
             ast::VisibilityKind::Restricted { ref path, .. } => {
-                let path = to_string(|s| s.print_path(path, false, 0));
+                let path = self.to_string(|s| s.print_path(path, false, 0));
                 if path == "self" || path == "super" {
                     self.word_nbsp(format!("pub({})", path))
                 } else {
@@ -1658,7 +1694,8 @@ impl<'a> State<'a> {
     }
 
     /// Prints `expr` or `(expr)` when `needs_par` holds.
-    fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
+    fn print_expr_cond_paren(&mut self, expr: &ast::Expr, mut needs_par: bool) {
+        needs_par &= self.insert_extra_parens;
         if needs_par {
             self.popen();
         }
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 94e2a40e1fe..9c309345000 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -76,6 +76,12 @@ pub enum InlineAttr {
 }
 
 #[derive(Clone, Encodable, Decodable)]
+pub enum InstructionSetAttr {
+    ArmA32,
+    ArmT32,
+}
+
+#[derive(Clone, Encodable, Decodable)]
 pub enum OptimizeAttr {
     None,
     Speed,
@@ -148,7 +154,7 @@ pub struct ConstStability {
 }
 
 /// The available stability levels.
-#[derive(Encodable, Decodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
+#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
 #[derive(HashStable_Generic)]
 pub enum StabilityLevel {
     // Reason for the current stability level and the relevant rust-lang issue
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 09985959b67..36cd6c281b4 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -81,7 +81,7 @@ fn parse_args<'a>(
         } // accept trailing commas
 
         // Parse options
-        if p.eat(&token::Ident(sym::options, false)) {
+        if p.eat_keyword(sym::options) {
             parse_options(&mut p, &mut args)?;
             allow_templates = false;
             continue;
@@ -101,19 +101,19 @@ fn parse_args<'a>(
         };
 
         let mut explicit_reg = false;
-        let op = if p.eat(&token::Ident(kw::In, false)) {
+        let op = if p.eat_keyword(kw::In) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::In { reg, expr }
-        } else if p.eat(&token::Ident(sym::out, false)) {
+        } else if p.eat_keyword(sym::out) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: false }
-        } else if p.eat(&token::Ident(sym::lateout, false)) {
+        } else if p.eat_keyword(sym::lateout) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
             let expr = if p.eat_keyword(kw::Underscore) { None } else { Some(p.parse_expr()?) };
             ast::InlineAsmOperand::Out { reg, expr, late: true }
-        } else if p.eat(&token::Ident(sym::inout, false)) {
+        } else if p.eat_keyword(sym::inout) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
             let expr = p.parse_expr()?;
             if p.eat(&token::FatArrow) {
@@ -123,7 +123,7 @@ fn parse_args<'a>(
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: false }
             }
-        } else if p.eat(&token::Ident(sym::inlateout, false)) {
+        } else if p.eat_keyword(sym::inlateout) {
             let reg = parse_reg(&mut p, &mut explicit_reg)?;
             let expr = p.parse_expr()?;
             if p.eat(&token::FatArrow) {
@@ -133,10 +133,10 @@ fn parse_args<'a>(
             } else {
                 ast::InlineAsmOperand::InOut { reg, expr, late: true }
             }
-        } else if p.eat(&token::Ident(kw::Const, false)) {
+        } else if p.eat_keyword(kw::Const) {
             let expr = p.parse_expr()?;
             ast::InlineAsmOperand::Const { expr }
-        } else if p.eat(&token::Ident(sym::sym, false)) {
+        } else if p.eat_keyword(sym::sym) {
             let expr = p.parse_expr()?;
             match expr.kind {
                 ast::ExprKind::Path(..) => {}
@@ -164,7 +164,7 @@ fn parse_args<'a>(
             args.templates.push(template);
             continue;
         } else {
-            return Err(p.expect_one_of(&[], &[]).unwrap_err());
+            return p.unexpected();
         };
 
         allow_templates = false;
@@ -333,21 +333,22 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn
     p.expect(&token::OpenDelim(token::DelimToken::Paren))?;
 
     while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) {
-        if p.eat(&token::Ident(sym::pure, false)) {
+        if p.eat_keyword(sym::pure) {
             try_set_option(p, args, sym::pure, ast::InlineAsmOptions::PURE);
-        } else if p.eat(&token::Ident(sym::nomem, false)) {
+        } else if p.eat_keyword(sym::nomem) {
             try_set_option(p, args, sym::nomem, ast::InlineAsmOptions::NOMEM);
-        } else if p.eat(&token::Ident(sym::readonly, false)) {
+        } else if p.eat_keyword(sym::readonly) {
             try_set_option(p, args, sym::readonly, ast::InlineAsmOptions::READONLY);
-        } else if p.eat(&token::Ident(sym::preserves_flags, false)) {
+        } else if p.eat_keyword(sym::preserves_flags) {
             try_set_option(p, args, sym::preserves_flags, ast::InlineAsmOptions::PRESERVES_FLAGS);
-        } else if p.eat(&token::Ident(sym::noreturn, false)) {
+        } else if p.eat_keyword(sym::noreturn) {
             try_set_option(p, args, sym::noreturn, ast::InlineAsmOptions::NORETURN);
-        } else if p.eat(&token::Ident(sym::nostack, false)) {
+        } else if p.eat_keyword(sym::nostack) {
             try_set_option(p, args, sym::nostack, ast::InlineAsmOptions::NOSTACK);
-        } else {
-            p.expect(&token::Ident(sym::att_syntax, false))?;
+        } else if p.eat_keyword(sym::att_syntax) {
             try_set_option(p, args, sym::att_syntax, ast::InlineAsmOptions::ATT_SYNTAX);
+        } else {
+            return p.unexpected();
         }
 
         // Allow trailing commas
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index 25181715540..5bfd8a2bf56 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -120,8 +120,7 @@ fn parse_assert<'a>(
         };
 
     if parser.token != token::Eof {
-        parser.expect_one_of(&[], &[])?;
-        unreachable!();
+        return parser.unexpected();
     }
 
     Ok(Assert { cond_expr, custom_message })
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index f4924997d1a..2e52d2a3923 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -1137,12 +1137,9 @@ impl<'a> MethodDef<'a> {
     /// for each of the self-args, carried in precomputed variables.
 
     /// ```{.text}
-    /// let __self0_vi = unsafe {
-    ///     std::intrinsics::discriminant_value(&self) };
-    /// let __self1_vi = unsafe {
-    ///     std::intrinsics::discriminant_value(&arg1) };
-    /// let __self2_vi = unsafe {
-    ///     std::intrinsics::discriminant_value(&arg2) };
+    /// let __self0_vi = std::intrinsics::discriminant_value(&self);
+    /// let __self1_vi = std::intrinsics::discriminant_value(&arg1);
+    /// let __self2_vi = std::intrinsics::discriminant_value(&arg2);
     ///
     /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... {
     ///     match (...) {
@@ -1325,7 +1322,7 @@ impl<'a> MethodDef<'a> {
                 // Since we know that all the arguments will match if we reach
                 // the match expression we add the unreachable intrinsics as the
                 // result of the catch all which should help llvm in optimizing it
-                Some(deriving::call_intrinsic(cx, sp, sym::unreachable, vec![]))
+                Some(deriving::call_unreachable(cx, sp))
             }
             _ => None,
         };
@@ -1356,12 +1353,9 @@ impl<'a> MethodDef<'a> {
             // with three Self args, builds three statements:
             //
             // ```
-            // let __self0_vi = unsafe {
-            //     std::intrinsics::discriminant_value(&self) };
-            // let __self1_vi = unsafe {
-            //     std::intrinsics::discriminant_value(&arg1) };
-            // let __self2_vi = unsafe {
-            //     std::intrinsics::discriminant_value(&arg2) };
+            // let __self0_vi = std::intrinsics::discriminant_value(&self);
+            // let __self1_vi = std::intrinsics::discriminant_value(&arg1);
+            // let __self2_vi = std::intrinsics::discriminant_value(&arg2);
             // ```
             let mut index_let_stmts: Vec<ast::Stmt> = Vec::with_capacity(vi_idents.len() + 1);
 
@@ -1474,7 +1468,7 @@ impl<'a> MethodDef<'a> {
             // derive Debug on such a type could here generate code
             // that needs the feature gate enabled.)
 
-            deriving::call_intrinsic(cx, sp, sym::unreachable, vec![])
+            deriving::call_unreachable(cx, sp)
         } else {
             // Final wrinkle: the self_args are expressions that deref
             // down to desired places, but we cannot actually deref
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index 9c8e0fc2f01..bf950934928 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -68,7 +68,14 @@ fn call_intrinsic(
 ) -> P<ast::Expr> {
     let span = cx.with_def_site_ctxt(span);
     let path = cx.std_path(&[sym::intrinsics, intrinsic]);
-    let call = cx.expr_call_global(span, path, args);
+    cx.expr_call_global(span, path, args)
+}
+
+/// Constructs an expression that calls the `unreachable` intrinsic.
+fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
+    let span = cx.with_def_site_ctxt(span);
+    let path = cx.std_path(&[sym::intrinsics, sym::unreachable]);
+    let call = cx.expr_call_global(span, path, vec![]);
 
     cx.expr_block(P(ast::Block {
         stmts: vec![cx.stmt_expr(call)],
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index ff81b5eca13..b69b00d65f2 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -385,7 +385,7 @@ pub mod printf {
         if let Start = state {
             match c {
                 '1'..='9' => {
-                    let end = at_next_cp_while(next, is_digit);
+                    let end = at_next_cp_while(next, char::is_ascii_digit);
                     match end.next_cp() {
                         // Yes, this *is* the parameter.
                         Some(('$', end2)) => {
@@ -427,7 +427,7 @@ pub mod printf {
                     move_to!(next);
                 }
                 '1'..='9' => {
-                    let end = at_next_cp_while(next, is_digit);
+                    let end = at_next_cp_while(next, char::is_ascii_digit);
                     state = Prec;
                     width = Some(Num::from_str(at.slice_between(end).unwrap(), None));
                     move_to!(end);
@@ -441,7 +441,7 @@ pub mod printf {
         }
 
         if let WidthArg = state {
-            let end = at_next_cp_while(at, is_digit);
+            let end = at_next_cp_while(at, char::is_ascii_digit);
             match end.next_cp() {
                 Some(('$', end2)) => {
                     state = Prec;
@@ -473,7 +473,7 @@ pub mod printf {
         if let PrecInner = state {
             match c {
                 '*' => {
-                    let end = at_next_cp_while(next, is_digit);
+                    let end = at_next_cp_while(next, char::is_ascii_digit);
                     match end.next_cp() {
                         Some(('$', end2)) => {
                             state = Length;
@@ -488,7 +488,7 @@ pub mod printf {
                     }
                 }
                 '0'..='9' => {
-                    let end = at_next_cp_while(next, is_digit);
+                    let end = at_next_cp_while(next, char::is_ascii_digit);
                     state = Length;
                     precision = Some(Num::from_str(at.slice_between(end).unwrap(), None));
                     move_to!(end);
@@ -563,12 +563,12 @@ pub mod printf {
 
     fn at_next_cp_while<F>(mut cur: Cur<'_>, mut pred: F) -> Cur<'_>
     where
-        F: FnMut(char) -> bool,
+        F: FnMut(&char) -> bool,
     {
         loop {
             match cur.next_cp() {
                 Some((c, next)) => {
-                    if pred(c) {
+                    if pred(&c) {
                         cur = next;
                     } else {
                         return cur;
@@ -579,14 +579,7 @@ pub mod printf {
         }
     }
 
-    fn is_digit(c: char) -> bool {
-        match c {
-            '0'..='9' => true,
-            _ => false,
-        }
-    }
-
-    fn is_flag(c: char) -> bool {
+    fn is_flag(c: &char) -> bool {
         match c {
             '0' | '-' | '+' | ' ' | '#' | '\'' => true,
             _ => false,
@@ -723,17 +716,11 @@ pub mod shell {
     }
 
     fn is_ident_head(c: char) -> bool {
-        match c {
-            'a'..='z' | 'A'..='Z' | '_' => true,
-            _ => false,
-        }
+        c.is_ascii_alphabetic() || c == '_'
     }
 
     fn is_ident_tail(c: char) -> bool {
-        match c {
-            '0'..='9' => true,
-            c => is_ident_head(c),
-        }
+        c.is_ascii_alphanumeric() || c == '_'
     }
 
     #[cfg(test)]
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 0a60ca8faaa..da74f0aeaa1 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -37,7 +37,7 @@ struct TestCtxt<'a> {
 pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) {
     let span_diagnostic = sess.diagnostic();
     let panic_strategy = sess.panic_strategy();
-    let platform_panic_strategy = sess.target.target.options.panic_strategy;
+    let platform_panic_strategy = sess.target.options.panic_strategy;
 
     // Check for #![reexport_test_harness_main = "some_name"] which gives the
     // main test function the name `some_name` without hygiene. This needs to be
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index e028b2c2dc7..d02bc41f4af 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -16,10 +16,10 @@ pub(crate) unsafe fn codegen(
 ) {
     let llcx = &*mods.llcx;
     let llmod = mods.llmod();
-    let usize = match &tcx.sess.target.target.target_pointer_width[..] {
-        "16" => llvm::LLVMInt16TypeInContext(llcx),
-        "32" => llvm::LLVMInt32TypeInContext(llcx),
-        "64" => llvm::LLVMInt64TypeInContext(llcx),
+    let usize = match tcx.sess.target.pointer_width {
+        16 => llvm::LLVMInt16TypeInContext(llcx),
+        32 => llvm::LLVMInt32TypeInContext(llcx),
+        64 => llvm::LLVMInt64TypeInContext(llcx),
         tws => bug!("Unsupported target word size for int: {}", tws),
     };
     let i8 = llvm::LLVMInt8TypeInContext(llcx);
@@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen(
         let name = format!("__rust_{}", method.name);
         let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
 
-        if tcx.sess.target.target.options.default_hidden_visibility {
+        if tcx.sess.target.options.default_hidden_visibility {
             llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
         }
         if tcx.sess.must_emit_unwind_tables() {
@@ -98,7 +98,7 @@ pub(crate) unsafe fn codegen(
     // -> ! DIFlagNoReturn
     llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn);
 
-    if tcx.sess.target.target.options.default_hidden_visibility {
+    if tcx.sess.target.options.default_hidden_visibility {
         llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
     }
     if tcx.sess.must_emit_unwind_tables() {
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index f801f845ac1..b096664bc74 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -60,7 +60,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
 
         // Default per-arch clobbers
         // Basically what clang does
-        let arch_clobbers = match &self.sess().target.target.arch[..] {
+        let arch_clobbers = match &self.sess().target.arch[..] {
             "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"],
             "mips" | "mips64" => vec!["~{$1}"],
             _ => Vec::new(),
@@ -259,7 +259,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
                 InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {}
                 InlineAsmArch::Nvptx64 => {}
                 InlineAsmArch::Hexagon => {}
-                InlineAsmArch::Mips => {}
+                InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
             }
         }
         if !options.contains(InlineAsmOptions::NOMEM) {
@@ -710,6 +710,7 @@ fn llvm_fixup_input(
             // MIPS only supports register-length arithmetics.
             Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()),
             Primitive::F32 => bx.bitcast(value, bx.cx.type_i32()),
+            Primitive::F64 => bx.bitcast(value, bx.cx.type_i64()),
             _ => value,
         },
         _ => value,
@@ -785,6 +786,7 @@ fn llvm_fixup_output(
             Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()),
             Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.cx.type_i16()),
             Primitive::F32 => bx.bitcast(value, bx.cx.type_f32()),
+            Primitive::F64 => bx.bitcast(value, bx.cx.type_f64()),
             _ => value,
         },
         _ => value,
@@ -854,6 +856,7 @@ fn llvm_fixup_output_type(
             // MIPS only supports register-length arithmetics.
             Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(),
             Primitive::F32 => cx.type_i32(),
+            Primitive::F64 => cx.type_i64(),
             _ => layout.llvm_type(cx),
         },
         _ => layout.llvm_type(cx),
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index a633ea5e5a9..2075c2e1911 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -6,7 +6,7 @@ use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::const_cstr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::small_c_str::SmallCStr;
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::layout::HasTyCtxt;
 use rustc_middle::ty::query::Providers;
@@ -18,7 +18,7 @@ use crate::attributes;
 use crate::llvm::AttributePlace::Function;
 use crate::llvm::{self, Attribute};
 use crate::llvm_util;
-pub use rustc_attr::{InlineAttr, OptimizeAttr};
+pub use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 
 use crate::context::CodegenCx;
 use crate::value::Value;
@@ -31,7 +31,7 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
         Hint => Attribute::InlineHint.apply_llfn(Function, val),
         Always => Attribute::AlwaysInline.apply_llfn(Function, val),
         Never => {
-            if cx.tcx().sess.target.target.arch != "amdgpu" {
+            if cx.tcx().sess.target.arch != "amdgpu" {
                 Attribute::NoInline.apply_llfn(Function, val);
             }
         }
@@ -91,8 +91,7 @@ fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
         // The function name varies on platforms.
         // See test/CodeGen/mcount.c in clang.
         let mcount_name =
-            CString::new(cx.sess().target.target.options.target_mcount.as_str().as_bytes())
-                .unwrap();
+            CString::new(cx.sess().target.options.target_mcount.as_str().as_bytes()).unwrap();
 
         llvm::AddFunctionAttrStringValue(
             llfn,
@@ -106,7 +105,7 @@ fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
 fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     // Only use stack probes if the target specification indicates that we
     // should be using stack probes
-    if !cx.sess().target.target.options.stack_probes {
+    if !cx.sess().target.options.stack_probes {
         return;
     }
 
@@ -175,7 +174,6 @@ pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> {
         .split(',')
         .filter(|f| !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s)));
     sess.target
-        .target
         .options
         .features
         .split(',')
@@ -194,6 +192,18 @@ pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     );
 }
 
+pub fn apply_tune_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+    if let Some(tune) = llvm_util::tune_cpu(cx.tcx.sess) {
+        let tune_cpu = SmallCStr::new(tune);
+        llvm::AddFunctionAttrStringValue(
+            llfn,
+            llvm::AttributePlace::Function,
+            const_cstr!("tune-cpu"),
+            tune_cpu.as_c_str(),
+        );
+    }
+}
+
 /// Sets the `NonLazyBind` LLVM attribute on a given function,
 /// assuming the codegen options allow skipping the PLT.
 pub fn non_lazy_bind(sess: &Session, llfn: &'ll Value) {
@@ -303,6 +313,9 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
     // Without this, ThinLTO won't inline Rust functions into Clang generated
     // functions (because Clang annotates functions this way too).
     apply_target_cpu_attr(cx, llfn);
+    // tune-cpu is only conveyed through the attribute for our purpose.
+    // The target doesn't care; the subtarget reads our attribute.
+    apply_tune_cpu_attr(cx, llfn);
 
     let features = llvm_target_features(cx.tcx.sess)
         .map(|s| s.to_string())
@@ -310,6 +323,10 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
             let feature = &f.as_str();
             format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature))
         }))
+        .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x {
+            InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(),
+            InstructionSetAttr::ArmT32 => "+thumb-mode".to_string(),
+        }))
         .collect::<Vec<String>>()
         .join(",");
 
@@ -326,7 +343,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
     // Note that currently the `wasm-import-module` doesn't do anything, but
     // eventually LLVM 7 should read this and ferry the appropriate import
     // module to the output file.
-    if cx.tcx.sess.target.target.arch == "wasm32" {
+    if cx.tcx.sess.target.arch == "wasm32" {
         if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) {
             llvm::AddFunctionAttrStringValue(
                 llfn,
@@ -348,23 +365,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
     }
 }
 
-pub fn provide(providers: &mut Providers) {
-    use rustc_codegen_ssa::target_features::{all_known_features, supported_target_features};
-    providers.supported_target_features = |tcx, cnum| {
-        assert_eq!(cnum, LOCAL_CRATE);
-        if tcx.sess.opts.actually_rustdoc {
-            // rustdoc needs to be able to document functions that use all the features, so
-            // provide them all.
-            all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
-        } else {
-            supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
-        }
-    };
-
-    provide_extern(providers);
-}
-
-pub fn provide_extern(providers: &mut Providers) {
+pub fn provide_both(providers: &mut Providers) {
     providers.wasm_import_module_map = |tcx, cnum| {
         // Build up a map from DefId to a `NativeLib` structure, where
         // `NativeLib` internally contains information about
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index a115a1e9516..595655b2ca2 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -206,7 +206,7 @@ impl<'a> LlvmArchiveBuilder<'a> {
     }
 
     fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> {
-        let kind = &*self.config.sess.target.target.options.archive_format;
+        let kind = &*self.config.sess.target.options.archive_format;
         kind.parse().map_err(|_| kind)
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 4b2d5907a02..ff312bade25 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -2,14 +2,14 @@ use crate::back::write::{
     self, save_temp_bitcode, to_llvm_opt_settings, with_llvm_pmb, DiagnosticHandlers,
 };
 use crate::llvm::archive_ro::ArchiveRO;
-use crate::llvm::{self, False, True};
+use crate::llvm::{self, build_string, False, True};
 use crate::{LlvmCodegenBackend, ModuleLlvm};
 use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
 use rustc_codegen_ssa::back::symbol_export;
 use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig};
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{FatalError, Handler};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::bug;
@@ -22,16 +22,14 @@ use tracing::{debug, info};
 use std::ffi::{CStr, CString};
 use std::fs::File;
 use std::io;
-use std::mem;
 use std::path::Path;
 use std::ptr;
 use std::slice;
 use std::sync::Arc;
 
-/// We keep track of past LTO imports that were used to produce the current set
-/// of compiled object files that we might choose to reuse during this
-/// compilation session.
-pub const THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-imports.bin";
+/// We keep track of the computed LTO cache keys from the previous
+/// session to determine which CGUs we can reuse.
+pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin";
 
 pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
     match crate_type {
@@ -485,31 +483,31 @@ fn thin_lto(
         )
         .ok_or_else(|| write::llvm_err(&diag_handler, "failed to prepare thin LTO context"))?;
 
-        info!("thin LTO data created");
+        let data = ThinData(data);
 
-        let (import_map_path, prev_import_map, curr_import_map) =
-            if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir {
-                let path = incr_comp_session_dir.join(THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME);
-                // If previous imports have been deleted, or we get an IO error
-                // reading the file storing them, then we'll just use `None` as the
-                // prev_import_map, which will force the code to be recompiled.
-                let prev = if path.exists() {
-                    ThinLTOImportMaps::load_from_file(&path).ok()
-                } else {
-                    None
-                };
-                let curr = ThinLTOImportMaps::from_thin_lto_data(data);
-                (Some(path), prev, curr)
-            } else {
-                // If we don't compile incrementally, we don't need to load the
-                // import data from LLVM.
-                assert!(green_modules.is_empty());
-                let curr = ThinLTOImportMaps::default();
-                (None, None, curr)
-            };
-        info!("thin LTO import map loaded");
+        info!("thin LTO data created");
 
-        let data = ThinData(data);
+        let (key_map_path, prev_key_map, curr_key_map) = if let Some(ref incr_comp_session_dir) =
+            cgcx.incr_comp_session_dir
+        {
+            let path = incr_comp_session_dir.join(THIN_LTO_KEYS_INCR_COMP_FILE_NAME);
+            // If the previous file was deleted, or we get an IO error
+            // reading the file, then we'll just use `None` as the
+            // prev_key_map, which will force the code to be recompiled.
+            let prev =
+                if path.exists() { ThinLTOKeysMap::load_from_file(&path).ok() } else { None };
+            let curr = ThinLTOKeysMap::from_thin_lto_modules(&data, &thin_modules, &module_names);
+            (Some(path), prev, curr)
+        } else {
+            // If we don't compile incrementally, we don't need to load the
+            // import data from LLVM.
+            assert!(green_modules.is_empty());
+            let curr = ThinLTOKeysMap::default();
+            (None, None, curr)
+        };
+        info!("thin LTO cache key map loaded");
+        info!("prev_key_map: {:#?}", prev_key_map);
+        info!("curr_key_map: {:#?}", curr_key_map);
 
         // Throw our data in an `Arc` as we'll be sharing it across threads. We
         // also put all memory referenced by the C++ data (buffers, ids, etc)
@@ -528,60 +526,14 @@ fn thin_lto(
         info!("checking which modules can be-reused and which have to be re-optimized.");
         for (module_index, module_name) in shared.module_names.iter().enumerate() {
             let module_name = module_name_to_str(module_name);
-
-            // If (1.) the module hasn't changed, and (2.) none of the modules
-            // it imports from have changed, *and* (3.) the import and export
-            // sets themselves have not changed from the previous compile when
-            // it was last ThinLTO'ed, then we can re-use the post-ThinLTO
-            // version of the module. Otherwise, freshly perform LTO
-            // optimization.
-            //
-            // (Note that globally, the export set is just the inverse of the
-            // import set.)
-            //
-            // For further justification of why the above is necessary and sufficient,
-            // see the LLVM blog post on ThinLTO:
-            //
-            // http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html
-            //
-            // which states the following:
-            //
-            // ```quote
-            // any particular ThinLTO backend must be redone iff:
-            //
-            // 1. The corresponding (primary) module’s bitcode changed
-            // 2. The list of imports into or exports from the module changed
-            // 3. The bitcode for any module being imported from has changed
-            // 4. Any global analysis result affecting either the primary module
-            //    or anything it imports has changed.
-            // ```
-            //
-            // This strategy means we can always save the computed imports as
-            // canon: when we reuse the post-ThinLTO version, condition (3.)
-            // ensures that the current import set is the same as the previous
-            // one. (And of course, when we don't reuse the post-ThinLTO
-            // version, the current import set *is* the correct one, since we
-            // are doing the ThinLTO in this current compilation cycle.)
-            //
-            // For more discussion, see rust-lang/rust#59535 (where the import
-            // issue was discovered) and rust-lang/rust#69798 (where the
-            // analogous export issue was discovered).
-            if let (Some(prev_import_map), true) =
-                (prev_import_map.as_ref(), green_modules.contains_key(module_name))
+            if let (Some(prev_key_map), true) =
+                (prev_key_map.as_ref(), green_modules.contains_key(module_name))
             {
                 assert!(cgcx.incr_comp_session_dir.is_some());
 
-                let prev_imports = prev_import_map.imports_of(module_name);
-                let curr_imports = curr_import_map.imports_of(module_name);
-                let prev_exports = prev_import_map.exports_of(module_name);
-                let curr_exports = curr_import_map.exports_of(module_name);
-                let imports_all_green = curr_imports
-                    .iter()
-                    .all(|imported_module| green_modules.contains_key(imported_module));
-                if imports_all_green
-                    && equivalent_as_sets(prev_imports, curr_imports)
-                    && equivalent_as_sets(prev_exports, curr_exports)
-                {
+                // If a module exists in both the current and the previous session,
+                // and has the same LTO cache key in both sessions, then we can re-use it
+                if prev_key_map.keys.get(module_name) == curr_key_map.keys.get(module_name) {
                     let work_product = green_modules[module_name].clone();
                     copy_jobs.push(work_product);
                     info!(" - {}: re-used", module_name);
@@ -599,10 +551,10 @@ fn thin_lto(
         }
 
         // Save the current ThinLTO import information for the next compilation
-        // session, overwriting the previous serialized imports (if any).
-        if let Some(path) = import_map_path {
-            if let Err(err) = curr_import_map.save_to_file(&path) {
-                let msg = format!("Error while writing ThinLTO import data: {}", err);
+        // session, overwriting the previous serialized data (if any).
+        if let Some(path) = key_map_path {
+            if let Err(err) = curr_key_map.save_to_file(&path) {
+                let msg = format!("Error while writing ThinLTO key data: {}", err);
                 return Err(write::llvm_err(&diag_handler, &msg));
             }
         }
@@ -611,24 +563,6 @@ fn thin_lto(
     }
 }
 
-/// Given two slices, each with no repeat elements. returns true if and only if
-/// the two slices have the same contents when considered as sets (i.e. when
-/// element order is disregarded).
-fn equivalent_as_sets(a: &[String], b: &[String]) -> bool {
-    // cheap path: unequal lengths means cannot possibly be set equivalent.
-    if a.len() != b.len() {
-        return false;
-    }
-    // fast path: before building new things, check if inputs are equivalent as is.
-    if a == b {
-        return true;
-    }
-    // slow path: general set comparison.
-    let a: FxHashSet<&str> = a.iter().map(|s| s.as_str()).collect();
-    let b: FxHashSet<&str> = b.iter().map(|s| s.as_str()).collect();
-    a == b
-}
-
 pub(crate) fn run_pass_manager(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
     module: &ModuleCodegen<ModuleLlvm>,
@@ -942,113 +876,56 @@ pub unsafe fn optimize_thin_module(
     Ok(module)
 }
 
-/// Summarizes module import/export relationships used by LLVM's ThinLTO pass.
-///
-/// Note that we tend to have two such instances of `ThinLTOImportMaps` in use:
-/// one loaded from a file that represents the relationships used during the
-/// compilation associated with the incremetnal build artifacts we are
-/// attempting to reuse, and another constructed via `from_thin_lto_data`, which
-/// captures the relationships of ThinLTO in the current compilation.
+/// Maps LLVM module identifiers to their corresponding LLVM LTO cache keys
 #[derive(Debug, Default)]
-pub struct ThinLTOImportMaps {
-    // key = llvm name of importing module, value = list of modules it imports from
-    imports: FxHashMap<String, Vec<String>>,
-    // key = llvm name of exporting module, value = list of modules it exports to
-    exports: FxHashMap<String, Vec<String>>,
+pub struct ThinLTOKeysMap {
+    // key = llvm name of importing module, value = LLVM cache key
+    keys: FxHashMap<String, String>,
 }
 
-impl ThinLTOImportMaps {
-    /// Returns modules imported by `llvm_module_name` during some ThinLTO pass.
-    fn imports_of(&self, llvm_module_name: &str) -> &[String] {
-        self.imports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[])
-    }
-
-    /// Returns modules exported by `llvm_module_name` during some ThinLTO pass.
-    fn exports_of(&self, llvm_module_name: &str) -> &[String] {
-        self.exports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[])
-    }
-
+impl ThinLTOKeysMap {
     fn save_to_file(&self, path: &Path) -> io::Result<()> {
         use std::io::Write;
         let file = File::create(path)?;
         let mut writer = io::BufWriter::new(file);
-        for (importing_module_name, imported_modules) in &self.imports {
-            writeln!(writer, "{}", importing_module_name)?;
-            for imported_module in imported_modules {
-                writeln!(writer, " {}", imported_module)?;
-            }
-            writeln!(writer)?;
+        for (module, key) in &self.keys {
+            writeln!(writer, "{} {}", module, key)?;
         }
         Ok(())
     }
 
-    fn load_from_file(path: &Path) -> io::Result<ThinLTOImportMaps> {
+    fn load_from_file(path: &Path) -> io::Result<Self> {
         use std::io::BufRead;
-        let mut imports = FxHashMap::default();
-        let mut exports: FxHashMap<_, Vec<_>> = FxHashMap::default();
-        let mut current_module: Option<String> = None;
-        let mut current_imports: Vec<String> = vec![];
+        let mut keys = FxHashMap::default();
         let file = File::open(path)?;
         for line in io::BufReader::new(file).lines() {
             let line = line?;
-            if line.is_empty() {
-                let importing_module = current_module.take().expect("Importing module not set");
-                for imported in &current_imports {
-                    exports.entry(imported.clone()).or_default().push(importing_module.clone());
-                }
-                imports.insert(importing_module, mem::replace(&mut current_imports, vec![]));
-            } else if line.starts_with(' ') {
-                // Space marks an imported module
-                assert_ne!(current_module, None);
-                current_imports.push(line.trim().to_string());
-            } else {
-                // Otherwise, beginning of a new module (must be start or follow empty line)
-                assert_eq!(current_module, None);
-                current_module = Some(line.trim().to_string());
-            }
+            let mut split = line.split(" ");
+            let module = split.next().unwrap();
+            let key = split.next().unwrap();
+            assert_eq!(split.next(), None, "Expected two space-separated values, found {:?}", line);
+            keys.insert(module.to_string(), key.to_string());
         }
-        Ok(ThinLTOImportMaps { imports, exports })
+        Ok(Self { keys })
     }
 
-    /// Loads the ThinLTO import map from ThinLTOData.
-    unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImportMaps {
-        unsafe extern "C" fn imported_module_callback(
-            payload: *mut libc::c_void,
-            importing_module_name: *const libc::c_char,
-            imported_module_name: *const libc::c_char,
-        ) {
-            let map = &mut *(payload as *mut ThinLTOImportMaps);
-            let importing_module_name = CStr::from_ptr(importing_module_name);
-            let importing_module_name = module_name_to_str(&importing_module_name);
-            let imported_module_name = CStr::from_ptr(imported_module_name);
-            let imported_module_name = module_name_to_str(&imported_module_name);
-
-            if !map.imports.contains_key(importing_module_name) {
-                map.imports.insert(importing_module_name.to_owned(), vec![]);
-            }
-
-            map.imports
-                .get_mut(importing_module_name)
-                .unwrap()
-                .push(imported_module_name.to_owned());
-
-            if !map.exports.contains_key(imported_module_name) {
-                map.exports.insert(imported_module_name.to_owned(), vec![]);
-            }
-
-            map.exports
-                .get_mut(imported_module_name)
-                .unwrap()
-                .push(importing_module_name.to_owned());
-        }
-
-        let mut map = ThinLTOImportMaps::default();
-        llvm::LLVMRustGetThinLTOModuleImports(
-            data,
-            imported_module_callback,
-            &mut map as *mut _ as *mut libc::c_void,
-        );
-        map
+    fn from_thin_lto_modules(
+        data: &ThinData,
+        modules: &[llvm::ThinLTOModule],
+        names: &[CString],
+    ) -> Self {
+        let keys = modules
+            .iter()
+            .zip(names.iter())
+            .map(|(module, name)| {
+                let key = build_string(|rust_str| unsafe {
+                    llvm::LLVMRustComputeLTOCacheKey(rust_str, module.identifier, data.0);
+                })
+                .expect("Invalid ThinLTO module key");
+                (name.clone().into_string().unwrap(), key)
+            })
+            .collect();
+        Self { keys }
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index f35c1016f86..ea1a7cfa5d3 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -128,40 +128,40 @@ pub fn target_machine_factory(
     let (opt_level, _) = to_llvm_opt_settings(optlvl);
     let use_softfp = sess.opts.cg.soft_float;
 
-    let ffunction_sections = sess.target.target.options.function_sections;
+    let ffunction_sections = sess.target.options.function_sections;
     let fdata_sections = ffunction_sections;
 
     let code_model = to_llvm_code_model(sess.code_model());
 
     let features = attributes::llvm_target_features(sess).collect::<Vec<_>>();
-    let mut singlethread = sess.target.target.options.singlethread;
+    let mut singlethread = sess.target.options.singlethread;
 
     // On the wasm target once the `atomics` feature is enabled that means that
     // we're no longer single-threaded, or otherwise we don't want LLVM to
     // lower atomic operations to single-threaded operations.
     if singlethread
-        && sess.target.target.llvm_target.contains("wasm32")
+        && sess.target.llvm_target.contains("wasm32")
         && sess.target_features.contains(&sym::atomics)
     {
         singlethread = false;
     }
 
-    let triple = SmallCStr::new(&sess.target.target.llvm_target);
+    let triple = SmallCStr::new(&sess.target.llvm_target);
     let cpu = SmallCStr::new(llvm_util::target_cpu(sess));
     let features = features.join(",");
     let features = CString::new(features).unwrap();
-    let abi = SmallCStr::new(&sess.target.target.options.llvm_abiname);
-    let trap_unreachable = sess.target.target.options.trap_unreachable;
+    let abi = SmallCStr::new(&sess.target.options.llvm_abiname);
+    let trap_unreachable = sess.target.options.trap_unreachable;
     let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;
 
     let asm_comments = sess.asm_comments();
-    let relax_elf_relocations = sess.target.target.options.relax_elf_relocations;
+    let relax_elf_relocations = sess.target.options.relax_elf_relocations;
 
     let use_init_array = !sess
         .opts
         .debugging_opts
         .use_ctors_section
-        .unwrap_or(sess.target.target.options.use_ctors_section);
+        .unwrap_or(sess.target.options.use_ctors_section);
 
     Arc::new(move || {
         let tm = unsafe {
diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs
index f35708b1d09..1090d4a25c7 100644
--- a/compiler/rustc_codegen_llvm/src/base.rs
+++ b/compiler/rustc_codegen_llvm/src/base.rs
@@ -60,7 +60,7 @@ pub fn write_compressed_metadata<'tcx>(
         unsafe { llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr()) };
     unsafe {
         llvm::LLVMSetInitializer(llglobal, llconst);
-        let section_name = metadata::metadata_section_name(&tcx.sess.target.target);
+        let section_name = metadata::metadata_section_name(&tcx.sess.target);
         let name = SmallCStr::new(section_name);
         llvm::LLVMSetSection(llglobal, name.as_ptr());
 
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index f496f3283da..174620ea2fa 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -308,8 +308,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         use rustc_middle::ty::{Int, Uint};
 
         let new_kind = match ty.kind() {
-            Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.ptr_width)),
-            Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.ptr_width)),
+            Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
+            Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)),
             t @ (Uint(_) | Int(_)) => t.clone(),
             _ => panic!("tried to get overflow intrinsic for op applied to non-int type"),
         };
@@ -541,7 +541,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn range_metadata(&mut self, load: &'ll Value, range: Range<u128>) {
-        if self.sess().target.target.arch == "amdgpu" {
+        if self.sess().target.arch == "amdgpu" {
             // amdgpu/LLVM does something weird and thinks a i64 value is
             // split into a v2i32, halving the bitwidth LLVM expects,
             // tripping an assertion. So, for now, just disable this
@@ -671,7 +671,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         // WebAssembly has saturating floating point to integer casts if the
         // `nontrapping-fptoint` target feature is activated. We'll use those if
         // they are available.
-        if self.sess().target.target.arch == "wasm32"
+        if self.sess().target.arch == "wasm32"
             && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
         {
             let src_ty = self.cx.val_ty(val);
@@ -696,7 +696,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         // WebAssembly has saturating floating point to integer casts if the
         // `nontrapping-fptoint` target feature is activated. We'll use those if
         // they are available.
-        if self.sess().target.target.arch == "wasm32"
+        if self.sess().target.arch == "wasm32"
             && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
         {
             let src_ty = self.cx.val_ty(val);
@@ -1427,7 +1427,7 @@ impl Builder<'a, 'll, 'tcx> {
     }
 
     fn wasm_and_missing_nontrapping_fptoint(&self) -> bool {
-        self.sess().target.target.arch == "wasm32"
+        self.sess().target.arch == "wasm32"
             && !self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 4afd906fce7..e2003472d12 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -176,7 +176,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
         // should use dllimport for functions.
         if cx.use_dll_storage_attrs
             && tcx.is_dllimport_foreign_item(instance_def_id)
-            && tcx.sess.target.target.target_env != "gnu"
+            && tcx.sess.target.target_env != "gnu"
         {
             unsafe {
                 llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 6d3582d3027..b57a23328b6 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -92,7 +92,7 @@ fn set_global_alignment(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Alig
     // The target may require greater alignment for globals than the type does.
     // Note: GCC and Clang also allow `__attribute__((aligned))` on variables,
     // which can force it to be smaller.  Rust doesn't support this yet.
-    if let Some(min) = cx.sess().target.target.options.min_global_align {
+    if let Some(min) = cx.sess().target.options.min_global_align {
         match Align::from_bits(min) {
             Ok(min) => align = align.max(min),
             Err(err) => {
@@ -283,7 +283,7 @@ impl CodegenCx<'ll, 'tcx> {
             // argument validation.
             debug_assert!(
                 !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled()
-                    && self.tcx.sess.target.target.options.is_like_windows
+                    && self.tcx.sess.target.options.is_like_windows
                     && self.tcx.sess.opts.cg.prefer_dynamic)
             );
 
@@ -437,7 +437,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
                 // will use load-unaligned instructions instead, and thus avoiding the crash.
                 //
                 // We could remove this hack whenever we decide to drop macOS 10.10 support.
-                if self.tcx.sess.target.target.options.is_like_osx {
+                if self.tcx.sess.target.options.is_like_osx {
                     // The `inspect` method is okay here because we checked relocations, and
                     // because we are doing this access to inspect the final interpreter state
                     // (not as part of the interpreter execution).
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 1696f35563d..150cedde7e8 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -118,18 +118,18 @@ pub unsafe fn create_module(
     let mod_name = SmallCStr::new(mod_name);
     let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
 
-    let mut target_data_layout = sess.target.target.data_layout.clone();
+    let mut target_data_layout = sess.target.data_layout.clone();
     if llvm_util::get_major_version() < 9 {
         target_data_layout = strip_function_ptr_alignment(target_data_layout);
     }
     if llvm_util::get_major_version() < 10 {
-        if sess.target.target.arch == "x86" || sess.target.target.arch == "x86_64" {
+        if sess.target.arch == "x86" || sess.target.arch == "x86_64" {
             target_data_layout = strip_x86_address_spaces(target_data_layout);
         }
     }
 
     // Ensure the data-layout values hardcoded remain the defaults.
-    if sess.target.target.options.is_builtin {
+    if sess.target.options.is_builtin {
         let tm = crate::back::write::create_informational_target_machine(tcx.sess);
         llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm);
         llvm::LLVMRustDisposeTargetMachine(tm);
@@ -160,7 +160,7 @@ pub unsafe fn create_module(
             bug!(
                 "data-layout for builtin `{}` target, `{}`, \
                   differs from LLVM default, `{}`",
-                sess.target.target.llvm_target,
+                sess.target.llvm_target,
                 target_data_layout,
                 llvm_data_layout
             );
@@ -170,7 +170,7 @@ pub unsafe fn create_module(
     let data_layout = SmallCStr::new(&target_data_layout);
     llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr());
 
-    let llvm_target = SmallCStr::new(&sess.target.target.llvm_target);
+    let llvm_target = SmallCStr::new(&sess.target.llvm_target);
     llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());
 
     if sess.relocation_model() == RelocModel::Pic {
@@ -190,7 +190,7 @@ pub unsafe fn create_module(
     }
 
     // Control Flow Guard is currently only supported by the MSVC linker on Windows.
-    if sess.target.target.options.is_like_msvc {
+    if sess.target.options.is_like_msvc {
         match sess.opts.cg.control_flow_guard {
             CFGuard::Disabled => {}
             CFGuard::NoChecks => {
@@ -265,7 +265,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
         // linker will take care of everything. Fixing this problem will likely
         // require adding a few attributes to Rust itself (feature gated at the
         // start) and then strongly recommending static linkage on Windows!
-        let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_windows;
+        let use_dll_storage_attrs = tcx.sess.target.options.is_like_windows;
 
         let check_overflow = tcx.sess.overflow_checks();
 
@@ -417,7 +417,8 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     }
 
     fn apply_target_cpu_attr(&self, llfn: &'ll Value) {
-        attributes::apply_target_cpu_attr(self, llfn)
+        attributes::apply_target_cpu_attr(self, llfn);
+        attributes::apply_tune_cpu_attr(self, llfn);
     }
 
     fn create_used_variable(&self) {
@@ -838,7 +839,7 @@ impl CodegenCx<'b, 'tcx> {
             return eh_catch_typeinfo;
         }
         let tcx = self.tcx;
-        assert!(self.sess().target.target.options.is_like_emscripten);
+        assert!(self.sess().target.options.is_like_emscripten);
         let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() {
             Some(def_id) => self.get_static(def_id),
             _ => {
@@ -877,7 +878,7 @@ impl HasDataLayout for CodegenCx<'ll, 'tcx> {
 
 impl HasTargetSpec for CodegenCx<'ll, 'tcx> {
     fn target_spec(&self) -> &Target {
-        &self.tcx.sess.target.target
+        &self.tcx.sess.target
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index 29edd66049c..79721ff7e2d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -67,5 +67,5 @@ pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
 
     !omit_gdb_pretty_printer_section
         && cx.sess().opts.debuginfo != DebugInfo::None
-        && cx.sess().target.target.options.emit_debug_gdb_scripts
+        && cx.sess().target.options.emit_debug_gdb_scripts
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 987149cb4c2..5587e6ead1d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -874,7 +874,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
 
     // When targeting MSVC, emit MSVC style type names for compatibility with
     // .natvis visualizers (and perhaps other existing native debuggers?)
-    let msvc_like_names = cx.tcx.sess.target.target.options.is_like_msvc;
+    let msvc_like_names = cx.tcx.sess.target.options.is_like_msvc;
 
     let (name, encoding) = match t.kind() {
         ty::Never => ("!", DW_ATE_unsigned),
@@ -985,7 +985,7 @@ pub fn compile_unit_metadata(
     // if multiple object files with the same `DW_AT_name` are linked together.
     // As a workaround we generate unique names for each object file. Those do
     // not correspond to an actual source file but that should be harmless.
-    if tcx.sess.target.target.options.is_like_osx {
+    if tcx.sess.target.options.is_like_osx {
         name_in_debuginfo.push("@");
         name_in_debuginfo.push(codegen_unit_name);
     }
@@ -1401,7 +1401,7 @@ fn prepare_union_metadata(
 /// on MSVC we have to use the fallback mode, because LLVM doesn't
 /// lower variant parts to PDB.
 fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool {
-    cx.sess().target.target.options.is_like_msvc
+    cx.sess().target.options.is_like_msvc
 }
 
 // FIXME(eddyb) maybe precompute this? Right now it's computed once
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 7cdd366175d..80e0e7bf2e0 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -120,14 +120,12 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
         // for macOS to understand. For more info see #11352
         // This can be overridden using --llvm-opts -dwarf-version,N.
         // Android has the same issue (#22398)
-        if cx.sess().target.target.options.is_like_osx
-            || cx.sess().target.target.options.is_like_android
-        {
-            llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), 2)
+        if let Some(version) = cx.sess().target.options.dwarf_version {
+            llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), version)
         }
 
         // Indicate that we want CodeView debug information on MSVC
-        if cx.sess().target.target.options.is_like_msvc {
+        if cx.sess().target.options.is_like_msvc {
             llvm::LLVMRustAddModuleFlag(cx.llmod, "CodeView\0".as_ptr().cast(), 1)
         }
 
@@ -348,7 +346,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             });
 
             // Arguments types
-            if cx.sess().target.target.options.is_like_msvc {
+            if cx.sess().target.options.is_like_msvc {
                 // FIXME(#42800):
                 // There is a bug in MSDIA that leads to a crash when it encounters
                 // a fixed-size array of `u8` or something zero-sized in a
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs
index 66ae9d72c3e..517246cd0b2 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs
@@ -38,7 +38,7 @@ impl CodegenCx<'ll, '_> {
         // For MSVC, omit the column number.
         // Otherwise, emit it. This mimics clang behaviour.
         // See discussion in https://github.com/rust-lang/rust/issues/42921
-        if self.sess().target.target.options.is_like_msvc {
+        if self.sess().target.options.is_like_msvc {
             DebugLoc { file, line, col: None }
         } else {
             DebugLoc { file, line, col }
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index a3d6882940a..9face778322 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -42,7 +42,7 @@ fn declare_raw_fn(
     // be merged.
     llvm::SetUnnamedAddress(llfn, llvm::UnnamedAddr::Global);
 
-    if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.target.options.disable_redzone) {
+    if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.options.disable_redzone) {
         llvm::Attribute::NoRedZone.apply_llfn(Function, llfn);
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index e76e86f5651..8379fe47225 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -367,7 +367,7 @@ fn try_intrinsic(
         bx.store(bx.const_i32(0), dest, ret_align);
     } else if wants_msvc_seh(bx.sess()) {
         codegen_msvc_try(bx, try_func, data, catch_func, dest);
-    } else if bx.sess().target.target.options.is_like_emscripten {
+    } else if bx.sess().target.options.is_like_emscripten {
         codegen_emcc_try(bx, try_func, data, catch_func, dest);
     } else {
         codegen_gnu_try(bx, try_func, data, catch_func, dest);
@@ -1722,10 +1722,10 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
 fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> {
     match ty.kind() {
         ty::Int(t) => {
-            Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), true))
+            Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), true))
         }
         ty::Uint(t) => {
-            Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), false))
+            Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), false))
         }
         _ => None,
     }
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 1237b39b300..5974b59d39e 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -23,18 +23,17 @@ use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig};
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::ModuleCodegen;
 use rustc_codegen_ssa::{CodegenResults, CompiledModule};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{ErrorReported, FatalError, Handler};
-use rustc_middle::dep_graph::{DepGraph, WorkProduct};
+use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_serialize::json;
-use rustc_session::config::{self, OptLevel, OutputFilenames, PrintRequest};
+use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest};
 use rustc_session::Session;
 use rustc_span::symbol::Symbol;
 
 use std::any::Any;
 use std::ffi::CStr;
-use std::fs;
 use std::sync::Arc;
 
 mod back {
@@ -116,6 +115,9 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
     fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
         llvm_util::target_cpu(sess)
     }
+    fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> {
+        llvm_util::tune_cpu(sess)
+    }
 }
 
 impl WriteBackendMethods for LlvmCodegenBackend {
@@ -249,11 +251,11 @@ impl CodegenBackend for LlvmCodegenBackend {
     }
 
     fn provide(&self, providers: &mut ty::query::Providers) {
-        attributes::provide(providers);
+        attributes::provide_both(providers);
     }
 
     fn provide_extern(&self, providers: &mut ty::query::Providers) {
-        attributes::provide_extern(providers);
+        attributes::provide_both(providers);
     }
 
     fn codegen_crate<'tcx>(
@@ -274,47 +276,27 @@ impl CodegenBackend for LlvmCodegenBackend {
         &self,
         ongoing_codegen: Box<dyn Any>,
         sess: &Session,
-        dep_graph: &DepGraph,
-    ) -> Result<Box<dyn Any>, ErrorReported> {
+    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
         let (codegen_results, work_products) = ongoing_codegen
             .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>()
             .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
             .join(sess);
-        if sess.opts.debugging_opts.incremental_info {
-            rustc_codegen_ssa::back::write::dump_incremental_data(&codegen_results);
-        }
 
-        sess.time("serialize_work_products", move || {
-            rustc_incremental::save_work_product_index(sess, &dep_graph, work_products)
+        sess.time("llvm_dump_timing_file", || {
+            if sess.opts.debugging_opts.llvm_time_trace {
+                llvm_util::time_trace_profiler_finish("llvm_timings.json");
+            }
         });
 
-        sess.compile_status()?;
-
-        Ok(Box::new(codegen_results))
+        Ok((codegen_results, work_products))
     }
 
     fn link(
         &self,
         sess: &Session,
-        codegen_results: Box<dyn Any>,
+        codegen_results: CodegenResults,
         outputs: &OutputFilenames,
     ) -> Result<(), ErrorReported> {
-        let codegen_results = codegen_results
-            .downcast::<CodegenResults>()
-            .expect("Expected CodegenResults, found Box<Any>");
-
-        if sess.opts.debugging_opts.no_link {
-            // FIXME: use a binary format to encode the `.rlink` file
-            let rlink_data = json::encode(&codegen_results).map_err(|err| {
-                sess.fatal(&format!("failed to encode rlink: {}", err));
-            })?;
-            let rlink_file = outputs.with_extension(config::RLINK_EXT);
-            fs::write(&rlink_file, rlink_data).map_err(|err| {
-                sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err));
-            })?;
-            return Ok(());
-        }
-
         // Run the linker on any artifacts that resulted from the LLVM run.
         // This should produce either a finished executable or library.
         sess.time("link_crate", || {
@@ -331,16 +313,6 @@ impl CodegenBackend for LlvmCodegenBackend {
             );
         });
 
-        // Now that we won't touch anything in the incremental compilation directory
-        // any more, we can finalize it (which involves renaming it)
-        rustc_incremental::finalize_session_directory(sess, codegen_results.crate_hash);
-
-        sess.time("llvm_dump_timing_file", || {
-            if sess.opts.debugging_opts.llvm_time_trace {
-                llvm_util::time_trace_profiler_finish("llvm_timings.json");
-            }
-        });
-
         Ok(())
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index af3f3e7aa03..4c1fee0106a 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2362,4 +2362,10 @@ extern "C" {
         bytecode_len: usize,
     ) -> bool;
     pub fn LLVMRustLinkerFree(linker: &'a mut Linker<'a>);
+    #[allow(improper_ctypes)]
+    pub fn LLVMRustComputeLTOCacheKey(
+        key_out: &RustString,
+        mod_id: *const c_char,
+        data: &ThinLTOData,
+    );
 }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index ed9b99188bb..53a404ee019 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -118,11 +118,6 @@ pub fn SetUnnamedAddress(global: &'a Value, unnamed: UnnamedAddr) {
     }
 }
 
-pub fn set_thread_local(global: &'a Value, is_thread_local: bool) {
-    unsafe {
-        LLVMSetThreadLocal(global, is_thread_local as Bool);
-    }
-}
 pub fn set_thread_local_mode(global: &'a Value, mode: ThreadLocalMode) {
     unsafe {
         LLVMSetThreadLocalMode(global, mode);
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index d42020047fd..9c1e1b8fac0 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -46,7 +46,7 @@ fn require_inited() {
 }
 
 unsafe fn configure_llvm(sess: &Session) {
-    let n_args = sess.opts.cg.llvm_args.len() + sess.target.target.options.llvm_args.len();
+    let n_args = sess.opts.cg.llvm_args.len() + sess.target.options.llvm_args.len();
     let mut llvm_c_strs = Vec::with_capacity(n_args + 1);
     let mut llvm_args = Vec::with_capacity(n_args + 1);
 
@@ -57,7 +57,7 @@ unsafe fn configure_llvm(sess: &Session) {
     }
 
     let cg_opts = sess.opts.cg.llvm_args.iter();
-    let tg_opts = sess.target.target.options.llvm_args.iter();
+    let tg_opts = sess.target.options.llvm_args.iter();
     let sess_args = cg_opts.chain(tg_opts);
 
     let user_specified_args: FxHashSet<_> =
@@ -88,7 +88,7 @@ unsafe fn configure_llvm(sess: &Session) {
             .opts
             .debugging_opts
             .merge_functions
-            .unwrap_or(sess.target.target.options.merge_functions)
+            .unwrap_or(sess.target.options.merge_functions)
         {
             MergeFunctions::Disabled | MergeFunctions::Trampolines => {}
             MergeFunctions::Aliases => {
@@ -96,9 +96,7 @@ unsafe fn configure_llvm(sess: &Session) {
             }
         }
 
-        if sess.target.target.target_os == "emscripten"
-            && sess.panic_strategy() == PanicStrategy::Unwind
-        {
+        if sess.target.target_os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
             add("-enable-emscripten-cxx-exceptions", false);
         }
 
@@ -122,7 +120,7 @@ unsafe fn configure_llvm(sess: &Session) {
 
     llvm::LLVMInitializePasses();
 
-    ::rustc_llvm::initialize_available_targets();
+    rustc_llvm::initialize_available_targets();
 
     llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr());
 }
@@ -140,7 +138,7 @@ pub fn time_trace_profiler_finish(file_name: &str) {
 // to LLVM or the feature detection code will walk past the end of the feature
 // array, leading to crashes.
 pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
-    let arch = if sess.target.target.arch == "x86_64" { "x86" } else { &*sess.target.target.arch };
+    let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
     match (arch, s) {
         ("x86", "pclmulqdq") => "pclmul",
         ("x86", "rdrand") => "rdrnd",
@@ -202,11 +200,7 @@ pub(crate) fn print(req: PrintRequest, sess: &Session) {
     }
 }
 
-pub fn target_cpu(sess: &Session) -> &str {
-    let name = match sess.opts.cg.target_cpu {
-        Some(ref s) => &**s,
-        None => &*sess.target.target.options.cpu,
-    };
+fn handle_native(name: &str) -> &str {
     if name != "native" {
         return name;
     }
@@ -217,3 +211,19 @@ pub fn target_cpu(sess: &Session) -> &str {
         str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap()
     }
 }
+
+pub fn target_cpu(sess: &Session) -> &str {
+    let name = match sess.opts.cg.target_cpu {
+        Some(ref s) => &**s,
+        None => &*sess.target.options.cpu,
+    };
+
+    handle_native(name)
+}
+
+pub fn tune_cpu(sess: &Session) -> Option<&str> {
+    match sess.opts.debugging_opts.tune_cpu {
+        Some(ref s) => Some(handle_native(&**s)),
+        None => None,
+    }
+}
diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs
index 22ed4dd7576..5f820f83a94 100644
--- a/compiler/rustc_codegen_llvm/src/va_arg.rs
+++ b/compiler/rustc_codegen_llvm/src/va_arg.rs
@@ -52,7 +52,7 @@ fn emit_direct_ptr_va_arg(
     let next = bx.inbounds_gep(addr, &[full_direct_size]);
     bx.store(next, va_list_addr, bx.tcx().data_layout.pointer_align.abi);
 
-    if size.bytes() < slot_size.bytes() && &*bx.tcx().sess.target.target.target_endian == "big" {
+    if size.bytes() < slot_size.bytes() && &*bx.tcx().sess.target.target_endian == "big" {
         let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32);
         let adjusted = bx.inbounds_gep(addr, &[adjusted_size]);
         (bx.bitcast(adjusted, bx.cx().type_ptr_to(llty)), addr_align)
@@ -105,7 +105,7 @@ fn emit_aapcs_va_arg(
     let mut end = bx.build_sibling_block("va_arg.end");
     let zero = bx.const_i32(0);
     let offset_align = Align::from_bytes(4).unwrap();
-    assert!(&*bx.tcx().sess.target.target.target_endian == "little");
+    assert!(&*bx.tcx().sess.target.target_endian == "little");
 
     let gr_type = target_ty.is_any_ptr() || target_ty.is_integral();
     let (reg_off, reg_top_index, slot_size) = if gr_type {
@@ -171,8 +171,8 @@ pub(super) fn emit_va_arg(
 ) -> &'ll Value {
     // Determine the va_arg implementation to use. The LLVM va_arg instruction
     // is lacking in some instances, so we should only use it as a fallback.
-    let target = &bx.cx.tcx.sess.target.target;
-    let arch = &bx.cx.tcx.sess.target.target.arch;
+    let target = &bx.cx.tcx.sess.target;
+    let arch = &bx.cx.tcx.sess.target.arch;
     match (&**arch, target.options.is_like_windows) {
         // Windows x86
         ("x86", true) => {
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index f83b4b2b0c0..ef722ecb599 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -9,9 +9,7 @@ pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session) -> P
     // times show up as foo.lib
     let oslibname = format!(
         "{}{}{}",
-        sess.target.target.options.staticlib_prefix,
-        name,
-        sess.target.target.options.staticlib_suffix
+        sess.target.options.staticlib_prefix, name, sess.target.options.staticlib_suffix
     );
     let unixlibname = format!("lib{}.a", name);
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 010fd4e9c5a..63d0a88858e 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -15,7 +15,7 @@ use rustc_session::{filesearch, Session};
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
 use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
-use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel};
+use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target};
 
 use super::archive::ArchiveBuilder;
 use super::command::Command;
@@ -152,7 +152,7 @@ fn get_linker(
         _ => match flavor {
             LinkerFlavor::Lld(f) => Command::lld(linker, f),
             LinkerFlavor::Msvc
-                if sess.opts.cg.linker.is_none() && sess.target.target.options.linker.is_none() =>
+                if sess.opts.cg.linker.is_none() && sess.target.options.linker.is_none() =>
             {
                 Command::new(msvc_tool.as_ref().map(|t| t.path()).unwrap_or(linker))
             }
@@ -163,7 +163,7 @@ fn get_linker(
     // UWP apps have API restrictions enforced during Store submissions.
     // To comply with the Windows App Certification Kit,
     // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
-    let t = &sess.target.target;
+    let t = &sess.target;
     if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link))
         && t.target_vendor == "uwp"
     {
@@ -197,7 +197,7 @@ fn get_linker(
     // PATH for the child.
     let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(self_contained);
     let mut msvc_changed_path = false;
-    if sess.target.target.options.is_like_msvc {
+    if sess.target.options.is_like_msvc {
         if let Some(ref tool) = msvc_tool {
             cmd.args(tool.args());
             for &(ref k, ref v) in tool.env() {
@@ -365,7 +365,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
             // After adding all files to the archive, we need to update the
             // symbol table of the archive. This currently dies on macOS (see
             // #11162), and isn't necessary there anyway
-            if !sess.target.target.options.is_like_osx {
+            if !sess.target.options.is_like_osx {
                 ab.update_symbols();
             }
         }
@@ -476,10 +476,10 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
 
     linker::disable_localization(&mut cmd);
 
-    for &(ref k, ref v) in &sess.target.target.options.link_env {
+    for &(ref k, ref v) in &sess.target.options.link_env {
         cmd.env(k, v);
     }
-    for k in &sess.target.target.options.link_env_remove {
+    for k in &sess.target.options.link_env_remove {
         cmd.env_remove(k);
     }
 
@@ -515,7 +515,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         // if the linker doesn't support -no-pie then it should not default to
         // linking executables as pie. Different versions of gcc seem to use
         // different quotes in the error message so don't check for them.
-        if sess.target.target.options.linker_is_gnu
+        if sess.target.options.linker_is_gnu
             && flavor != LinkerFlavor::Ld
             && (out.contains("unrecognized command line option")
                 || out.contains("unknown argument"))
@@ -535,7 +535,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
 
         // Detect '-static-pie' used with an older version of gcc or clang not supporting it.
         // Fallback from '-static-pie' to '-static' in that case.
-        if sess.target.target.options.linker_is_gnu
+        if sess.target.options.linker_is_gnu
             && flavor != LinkerFlavor::Ld
             && (out.contains("unrecognized command line option")
                 || out.contains("unknown argument"))
@@ -548,7 +548,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
             );
             // Mirror `add_(pre,post)_link_objects` to replace CRT objects.
             let self_contained = crt_objects_fallback(sess, crate_type);
-            let opts = &sess.target.target.options;
+            let opts = &sess.target.options;
             let pre_objects = if self_contained {
                 &opts.pre_link_objects_fallback
             } else {
@@ -670,7 +670,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
                 // is not a Microsoft LNK error then suggest a way to fix or
                 // install the Visual Studio build tools.
                 if let Some(code) = prog.status.code() {
-                    if sess.target.target.options.is_like_msvc
+                    if sess.target.options.is_like_msvc
                         && flavor == LinkerFlavor::Msvc
                         // Respect the command line override
                         && sess.opts.cg.linker.is_none()
@@ -741,7 +741,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
 
             linker_error.emit();
 
-            if sess.target.target.options.is_like_msvc && linker_not_found {
+            if sess.target.options.is_like_msvc && linker_not_found {
                 sess.note_without_error(
                     "the msvc targets depend on the msvc linker \
                      but `link.exe` was not found",
@@ -758,7 +758,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
     // On macOS, debuggers need this utility to get run to do some munging of
     // the symbols. Note, though, that if the object files are being preserved
     // for their debug information there's no need for us to run dsymutil.
-    if sess.target.target.options.is_like_osx
+    if sess.target.options.is_like_osx
         && sess.opts.debuginfo != DebugInfo::None
         && !preserve_objects_for_their_debuginfo(sess)
     {
@@ -776,7 +776,7 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke
     let needs_runtime = match crate_type {
         CrateType::Executable => true,
         CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
-            sess.target.target.options.is_like_osx
+            sess.target.options.is_like_osx
         }
         CrateType::Rlib | CrateType::Staticlib => false,
     };
@@ -846,7 +846,7 @@ pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool
     // If our target enables builtin function lowering in LLVM then the
     // crates providing these functions don't participate in LTO (e.g.
     // no_builtins or compiler builtins crates).
-    !sess.target.target.options.no_builtins
+    !sess.target.options.no_builtins
         && (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum))
 }
 
@@ -906,10 +906,10 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
                 } else if stem == "link" || stem == "lld-link" {
                     LinkerFlavor::Msvc
                 } else if stem == "lld" || stem == "rust-lld" {
-                    LinkerFlavor::Lld(sess.target.target.options.lld_flavor)
+                    LinkerFlavor::Lld(sess.target.options.lld_flavor)
                 } else {
                     // fall back to the value in the target spec
-                    sess.target.target.linker_flavor
+                    sess.target.linker_flavor
                 };
 
                 Some((linker, flavor))
@@ -926,8 +926,8 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
 
     if let Some(ret) = infer_from(
         sess,
-        sess.target.target.options.linker.clone().map(PathBuf::from),
-        Some(sess.target.target.linker_flavor),
+        sess.target.options.linker.clone().map(PathBuf::from),
+        Some(sess.target.linker_flavor),
     ) {
         return ret;
     }
@@ -962,7 +962,7 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
     // Basically as a result this just means that if we're on OSX and we're
     // *not* running dsymutil then the object files are the only source of truth
     // for debug information, so we must preserve them.
-    if sess.target.target.options.is_like_osx {
+    if sess.target.options.is_like_osx {
         return !sess.opts.debugging_opts.run_dsymutil;
     }
 
@@ -988,7 +988,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
                 NativeLibKind::StaticNoBundle
                 | NativeLibKind::Dylib
                 | NativeLibKind::Unspecified => {
-                    if sess.target.target.options.is_like_msvc {
+                    if sess.target.options.is_like_msvc {
                         Some(format!("{}.lib", name))
                     } else {
                         Some(format!("-l{}", name))
@@ -1070,16 +1070,13 @@ fn exec_linker(
     let mut args = String::new();
     for arg in cmd2.take_args() {
         args.push_str(
-            &Escape {
-                arg: arg.to_str().unwrap(),
-                is_like_msvc: sess.target.target.options.is_like_msvc,
-            }
-            .to_string(),
+            &Escape { arg: arg.to_str().unwrap(), is_like_msvc: sess.target.options.is_like_msvc }
+                .to_string(),
         );
         args.push('\n');
     }
     let file = tmpdir.join("linker-arguments");
-    let bytes = if sess.target.target.options.is_like_msvc {
+    let bytes = if sess.target.options.is_like_msvc {
         let mut out = Vec::with_capacity((1 + args.len()) * 2);
         // start the stream with a UTF-16 BOM
         for c in std::iter::once(0xFEFF).chain(args.encode_utf16()) {
@@ -1195,7 +1192,7 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
     };
 
     // Adjust the output kind to target capabilities.
-    let opts = &sess.target.target.options;
+    let opts = &sess.target.options;
     let pic_exe_supported = opts.position_independent_executables;
     let static_pic_exe_supported = opts.static_position_independent_executables;
     let static_dylib_supported = opts.crt_static_allows_dylibs;
@@ -1236,14 +1233,14 @@ fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
         return self_contained;
     }
 
-    match sess.target.target.options.crt_objects_fallback {
+    match sess.target.options.crt_objects_fallback {
         // FIXME: Find a better heuristic for "native musl toolchain is available",
         // based on host and linker path, for example.
         // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237).
         Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)),
         Some(CrtObjectsFallback::Mingw) => {
-            sess.host == sess.target.target
-                && sess.target.target.target_vendor != "uwp"
+            sess.host == sess.target
+                && sess.target.target_vendor != "uwp"
                 && detect_self_contained_mingw(&sess)
         }
         // FIXME: Figure out cases in which WASM needs to link with a native toolchain.
@@ -1259,7 +1256,7 @@ fn add_pre_link_objects(
     link_output_kind: LinkOutputKind,
     self_contained: bool,
 ) {
-    let opts = &sess.target.target.options;
+    let opts = &sess.target.options;
     let objects =
         if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
@@ -1274,7 +1271,7 @@ fn add_post_link_objects(
     link_output_kind: LinkOutputKind,
     self_contained: bool,
 ) {
-    let opts = &sess.target.target.options;
+    let opts = &sess.target.options;
     let objects =
         if self_contained { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
@@ -1285,7 +1282,7 @@ fn add_post_link_objects(
 /// Add arbitrary "pre-link" args defined by the target spec or from command line.
 /// FIXME: Determine where exactly these args need to be inserted.
 fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
-    if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
+    if let Some(args) = sess.target.options.pre_link_args.get(&flavor) {
         cmd.args(args);
     }
     cmd.args(&sess.opts.debugging_opts.pre_link_args);
@@ -1293,13 +1290,13 @@ fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor)
 
 /// Add a link script embedded in the target, if applicable.
 fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_type: CrateType) {
-    match (crate_type, &sess.target.target.options.link_script) {
+    match (crate_type, &sess.target.options.link_script) {
         (CrateType::Cdylib | CrateType::Executable, Some(script)) => {
-            if !sess.target.target.options.linker_is_gnu {
+            if !sess.target.options.linker_is_gnu {
                 sess.fatal("can only use link script when linking with GNU-like linker");
             }
 
-            let file_name = ["rustc", &sess.target.target.llvm_target, "linkfile.ld"].join("-");
+            let file_name = ["rustc", &sess.target.llvm_target, "linkfile.ld"].join("-");
 
             let path = tmpdir.join(file_name);
             if let Err(e) = fs::write(&path, script) {
@@ -1338,15 +1335,15 @@ fn add_late_link_args(
             *ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
         });
     if any_dynamic_crate {
-        if let Some(args) = sess.target.target.options.late_link_args_dynamic.get(&flavor) {
+        if let Some(args) = sess.target.options.late_link_args_dynamic.get(&flavor) {
             cmd.args(args);
         }
     } else {
-        if let Some(args) = sess.target.target.options.late_link_args_static.get(&flavor) {
+        if let Some(args) = sess.target.options.late_link_args_static.get(&flavor) {
             cmd.args(args);
         }
     }
-    if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) {
+    if let Some(args) = sess.target.options.late_link_args.get(&flavor) {
         cmd.args(args);
     }
 }
@@ -1354,7 +1351,7 @@ fn add_late_link_args(
 /// Add arbitrary "post-link" args defined by the target spec.
 /// FIXME: Determine where exactly these args need to be inserted.
 fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
-    if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
+    if let Some(args) = sess.target.options.post_link_args.get(&flavor) {
         cmd.args(args);
     }
 }
@@ -1456,7 +1453,7 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained:
 /// Add options making relocation sections in the produced ELF files read-only
 /// and suppressing lazy binding.
 fn add_relro_args(cmd: &mut dyn Linker, sess: &Session) {
-    match sess.opts.debugging_opts.relro_level.unwrap_or(sess.target.target.options.relro_level) {
+    match sess.opts.debugging_opts.relro_level.unwrap_or(sess.target.options.relro_level) {
         RelroLevel::Full => cmd.full_relro(),
         RelroLevel::Partial => cmd.partial_relro(),
         RelroLevel::Off => cmd.no_relro(),
@@ -1487,9 +1484,9 @@ fn add_rpath_args(
         let mut rpath_config = RPathConfig {
             used_crates: &codegen_results.crate_info.used_crates_dynamic,
             out_filename: out_filename.to_path_buf(),
-            has_rpath: sess.target.target.options.has_rpath,
-            is_like_osx: sess.target.target.options.is_like_osx,
-            linker_is_gnu: sess.target.target.options.linker_is_gnu,
+            has_rpath: sess.target.options.has_rpath,
+            is_like_osx: sess.target.options.is_like_osx,
+            linker_is_gnu: sess.target.options.linker_is_gnu,
             get_install_prefix_lib_path: &mut get_install_prefix_lib_path,
         };
         cmd.args(&rpath::get_rpath_flags(&mut rpath_config));
@@ -1517,7 +1514,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     let base_cmd = get_linker(sess, path, flavor, crt_objects_fallback);
     // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
     // to the linker args construction.
-    assert!(base_cmd.get_args().is_empty() || sess.target.target.target_vendor == "uwp");
+    assert!(base_cmd.get_args().is_empty() || sess.target.target_vendor == "uwp");
     let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor, target_cpu);
     let link_output_kind = link_output_kind(sess, crate_type);
 
@@ -1531,7 +1528,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     add_link_script(cmd, sess, tmpdir, crate_type);
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.target.target.options.is_like_fuchsia && crate_type == CrateType::Executable {
+    if sess.target.options.is_like_fuchsia && crate_type == CrateType::Executable {
         let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
             "asan/"
         } else {
@@ -1541,7 +1538,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     }
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.target.target.options.eh_frame_header {
+    if sess.target.options.eh_frame_header {
         cmd.add_eh_frame_header();
     }
 
@@ -1554,7 +1551,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
 
     // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
-    if sess.target.target.options.is_like_emscripten {
+    if sess.target.options.is_like_emscripten {
         cmd.arg("-s");
         cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
             "DISABLE_EXCEPTION_CATCHING=1"
@@ -1582,7 +1579,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     cmd.output_filename(out_filename);
 
     // OBJECT-FILES-NO, AUDIT-ORDER
-    if crate_type == CrateType::Executable && sess.target.target.options.is_like_windows {
+    if crate_type == CrateType::Executable && sess.target.options.is_like_windows {
         if let Some(ref s) = codegen_results.windows_subsystem {
             cmd.subsystem(s);
         }
@@ -1626,7 +1623,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
     // OBJECT-FILES-NO, AUDIT-ORDER
     // We want to prevent the compiler from accidentally leaking in any system libraries,
     // so by default we tell linkers not to link to any default libraries.
-    if !sess.opts.cg.default_linker_libraries && sess.target.target.options.no_default_libraries {
+    if !sess.opts.cg.default_linker_libraries && sess.target.options.no_default_libraries {
         cmd.no_default_libraries();
     }
 
@@ -1845,12 +1842,8 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
     }
 
     // Converts a library file-stem into a cc -l argument
-    fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str {
-        if stem.starts_with("lib") && !config.target.options.is_like_windows {
-            &stem[3..]
-        } else {
-            stem
-        }
+    fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str {
+        if stem.starts_with("lib") && !target.options.is_like_windows { &stem[3..] } else { stem }
     }
 
     // Adds the static "rlib" versions of all crates to the command line.
@@ -1945,7 +1938,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>(
                 // though, so we let that object file slide.
                 let skip_because_lto = are_upstream_rust_objects_already_included(sess)
                     && is_rust_object
-                    && (sess.target.target.options.no_builtins
+                    && (sess.target.options.no_builtins
                         || !codegen_results.crate_info.is_no_builtins.contains(&cnum));
 
                 if skip_because_cfg_say_so || skip_because_lto {
@@ -2088,10 +2081,10 @@ fn are_upstream_rust_objects_already_included(sess: &Session) -> bool {
 }
 
 fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
-    let arch = &sess.target.target.arch;
-    let os = &sess.target.target.target_os;
-    let llvm_target = &sess.target.target.llvm_target;
-    if sess.target.target.target_vendor != "apple"
+    let arch = &sess.target.arch;
+    let os = &sess.target.target_os;
+    let llvm_target = &sess.target.llvm_target;
+    if sess.target.target_vendor != "apple"
         || !matches!(os.as_str(), "ios" | "tvos")
         || flavor != LinkerFlavor::Gcc
     {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 0ddf8bd316f..3e13a1daecd 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -184,7 +184,7 @@ impl<'a> GccLinker<'a> {
         // * On OSX they have their own linker, not binutils'
         // * For WebAssembly the only functional linker is LLD, which doesn't
         //   support hint flags
-        !self.sess.target.target.options.is_like_osx && self.sess.target.target.arch != "wasm32"
+        !self.sess.target.options.is_like_osx && self.sess.target.arch != "wasm32"
     }
 
     // Some platforms take hints about whether a library is static or dynamic.
@@ -221,10 +221,8 @@ impl<'a> GccLinker<'a> {
         let opt_level = match self.sess.opts.optimize {
             config::OptLevel::No => "O0",
             config::OptLevel::Less => "O1",
-            config::OptLevel::Default => "O2",
+            config::OptLevel::Default | config::OptLevel::Size | config::OptLevel::SizeMin => "O2",
             config::OptLevel::Aggressive => "O3",
-            config::OptLevel::Size => "Os",
-            config::OptLevel::SizeMin => "Oz",
         };
 
         self.linker_arg(&format!("-plugin-opt={}", opt_level));
@@ -234,7 +232,7 @@ impl<'a> GccLinker<'a> {
 
     fn build_dylib(&mut self, out_filename: &Path) {
         // On mac we need to tell the linker to let this library be rpathed
-        if self.sess.target.target.options.is_like_osx {
+        if self.sess.target.options.is_like_osx {
             self.cmd.arg("-dynamiclib");
             self.linker_arg("-dylib");
 
@@ -250,7 +248,7 @@ impl<'a> GccLinker<'a> {
             }
         } else {
             self.cmd.arg("-shared");
-            if self.sess.target.target.options.is_like_windows {
+            if self.sess.target.options.is_like_windows {
                 // The output filename already contains `dll_suffix` so
                 // the resulting import library will have a name in the
                 // form of libfoo.dll.a
@@ -258,9 +256,9 @@ impl<'a> GccLinker<'a> {
                     out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
                         format!(
                             "{}{}{}",
-                            self.sess.target.target.options.staticlib_prefix,
+                            self.sess.target.options.staticlib_prefix,
                             file,
-                            self.sess.target.target.options.staticlib_suffix
+                            self.sess.target.options.staticlib_suffix
                         )
                     });
                 if let Some(implib_name) = implib_name {
@@ -282,7 +280,7 @@ impl<'a> Linker for GccLinker<'a> {
     fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
         match output_kind {
             LinkOutputKind::DynamicNoPicExe => {
-                if !self.is_ld && self.sess.target.target.options.linker_is_gnu {
+                if !self.is_ld && self.sess.target.options.linker_is_gnu {
                     self.cmd.arg("-no-pie");
                 }
             }
@@ -293,7 +291,7 @@ impl<'a> Linker for GccLinker<'a> {
             LinkOutputKind::StaticNoPicExe => {
                 // `-static` works for both gcc wrapper and ld.
                 self.cmd.arg("-static");
-                if !self.is_ld && self.sess.target.target.options.linker_is_gnu {
+                if !self.is_ld && self.sess.target.options.linker_is_gnu {
                     self.cmd.arg("-no-pie");
                 }
             }
@@ -322,7 +320,7 @@ impl<'a> Linker for GccLinker<'a> {
         // any `#[link]` attributes in the `libc` crate, see #72782 for details.
         // FIXME: Switch to using `#[link]` attributes in the `libc` crate
         // similarly to other targets.
-        if self.sess.target.target.target_os == "vxworks"
+        if self.sess.target.target_os == "vxworks"
             && matches!(
                 output_kind,
                 LinkOutputKind::StaticNoPicExe
@@ -387,7 +385,7 @@ impl<'a> Linker for GccLinker<'a> {
     // functions, etc.
     fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) {
         self.hint_static();
-        let target = &self.sess.target.target;
+        let target = &self.sess.target;
         if !target.options.is_like_osx {
             self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib));
             self.linker_arg("--no-whole-archive");
@@ -402,7 +400,7 @@ impl<'a> Linker for GccLinker<'a> {
 
     fn link_whole_rlib(&mut self, lib: &Path) {
         self.hint_static();
-        if self.sess.target.target.options.is_like_osx {
+        if self.sess.target.options.is_like_osx {
             self.linker_arg("-force_load");
             self.linker_arg(&lib);
         } else {
@@ -426,9 +424,9 @@ impl<'a> Linker for GccLinker<'a> {
         // -dead_strip can't be part of the pre_link_args because it's also used
         // for partial linking when using multiple codegen units (-r).  So we
         // insert it here.
-        if self.sess.target.target.options.is_like_osx {
+        if self.sess.target.options.is_like_osx {
             self.linker_arg("-dead_strip");
-        } else if self.sess.target.target.options.is_like_solaris {
+        } else if self.sess.target.options.is_like_solaris {
             self.linker_arg("-zignore");
 
         // If we're building a dylib, we don't use --gc-sections because LLVM
@@ -442,7 +440,7 @@ impl<'a> Linker for GccLinker<'a> {
     }
 
     fn optimize(&mut self) {
-        if !self.sess.target.target.options.linker_is_gnu {
+        if !self.sess.target.options.linker_is_gnu {
             return;
         }
 
@@ -456,7 +454,7 @@ impl<'a> Linker for GccLinker<'a> {
     }
 
     fn pgo_gen(&mut self) {
-        if !self.sess.target.target.options.linker_is_gnu {
+        if !self.sess.target.options.linker_is_gnu {
             return;
         }
 
@@ -506,7 +504,7 @@ impl<'a> Linker for GccLinker<'a> {
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
         // Symbol visibility in object files typically takes care of this.
         if crate_type == CrateType::Executable
-            && self.sess.target.target.options.override_export_symbols.is_none()
+            && self.sess.target.options.override_export_symbols.is_none()
         {
             return;
         }
@@ -515,7 +513,7 @@ impl<'a> Linker for GccLinker<'a> {
         // The object files have far more public symbols than we actually want to export,
         // so we hide them all here.
 
-        if !self.sess.target.target.options.limit_rdylib_exports {
+        if !self.sess.target.options.limit_rdylib_exports {
             return;
         }
 
@@ -523,13 +521,13 @@ impl<'a> Linker for GccLinker<'a> {
             return;
         }
 
-        let is_windows = self.sess.target.target.options.is_like_windows;
+        let is_windows = self.sess.target.options.is_like_windows;
         let mut arg = OsString::new();
         let path = tmpdir.join(if is_windows { "list.def" } else { "list" });
 
         debug!("EXPORTED SYMBOLS:");
 
-        if self.sess.target.target.options.is_like_osx {
+        if self.sess.target.options.is_like_osx {
             // Write a plain, newline-separated list of symbols
             let res: io::Result<()> = try {
                 let mut f = BufWriter::new(File::create(&path)?);
@@ -575,12 +573,12 @@ impl<'a> Linker for GccLinker<'a> {
             }
         }
 
-        if self.sess.target.target.options.is_like_osx {
+        if self.sess.target.options.is_like_osx {
             if !self.is_ld {
                 arg.push("-Wl,")
             }
             arg.push("-exported_symbols_list,");
-        } else if self.sess.target.target.options.is_like_solaris {
+        } else if self.sess.target.options.is_like_solaris {
             if !self.is_ld {
                 arg.push("-Wl,")
             }
@@ -1205,7 +1203,7 @@ impl<'a> Linker for WasmLd<'a> {
 }
 
 fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
-    if let Some(ref exports) = tcx.sess.target.target.options.override_export_symbols {
+    if let Some(ref exports) = tcx.sess.target.options.override_export_symbols {
         return exports.clone();
     }
 
@@ -1295,7 +1293,7 @@ impl<'a> Linker for PtxLinker<'a> {
         // Provide the linker with fallback to internal `target-cpu`.
         self.cmd.arg("--fallback-arch").arg(match self.sess.opts.cg.target_cpu {
             Some(ref s) => s,
-            None => &self.sess.target.target.options.cpu,
+            None => &self.sess.target.options.cpu,
         });
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 51cc1ada432..dd8d751d045 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -229,8 +229,8 @@ fn exported_symbols_provider_local(
         // needs to be exported.
         // However, on platforms that don't allow for Rust dylibs, having
         // external linkage is enough for monomorphization to be linked to.
-        let need_visibility = tcx.sess.target.target.options.dynamic_linking
-            && !tcx.sess.target.target.options.only_cdylib;
+        let need_visibility =
+            tcx.sess.target.options.dynamic_linking && !tcx.sess.target.options.only_cdylib;
 
         let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE);
 
@@ -391,7 +391,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel
         codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
 
     if is_extern && !std_internal {
-        let target = &tcx.sess.target.target.llvm_target;
+        let target = &tcx.sess.target.llvm_target;
         // WebAssembly cannot export data symbols, so reduce their export level
         if target.contains("emscripten") {
             if let Some(Node::Item(&hir::Item { kind: hir::ItemKind::Static(..), .. })) =
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 0edf0fcd1a2..4d2cea18dcc 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -13,7 +13,6 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::profiling::TimingGuard;
 use rustc_data_structures::profiling::VerboseTimingGuard;
-use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::Emitter;
 use rustc_errors::{DiagnosticId, FatalError, Handler, Level};
@@ -140,7 +139,7 @@ impl ModuleConfig {
 
         let emit_obj = if !should_emit_obj {
             EmitObj::None
-        } else if sess.target.target.options.obj_is_bitcode
+        } else if sess.target.options.obj_is_bitcode
             || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins)
         {
             // This case is selected if the target uses objects as bitcode, or
@@ -222,11 +221,11 @@ impl ModuleConfig {
                 false
             ),
             emit_obj,
-            bc_cmdline: sess.target.target.options.bitcode_llvm_cmdline.clone(),
+            bc_cmdline: sess.target.options.bitcode_llvm_cmdline.clone(),
 
             verify_llvm_ir: sess.verify_llvm_ir(),
             no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes,
-            no_builtins: no_builtins || sess.target.target.options.no_builtins,
+            no_builtins: no_builtins || sess.target.options.no_builtins,
 
             // Exclude metadata and allocator modules from time_passes output,
             // since they throw off the "LLVM passes" measurement.
@@ -253,7 +252,7 @@ impl ModuleConfig {
                 .opts
                 .debugging_opts
                 .merge_functions
-                .unwrap_or(sess.target.target.options.merge_functions)
+                .unwrap_or(sess.target.options.merge_functions)
             {
                 MergeFunctions::Disabled => false,
                 MergeFunctions::Trampolines | MergeFunctions::Aliases => {
@@ -308,7 +307,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub allocator_module_config: Arc<ModuleConfig>,
     pub tm_factory: TargetMachineFactory<B>,
     pub msvc_imps_needed: bool,
-    pub target_pointer_width: String,
+    pub target_pointer_width: u32,
     pub target_arch: String,
     pub debuginfo: config::DebugInfo,
 
@@ -389,7 +388,7 @@ fn need_bitcode_in_object(sess: &Session) -> bool {
     let requested_for_rlib = sess.opts.cg.embed_bitcode
         && sess.crate_types().contains(&CrateType::Rlib)
         && sess.opts.output_types.contains_key(&OutputType::Exe);
-    let forced_by_target = sess.target.target.options.forces_embed_bitcode;
+    let forced_by_target = sess.target.options.forces_embed_bitcode;
     requested_for_rlib || forced_by_target
 }
 
@@ -414,7 +413,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
     let sess = tcx.sess;
 
     let crate_name = tcx.crate_name(LOCAL_CRATE);
-    let crate_hash = tcx.crate_hash(LOCAL_CRATE);
     let no_builtins = tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::no_builtins);
     let is_compiler_builtins =
         tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::compiler_builtins);
@@ -463,7 +461,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
     OngoingCodegen {
         backend,
         crate_name,
-        crate_hash,
         metadata,
         windows_subsystem,
         linker_info,
@@ -658,15 +655,6 @@ fn produce_final_output_artifacts(
     // These are used in linking steps and will be cleaned up afterward.
 }
 
-pub fn dump_incremental_data(_codegen_results: &CodegenResults) {
-    // FIXME(mw): This does not work at the moment because the situation has
-    //            become more complicated due to incremental LTO. Now a CGU
-    //            can have more than two caching states.
-    // println!("[incremental] Re-using {} out of {} modules",
-    //           codegen_results.modules.iter().filter(|m| m.pre_existing).count(),
-    //           codegen_results.modules.len());
-}
-
 pub enum WorkItem<B: WriteBackendMethods> {
     /// Optimize a newly codegened, totally unoptimized module.
     Optimize(ModuleCodegen<B::Module>),
@@ -1034,8 +1022,8 @@ fn start_executing_work<B: ExtraBackendMethods>(
         tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol)),
         total_cgus,
         msvc_imps_needed: msvc_imps_needed(tcx),
-        target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
-        target_arch: tcx.sess.target.target.arch.clone(),
+        target_pointer_width: tcx.sess.target.pointer_width,
+        target_arch: tcx.sess.target.arch.clone(),
         debuginfo: tcx.sess.opts.debuginfo,
     };
 
@@ -1175,7 +1163,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
     // necessary. There's already optimizations in place to avoid sending work
     // back to the coordinator if LTO isn't requested.
     return thread::spawn(move || {
-        let max_workers = ::num_cpus::get();
+        let max_workers = num_cpus::get();
         let mut worker_id_counter = 0;
         let mut free_worker_ids = Vec::new();
         let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| {
@@ -1531,8 +1519,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
     }
 }
 
-pub const CODEGEN_WORKER_ID: usize = usize::MAX;
-
 /// `FatalError` is explicitly not `Send`.
 #[must_use]
 pub struct WorkerFatalError;
@@ -1720,7 +1706,6 @@ impl SharedEmitterMain {
 pub struct OngoingCodegen<B: ExtraBackendMethods> {
     pub backend: B,
     pub crate_name: Symbol,
-    pub crate_hash: Svh,
     pub metadata: EncodedMetadata,
     pub windows_subsystem: Option<String>,
     pub linker_info: LinkerInfo,
@@ -1766,7 +1751,6 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
         (
             CodegenResults {
                 crate_name: self.crate_name,
-                crate_hash: self.crate_hash,
                 metadata: self.metadata,
                 windows_subsystem: self.windows_subsystem,
                 linker_info: self.linker_info,
@@ -1881,11 +1865,11 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool {
     // something is wrong with commandline arg validation.
     assert!(
         !(tcx.sess.opts.cg.linker_plugin_lto.enabled()
-            && tcx.sess.target.target.options.is_like_windows
+            && tcx.sess.target.options.is_like_windows
             && tcx.sess.opts.cg.prefer_dynamic)
     );
 
-    tcx.sess.target.target.options.is_like_windows &&
+    tcx.sess.target.options.is_like_windows &&
         tcx.sess.crate_types().iter().any(|ct| *ct == CrateType::Rlib) &&
     // ThinLTO can't handle this workaround in all cases, so we don't
     // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 8e6f8e193c0..4d937609132 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -327,7 +327,7 @@ fn cast_shift_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 /// currently uses SEH-ish unwinding with DWARF info tables to the side (same as
 /// 64-bit MinGW) instead of "full SEH".
 pub fn wants_msvc_seh(sess: &Session) -> bool {
-    sess.target.target.options.is_like_msvc
+    sess.target.options.is_like_msvc
 }
 
 pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
@@ -393,7 +393,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     ) -> Bx::Function {
         // The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
         // depending on whether the target needs `argc` and `argv` to be passed in.
-        let llfty = if cx.sess().target.target.options.main_needs_argc_argv {
+        let llfty = if cx.sess().target.options.main_needs_argc_argv {
             cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int())
         } else {
             cx.type_func(&[], cx.type_int())
@@ -464,7 +464,7 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     cx: &'a Bx::CodegenCx,
     bx: &mut Bx,
 ) -> (Bx::Value, Bx::Value) {
-    if cx.sess().target.target.options.main_needs_argc_argv {
+    if cx.sess().target.options.main_needs_argc_argv {
         // Params from native `main()` used as args for rust start function
         let param_argc = bx.get_param(0);
         let param_argv = bx.get_param(1);
@@ -479,8 +479,6 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     }
 }
 
-pub const CODEGEN_WORKER_ID: usize = usize::MAX;
-
 pub fn codegen_crate<B: ExtraBackendMethods>(
     backend: B,
     tcx: TyCtxt<'tcx>,
@@ -695,7 +693,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         total_codegen_time.into_inner(),
     );
 
-    ::rustc_incremental::assert_module_sources::assert_module_sources(tcx);
+    rustc_incremental::assert_module_sources::assert_module_sources(tcx);
 
     symbol_names_test::report_symbol_names(tcx);
 
@@ -754,8 +752,8 @@ impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> {
 }
 
 fn finalize_tcx(tcx: TyCtxt<'_>) {
-    tcx.sess.time("assert_dep_graph", || ::rustc_incremental::assert_dep_graph(tcx));
-    tcx.sess.time("serialize_dep_graph", || ::rustc_incremental::save_dep_graph(tcx));
+    tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx));
+    tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx));
 
     // We assume that no queries are run past here. If there are new queries
     // after this point, they'll show up as "<unknown>" in self-profiling data.
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 45ecb793387..c4c51d146a6 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -33,7 +33,7 @@ pub fn push_debuginfo_type_name<'tcx>(
 ) {
     // When targeting MSVC, emit C++ style type names for compatibility with
     // .natvis visualizers (and perhaps other existing native debuggers?)
-    let cpp_like_names = tcx.sess.target.target.options.is_like_msvc;
+    let cpp_like_names = tcx.sess.target.options.is_like_msvc;
 
     match *t.kind() {
         ty::Bool => output.push_str("bool"),
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index e34371ef59a..70b92b234e9 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -21,7 +21,6 @@ extern crate tracing;
 extern crate rustc_middle;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::LangItem;
@@ -134,7 +133,6 @@ pub struct CodegenResults {
     pub modules: Vec<CompiledModule>,
     pub allocator_module: Option<CompiledModule>,
     pub metadata_module: Option<CompiledModule>,
-    pub crate_hash: Svh,
     pub metadata: rustc_middle::middle::cstore::EncodedMetadata,
     pub windows_subsystem: Option<String>,
     pub linker_info: back::linker::LinkerInfo,
@@ -144,6 +142,7 @@ pub struct CodegenResults {
 pub fn provide(providers: &mut Providers) {
     crate::back::symbol_export::provide(providers);
     crate::base::provide_both(providers);
+    crate::target_features::provide(providers);
 }
 
 pub fn provide_extern(providers: &mut Providers) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 703a17b200a..a051ae25a9c 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -12,9 +12,9 @@ use crate::MemFlags;
 use rustc_ast as ast;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::vec::Idx;
-use rustc_middle::mir;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::mir::AssertKind;
+use rustc_middle::mir::{self, SwitchTargets};
 use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
@@ -24,8 +24,6 @@ use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
 use rustc_target::abi::{self, LayoutOf};
 use rustc_target::spec::abi::Abi;
 
-use std::borrow::Cow;
-
 /// Used by `FunctionCx::codegen_terminator` for emitting common patterns
 /// e.g., creating a basic block, calling a function, etc.
 struct TerminatorCodegenHelper<'tcx> {
@@ -198,42 +196,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         mut bx: Bx,
         discr: &mir::Operand<'tcx>,
         switch_ty: Ty<'tcx>,
-        values: &Cow<'tcx, [u128]>,
-        targets: &Vec<mir::BasicBlock>,
+        targets: &SwitchTargets,
     ) {
         let discr = self.codegen_operand(&mut bx, &discr);
         // `switch_ty` is redundant, sanity-check that.
         assert_eq!(discr.layout.ty, switch_ty);
-        if targets.len() == 2 {
-            // If there are two targets, emit br instead of switch
-            let lltrue = helper.llblock(self, targets[0]);
-            let llfalse = helper.llblock(self, targets[1]);
+        helper.maybe_sideeffect(self.mir, &mut bx, targets.all_targets());
+
+        let mut target_iter = targets.iter();
+        if target_iter.len() == 1 {
+            // If there are two targets (one conditional, one fallback), emit br instead of switch
+            let (test_value, target) = target_iter.next().unwrap();
+            let lltrue = helper.llblock(self, target);
+            let llfalse = helper.llblock(self, targets.otherwise());
             if switch_ty == bx.tcx().types.bool {
-                helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice());
                 // Don't generate trivial icmps when switching on bool
-                if let [0] = values[..] {
-                    bx.cond_br(discr.immediate(), llfalse, lltrue);
-                } else {
-                    assert_eq!(&values[..], &[1]);
-                    bx.cond_br(discr.immediate(), lltrue, llfalse);
+                match test_value {
+                    0 => bx.cond_br(discr.immediate(), llfalse, lltrue),
+                    1 => bx.cond_br(discr.immediate(), lltrue, llfalse),
+                    _ => bug!(),
                 }
             } else {
                 let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty));
-                let llval = bx.const_uint_big(switch_llty, values[0]);
+                let llval = bx.const_uint_big(switch_llty, test_value);
                 let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval);
-                helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice());
                 bx.cond_br(cmp, lltrue, llfalse);
             }
         } else {
-            helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice());
-            let (otherwise, targets) = targets.split_last().unwrap();
             bx.switch(
                 discr.immediate(),
-                helper.llblock(self, *otherwise),
-                values
-                    .iter()
-                    .zip(targets)
-                    .map(|(&value, target)| (value, helper.llblock(self, *target))),
+                helper.llblock(self, targets.otherwise()),
+                target_iter.map(|(value, target)| (value, helper.llblock(self, target))),
             );
         }
     }
@@ -879,7 +872,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         let string = match ty.kind() {
                             ty::Uint(_) => value.to_string(),
                             ty::Int(int_ty) => {
-                                match int_ty.normalize(bx.tcx().sess.target.ptr_width) {
+                                match int_ty.normalize(bx.tcx().sess.target.pointer_width) {
                                     ast::IntTy::I8 => (value as i8).to_string(),
                                     ast::IntTy::I16 => (value as i16).to_string(),
                                     ast::IntTy::I32 => (value as i32).to_string(),
@@ -975,8 +968,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 helper.funclet_br(self, &mut bx, target);
             }
 
-            mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
-                self.codegen_switchint_terminator(helper, bx, discr, switch_ty, values, targets);
+            mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => {
+                self.codegen_switchint_terminator(helper, bx, discr, switch_ty, targets);
             }
 
             mir::TerminatorKind::Return => {
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 14f1ed59a67..2bf1ee43c73 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -580,8 +580,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 // stuffs.
 fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> {
     match ty.kind() {
-        ty::Int(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), true)),
-        ty::Uint(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), false)),
+        ty::Int(t) => {
+            Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), true))
+        }
+        ty::Uint(t) => {
+            Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), false))
+        }
         _ => None,
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 91609b22615..e1cc0268723 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -346,8 +346,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
                 ..
             } => {
                 if variant_index != dataful_variant {
-                    if bx.cx().sess().target.target.arch == "arm"
-                        || bx.cx().sess().target.target.arch == "aarch64"
+                    if bx.cx().sess().target.arch == "arm"
+                        || bx.cx().sess().target.arch == "aarch64"
                     {
                         // FIXME(#34427): as workaround for LLVM bug on ARM,
                         // use memset of 0 before assigning niche value.
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 4c61e21901b..a8d88a95f7a 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,3 +1,5 @@
+use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_middle::ty::query::Providers;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::symbol::Symbol;
@@ -136,7 +138,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol
 }
 
 pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option<Symbol>)] {
-    match &*sess.target.target.arch {
+    match &*sess.target.arch {
         "arm" => ARM_ALLOWED_FEATURES,
         "aarch64" => AARCH64_ALLOWED_FEATURES,
         "x86" | "x86_64" => X86_ALLOWED_FEATURES,
@@ -148,3 +150,16 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt
         _ => &[],
     }
 }
+
+pub(crate) fn provide(providers: &mut Providers) {
+    providers.supported_target_features = |tcx, cnum| {
+        assert_eq!(cnum, LOCAL_CRATE);
+        if tcx.sess.opts.actually_rustdoc {
+            // rustdoc needs to be able to document functions that use all the features, so
+            // whitelist them all
+            all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
+        } else {
+            supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
+        }
+    };
+}
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 48c07b00894..3fb189e1984 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -1,10 +1,11 @@
 use super::write::WriteBackendMethods;
 use super::CodegenObject;
-use crate::ModuleCodegen;
+use crate::{CodegenResults, ModuleCodegen};
 
 use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorReported;
-use rustc_middle::dep_graph::DepGraph;
+use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
 use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout};
 use rustc_middle::ty::query::Providers;
@@ -80,8 +81,7 @@ pub trait CodegenBackend {
         &self,
         ongoing_codegen: Box<dyn Any>,
         sess: &Session,
-        dep_graph: &DepGraph,
-    ) -> Result<Box<dyn Any>, ErrorReported>;
+    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported>;
 
     /// This is called on the returned `Box<dyn Any>` from `join_codegen`
     ///
@@ -91,7 +91,7 @@ pub trait CodegenBackend {
     fn link(
         &self,
         sess: &Session,
-        codegen_results: Box<dyn Any>,
+        codegen_results: CodegenResults,
         outputs: &OutputFilenames,
     ) -> Result<(), ErrorReported>;
 }
@@ -124,4 +124,5 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
         opt_level: config::OptLevel,
     ) -> Arc<dyn Fn() -> Result<Self::TargetMachine, String> + Send + Sync>;
     fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str;
+    fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>;
 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs
index 698ef6083e6..82518b7f0c3 100644
--- a/compiler/rustc_codegen_ssa/src/traits/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs
@@ -85,7 +85,7 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where
 }
 
 pub trait HasCodegen<'tcx>:
-    Backend<'tcx> + ::std::ops::Deref<Target = <Self as HasCodegen<'tcx>>::CodegenCx>
+    Backend<'tcx> + std::ops::Deref<Target = <Self as HasCodegen<'tcx>>::CodegenCx>
 {
     type CodegenCx: CodegenMethods<'tcx>
         + BackendTypes<
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index cec07b977e6..43bc0c83155 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -51,7 +51,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
     }
 
     fn type_int(&self) -> Self::Type {
-        match &self.sess().target.target.target_c_int_width[..] {
+        match &self.sess().target.target_c_int_width[..] {
             "16" => self.type_i16(),
             "32" => self.type_i32(),
             "64" => self.type_i64(),
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index aba0bbbac80..ec2f9597b18 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -71,8 +71,8 @@ impl Fingerprint {
     }
 }
 
-impl ::std::fmt::Display for Fingerprint {
-    fn fmt(&self, formatter: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+impl std::fmt::Display for Fingerprint {
+    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(formatter, "{:x}-{:x}", self.0, self.1)
     }
 }
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 7cf5202d919..c0193e9fa0c 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -129,7 +129,7 @@ pub enum ProcessResult<O, E> {
 struct ObligationTreeId(usize);
 
 type ObligationTreeIdGenerator =
-    ::std::iter::Map<::std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>;
+    std::iter::Map<std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>;
 
 pub struct ObligationForest<O: ForestObligation> {
     /// The list of obligations. In between calls to `process_obligations`,
diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs
index 4807380595d..9a28f8f4e21 100644
--- a/compiler/rustc_data_structures/src/sorted_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map.rs
@@ -93,7 +93,7 @@ impl<K: Ord, V> SortedMap<K, V> {
 
     /// Iterate over elements, sorted by key
     #[inline]
-    pub fn iter(&self) -> ::std::slice::Iter<'_, (K, V)> {
+    pub fn iter(&self) -> std::slice::Iter<'_, (K, V)> {
         self.data.iter()
     }
 
@@ -134,7 +134,7 @@ impl<K: Ord, V> SortedMap<K, V> {
         R: RangeBounds<K>,
     {
         let (start, end) = self.range_slice_indices(range);
-        self.data.splice(start..end, ::std::iter::empty());
+        self.data.splice(start..end, std::iter::empty());
     }
 
     /// Mutate all keys with the given function `f`. This mutation must not
@@ -241,7 +241,7 @@ impl<K: Ord, V> SortedMap<K, V> {
 
 impl<K: Ord, V> IntoIterator for SortedMap<K, V> {
     type Item = (K, V);
-    type IntoIter = ::std::vec::IntoIter<(K, V)>;
+    type IntoIter = std::vec::IntoIter<(K, V)>;
 
     fn into_iter(self) -> Self::IntoIter {
         self.data.into_iter()
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 68875b3fbde..579eb1cb7da 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -20,7 +20,7 @@ pub struct StableHasher {
 }
 
 impl ::std::fmt::Debug for StableHasher {
-    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "{:?}", self.state)
     }
 }
diff --git a/compiler/rustc_data_structures/src/work_queue.rs b/compiler/rustc_data_structures/src/work_queue.rs
index 0c848eb144d..cc562bc1e4d 100644
--- a/compiler/rustc_data_structures/src/work_queue.rs
+++ b/compiler/rustc_data_structures/src/work_queue.rs
@@ -14,12 +14,6 @@ pub struct WorkQueue<T: Idx> {
 }
 
 impl<T: Idx> WorkQueue<T> {
-    /// Creates a new work queue with all the elements from (0..len).
-    #[inline]
-    pub fn with_all(len: usize) -> Self {
-        WorkQueue { deque: (0..len).map(T::new).collect(), set: BitSet::new_filled(len) }
-    }
-
     /// Creates a new work queue that starts empty, where elements range from (0..len).
     #[inline]
     pub fn with_none(len: usize) -> Self {
diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml
index f610e88b7fc..0adc006b624 100644
--- a/compiler/rustc_driver/Cargo.toml
+++ b/compiler/rustc_driver/Cargo.toml
@@ -10,7 +10,7 @@ crate-type = ["dylib"]
 [dependencies]
 libc = "0.2"
 tracing = { version = "0.1.18" }
-tracing-subscriber = { version = "0.2.10", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
+tracing-subscriber = { version = "0.2.13", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
 tracing-tree = "0.1.6"
 rustc_middle = { path = "../rustc_middle" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 3f50c68e3eb..d99e335a77a 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -134,9 +134,52 @@ pub fn diagnostics_registry() -> Registry {
     Registry::new(&rustc_error_codes::DIAGNOSTICS)
 }
 
+pub struct RunCompiler<'a, 'b> {
+    at_args: &'a [String],
+    callbacks: &'b mut (dyn Callbacks + Send),
+    file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
+    emitter: Option<Box<dyn Write + Send>>,
+    make_codegen_backend:
+        Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>,
+}
+
+impl<'a, 'b> RunCompiler<'a, 'b> {
+    pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self {
+        Self { at_args, callbacks, file_loader: None, emitter: None, make_codegen_backend: None }
+    }
+    pub fn set_make_codegen_backend(
+        &mut self,
+        make_codegen_backend: Option<
+            Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
+        >,
+    ) -> &mut Self {
+        self.make_codegen_backend = make_codegen_backend;
+        self
+    }
+    pub fn set_emitter(&mut self, emitter: Option<Box<dyn Write + Send>>) -> &mut Self {
+        self.emitter = emitter;
+        self
+    }
+    pub fn set_file_loader(
+        &mut self,
+        file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
+    ) -> &mut Self {
+        self.file_loader = file_loader;
+        self
+    }
+    pub fn run(self) -> interface::Result<()> {
+        run_compiler(
+            self.at_args,
+            self.callbacks,
+            self.file_loader,
+            self.emitter,
+            self.make_codegen_backend,
+        )
+    }
+}
 // Parse args and run the compiler. This is the primary entry point for rustc.
 // The FileLoader provides a way to load files from sources other than the file system.
-pub fn run_compiler(
+fn run_compiler(
     at_args: &[String],
     callbacks: &mut (dyn Callbacks + Send),
     file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
@@ -155,8 +198,7 @@ pub fn run_compiler(
             ),
         }
     }
-    let diagnostic_output =
-        emitter.map(|emitter| DiagnosticOutput::Raw(emitter)).unwrap_or(DiagnosticOutput::Default);
+    let diagnostic_output = emitter.map_or(DiagnosticOutput::Default, DiagnosticOutput::Raw);
     let matches = match handle_options(&args) {
         Some(matches) => matches,
         None => return Ok(()),
@@ -600,7 +642,7 @@ impl RustcDefaultCalls {
             let codegen_results: CodegenResults = json::decode(&rlink_data).unwrap_or_else(|err| {
                 sess.fatal(&format!("failed to decode rlink: {}", err));
             });
-            compiler.codegen_backend().link(&sess, Box::new(codegen_results), &outputs)
+            compiler.codegen_backend().link(&sess, codegen_results, &outputs)
         } else {
             sess.fatal("rlink must be a file")
         }
@@ -628,7 +670,7 @@ impl RustcDefaultCalls {
                 Input::File(ref ifile) => {
                     let path = &(*ifile);
                     let mut v = Vec::new();
-                    locator::list_file_metadata(&sess.target.target, path, metadata_loader, &mut v)
+                    locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v)
                         .unwrap();
                     println!("{}", String::from_utf8(v).unwrap());
                 }
@@ -672,7 +714,8 @@ impl RustcDefaultCalls {
         for req in &sess.opts.prints {
             match *req {
                 TargetList => {
-                    let mut targets = rustc_target::spec::get_targets().collect::<Vec<String>>();
+                    let mut targets =
+                        rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>();
                     targets.sort();
                     println!("{}", targets.join("\n"));
                 }
@@ -681,7 +724,7 @@ impl RustcDefaultCalls {
                     "{}",
                     sess.target_tlib_path.as_ref().unwrap_or(&sess.host_tlib_path).dir.display()
                 ),
-                TargetSpec => println!("{}", sess.target.target.to_json().pretty()),
+                TargetSpec => println!("{}", sess.target.to_json().pretty()),
                 FileNames | CrateName => {
                     let input = input.unwrap_or_else(|| {
                         early_error(ErrorOutputType::default(), "no input file provided")
@@ -1215,9 +1258,9 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     // If backtraces are enabled, also print the query stack
     let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false);
 
-    if backtrace {
-        TyCtxt::try_print_query_stack(&handler);
-    }
+    let num_frames = if backtrace { None } else { Some(2) };
+
+    TyCtxt::try_print_query_stack(&handler, num_frames);
 
     #[cfg(windows)]
     unsafe {
@@ -1285,7 +1328,7 @@ pub fn main() -> ! {
                 })
             })
             .collect::<Vec<_>>();
-        run_compiler(&args, &mut callbacks, None, None, None)
+        RunCompiler::new(&args, &mut callbacks).run()
     });
     // The extra `\t` is necessary to align this label with the others.
     print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed());
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 981b5bb8ba7..0a88759f84c 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -460,6 +460,8 @@ E0774: include_str!("./error_codes/E0774.md"),
 E0775: include_str!("./error_codes/E0775.md"),
 E0776: include_str!("./error_codes/E0776.md"),
 E0777: include_str!("./error_codes/E0777.md"),
+E0778: include_str!("./error_codes/E0778.md"),
+E0779: include_str!("./error_codes/E0779.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
diff --git a/compiler/rustc_error_codes/src/error_codes/E0007.md b/compiler/rustc_error_codes/src/error_codes/E0007.md
index 2be7870d5ae..2c22b86af92 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0007.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0007.md
@@ -1,3 +1,5 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 This error indicates that the bindings in a match arm would require a value to
 be moved into more than one location, thus violating unique ownership. Code
 like the following is invalid as it requires the entire `Option<String>` to be
@@ -6,11 +8,13 @@ inner `String` to be moved into a variable called `s`.
 
 Erroneous code example:
 
-```compile_fail,E0007
+```compile_fail,E0382
+#![feature(bindings_after_at)]
+
 let x = Some("s".to_string());
 
 match x {
-    op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings
+    op_string @ Some(s) => {}, // error: use of moved value
     None => {},
 }
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0424.md b/compiler/rustc_error_codes/src/error_codes/E0424.md
index a9f6f579b42..a58c16b59e9 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0424.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0424.md
@@ -21,7 +21,7 @@ impl Foo {
 The `self` keyword can only be used inside methods, which are associated
 functions (functions defined inside of a `trait` or `impl` block) that have a
 `self` receiver as its first parameter, like `self`, `&self`, `&mut self` or
-`self: &mut Pin<Self>` (this last one is an example of an ["abitrary `self`
+`self: &mut Pin<Self>` (this last one is an example of an ["arbitrary `self`
 type"](https://github.com/rust-lang/rust/issues/44874)).
 
 Check if the associated function's parameter list should have contained a `self`
diff --git a/compiler/rustc_error_codes/src/error_codes/E0723.md b/compiler/rustc_error_codes/src/error_codes/E0723.md
index 95d47ab21cb..bc224421915 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0723.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0723.md
@@ -3,12 +3,8 @@ An unstable feature in `const` contexts was used.
 Erroneous code example:
 
 ```compile_fail,E0723
-trait T {}
-
-impl T for () {}
-
-const fn foo() -> impl T { // error: `impl Trait` in const fn is unstable
-    ()
+const fn foo<T: Copy>(_: T) { // error!
+   // ...
 }
 ```
 
@@ -18,11 +14,7 @@ feature flag:
 ```
 #![feature(const_fn)]
 
-trait T {}
-
-impl T for () {}
-
-const fn foo() -> impl T {
-    ()
+const fn foo<T: Copy>(_: T) { // ok!
+   // ...
 }
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0778.md b/compiler/rustc_error_codes/src/error_codes/E0778.md
new file mode 100644
index 00000000000..467362dca58
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0778.md
@@ -0,0 +1,35 @@
+The `instruction_set` attribute was malformed.
+
+Erroneous code example:
+
+```compile_fail,E0778
+#![feature(isa_attribute)]
+
+#[instruction_set()] // error: expected one argument
+pub fn something() {}
+fn main() {}
+```
+
+The parenthesized `instruction_set` attribute requires the parameter to be
+specified:
+
+```
+#![feature(isa_attribute)]
+
+#[cfg_attr(target_arch="arm", instruction_set(arm::a32))]
+fn something() {}
+```
+
+or:
+
+```
+#![feature(isa_attribute)]
+
+#[cfg_attr(target_arch="arm", instruction_set(arm::t32))]
+fn something() {}
+```
+
+For more information see the [`instruction_set` attribute][isa-attribute]
+section of the Reference.
+
+[isa-attribute]: https://doc.rust-lang.org/reference/attributes/codegen.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0779.md b/compiler/rustc_error_codes/src/error_codes/E0779.md
new file mode 100644
index 00000000000..146e20c2626
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0779.md
@@ -0,0 +1,32 @@
+An unknown argument was given to the `instruction_set` attribute.
+
+Erroneous code example:
+
+```compile_fail,E0779
+#![feature(isa_attribute)]
+
+#[instruction_set(intel::x64)] // error: invalid argument
+pub fn something() {}
+fn main() {}
+```
+
+The `instruction_set` attribute only supports two arguments currently:
+
+ * arm::a32
+ * arm::t32
+
+All other arguments given to the `instruction_set` attribute will return this
+error. Example:
+
+```
+#![feature(isa_attribute)]
+
+#[cfg_attr(target_arch="arm", instruction_set(arm::a32))] // ok!
+pub fn something() {}
+fn main() {}
+```
+
+For more information see the [`instruction_set` attribute][isa-attribute]
+section of the Reference.
+
+[isa-attribute]: https://doc.rust-lang.org/reference/attributes/codegen.html
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 870f7b81e21..91bfc6296b1 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -121,11 +121,6 @@ impl Diagnostic {
         self.level == Level::Cancelled
     }
 
-    /// Set the sorting span.
-    pub fn set_sort_span(&mut self, sp: Span) {
-        self.sort_span = sp;
-    }
-
     /// Adds a span/label to be included in the resulting snippet.
     ///
     /// This is pushed onto the [`MultiSpan`] that was created when the diagnostic
@@ -535,14 +530,6 @@ impl Diagnostic {
         &self.message
     }
 
-    /// Used by a lint. Copies over all details *but* the "main
-    /// message".
-    pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
-        self.span = from.span.clone();
-        self.code = from.code.clone();
-        self.children.extend(from.children.iter().cloned())
-    }
-
     /// Convenience function for internal use, clients should use one of the
     /// public methods above.
     pub fn sub(
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 98cbf98df92..b5155f8e910 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -510,8 +510,6 @@ impl Emitter for SilentEmitter {
     fn emit_diagnostic(&mut self, _: &Diagnostic) {}
 }
 
-/// Maximum number of lines we will print for each error; arbitrary.
-pub const MAX_HIGHLIGHT_LINES: usize = 6;
 /// Maximum number of lines we will print for a multiline suggestion; arbitrary.
 ///
 /// This should be replaced with a more involved mechanism to output multiline suggestions that
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index f7651ca0ba6..b0e43a260e9 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -148,17 +148,6 @@ impl Annotatable {
         }
     }
 
-    pub fn map_item_or<F, G>(self, mut f: F, mut or: G) -> Annotatable
-    where
-        F: FnMut(P<ast::Item>) -> P<ast::Item>,
-        G: FnMut(Annotatable) -> Annotatable,
-    {
-        match self {
-            Annotatable::Item(i) => Annotatable::Item(f(i)),
-            _ => or(self),
-        }
-    }
-
     pub fn expect_trait_item(self) -> P<ast::AssocItem> {
         match self {
             Annotatable::TraitItem(i) => i,
@@ -1052,9 +1041,6 @@ impl<'a> ExtCtxt<'a> {
             .chain(components.iter().map(|&s| Ident::with_dummy_span(s)))
             .collect()
     }
-    pub fn name_of(&self, st: &str) -> Symbol {
-        Symbol::intern(st)
-    }
 
     pub fn check_unused_macros(&mut self) {
         self.resolver.check_unused_macros();
diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs
index a5a7ee6c9a3..1c9bfb902d6 100644
--- a/compiler/rustc_expand/src/build.rs
+++ b/compiler/rustc_expand/src/build.rs
@@ -139,24 +139,6 @@ impl<'a> ExtCtxt<'a> {
         ast::Lifetime { id: ast::DUMMY_NODE_ID, ident: ident.with_span_pos(span) }
     }
 
-    pub fn lifetime_def(
-        &self,
-        span: Span,
-        ident: Ident,
-        attrs: Vec<ast::Attribute>,
-        bounds: ast::GenericBounds,
-    ) -> ast::GenericParam {
-        let lifetime = self.lifetime(span, ident);
-        ast::GenericParam {
-            ident: lifetime.ident,
-            id: lifetime.id,
-            attrs: attrs.into(),
-            bounds,
-            kind: ast::GenericParamKind::Lifetime,
-            is_placeholder: false,
-        }
-    }
-
     pub fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt {
         ast::Stmt {
             id: ast::DUMMY_NODE_ID,
@@ -465,24 +447,6 @@ impl<'a> ExtCtxt<'a> {
         self.pat_tuple_struct(span, path, vec![pat])
     }
 
-    pub fn pat_none(&self, span: Span) -> P<ast::Pat> {
-        let some = self.std_path(&[sym::option, sym::Option, sym::None]);
-        let path = self.path_global(span, some);
-        self.pat_path(span, path)
-    }
-
-    pub fn pat_ok(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
-        let some = self.std_path(&[sym::result, sym::Result, sym::Ok]);
-        let path = self.path_global(span, some);
-        self.pat_tuple_struct(span, path, vec![pat])
-    }
-
-    pub fn pat_err(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
-        let some = self.std_path(&[sym::result, sym::Result, sym::Err]);
-        let path = self.path_global(span, some);
-        self.pat_tuple_struct(span, path, vec![pat])
-    }
-
     pub fn arm(&self, span: Span, pat: P<ast::Pat>, expr: P<ast::Expr>) -> ast::Arm {
         ast::Arm {
             attrs: vec![],
@@ -514,26 +478,6 @@ impl<'a> ExtCtxt<'a> {
         self.expr(span, ast::ExprKind::If(cond, self.block_expr(then), els))
     }
 
-    pub fn lambda_fn_decl(
-        &self,
-        span: Span,
-        fn_decl: P<ast::FnDecl>,
-        body: P<ast::Expr>,
-        fn_decl_span: Span,
-    ) -> P<ast::Expr> {
-        self.expr(
-            span,
-            ast::ExprKind::Closure(
-                ast::CaptureBy::Ref,
-                ast::Async::No,
-                ast::Movability::Movable,
-                fn_decl,
-                body,
-                fn_decl_span,
-            ),
-        )
-    }
-
     pub fn lambda(&self, span: Span, ids: Vec<Ident>, body: P<ast::Expr>) -> P<ast::Expr> {
         let fn_decl = self.fn_decl(
             ids.iter().map(|id| self.param(span, *id, self.ty(span, ast::TyKind::Infer))).collect(),
@@ -610,47 +554,6 @@ impl<'a> ExtCtxt<'a> {
         })
     }
 
-    pub fn variant(&self, span: Span, ident: Ident, tys: Vec<P<ast::Ty>>) -> ast::Variant {
-        let vis_span = span.shrink_to_lo();
-        let fields: Vec<_> = tys
-            .into_iter()
-            .map(|ty| ast::StructField {
-                span: ty.span,
-                ty,
-                ident: None,
-                vis: ast::Visibility {
-                    span: vis_span,
-                    kind: ast::VisibilityKind::Inherited,
-                    tokens: None,
-                },
-                attrs: Vec::new(),
-                id: ast::DUMMY_NODE_ID,
-                is_placeholder: false,
-            })
-            .collect();
-
-        let vdata = if fields.is_empty() {
-            ast::VariantData::Unit(ast::DUMMY_NODE_ID)
-        } else {
-            ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID)
-        };
-
-        ast::Variant {
-            attrs: Vec::new(),
-            data: vdata,
-            disr_expr: None,
-            id: ast::DUMMY_NODE_ID,
-            ident,
-            vis: ast::Visibility {
-                span: vis_span,
-                kind: ast::VisibilityKind::Inherited,
-                tokens: None,
-            },
-            span,
-            is_placeholder: false,
-        }
-    }
-
     pub fn item_static(
         &self,
         span: Span,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index c6287693dc9..0b43225a242 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -20,7 +20,7 @@ use rustc_data_structures::map_in_place::MapInPlace;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{struct_span_err, Applicability, PResult};
 use rustc_feature::Features;
-use rustc_parse::parser::Parser;
+use rustc_parse::parser::{AttemptLocalParseRecovery, Parser};
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
 use rustc_session::lint::BuiltinLintDiagnostics;
@@ -921,7 +921,7 @@ pub fn parse_ast_fragment<'a>(
             let mut stmts = SmallVec::new();
             // Won't make progress on a `}`.
             while this.token != token::Eof && this.token != token::CloseDelim(token::Brace) {
-                if let Some(stmt) = this.parse_full_stmt()? {
+                if let Some(stmt) = this.parse_full_stmt(AttemptLocalParseRecovery::Yes)? {
                     stmts.push(stmt);
                 }
             }
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index e2492efb9d7..4401ec0a04e 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -270,6 +270,9 @@ declare_features! (
     (accepted, track_caller, "1.46.0", Some(47809), None),
     /// Allows `#[doc(alias = "...")]`.
     (accepted, doc_alias, "1.48.0", Some(50146), None),
+    /// Allows patterns with concurrent by-move and by-ref bindings.
+    /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
+    (accepted, move_ref_pattern, "1.48.0", Some(68354), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index cd018ae1204..7fbd070a609 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -526,10 +526,6 @@ declare_features! (
     /// For example, you can write `x @ Some(y)`.
     (active, bindings_after_at, "1.41.0", Some(65490), None),
 
-    /// Allows patterns with concurrent by-move and by-ref bindings.
-    /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
-    (active, move_ref_pattern, "1.42.0", Some(68354), None),
-
     /// Allows `impl const Trait for T` syntax.
     (active, const_trait_impl, "1.42.0", Some(67792), None),
 
@@ -596,6 +592,12 @@ declare_features! (
     /// Allows rustc to inject a default alloc_error_handler
     (active, default_alloc_error_handler, "1.48.0", Some(66741), None),
 
+    /// Allows argument and return position `impl Trait` in a `const fn`.
+    (active, const_impl_trait, "1.48.0", Some(77463), None),
+
+    /// Allows `#[instruction_set(_)]` attribute
+    (active, isa_attribute, "1.48.0", Some(74727), 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 b7e113e6010..527a49b0538 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -336,6 +336,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         optimize, AssumedUsed, template!(List: "size|speed"), optimize_attribute,
         experimental!(optimize),
     ),
+    // RFC 2867
+    gated!(instruction_set, AssumedUsed, template!(List: "set"), isa_attribute, experimental!(instruction_set)),
 
     gated!(ffi_returns_twice, AssumedUsed, template!(Word), experimental!(ffi_returns_twice)),
     gated!(ffi_pure, AssumedUsed, template!(Word), experimental!(ffi_pure)),
diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs
index 289b9f30c3b..7742961e65d 100644
--- a/compiler/rustc_fs_util/src/lib.rs
+++ b/compiler/rustc_fs_util/src/lib.rs
@@ -75,33 +75,6 @@ pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<Li
     }
 }
 
-#[derive(Debug)]
-pub enum RenameOrCopyRemove {
-    Rename,
-    CopyRemove,
-}
-
-/// Rename `p` into `q`, preferring to use `rename` if possible.
-/// If `rename` fails (rename may fail for reasons such as crossing
-/// filesystem), fallback to copy & remove
-pub fn rename_or_copy_remove<P: AsRef<Path>, Q: AsRef<Path>>(
-    p: P,
-    q: Q,
-) -> io::Result<RenameOrCopyRemove> {
-    let p = p.as_ref();
-    let q = q.as_ref();
-    match fs::rename(p, q) {
-        Ok(()) => Ok(RenameOrCopyRemove::Rename),
-        Err(_) => match fs::copy(p, q) {
-            Ok(_) => {
-                fs::remove_file(p)?;
-                Ok(RenameOrCopyRemove::CopyRemove)
-            }
-            Err(e) => Err(e),
-        },
-    }
-}
-
 #[cfg(unix)]
 pub fn path_to_c_string(p: &Path) -> CString {
     use std::ffi::OsStr;
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index afefde07f92..3f109376a3e 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -118,7 +118,7 @@ impl DefKey {
 
         let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data;
 
-        ::std::mem::discriminant(data).hash(&mut hasher);
+        std::mem::discriminant(data).hash(&mut hasher);
         if let Some(name) = data.get_opt_name() {
             // Get a stable hash by considering the symbol chars rather than
             // the symbol index.
@@ -188,10 +188,6 @@ pub struct DefPath {
 }
 
 impl DefPath {
-    pub fn is_local(&self) -> bool {
-        self.krate == LOCAL_CRATE
-    }
-
     pub fn make<FN>(krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath
     where
         FN: FnMut(DefIndex) -> DefKey,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 636f67a77c8..52727e3a619 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3,7 +3,6 @@ use crate::def_id::DefId;
 crate use crate::hir_id::HirId;
 use crate::{itemlikevisit, LangItem};
 
-use rustc_ast::node_id::NodeMap;
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect};
 use rustc_ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy};
@@ -306,10 +305,6 @@ impl GenericArgs<'_> {
         Self { args: &[], bindings: &[], parenthesized: false }
     }
 
-    pub fn is_empty(&self) -> bool {
-        self.args.is_empty() && self.bindings.is_empty() && !self.parenthesized
-    }
-
     pub fn inputs(&self) -> &[Ty<'_>] {
         if self.parenthesized {
             for arg in self.args {
@@ -467,23 +462,6 @@ impl Generics<'hir> {
         }
     }
 
-    pub fn own_counts(&self) -> GenericParamCount {
-        // We could cache this as a property of `GenericParamCount`, but
-        // the aim is to refactor this away entirely eventually and the
-        // presence of this method will be a constant reminder.
-        let mut own_counts: GenericParamCount = Default::default();
-
-        for param in self.params {
-            match param.kind {
-                GenericParamKind::Lifetime { .. } => own_counts.lifetimes += 1,
-                GenericParamKind::Type { .. } => own_counts.types += 1,
-                GenericParamKind::Const { .. } => own_counts.consts += 1,
-            };
-        }
-
-        own_counts
-    }
-
     pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'_>> {
         for param in self.params {
             if name == param.name.ident().name {
@@ -2679,8 +2657,6 @@ pub struct Upvar {
     pub span: Span,
 }
 
-pub type CaptureModeMap = NodeMap<CaptureBy>;
-
 // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
 // has length > 0 if the trait is found through an chain of imports, starting with the
 // import/use statement in the scope where the trait is used.
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index fea850c12d9..cc8ac4cf5be 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -45,5 +45,3 @@ pub const CRATE_HIR_ID: HirId = HirId {
     owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
     local_id: ItemLocalId::from_u32(0),
 };
-
-pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId::MAX;
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index 2f1b5da8e13..c05d3e44423 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -58,25 +58,6 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T {
 }
 
 impl hir::Pat<'_> {
-    pub fn is_refutable(&self) -> bool {
-        match self.kind {
-            PatKind::Lit(_)
-            | PatKind::Range(..)
-            | PatKind::Path(hir::QPath::Resolved(Some(..), _) | hir::QPath::TypeRelative(..)) => {
-                true
-            }
-
-            PatKind::Path(hir::QPath::Resolved(_, ref path))
-            | PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..)
-            | PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => match path.res {
-                Res::Def(DefKind::Variant, _) => true,
-                _ => false,
-            },
-            PatKind::Slice(..) => true,
-            _ => false,
-        }
-    }
-
     /// Call `f` on every "binding" in a pattern, e.g., on `a` in
     /// `match foo() { Some(a) => (), None => () }`
     pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, Ident)) {
@@ -117,15 +98,6 @@ impl hir::Pat<'_> {
         })
     }
 
-    /// Checks if the pattern contains any patterns that bind something to
-    /// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`,
-    pub fn contains_bindings_or_wild(&self) -> bool {
-        self.satisfies(|p| match p.kind {
-            PatKind::Binding(..) | PatKind::Wild => true,
-            _ => false,
-        })
-    }
-
     /// Checks if the pattern satisfies the given predicate on some sub-pattern.
     fn satisfies(&self, pred: impl Fn(&hir::Pat<'_>) -> bool) -> bool {
         let mut satisfies = false;
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index f6e4b1fb418..57a38adc169 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -44,9 +44,6 @@ pub trait PpAnn {
     fn nested(&self, _state: &mut State<'_>, _nested: Nested) {}
     fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
     fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
-    fn try_fetch_item(&self, _: hir::HirId) -> Option<&hir::Item<'_>> {
-        None
-    }
 }
 
 pub struct NoAnn;
@@ -54,9 +51,6 @@ impl PpAnn for NoAnn {}
 pub const NO_ANN: &dyn PpAnn = &NoAnn;
 
 impl PpAnn for hir::Crate<'_> {
-    fn try_fetch_item(&self, item: hir::HirId) -> Option<&hir::Item<'_>> {
-        Some(self.item(item))
-    }
     fn nested(&self, state: &mut State<'_>, nested: Nested) {
         match nested {
             Nested::Item(id) => state.print_item(self.item(id.id)),
@@ -141,6 +135,9 @@ impl std::ops::DerefMut for State<'_> {
 }
 
 impl<'a> PrintState<'a> for State<'a> {
+    fn insert_extra_parens(&self) -> bool {
+        true
+    }
     fn comments(&mut self) -> &mut Option<Comments<'a>> {
         &mut self.comments
     }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 9742f5e2346..ff7bbf0562f 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -113,13 +113,6 @@ impl Default for RegionckMode {
 }
 
 impl RegionckMode {
-    pub fn suppressed(self) -> bool {
-        match self {
-            Self::Solve => false,
-            Self::Erase { suppress_errors } => suppress_errors,
-        }
-    }
-
     /// Indicates that the MIR borrowck will repeat these region
     /// checks, so we should ignore errors if NLL is (unconditionally)
     /// enabled.
@@ -420,15 +413,6 @@ pub enum SubregionOrigin<'tcx> {
 #[cfg(target_arch = "x86_64")]
 static_assert_size!(SubregionOrigin<'_>, 32);
 
-/// Places that type/region parameters can appear.
-#[derive(Clone, Copy, Debug)]
-pub enum ParameterOrigin {
-    Path,               // foo::bar
-    MethodCall,         // foo.bar() <-- parameters on impl providing bar()
-    OverloadedOperator, // a + b when overloaded
-    OverloadedDeref,    // *a when overloaded
-}
-
 /// Times when we replace late-bound regions with variables:
 #[derive(Clone, Copy, Debug)]
 pub enum LateBoundRegionConversionTime {
@@ -508,21 +492,6 @@ pub enum NLLRegionVariableOrigin {
     },
 }
 
-impl NLLRegionVariableOrigin {
-    pub fn is_universal(self) -> bool {
-        match self {
-            NLLRegionVariableOrigin::FreeRegion => true,
-            NLLRegionVariableOrigin::Placeholder(..) => true,
-            NLLRegionVariableOrigin::Existential { .. } => false,
-            NLLRegionVariableOrigin::RootEmptyRegion => false,
-        }
-    }
-
-    pub fn is_existential(self) -> bool {
-        !self.is_universal()
-    }
-}
-
 // FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`.
 #[derive(Copy, Clone, Debug)]
 pub enum FixupError<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 839891f322c..2fb9f638e36 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -28,7 +28,6 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::subst::GenericArg;
 use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
 use std::fmt::Debug;
 
@@ -119,12 +118,6 @@ pub trait TypeRelatingDelegate<'tcx> {
     fn forbid_inference_vars() -> bool;
 }
 
-#[derive(Clone, Debug)]
-struct ScopesAndKind<'tcx> {
-    scopes: Vec<BoundRegionScope<'tcx>>,
-    kind: GenericArg<'tcx>,
-}
-
 #[derive(Clone, Debug, Default)]
 struct BoundRegionScope<'tcx> {
     map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
@@ -341,7 +334,7 @@ where
         // been fully instantiated and hence the set of scopes we have
         // doesn't matter -- just to be sure, put an empty vector
         // in there.
-        let old_a_scopes = ::std::mem::take(pair.vid_scopes(self));
+        let old_a_scopes = std::mem::take(pair.vid_scopes(self));
 
         // Relate the generalized kind to the original one.
         let result = pair.relate_generalized_ty(self, generalized_ty);
@@ -680,7 +673,7 @@ where
             //   itself occurs. Note that `'b` and `'c` must both
             //   include P. At the point, the call works because of
             //   subtyping (i.e., `&'b u32 <: &{P} u32`).
-            let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
+            let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant);
 
             self.relate(a.skip_binder(), b.skip_binder())?;
 
@@ -709,7 +702,7 @@ where
             // Reset ambient variance to contravariance. See the
             // covariant case above for an explanation.
             let variance =
-                ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
+                std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant);
 
             self.relate(a.skip_binder(), b.skip_binder())?;
 
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 2851da89ab2..eb1a7806256 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -110,7 +110,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
 
     /// Trait queries just want to pass back type obligations "as is"
     pub fn take_registered_region_obligations(&self) -> Vec<(hir::HirId, RegionObligation<'tcx>)> {
-        ::std::mem::take(&mut self.inner.borrow_mut().region_obligations)
+        std::mem::take(&mut self.inner.borrow_mut().region_obligations)
     }
 
     /// Process the region obligations that must be proven (during
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index a3c4920fa8a..aaf5e958c26 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -59,9 +59,7 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
 #[cfg(target_arch = "x86_64")]
 static_assert_size!(PredicateObligation<'_>, 32);
 
-pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
 pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
-pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;
 
 pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>;
 
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 66d3765d347..d9c24cc3994 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -551,6 +551,10 @@ fn write_out_deps(
             .map(|fmap| escape_dep_filename(&fmap.unmapped_path.as_ref().unwrap_or(&fmap.name)))
             .collect();
 
+        if let Some(ref backend) = sess.opts.debugging_opts.codegen_backend {
+            files.push(backend.to_string());
+        }
+
         if sess.binary_dep_depinfo() {
             boxed_resolver.borrow().borrow_mut().access(|resolver| {
                 for cnum in resolver.cstore().crates_untracked() {
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 8b82217a91a..1de7350a3e2 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -3,6 +3,7 @@ use crate::passes::{self, BoxedResolver, QueryContext};
 
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
+use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::LOCAL_CRATE;
@@ -13,7 +14,8 @@ use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::ty::steal::Steal;
 use rustc_middle::ty::{GlobalCtxt, ResolverOutputs, TyCtxt};
-use rustc_session::config::{OutputFilenames, OutputType};
+use rustc_serialize::json;
+use rustc_session::config::{self, OutputFilenames, OutputType};
 use rustc_session::{output::find_crate_name, Session};
 use rustc_span::symbol::sym;
 use std::any::Any;
@@ -331,6 +333,7 @@ impl<'tcx> Queries<'tcx> {
     pub fn linker(&'tcx self) -> Result<Linker> {
         let dep_graph = self.dep_graph()?;
         let prepare_outputs = self.prepare_outputs()?;
+        let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE));
         let ongoing_codegen = self.ongoing_codegen()?;
 
         let sess = self.session().clone();
@@ -340,6 +343,7 @@ impl<'tcx> Queries<'tcx> {
             sess,
             dep_graph: dep_graph.peek().clone(),
             prepare_outputs: prepare_outputs.take(),
+            crate_hash,
             ongoing_codegen: ongoing_codegen.take(),
             codegen_backend,
         })
@@ -350,18 +354,31 @@ pub struct Linker {
     sess: Lrc<Session>,
     dep_graph: DepGraph,
     prepare_outputs: OutputFilenames,
+    crate_hash: Svh,
     ongoing_codegen: Box<dyn Any>,
     codegen_backend: Lrc<Box<dyn CodegenBackend>>,
 }
 
 impl Linker {
     pub fn link(self) -> Result<()> {
-        let codegen_results =
-            self.codegen_backend.join_codegen(self.ongoing_codegen, &self.sess, &self.dep_graph)?;
-        let prof = self.sess.prof.clone();
+        let (codegen_results, work_products) =
+            self.codegen_backend.join_codegen(self.ongoing_codegen, &self.sess)?;
+
+        self.sess.compile_status()?;
+
+        let sess = &self.sess;
         let dep_graph = self.dep_graph;
+        sess.time("serialize_work_products", || {
+            rustc_incremental::save_work_product_index(&sess, &dep_graph, work_products)
+        });
+
+        let prof = self.sess.prof.clone();
         prof.generic_activity("drop_dep_graph").run(move || drop(dep_graph));
 
+        // Now that we won't touch anything in the incremental compilation directory
+        // any more, we can finalize it (which involves renaming it)
+        rustc_incremental::finalize_session_directory(&self.sess, self.crate_hash);
+
         if !self
             .sess
             .opts
@@ -371,6 +388,19 @@ impl Linker {
         {
             return Ok(());
         }
+
+        if sess.opts.debugging_opts.no_link {
+            // FIXME: use a binary format to encode the `.rlink` file
+            let rlink_data = json::encode(&codegen_results).map_err(|err| {
+                sess.fatal(&format!("failed to encode rlink: {}", err));
+            })?;
+            let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT);
+            std::fs::write(&rlink_file, rlink_data).map_err(|err| {
+                sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err));
+            })?;
+            return Ok(());
+        }
+
         self.codegen_backend.link(&self.sess, codegen_results, &self.prepare_outputs)
     }
 }
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 07ce9d0cd94..6553d0ecfdb 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -585,6 +585,7 @@ fn test_debugging_options_tracking_hash() {
     tracked!(symbol_mangling_version, SymbolManglingVersion::V0);
     tracked!(teach, true);
     tracked!(thinlto, Some(true));
+    tracked!(tune_cpu, Some(String::from("abc")));
     tracked!(tls_model, Some(TlsModel::GeneralDynamic));
     tracked!(treat_err_as_bug, Some(1));
     tracked!(unleash_the_miri_inside_of_you, true);
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 7ace707cc88..c1b359c7d0d 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -187,7 +187,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
         config = config.stack_size(size);
     }
 
-    let with_pool = move |pool: &rayon::ThreadPool| pool.install(move || f());
+    let with_pool = move |pool: &rayon::ThreadPool| pool.install(f);
 
     rustc_span::with_session_globals(edition, || {
         rustc_span::SESSION_GLOBALS.with(|session_globals| {
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index d784a86f14c..c5b59a041ab 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -48,6 +48,7 @@ impl Token {
 }
 
 /// Enum representing common lexeme types.
+// perf note: Changing all `usize` to `u32` doesn't change performance. See #77629
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub enum TokenKind {
     // Multi-char tokens:
@@ -160,6 +161,7 @@ pub enum LiteralKind {
 /// - `r##~"abcde"##`: `InvalidStarter`
 /// - `r###"abcde"##`: `NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)`
 /// - Too many `#`s (>65535): `TooManyDelimiters`
+// perf note: It doesn't matter that this makes `Token` 36 bytes bigger. See #77629
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub enum RawStrError {
     /// Non `#` characters exist between `r` and `"` eg. `r#~"..`
@@ -689,7 +691,12 @@ impl Cursor<'_> {
         let mut max_hashes = 0;
 
         // Count opening '#' symbols.
-        let n_start_hashes = self.eat_while(|c| c == '#');
+        let mut eaten = 0;
+        while self.first() == '#' {
+            eaten += 1;
+            self.bump();
+        }
+        let n_start_hashes = eaten;
 
         // Check that string is started.
         match self.bump() {
@@ -724,16 +731,11 @@ impl Cursor<'_> {
             // Note that this will not consume extra trailing `#` characters:
             // `r###"abcde"####` is lexed as a `RawStr { n_hashes: 3 }`
             // followed by a `#` token.
-            let mut hashes_left = n_start_hashes;
-            let is_closing_hash = |c| {
-                if c == '#' && hashes_left != 0 {
-                    hashes_left -= 1;
-                    true
-                } else {
-                    false
-                }
-            };
-            let n_end_hashes = self.eat_while(is_closing_hash);
+            let mut n_end_hashes = 0;
+            while self.first() == '#' && n_end_hashes < n_start_hashes {
+                n_end_hashes += 1;
+                self.bump();
+            }
 
             if n_end_hashes == n_start_hashes {
                 return (n_start_hashes, None);
@@ -807,17 +809,9 @@ impl Cursor<'_> {
     }
 
     /// Eats symbols while predicate returns true or until the end of file is reached.
-    /// Returns amount of eaten symbols.
-    fn eat_while<F>(&mut self, mut predicate: F) -> usize
-    where
-        F: FnMut(char) -> bool,
-    {
-        let mut eaten: usize = 0;
+    fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) {
         while predicate(self.first()) && !self.is_eof() {
-            eaten += 1;
             self.bump();
         }
-
-        eaten
     }
 }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 7a3035e5b46..48270eb59a0 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -711,10 +711,6 @@ impl<'tcx> LateContext<'tcx> {
         }
     }
 
-    pub fn current_lint_root(&self) -> hir::HirId {
-        self.last_node_with_lint_attrs
-    }
-
     /// Check if a `DefId`'s path matches the given absolute type path usage.
     ///
     /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`;
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 49e80f9d8a5..1db59bfc39d 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -64,8 +64,8 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::{
     BARE_TRAIT_OBJECTS, BROKEN_INTRA_DOC_LINKS, ELIDED_LIFETIMES_IN_PATHS,
-    EXPLICIT_OUTLIVES_REQUIREMENTS, INVALID_CODEBLOCK_ATTRIBUTES, MISSING_DOC_CODE_EXAMPLES,
-    PRIVATE_DOC_TESTS,
+    EXPLICIT_OUTLIVES_REQUIREMENTS, INVALID_CODEBLOCK_ATTRIBUTES, INVALID_HTML_TAGS,
+    MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS,
 };
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
@@ -311,7 +311,8 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
         PRIVATE_INTRA_DOC_LINKS,
         INVALID_CODEBLOCK_ATTRIBUTES,
         MISSING_DOC_CODE_EXAMPLES,
-        PRIVATE_DOC_TESTS
+        PRIVATE_DOC_TESTS,
+        INVALID_HTML_TAGS
     );
 
     // Register renamed and removed lints.
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 9925444b869..af14f28ff9f 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -304,7 +304,7 @@ fn lint_int_literal<'tcx>(
     t: ast::IntTy,
     v: u128,
 ) {
-    let int_type = t.normalize(cx.sess().target.ptr_width);
+    let int_type = t.normalize(cx.sess().target.pointer_width);
     let (min, max) = int_ty_range(int_type);
     let max = max as u128;
     let negative = type_limits.negated_expr_id == Some(e.hir_id);
@@ -352,7 +352,7 @@ fn lint_uint_literal<'tcx>(
     lit: &hir::Lit,
     t: ast::UintTy,
 ) {
-    let uint_type = t.normalize(cx.sess().target.ptr_width);
+    let uint_type = t.normalize(cx.sess().target.pointer_width);
     let (min, max) = uint_ty_range(uint_type);
     let lit_val: u128 = match lit.node {
         // _v is u8, within range by definition
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 7f1e5cf336a..54b22ca49a2 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -70,7 +70,7 @@ fn main() {
     let host = env::var("HOST").expect("HOST was not set");
     let is_crossed = target != host;
 
-    let mut optional_components = vec![
+    let optional_components = &[
         "x86",
         "arm",
         "aarch64",
@@ -85,6 +85,7 @@ fn main() {
         "sparc",
         "nvptx",
         "hexagon",
+        "riscv",
     ];
 
     let mut version_cmd = Command::new(&llvm_config);
@@ -94,13 +95,9 @@ fn main() {
     let (major, _minor) = if let (Some(major), Some(minor)) = (parts.next(), parts.next()) {
         (major, minor)
     } else {
-        (6, 0)
+        (8, 0)
     };
 
-    if major > 6 {
-        optional_components.push("riscv");
-    }
-
     let required_components = &[
         "ipo",
         "bitreader",
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 7b1c3f9ba2c..71ca4f23bbb 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -1212,6 +1212,7 @@ struct LLVMRustThinLTOData {
   StringMap<FunctionImporter::ImportMapTy> ImportLists;
   StringMap<FunctionImporter::ExportSetTy> ExportLists;
   StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries;
+  StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
 
   LLVMRustThinLTOData() : Index(/* HaveGVs = */ false) {}
 };
@@ -1308,7 +1309,6 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
   //
   // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp` with some of this
   // being lifted from `lib/LTO/LTO.cpp` as well
-  StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
   DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
   for (auto &I : Ret->Index) {
     if (I.second.SummaryList.size() > 1)
@@ -1323,7 +1323,7 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
   auto recordNewLinkage = [&](StringRef ModuleIdentifier,
                               GlobalValue::GUID GUID,
                               GlobalValue::LinkageTypes NewLinkage) {
-    ResolvedODR[ModuleIdentifier][GUID] = NewLinkage;
+    Ret->ResolvedODR[ModuleIdentifier][GUID] = NewLinkage;
   };
 #if LLVM_VERSION_GE(9, 0)
   thinLTOResolvePrevailingInIndex(Ret->Index, isPrevailing, recordNewLinkage,
@@ -1491,7 +1491,7 @@ extern "C" typedef void (*LLVMRustModuleNameCallback)(void*, // payload
 // Calls `module_name_callback` for each module import done by ThinLTO.
 // The callback is provided with regular null-terminated C strings.
 extern "C" void
-LLVMRustGetThinLTOModuleImports(const LLVMRustThinLTOData *data,
+LLVMRustGetThinLTOModules(const LLVMRustThinLTOData *data,
                                 LLVMRustModuleNameCallback module_name_callback,
                                 void* callback_payload) {
   for (const auto& importing_module : data->ImportLists) {
@@ -1653,3 +1653,36 @@ LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) {
   MD->clearOperands();
   MD->addOperand(Unit);
 }
+
+// Computes the LTO cache key for the provided 'ModId' in the given 'Data',
+// storing the result in 'KeyOut'.
+// Currently, this cache key is a SHA-1 hash of anything that could affect
+// the result of optimizing this module (e.g. module imports, exports, liveness
+// of access globals, etc).
+// The precise details are determined by LLVM in `computeLTOCacheKey`, which is
+// used during the normal linker-plugin incremental thin-LTO process.
+extern "C" void
+LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, const char *ModId, LLVMRustThinLTOData *Data) {
+  SmallString<40> Key;
+  llvm::lto::Config conf;
+  const auto &ImportList = Data->ImportLists.lookup(ModId);
+  const auto &ExportList = Data->ExportLists.lookup(ModId);
+  const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId);
+  const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId);
+  std::set<GlobalValue::GUID> CfiFunctionDefs;
+  std::set<GlobalValue::GUID> CfiFunctionDecls;
+
+  // Based on the 'InProcessThinBackend' constructor in LLVM
+  for (auto &Name : Data->Index.cfiFunctionDefs())
+    CfiFunctionDefs.insert(
+        GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
+  for (auto &Name : Data->Index.cfiFunctionDecls())
+    CfiFunctionDecls.insert(
+        GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
+
+  llvm::computeLTOCacheKey(Key, conf, Data->Index, ModId,
+      ImportList, ExportList, ResolvedODR, DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls
+  );
+
+  LLVMRustStringWriteImpl(KeyOut, Key.c_str(), Key.size());
+}
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index f7454da90a3..44f57cfbe28 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -127,7 +127,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
         if ty == CrateType::Staticlib
             || (ty == CrateType::Executable
                 && sess.crt_static(Some(ty))
-                && !sess.target.target.options.crt_static_allows_dylibs)
+                && !sess.target.options.crt_static_allows_dylibs)
         {
             for &cnum in tcx.crates().iter() {
                 if tcx.dep_kind(cnum).macros_only() {
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 0869ec28367..f225f8acc89 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -325,7 +325,7 @@ impl<'a> CrateLocator<'a> {
             hash,
             host_hash,
             extra_filename,
-            target: if is_host { &sess.host } else { &sess.target.target },
+            target: if is_host { &sess.host } else { &sess.target },
             triple: if is_host {
                 TargetTriple::from_triple(config::host_triple())
             } else {
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index e76c2cb356f..5e65f075ea4 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -149,7 +149,7 @@ impl Collector<'tcx> {
             }
             return;
         }
-        let is_osx = self.tcx.sess.target.target.options.is_like_osx;
+        let is_osx = self.tcx.sess.target.options.is_like_osx;
         if lib.kind == NativeLibKind::Framework && !is_osx {
             let msg = "native frameworks are only available on macOS targets";
             match span {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 2662f6b6ed6..b01a55b48da 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -313,27 +313,6 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
         Ok(ty)
     }
 
-    fn cached_predicate_for_shorthand<F>(
-        &mut self,
-        shorthand: usize,
-        or_insert_with: F,
-    ) -> Result<ty::Predicate<'tcx>, Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>,
-    {
-        let tcx = self.tcx();
-
-        let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand };
-
-        if let Some(&pred) = tcx.pred_rcache.borrow().get(&key) {
-            return Ok(pred);
-        }
-
-        let pred = or_insert_with(self)?;
-        tcx.pred_rcache.borrow_mut().insert(key, pred);
-        Ok(pred)
-    }
-
     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 60705f68681..05b8dad3097 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -94,7 +94,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     adt_def => { cdata.get_adt_def(def_id.index, tcx) }
     adt_destructor => {
         let _ = cdata;
-        tcx.calculate_dtor(def_id, &mut |_,_| Ok(()))
+        tcx.calculate_dtor(def_id, |_,_| Ok(()))
     }
     variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) }
     associated_item_def_ids => {
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index f9a450305d0..bdbc9ab52bf 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.31.0"
+chalk-ir = "0.32.0"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 measureme = "0.7.1"
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_middle/src/ich/impls_hir.rs b/compiler/rustc_middle/src/ich/impls_hir.rs
index c2d177b69b6..d6c6cef1751 100644
--- a/compiler/rustc_middle/src/ich/impls_hir.rs
+++ b/compiler/rustc_middle/src/ich/impls_hir.rs
@@ -221,6 +221,12 @@ impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InlineAttr {
     }
 }
 
+impl<'hir> HashStable<StableHashingContext<'hir>> for attr::InstructionSetAttr {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+    }
+}
+
 impl<'hir> HashStable<StableHashingContext<'hir>> for attr::OptimizeAttr {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) {
         mem::discriminant(self).hash_stable(hcx, hasher);
diff --git a/compiler/rustc_middle/src/ich/impls_syntax.rs b/compiler/rustc_middle/src/ich/impls_syntax.rs
index e3d4655831b..7aba4fc64a9 100644
--- a/compiler/rustc_middle/src/ich/impls_syntax.rs
+++ b/compiler/rustc_middle/src/ich/impls_syntax.rs
@@ -5,7 +5,7 @@ use crate::ich::StableHashingContext;
 
 use rustc_ast as ast;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_span::SourceFile;
+use rustc_span::{BytePos, NormalizedPos, SourceFile};
 
 use smallvec::SmallVec;
 
@@ -102,22 +102,19 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
     }
 }
 
-fn stable_byte_pos(pos: ::rustc_span::BytePos, source_file_start: ::rustc_span::BytePos) -> u32 {
+fn stable_byte_pos(pos: BytePos, source_file_start: BytePos) -> u32 {
     pos.0 - source_file_start.0
 }
 
-fn stable_multibyte_char(
-    mbc: ::rustc_span::MultiByteChar,
-    source_file_start: ::rustc_span::BytePos,
-) -> (u32, u32) {
-    let ::rustc_span::MultiByteChar { pos, bytes } = mbc;
+fn stable_multibyte_char(mbc: rustc_span::MultiByteChar, source_file_start: BytePos) -> (u32, u32) {
+    let rustc_span::MultiByteChar { pos, bytes } = mbc;
 
     (pos.0 - source_file_start.0, bytes as u32)
 }
 
 fn stable_non_narrow_char(
-    swc: ::rustc_span::NonNarrowChar,
-    source_file_start: ::rustc_span::BytePos,
+    swc: rustc_span::NonNarrowChar,
+    source_file_start: BytePos,
 ) -> (u32, u32) {
     let pos = swc.pos();
     let width = swc.width();
@@ -125,11 +122,8 @@ fn stable_non_narrow_char(
     (pos.0 - source_file_start.0, width as u32)
 }
 
-fn stable_normalized_pos(
-    np: ::rustc_span::NormalizedPos,
-    source_file_start: ::rustc_span::BytePos,
-) -> (u32, u32) {
-    let ::rustc_span::NormalizedPos { pos, diff } = np;
+fn stable_normalized_pos(np: NormalizedPos, source_file_start: BytePos) -> (u32, u32) {
+    let NormalizedPos { pos, diff } = np;
 
     (pos.0 - source_file_start.0, diff)
 }
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index d71cdc4e67d..a4363bb580a 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -1,5 +1,5 @@
 use crate::mir::mono::Linkage;
-use rustc_attr::{InlineAttr, OptimizeAttr};
+use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_session::config::SanitizerSet;
 use rustc_span::symbol::Symbol;
 
@@ -34,6 +34,10 @@ pub struct CodegenFnAttrs {
     /// The `#[no_sanitize(...)]` attribute. Indicates sanitizers for which
     /// instrumentation should be disabled inside the annotated function.
     pub no_sanitize: SanitizerSet,
+    /// The `#[instruction_set(set)]` attribute. Indicates if the generated code should
+    /// be generated against a specific instruction set. Only usable on architectures which allow
+    /// switching between multiple instruction sets.
+    pub instruction_set: Option<InstructionSetAttr>,
 }
 
 bitflags! {
@@ -98,6 +102,7 @@ impl CodegenFnAttrs {
             linkage: None,
             link_section: None,
             no_sanitize: SanitizerSet::empty(),
+            instruction_set: None,
         }
     }
 
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 4756e83b5e9..254b57a005e 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -3,7 +3,6 @@
 //! which are available for use externally when compiled as a library.
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::DefIdSet;
 use rustc_hir::HirId;
 use rustc_macros::HashStable;
 use std::fmt;
@@ -59,7 +58,3 @@ impl<Id: Hash + Eq + fmt::Debug> fmt::Debug for AccessLevels<Id> {
         fmt::Debug::fmt(&self.map, f)
     }
 }
-
-/// A set containing all exported definitions from external crates.
-/// The set does not contain any entries from local crates.
-pub type ExternalExports = DefIdSet;
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 4c6ac820604..38cb3c1701f 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -283,23 +283,27 @@ pub struct ScopeTree {
     /// To see that this method works, consider:
     ///
     /// Let `D` be our binding/temporary and `U` be our other HIR node, with
-    /// `HIR-postorder(U) < HIR-postorder(D)` (in our example, U would be
-    /// the yield and D would be one of the calls). Let's show that
-    /// `D` is storage-dead at `U`.
+    /// `HIR-postorder(U) < HIR-postorder(D)`. Suppose, as in our example,
+    /// U is the yield and D is one of the calls.
+    /// Let's show that `D` is storage-dead at `U`.
     ///
     /// Remember that storage-live/storage-dead refers to the state of
     /// the *storage*, and does not consider moves/drop flags.
     ///
     /// Then:
+    ///
     ///     1. From the ordering guarantee of HIR visitors (see
     ///     `rustc_hir::intravisit`), `D` does not dominate `U`.
+    ///
     ///     2. Therefore, `D` is *potentially* storage-dead at `U` (because
     ///     we might visit `U` without ever getting to `D`).
+    ///
     ///     3. However, we guarantee that at each HIR point, each
     ///     binding/temporary is always either always storage-live
     ///     or always storage-dead. This is what is being guaranteed
     ///     by `terminating_scopes` including all blocks where the
     ///     count of executions is not guaranteed.
+    ///
     ///     4. By `2.` and `3.`, `D` is *statically* storage-dead at `U`,
     ///     QED.
     ///
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index ee1ea816e01..5ebe38b2d7e 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -40,7 +40,7 @@ pub struct Allocation<Tag = (), Extra = ()> {
     pub extra: Extra,
 }
 
-pub trait AllocationExtra<Tag>: ::std::fmt::Debug + Clone {
+pub trait AllocationExtra<Tag>: std::fmt::Debug + Clone {
     // There is no constructor in here because the constructor's type depends
     // on `MemoryKind`, and making things sufficiently generic leads to painful
     // inference failure.
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 3751249853f..cb8782ce817 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -56,15 +56,6 @@ impl<'tcx> ConstValue<'tcx> {
         }
     }
 
-    pub fn try_to_str_slice(&self) -> Option<&'tcx str> {
-        if let ConstValue::Slice { data, start, end } = *self {
-            ::std::str::from_utf8(data.inspect_with_uninit_and_ptr_outside_interpreter(start..end))
-                .ok()
-        } else {
-            None
-        }
-    }
-
     pub fn try_to_bits(&self, size: Size) -> Option<u128> {
         self.try_to_scalar()?.to_bits(size).ok()
     }
@@ -465,7 +456,7 @@ impl<'tcx, Tag> Scalar<Tag> {
 
     pub fn to_char(self) -> InterpResult<'tcx, char> {
         let val = self.to_u32()?;
-        match ::std::char::from_u32(val) {
+        match std::char::from_u32(val) {
             Some(c) => Ok(c),
             None => throw_ub!(InvalidChar(val)),
         }
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index da7677f802b..16472c78757 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -3,7 +3,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
 
 use crate::mir::coverage::{CodeRegion, CoverageKind};
-use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar};
+use crate::mir::interpret::{Allocation, GlobalAlloc, Scalar};
 use crate::mir::visit::MirVisitable;
 use crate::ty::adjustment::PointerCast;
 use crate::ty::codec::{TyDecoder, TyEncoder};
@@ -460,17 +460,6 @@ impl<'tcx> Body<'tcx> {
         }
     }
 
-    /// Checks if `sub` is a sub scope of `sup`
-    pub fn is_sub_scope(&self, mut sub: SourceScope, sup: SourceScope) -> bool {
-        while sub != sup {
-            match self.source_scopes[sub].parent_scope {
-                None => return false,
-                Some(p) => sub = p,
-            }
-        }
-        true
-    }
-
     /// Returns the return type; it always return first element from `local_decls` array.
     #[inline]
     pub fn return_ty(&self) -> Ty<'tcx> {
@@ -775,7 +764,7 @@ mod binding_form_impl {
     impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> {
         fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
             use super::BindingForm::*;
-            ::std::mem::discriminant(self).hash_stable(hcx, hasher);
+            std::mem::discriminant(self).hash_stable(hcx, hasher);
 
             match self {
                 Var(binding) => binding.hash_stable(hcx, hasher),
@@ -813,7 +802,7 @@ pub struct BlockTailInfo {
 /// argument, or the return place.
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct LocalDecl<'tcx> {
-    /// Whether this is a mutable minding (i.e., `let x` or `let mut x`).
+    /// Whether this is a mutable binding (i.e., `let x` or `let mut x`).
     ///
     /// Temporaries and the return place are always mutable.
     pub mutability: Mutability,
@@ -1978,45 +1967,6 @@ impl<'tcx> Operand<'tcx> {
         })
     }
 
-    /// Convenience helper to make a `Scalar` from the given `Operand`, assuming that `Operand`
-    /// wraps a constant literal value. Panics if this is not the case.
-    pub fn scalar_from_const(operand: &Operand<'tcx>) -> Scalar {
-        match operand {
-            Operand::Constant(constant) => match constant.literal.val.try_to_scalar() {
-                Some(scalar) => scalar,
-                _ => panic!("{:?}: Scalar value expected", constant.literal.val),
-            },
-            _ => panic!("{:?}: Constant expected", operand),
-        }
-    }
-
-    /// Convenience helper to make a literal-like constant from a given `&str` slice.
-    /// Since this is used to synthesize MIR, assumes `user_ty` is None.
-    pub fn const_from_str(tcx: TyCtxt<'tcx>, val: &str, span: Span) -> Operand<'tcx> {
-        let tcx = tcx;
-        let allocation = Allocation::from_byte_aligned_bytes(val.as_bytes());
-        let allocation = tcx.intern_const_alloc(allocation);
-        let const_val = ConstValue::Slice { data: allocation, start: 0, end: val.len() };
-        let ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.types.str_);
-        Operand::Constant(box Constant {
-            span,
-            user_ty: None,
-            literal: ty::Const::from_value(tcx, const_val, ty),
-        })
-    }
-
-    /// Convenience helper to make a `ConstValue` from the given `Operand`, assuming that `Operand`
-    /// wraps a constant value (such as a `&str` slice). Panics if this is not the case.
-    pub fn value_from_const(operand: &Operand<'tcx>) -> ConstValue<'tcx> {
-        match operand {
-            Operand::Constant(constant) => match constant.literal.val.try_to_value() {
-                Some(const_value) => const_value,
-                _ => panic!("{:?}: ConstValue expected", constant.literal.val),
-            },
-            _ => panic!("{:?}: Constant expected", operand),
-        }
-    }
-
     pub fn to_copy(&self) -> Self {
         match *self {
             Operand::Copy(_) | Operand::Constant(_) => self.clone(),
@@ -2413,10 +2363,6 @@ impl<'tcx> UserTypeProjections {
         self.contents.is_empty()
     }
 
-    pub fn from_projections(projs: impl Iterator<Item = (UserTypeProjection, Span)>) -> Self {
-        UserTypeProjections { contents: projs.collect() }
-    }
-
     pub fn projections_and_spans(
         &self,
     ) -> impl Iterator<Item = &(UserTypeProjection, Span)> + ExactSizeIterator {
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 0878e9313d8..6022194342d 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -1,9 +1,10 @@
 //! Values computed by queries that use MIR.
 
-use crate::mir::{Body, Promoted};
+use crate::mir::{abstract_const, Body, Promoted};
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
+use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_index::bit_set::BitMatrix;
@@ -407,18 +408,12 @@ pub struct CoverageInfo {
     pub num_expressions: u32,
 }
 
+/// Shims which make dealing with `WithOptConstParam` easier.
+///
+/// For more information on why this is needed, consider looking
+/// at the docs for `WithOptConstParam` itself.
 impl<'tcx> TyCtxt<'tcx> {
-    pub fn mir_borrowck_opt_const_arg(
-        self,
-        def: ty::WithOptConstParam<LocalDefId>,
-    ) -> &'tcx BorrowCheckResult<'tcx> {
-        if let Some(param_did) = def.const_param_did {
-            self.mir_borrowck_const_arg((def.did, param_did))
-        } else {
-            self.mir_borrowck(def.did)
-        }
-    }
-
+    #[inline]
     pub fn mir_const_qualif_opt_const_arg(
         self,
         def: ty::WithOptConstParam<LocalDefId>,
@@ -430,7 +425,8 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    pub fn promoted_mir_of_opt_const_arg(
+    #[inline]
+    pub fn promoted_mir_opt_const_arg(
         self,
         def: ty::WithOptConstParam<DefId>,
     ) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
@@ -440,4 +436,28 @@ impl<'tcx> TyCtxt<'tcx> {
             self.promoted_mir(def.did)
         }
     }
+
+    #[inline]
+    pub fn optimized_mir_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<DefId>,
+    ) -> &'tcx Body<'tcx> {
+        if let Some((did, param_did)) = def.as_const_arg() {
+            self.optimized_mir_of_const_arg((did, param_did))
+        } else {
+            self.optimized_mir(def.did)
+        }
+    }
+
+    #[inline]
+    pub fn mir_abstract_const_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<DefId>,
+    ) -> Result<Option<&'tcx [abstract_const::Node<'tcx>]>, ErrorReported> {
+        if let Some((did, param_did)) = def.as_const_arg() {
+            self.mir_abstract_const_of_const_arg((did, param_did))
+        } else {
+            self.mir_abstract_const(def.did)
+        }
+    }
 }
diff --git a/compiler/rustc_middle/src/mir/terminator/mod.rs b/compiler/rustc_middle/src/mir/terminator/mod.rs
index 8909f02270c..e1071454e65 100644
--- a/compiler/rustc_middle/src/mir/terminator/mod.rs
+++ b/compiler/rustc_middle/src/mir/terminator/mod.rs
@@ -1,6 +1,7 @@
 use crate::mir::interpret::Scalar;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use smallvec::{smallvec, SmallVec};
 
 use super::{
     AssertMessage, BasicBlock, InlineAsmOperand, Operand, Place, SourceInfo, Successors,
@@ -16,6 +17,87 @@ use std::slice;
 
 pub use super::query::*;
 
+#[derive(Debug, Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
+pub struct SwitchTargets {
+    /// Possible values. The locations to branch to in each case
+    /// are found in the corresponding indices from the `targets` vector.
+    values: SmallVec<[u128; 1]>,
+
+    /// Possible branch sites. The last element of this vector is used
+    /// for the otherwise branch, so targets.len() == values.len() + 1
+    /// should hold.
+    //
+    // This invariant is quite non-obvious and also could be improved.
+    // One way to make this invariant is to have something like this instead:
+    //
+    // branches: Vec<(ConstInt, BasicBlock)>,
+    // otherwise: Option<BasicBlock> // exhaustive if None
+    //
+    // However we’ve decided to keep this as-is until we figure a case
+    // where some other approach seems to be strictly better than other.
+    targets: SmallVec<[BasicBlock; 2]>,
+}
+
+impl SwitchTargets {
+    /// Creates switch targets from an iterator of values and target blocks.
+    ///
+    /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to
+    /// `goto otherwise;`.
+    pub fn new(targets: impl Iterator<Item = (u128, BasicBlock)>, otherwise: BasicBlock) -> Self {
+        let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip();
+        targets.push(otherwise);
+        Self { values: values.into(), targets }
+    }
+
+    /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`,
+    /// and to `else_` if not.
+    pub fn static_if(value: u128, then: BasicBlock, else_: BasicBlock) -> Self {
+        Self { values: smallvec![value], targets: smallvec![then, else_] }
+    }
+
+    /// Returns the fallback target that is jumped to when none of the values match the operand.
+    pub fn otherwise(&self) -> BasicBlock {
+        *self.targets.last().unwrap()
+    }
+
+    /// Returns an iterator over the switch targets.
+    ///
+    /// The iterator will yield tuples containing the value and corresponding target to jump to, not
+    /// including the `otherwise` fallback target.
+    ///
+    /// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory.
+    pub fn iter(&self) -> SwitchTargetsIter<'_> {
+        SwitchTargetsIter { inner: self.values.iter().zip(self.targets.iter()) }
+    }
+
+    /// Returns a slice with all possible jump targets (including the fallback target).
+    pub fn all_targets(&self) -> &[BasicBlock] {
+        &self.targets
+    }
+
+    pub fn all_targets_mut(&mut self) -> &mut [BasicBlock] {
+        &mut self.targets
+    }
+}
+
+pub struct SwitchTargetsIter<'a> {
+    inner: iter::Zip<slice::Iter<'a, u128>, slice::Iter<'a, BasicBlock>>,
+}
+
+impl<'a> Iterator for SwitchTargetsIter<'a> {
+    type Item = (u128, BasicBlock);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.inner.next().map(|(val, bb)| (*val, *bb))
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+}
+
+impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
+
 #[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)]
 pub enum TerminatorKind<'tcx> {
     /// Block should have one successor in the graph; we jump there.
@@ -32,23 +114,7 @@ pub enum TerminatorKind<'tcx> {
         /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing.
         switch_ty: Ty<'tcx>,
 
-        /// Possible values. The locations to branch to in each case
-        /// are found in the corresponding indices from the `targets` vector.
-        values: Cow<'tcx, [u128]>,
-
-        /// Possible branch sites. The last element of this vector is used
-        /// for the otherwise branch, so targets.len() == values.len() + 1
-        /// should hold.
-        //
-        // This invariant is quite non-obvious and also could be improved.
-        // One way to make this invariant is to have something like this instead:
-        //
-        // branches: Vec<(ConstInt, BasicBlock)>,
-        // otherwise: Option<BasicBlock> // exhaustive if None
-        //
-        // However we’ve decided to keep this as-is until we figure a case
-        // where some other approach seems to be strictly better than other.
-        targets: Vec<BasicBlock>,
+        targets: SwitchTargets,
     },
 
     /// Indicates that the landing pad is finished and unwinding should
@@ -227,12 +293,10 @@ impl<'tcx> TerminatorKind<'tcx> {
         t: BasicBlock,
         f: BasicBlock,
     ) -> TerminatorKind<'tcx> {
-        static BOOL_SWITCH_FALSE: &[u128] = &[0];
         TerminatorKind::SwitchInt {
             discr: cond,
             switch_ty: tcx.types.bool,
-            values: From::from(BOOL_SWITCH_FALSE),
-            targets: vec![f, t],
+            targets: SwitchTargets::static_if(0, f, t),
         }
     }
 
@@ -263,7 +327,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => {
                 Some(t).into_iter().chain(slice::from_ref(u))
             }
-            SwitchInt { ref targets, .. } => None.into_iter().chain(&targets[..]),
+            SwitchInt { ref targets, .. } => None.into_iter().chain(&targets.targets[..]),
             FalseEdge { ref real_target, ref imaginary_target } => {
                 Some(real_target).into_iter().chain(slice::from_ref(imaginary_target))
             }
@@ -297,7 +361,7 @@ impl<'tcx> TerminatorKind<'tcx> {
             | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => {
                 Some(t).into_iter().chain(slice::from_mut(u))
             }
-            SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets[..]),
+            SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets[..]),
             FalseEdge { ref mut real_target, ref mut imaginary_target } => {
                 Some(real_target).into_iter().chain(slice::from_mut(imaginary_target))
             }
@@ -469,11 +533,12 @@ impl<'tcx> TerminatorKind<'tcx> {
         match *self {
             Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
             Goto { .. } => vec!["".into()],
-            SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| {
+            SwitchInt { ref targets, switch_ty, .. } => ty::tls::with(|tcx| {
                 let param_env = ty::ParamEnv::empty();
                 let switch_ty = tcx.lift(&switch_ty).unwrap();
                 let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
-                values
+                targets
+                    .values
                     .iter()
                     .map(|&u| {
                         ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty)
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index ad2eae0298c..9297aed66a4 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -21,10 +21,9 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
 
         let kind = match self.kind {
             Goto { target } => Goto { target },
-            SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt {
+            SwitchInt { ref discr, switch_ty, ref targets } => SwitchInt {
                 discr: discr.fold_with(folder),
                 switch_ty: switch_ty.fold_with(folder),
-                values: values.clone(),
                 targets: targets.clone(),
             },
             Drop { ref place, target, unwind } => {
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 9a6bfa10189..58dd0bc00d2 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -453,7 +453,6 @@ macro_rules! make_mir_visitor {
                     TerminatorKind::SwitchInt {
                         discr,
                         switch_ty,
-                        values: _,
                         targets: _
                     } => {
                         self.visit_operand(discr, location);
@@ -1187,16 +1186,6 @@ impl PlaceContext {
         )
     }
 
-    /// Returns `true` if this place context represents a storage live marker.
-    pub fn is_storage_live_marker(&self) -> bool {
-        matches!(self, PlaceContext::NonUse(NonUseContext::StorageLive))
-    }
-
-    /// Returns `true` if this place context represents a storage dead marker.
-    pub fn is_storage_dead_marker(&self) -> bool {
-        matches!(self, PlaceContext::NonUse(NonUseContext::StorageDead))
-    }
-
     /// Returns `true` if this place context represents a use that potentially changes the value.
     pub fn is_mutating_use(&self) -> bool {
         matches!(self, PlaceContext::MutatingUse(..))
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index fc4c343372a..1acb44f6d22 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -92,7 +92,7 @@ rustc_queries! {
         /// Computes the `DefId` of the corresponding const parameter in case the `key` is a
         /// const argument and returns `None` otherwise.
         ///
-        /// ```rust
+        /// ```ignore (incomplete)
         /// let a = foo::<7>();
         /// //            ^ Calling `opt_const_param_of` for this argument,
         ///
@@ -162,10 +162,12 @@ rustc_queries! {
         /// Specifically this is the bounds written on the trait's type
         /// definition, or those after the `impl` keyword
         ///
+        /// ```ignore (incomplete)
         /// type X: Bound + 'lt
-        ///         ^^^^^^^^^^^
+        /// //      ^^^^^^^^^^^
         /// impl Debug + Display
-        ///      ^^^^^^^^^^^^^^^
+        /// //   ^^^^^^^^^^^^^^^
+        /// ```
         ///
         /// `key` is the `DefId` of the associated type or opaque type.
         ///
@@ -176,18 +178,22 @@ rustc_queries! {
 
         /// Elaborated version of the predicates from `explicit_item_bounds`.
         ///
-        /// Example for
+        /// For example:
         ///
+        /// ```
         /// trait MyTrait {
-        ///     type MyAType: Eq + ?Sized`
+        ///     type MyAType: Eq + ?Sized;
         /// }
+        /// ```
         ///
         /// `explicit_item_bounds` returns `[<Self as MyTrait>::MyAType: Eq]`,
         /// and `item_bounds` returns
+        /// ```text
         /// [
         ///     <Self as Trait>::MyAType: Eq,
         ///     <Self as Trait>::MyAType: PartialEq<<Self as Trait>::MyAType>
         /// ]
+        /// ```
         ///
         /// Bounds from the parent (e.g. with nested impl trait) are not included.
         query item_bounds(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> {
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 8ea34f9161a..aaf6a857043 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -182,14 +182,6 @@ pub trait TyDecoder<'tcx>: Decoder {
     where
         F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>;
 
-    fn cached_predicate_for_shorthand<F>(
-        &mut self,
-        shorthand: usize,
-        or_insert_with: F,
-    ) -> Result<ty::Predicate<'tcx>, Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>;
-
     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R;
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index e67a76f0111..e24ba6d7a1e 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -534,10 +534,6 @@ impl<'tcx> TypeckResults<'tcx> {
         self.node_type(pat.hir_id)
     }
 
-    pub fn pat_ty_opt(&self, pat: &hir::Pat<'_>) -> Option<Ty<'tcx>> {
-        self.node_type_opt(pat.hir_id)
-    }
-
     // Returns the type of an expression as a monotype.
     //
     // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression.  That is, in
@@ -1083,7 +1079,7 @@ impl<'tcx> TyCtxt<'tcx> {
         crate_name: &str,
         output_filenames: &OutputFilenames,
     ) -> GlobalCtxt<'tcx> {
-        let data_layout = TargetDataLayout::parse(&s.target.target).unwrap_or_else(|err| {
+        let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| {
             s.fatal(&err);
         });
         let interners = CtxtInterners::new(arena);
@@ -1526,7 +1522,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Determines whether identifiers in the assembly have strict naming rules.
     /// Currently, only NVPTX* targets need it.
     pub fn has_strict_asm_symbol_naming(self) -> bool {
-        self.sess.target.target.arch.contains("nvptx")
+        self.sess.target.arch.contains("nvptx")
     }
 
     /// Returns `&'static core::panic::Location<'static>`.
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 84134bedef0..5524d91a6d5 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -97,9 +97,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     fn has_infer_types_or_consts(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER)
     }
-    fn has_infer_consts(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_CT_INFER)
-    }
     fn needs_infer(&self) -> bool {
         self.has_type_flags(TypeFlags::NEEDS_INFER)
     }
@@ -113,9 +110,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     fn needs_subst(&self) -> bool {
         self.has_type_flags(TypeFlags::NEEDS_SUBST)
     }
-    fn has_re_placeholders(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER)
-    }
     /// "Free" regions in this context means that it has any region
     /// that is not (a) erased or (b) late-bound.
     fn has_free_regions(&self) -> bool {
@@ -719,21 +713,15 @@ impl<'tcx> TyCtxt<'tcx> {
 // vars. See comment on `shift_vars_through_binders` method in
 // `subst.rs` for more details.
 
-enum Direction {
-    In,
-    Out,
-}
-
 struct Shifter<'tcx> {
     tcx: TyCtxt<'tcx>,
     current_index: ty::DebruijnIndex,
     amount: u32,
-    direction: Direction,
 }
 
 impl Shifter<'tcx> {
-    pub fn new(tcx: TyCtxt<'tcx>, amount: u32, direction: Direction) -> Self {
-        Shifter { tcx, current_index: ty::INNERMOST, amount, direction }
+    pub fn new(tcx: TyCtxt<'tcx>, amount: u32) -> Self {
+        Shifter { tcx, current_index: ty::INNERMOST, amount }
     }
 }
 
@@ -755,13 +743,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> {
                 if self.amount == 0 || debruijn < self.current_index {
                     r
                 } else {
-                    let debruijn = match self.direction {
-                        Direction::In => debruijn.shifted_in(self.amount),
-                        Direction::Out => {
-                            assert!(debruijn.as_u32() >= self.amount);
-                            debruijn.shifted_out(self.amount)
-                        }
-                    };
+                    let debruijn = debruijn.shifted_in(self.amount);
                     let shifted = ty::ReLateBound(debruijn, br);
                     self.tcx.mk_region(shifted)
                 }
@@ -776,13 +758,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> {
                 if self.amount == 0 || debruijn < self.current_index {
                     ty
                 } else {
-                    let debruijn = match self.direction {
-                        Direction::In => debruijn.shifted_in(self.amount),
-                        Direction::Out => {
-                            assert!(debruijn.as_u32() >= self.amount);
-                            debruijn.shifted_out(self.amount)
-                        }
-                    };
+                    let debruijn = debruijn.shifted_in(self.amount);
                     self.tcx.mk_ty(ty::Bound(debruijn, bound_ty))
                 }
             }
@@ -796,13 +772,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> {
             if self.amount == 0 || debruijn < self.current_index {
                 ct
             } else {
-                let debruijn = match self.direction {
-                    Direction::In => debruijn.shifted_in(self.amount),
-                    Direction::Out => {
-                        assert!(debruijn.as_u32() >= self.amount);
-                        debruijn.shifted_out(self.amount)
-                    }
-                };
+                let debruijn = debruijn.shifted_in(self.amount);
                 self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty })
             }
         } else {
@@ -830,16 +800,7 @@ where
 {
     debug!("shift_vars(value={:?}, amount={})", value, amount);
 
-    value.fold_with(&mut Shifter::new(tcx, amount, Direction::In))
-}
-
-pub fn shift_out_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: &T, amount: u32) -> T
-where
-    T: TypeFoldable<'tcx>,
-{
-    debug!("shift_out_vars(value={:?}, amount={})", value, amount);
-
-    value.fold_with(&mut Shifter::new(tcx, amount, Direction::Out))
+    value.fold_with(&mut Shifter::new(tcx, amount))
 }
 
 /// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 2c1179c21fb..bf1f5b81c9f 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -104,14 +104,6 @@ impl<'tcx> TyCtxt<'tcx> {
         // ```
         ty.uninhabited_from(self, param_env).contains(self, module)
     }
-
-    pub fn is_ty_uninhabited_from_any_module(
-        self,
-        ty: Ty<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> bool {
-        !ty.uninhabited_from(self, param_env).is_empty()
-    }
 }
 
 impl<'tcx> AdtDef {
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index f8e8c209d37..4a2c97b4a40 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -291,7 +291,17 @@ impl<'tcx> Instance<'tcx> {
     }
 
     pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> {
-        Instance::new(def_id, tcx.empty_substs_for_def_id(def_id))
+        let substs = InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind {
+            ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+            ty::GenericParamDefKind::Type { .. } => {
+                bug!("Instance::mono: {:?} has type parameters", def_id)
+            }
+            ty::GenericParamDefKind::Const { .. } => {
+                bug!("Instance::mono: {:?} has const parameters", def_id)
+            }
+        });
+
+        Instance::new(def_id, substs)
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index f6f71d002a8..91c3dcbfa81 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -106,7 +106,7 @@ impl IntegerExt for Integer {
         }
 
         if repr.c() {
-            match &tcx.sess.target.target.arch[..] {
+            match &tcx.sess.target.arch[..] {
                 // WARNING: the ARM EABI has two variants; the one corresponding
                 // to `at_least == I32` appears to be used on Linux and NetBSD,
                 // but some systems may use the variant corresponding to no
@@ -1894,7 +1894,7 @@ impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
     }
 }
 
-pub type TyAndLayout<'tcx> = ::rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
+pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>;
 
 impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> {
     type Ty = Ty<'tcx>;
@@ -2548,7 +2548,7 @@ where
         let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
 
         use rustc_target::spec::abi::Abi::*;
-        let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) {
+        let conv = match cx.tcx().sess.target.adjust_abi(sig.abi) {
             RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
 
             // It's the ABI's job to select this, not ours.
@@ -2600,7 +2600,7 @@ where
             extra_args.to_vec()
         };
 
-        let target = &cx.tcx().sess.target.target;
+        let target = &cx.tcx().sess.target;
         let target_env_gnu_like = matches!(&target.target_env[..], "gnu" | "musl");
         let win_x64_gnu =
             target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu";
@@ -2775,7 +2775,7 @@ where
                     // anyway, we control all calls to it in libstd.
                     Abi::Vector { .. }
                         if abi != SpecAbi::PlatformIntrinsic
-                            && cx.tcx().sess.target.target.options.simd_types_indirect =>
+                            && cx.tcx().sess.target.options.simd_types_indirect =>
                     {
                         arg.make_indirect();
                         return;
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index f069faed9e2..275888b0ce2 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -7,7 +7,6 @@ pub use self::Variance::*;
 
 use crate::hir::exports::ExportMap;
 use crate::ich::StableHashingContext;
-use crate::infer::canonical::Canonical;
 use crate::middle::cstore::CrateStoreDyn;
 use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
 use crate::mir::interpret::ErrorHandled;
@@ -656,8 +655,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
 #[rustc_diagnostic_item = "Ty"]
 pub type Ty<'tcx> = &'tcx TyS<'tcx>;
 
-pub type CanonicalTy<'tcx> = Canonical<'tcx, Ty<'tcx>>;
-
 #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
 pub struct UpvarPath {
     pub hir_id: hir::HirId,
@@ -767,10 +764,6 @@ pub enum IntVarValue {
 pub struct FloatVarValue(pub ast::FloatTy);
 
 impl ty::EarlyBoundRegion {
-    pub fn to_bound_region(&self) -> ty::BoundRegion {
-        ty::BoundRegion::BrNamed(self.def_id, self.name)
-    }
-
     /// Does this early bound region have a name? Early bound regions normally
     /// always have names except when using anonymous lifetimes (`'_`).
     pub fn has_name(&self) -> bool {
@@ -821,14 +814,6 @@ impl GenericParamDef {
             bug!("cannot convert a non-lifetime parameter def to an early bound region")
         }
     }
-
-    pub fn to_bound_region(&self) -> ty::BoundRegion {
-        if let GenericParamDefKind::Lifetime = self.kind {
-            self.to_early_bound_region_data().to_bound_region()
-        } else {
-            bug!("cannot convert a non-lifetime parameter def to an early bound region")
-        }
-    }
 }
 
 #[derive(Default)]
@@ -1003,22 +988,6 @@ impl<'tcx> GenericPredicates<'tcx> {
         instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p));
         instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s));
     }
-
-    pub fn instantiate_supertrait(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        poly_trait_ref: &ty::PolyTraitRef<'tcx>,
-    ) -> InstantiatedPredicates<'tcx> {
-        assert_eq!(self.parent, None);
-        InstantiatedPredicates {
-            predicates: self
-                .predicates
-                .iter()
-                .map(|(pred, _)| pred.subst_supertrait(tcx, poly_trait_ref))
-                .collect(),
-            spans: self.predicates.iter().map(|(_, sp)| *sp).collect(),
-        }
-    }
 }
 
 #[derive(Debug)]
@@ -1303,7 +1272,6 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable, TypeFoldable)]
 pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B`
-pub type PolyOutlivesPredicate<A, B> = ty::Binder<OutlivesPredicate<A, B>>;
 pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>;
 pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;
 pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<RegionOutlivesPredicate<'tcx>>;
@@ -2953,13 +2921,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// 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 {
-            ty::InstanceDef::Item(def) => {
-                if let Some((did, param_did)) = def.as_const_arg() {
-                    self.optimized_mir_of_const_arg((did, param_did))
-                } else {
-                    self.optimized_mir(def.did)
-                }
-            }
+            ty::InstanceDef::Item(def) => self.optimized_mir_opt_const_arg(def),
             ty::InstanceDef::VtableShim(..)
             | ty::InstanceDef::ReifyShim(..)
             | ty::InstanceDef::Intrinsic(..)
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 48a62b64604..a594a8ad512 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -23,7 +23,7 @@ impl<'tcx> TyCtxt<'tcx> {
     {
         debug!(
             "normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
-            ::std::any::type_name::<T>(),
+            std::any::type_name::<T>(),
             value,
             param_env,
         );
diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs
index 4c20141bbe6..86750d5c081 100644
--- a/compiler/rustc_middle/src/ty/outlives.rs
+++ b/compiler/rustc_middle/src/ty/outlives.rs
@@ -96,16 +96,14 @@ fn compute_components(
             }
 
             ty::Closure(_, ref substs) => {
-                for upvar_ty in substs.as_closure().upvar_tys() {
-                    compute_components(tcx, upvar_ty, out, visited);
-                }
+                let tupled_ty = substs.as_closure().tupled_upvars_ty();
+                compute_components(tcx, tupled_ty, out, visited);
             }
 
             ty::Generator(_, ref substs, _) => {
                 // Same as the closure case
-                for upvar_ty in substs.as_generator().upvar_tys() {
-                    compute_components(tcx, upvar_ty, out, visited);
-                }
+                let tupled_ty = substs.as_generator().tupled_upvars_ty();
+                compute_components(tcx, tupled_ty, out, visited);
 
                 // We ignore regions in the generator interior as we don't
                 // want these to affect region inference
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index e1f02d0f704..08f88eed66f 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -663,18 +663,13 @@ pub trait PrettyPrinter<'tcx>:
                     }
                 } else {
                     p!(print_def_path(did, substs));
-                    if substs.as_generator().is_valid() {
-                        // Search for the first inference variable
-                        p!(" upvar_tys=(");
-                        let mut uninferred_ty =
-                            substs.as_generator().upvar_tys().filter(|ty| ty.is_ty_infer());
-                        if uninferred_ty.next().is_some() {
-                            p!(write("unavailable"));
-                        } else {
-                            self = self.comma_sep(substs.as_generator().upvar_tys())?;
-                        }
-                        p!(")");
+                    p!(" upvar_tys=(");
+                    if !substs.as_generator().is_valid() {
+                        p!("unavailable");
+                    } else {
+                        self = self.comma_sep(substs.as_generator().upvar_tys())?;
                     }
+                    p!(")");
                 }
 
                 if substs.as_generator().is_valid() {
@@ -704,24 +699,17 @@ pub trait PrettyPrinter<'tcx>:
                     }
                 } else {
                     p!(print_def_path(did, substs));
-                    if substs.as_closure().is_valid() {
-                        // Search for the first inference variable
-                        let mut uninferred_ty =
-                            substs.as_closure().upvar_tys().filter(|ty| ty.is_ty_infer());
-                        if uninferred_ty.next().is_some() {
-                            // If the upvar substs contain an inference variable we haven't
-                            // finished capture analysis.
-                            p!(" closure_substs=(unavailable)");
-                        } else {
-                            p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
-                            p!(
-                                " closure_sig_as_fn_ptr_ty=",
-                                print(substs.as_closure().sig_as_fn_ptr_ty())
-                            );
-                            p!(" upvar_tys=(");
-                            self = self.comma_sep(substs.as_closure().upvar_tys())?;
-                            p!(")");
-                        }
+                    if !substs.as_closure().is_valid() {
+                        p!(" closure_substs=(unavailable)");
+                    } else {
+                        p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
+                        p!(
+                            " closure_sig_as_fn_ptr_ty=",
+                            print(substs.as_closure().sig_as_fn_ptr_ty())
+                        );
+                        p!(" upvar_tys=(");
+                        self = self.comma_sep(substs.as_closure().upvar_tys())?;
+                        p!(")");
                     }
                 }
                 p!("]");
@@ -1142,7 +1130,7 @@ pub trait PrettyPrinter<'tcx>:
                 // relocations (we have an active `str` reference here). We don't use this
                 // result to affect interpreter execution.
                 let slice = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
-                let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
+                let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
                 p!(write("{:?}", s));
                 Ok(self)
             }
diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
index b0c48a860eb..173e9a31928 100644
--- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
@@ -543,7 +543,7 @@ impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> {
 // tag matches and the correct amount of bytes was read.
 fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error>
 where
-    T: Decodable<D> + Eq + ::std::fmt::Debug,
+    T: Decodable<D> + Eq + std::fmt::Debug,
     V: Decodable<D>,
     D: DecoderWithPosition,
 {
@@ -601,29 +601,6 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
         Ok(ty)
     }
 
-    fn cached_predicate_for_shorthand<F>(
-        &mut self,
-        shorthand: usize,
-        or_insert_with: F,
-    ) -> Result<ty::Predicate<'tcx>, Self::Error>
-    where
-        F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>,
-    {
-        let tcx = self.tcx();
-
-        let cache_key =
-            ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand };
-
-        if let Some(&pred) = tcx.pred_rcache.borrow().get(&cache_key) {
-            return Ok(pred);
-        }
-
-        let pred = or_insert_with(self)?;
-        // This may overwrite the entry, but it should overwrite with the same value.
-        tcx.pred_rcache.borrow_mut().insert_same(cache_key, pred);
-        Ok(pred)
-    }
-
     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
     where
         F: FnOnce(&mut Self) -> R,
@@ -1023,7 +1000,7 @@ where
     let _timer = tcx
         .sess
         .prof
-        .extra_verbose_generic_activity("encode_query_results_for", ::std::any::type_name::<Q>());
+        .extra_verbose_generic_activity("encode_query_results_for", std::any::type_name::<Q>());
 
     let state = Q::query_state(tcx);
     assert!(state.all_inactive());
diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs
index f3fa3634026..27bf22dac75 100644
--- a/compiler/rustc_middle/src/ty/query/plumbing.rs
+++ b/compiler/rustc_middle/src/ty/query/plumbing.rs
@@ -124,20 +124,23 @@ impl<'tcx> TyCtxt<'tcx> {
         })
     }
 
-    pub fn try_print_query_stack(handler: &Handler) {
+    pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
         eprintln!("query stack during panic:");
 
         // Be careful reyling on global state here: this code is called from
         // a panic hook, which means that the global `Handler` may be in a weird
         // state if it was responsible for triggering the panic.
+        let mut i = 0;
         ty::tls::with_context_opt(|icx| {
             if let Some(icx) = icx {
                 let query_map = icx.tcx.queries.try_collect_active_jobs();
 
                 let mut current_query = icx.query;
-                let mut i = 0;
 
                 while let Some(query) = current_query {
+                    if Some(i) == num_frames {
+                        break;
+                    }
                     let query_info =
                         if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) {
                             info
@@ -163,7 +166,11 @@ impl<'tcx> TyCtxt<'tcx> {
             }
         });
 
-        eprintln!("end of query stack");
+        if num_frames == None || num_frames >= Some(i) {
+            eprintln!("end of query stack");
+        } else {
+            eprintln!("we're just showing a limited slice of the query stack");
+        }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 1af56972ad0..870cc4eee05 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -656,6 +656,14 @@ impl<'tcx> UpvarSubsts<'tcx> {
         };
         tupled_upvars_ty.expect_ty().tuple_fields()
     }
+
+    #[inline]
+    pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
+        match self {
+            UpvarSubsts::Closure(substs) => substs.as_closure().tupled_upvars_ty(),
+            UpvarSubsts::Generator(substs) => substs.as_generator().tupled_upvars_ty(),
+        }
+    }
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 1bd3bcb6a4d..7d96adb7c8b 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -1,6 +1,5 @@
 // Type substitutions.
 
-use crate::infer::canonical::Canonical;
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
@@ -648,8 +647,6 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> {
     }
 }
 
-pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>;
-
 /// Stores the user-given substs to reach some fully qualified path
 /// (e.g., `<T>::Item` or `<T as Trait>::Item`).
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 9d5b558234b..86476dffc03 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -123,10 +123,26 @@ impl<'tcx> TyCtxt<'tcx> {
         self_ty: Ty<'tcx>,
         mut f: F,
     ) {
+        let _: Option<()> = self.find_map_relevant_impl(def_id, self_ty, |did| {
+            f(did);
+            None
+        });
+    }
+
+    /// Applies function to every impl that could possibly match the self type `self_ty` and returns
+    /// the first non-none value.
+    pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>(
+        self,
+        def_id: DefId,
+        self_ty: Ty<'tcx>,
+        mut f: F,
+    ) -> Option<T> {
         let impls = self.trait_impls_of(def_id);
 
         for &impl_def_id in impls.blanket_impls.iter() {
-            f(impl_def_id);
+            if let result @ Some(_) = f(impl_def_id) {
+                return result;
+            }
         }
 
         // simplify_type(.., false) basically replaces type parameters and
@@ -157,14 +173,20 @@ impl<'tcx> TyCtxt<'tcx> {
         if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 for &impl_def_id in impls {
-                    f(impl_def_id);
+                    if let result @ Some(_) = f(impl_def_id) {
+                        return result;
+                    }
                 }
             }
         } else {
             for &impl_def_id in impls.non_blanket_impls.values().flatten() {
-                f(impl_def_id);
+                if let result @ Some(_) = f(impl_def_id) {
+                    return result;
+                }
             }
         }
+
+        None
     }
 
     /// Returns an iterator containing all impls
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 4127b6535bc..b0f0f0ba57f 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -6,9 +6,9 @@ use crate::mir::interpret::{sign_extend, truncate};
 use crate::ty::fold::TypeFolder;
 use crate::ty::layout::IntegerExt;
 use crate::ty::query::TyCtxtAt;
-use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef};
+use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
 use crate::ty::TyKind::*;
-use crate::ty::{self, DefIdTree, GenericParamDefKind, List, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, DefIdTree, List, Ty, TyCtxt, TypeFoldable};
 use rustc_apfloat::Float as _;
 use rustc_ast as ast;
 use rustc_attr::{self as attr, SignedInt, UnsignedInt};
@@ -341,19 +341,19 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn calculate_dtor(
         self,
         adt_did: DefId,
-        validate: &mut dyn FnMut(Self, DefId) -> Result<(), ErrorReported>,
+        validate: impl Fn(Self, DefId) -> Result<(), ErrorReported>,
     ) -> Option<ty::Destructor> {
         let drop_trait = self.lang_items().drop_trait()?;
         self.ensure().coherent_trait(drop_trait);
 
-        let mut dtor_did = None;
         let ty = self.type_of(adt_did);
-        self.for_each_relevant_impl(drop_trait, ty, |impl_did| {
+        let dtor_did = self.find_map_relevant_impl(drop_trait, ty, |impl_did| {
             if let Some(item) = self.associated_items(impl_did).in_definition_order().next() {
                 if validate(self, impl_did).is_ok() {
-                    dtor_did = Some(item.def_id);
+                    return Some(item.def_id);
                 }
             }
+            None
         });
 
         Some(ty::Destructor { did: dtor_did? })
@@ -509,20 +509,6 @@ impl<'tcx> TyCtxt<'tcx> {
         Some(ty::Binder::bind(env_ty))
     }
 
-    /// Given the `DefId` of some item that has no type or const parameters, make
-    /// a suitable "empty substs" for it.
-    pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> SubstsRef<'tcx> {
-        InternalSubsts::for_item(self, item_def_id, |param, _| match param.kind {
-            GenericParamDefKind::Lifetime => self.lifetimes.re_erased.into(),
-            GenericParamDefKind::Type { .. } => {
-                bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
-            }
-            GenericParamDefKind::Const { .. } => {
-                bug!("empty_substs_for_def_id: {:?} has const parameters", item_def_id)
-            }
-        })
-    }
-
     /// Returns `true` if the node pointed to by `def_id` is a `static` item.
     pub fn is_static(self, def_id: DefId) -> bool {
         self.static_mutability(def_id).is_some()
@@ -646,8 +632,8 @@ impl<'tcx> ty::TyS<'tcx> {
             }
             ty::Char => Some(std::char::MAX as u128),
             ty::Float(fty) => Some(match fty {
-                ast::FloatTy::F32 => ::rustc_apfloat::ieee::Single::INFINITY.to_bits(),
-                ast::FloatTy::F64 => ::rustc_apfloat::ieee::Double::INFINITY.to_bits(),
+                ast::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(),
+                ast::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(),
             }),
             _ => None,
         };
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
index 9728662c984..e1af6fc07cf 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -1,11 +1,11 @@
 use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_index::vec::Idx;
-use rustc_middle::mir::{self, ClearCrossCrate, Local, LocalInfo, Location};
+use rustc_middle::mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location};
 use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::source_map::DesugaringKind;
-use rustc_span::symbol::kw;
+use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
 
 use crate::borrow_check::diagnostics::BorrowedContentSource;
@@ -211,36 +211,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
             // Suggest removing a `&mut` from the use of a mutable reference.
             PlaceRef { local, projection: [] }
-                if {
-                    self.body
-                        .local_decls
-                        .get(local)
-                        .map(|local_decl| {
-                            if let Some(box LocalInfo::User(ClearCrossCrate::Set(
-                                mir::BindingForm::ImplicitSelf(kind),
-                            ))) = local_decl.local_info
-                            {
-                                // Check if the user variable is a `&mut self` and we can therefore
-                                // suggest removing the `&mut`.
-                                //
-                                // Deliberately fall into this case for all implicit self types,
-                                // so that we don't fall in to the next case with them.
-                                kind == mir::ImplicitSelfKind::MutRef
-                            } else if Some(kw::SelfLower) == self.local_names[local] {
-                                // Otherwise, check if the name is the self kewyord - in which case
-                                // we have an explicit self. Do the same thing in this case and check
-                                // for a `self: &mut Self` to suggest removing the `&mut`.
-                                if let ty::Ref(_, _, hir::Mutability::Mut) = local_decl.ty.kind() {
-                                    true
-                                } else {
-                                    false
-                                }
-                            } else {
-                                false
-                            }
-                        })
-                        .unwrap_or(false)
-                } =>
+                if self
+                    .body
+                    .local_decls
+                    .get(local)
+                    .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local]))
+                    .unwrap_or(false) =>
             {
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
                 err.span_label(span, "try removing `&mut` here");
@@ -581,6 +557,34 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
     }
 }
 
+fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
+    debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());
+
+    match local_decl.local_info.as_deref() {
+        // Check if mutably borrowing a mutable reference.
+        Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var(
+            mir::VarBindingForm {
+                binding_mode: ty::BindingMode::BindByValue(Mutability::Not), ..
+            },
+        )))) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
+        Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(kind)))) => {
+            // Check if the user variable is a `&mut self` and we can therefore
+            // suggest removing the `&mut`.
+            //
+            // Deliberately fall into this case for all implicit self types,
+            // so that we don't fall in to the next case with them.
+            *kind == mir::ImplicitSelfKind::MutRef
+        }
+        _ if Some(kw::SelfLower) == local_name => {
+            // Otherwise, check if the name is the `self` keyword - in which case
+            // we have an explicit self. Do the same thing in this case and check
+            // for a `self: &mut Self` to suggest removing the `&mut`.
+            matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut))
+        }
+        _ => false,
+    }
+}
+
 fn suggest_ampmut_self<'tcx>(
     tcx: TyCtxt<'tcx>,
     local_decl: &mir::LocalDecl<'tcx>,
diff --git a/compiler/rustc_mir/src/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs
index c84ccafaff5..8c05e6fd5d0 100644
--- a/compiler/rustc_mir/src/borrow_check/invalidation.rs
+++ b/compiler/rustc_mir/src/borrow_check/invalidation.rs
@@ -117,7 +117,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
         self.check_activations(location);
 
         match &terminator.kind {
-            TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => {
+            TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => {
                 self.consume_operand(location, discr);
             }
             TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => {
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index 9b34db1de40..4b7af271bae 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -671,7 +671,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc
         self.check_activations(loc, span, flow_state);
 
         match term.kind {
-            TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => {
+            TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => {
                 self.consume_operand(loc, (discr, span), flow_state);
             }
             TerminatorKind::Drop { place: ref drop_place, target: _, unwind: _ } => {
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
index f8a8801595a..4fc1c570e46 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -1777,7 +1777,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 self.assert_iscleanup(body, block_data, target, is_cleanup)
             }
             TerminatorKind::SwitchInt { ref targets, .. } => {
-                for target in targets {
+                for target in targets.all_targets() {
                     self.assert_iscleanup(body, block_data, *target, is_cleanup);
                 }
             }
diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs
index 57aa216850a..6ef73b04238 100644
--- a/compiler/rustc_mir/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs
@@ -343,7 +343,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
                     // deny-by-default lint
                     _ => {
                         if let Some(p) = cid.promoted {
-                            let span = tcx.promoted_mir_of_opt_const_arg(def.to_global())[p].span;
+                            let span = tcx.promoted_mir_opt_const_arg(def.to_global())[p].span;
                             if let err_inval!(ReferencedConstant) = err.error {
                                 Err(err.report_as_error(
                                     tcx.at(span),
diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs
index 978d2fe0004..4b235e1aa4a 100644
--- a/compiler/rustc_mir/src/const_eval/mod.rs
+++ b/compiler/rustc_mir/src/const_eval/mod.rs
@@ -50,7 +50,7 @@ pub(crate) fn destructure_const<'tcx>(
     let (field_count, variant, down) = match val.ty.kind() {
         ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
         ty::Adt(def, _) if def.variants.is_empty() => {
-            return mir::DestructuredConst { variant: None, fields: tcx.arena.alloc_slice(&[]) };
+            return mir::DestructuredConst { variant: None, fields: &[] };
         }
         ty::Adt(def, _) => {
             let variant = ecx.read_discriminant(op).unwrap().1;
diff --git a/compiler/rustc_mir/src/dataflow/framework/direction.rs b/compiler/rustc_mir/src/dataflow/framework/direction.rs
index ca2bb6e0bf7..8a9ced91eb3 100644
--- a/compiler/rustc_mir/src/dataflow/framework/direction.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/direction.rs
@@ -1,5 +1,5 @@
 use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::{self, BasicBlock, Location};
+use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets};
 use rustc_middle::ty::TyCtxt;
 use std::ops::RangeInclusive;
 
@@ -488,11 +488,10 @@ impl Direction for Forward {
                 }
             }
 
-            SwitchInt { ref targets, ref values, ref discr, switch_ty: _ } => {
+            SwitchInt { ref targets, ref discr, switch_ty: _ } => {
                 let mut applier = SwitchIntEdgeEffectApplier {
                     exit_state,
-                    targets: targets.as_ref(),
-                    values: values.as_ref(),
+                    targets,
                     propagate,
                     effects_applied: false,
                 };
@@ -504,8 +503,8 @@ impl Direction for Forward {
                 } = applier;
 
                 if !effects_applied {
-                    for &target in targets.iter() {
-                        propagate(target, exit_state);
+                    for target in targets.all_targets() {
+                        propagate(*target, exit_state);
                     }
                 }
             }
@@ -515,8 +514,7 @@ impl Direction for Forward {
 
 struct SwitchIntEdgeEffectApplier<'a, D, F> {
     exit_state: &'a mut D,
-    values: &'a [u128],
-    targets: &'a [BasicBlock],
+    targets: &'a SwitchTargets,
     propagate: F,
 
     effects_applied: bool,
@@ -531,7 +529,7 @@ where
         assert!(!self.effects_applied);
 
         let mut tmp = None;
-        for (&value, &target) in self.values.iter().zip(self.targets.iter()) {
+        for (value, target) in self.targets.iter() {
             let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state);
             apply_edge_effect(tmp, SwitchIntTarget { value: Some(value), target });
             (self.propagate)(target, tmp);
@@ -539,7 +537,7 @@ where
 
         // Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`,
         // so pass it directly to `apply_edge_effect` to save a clone of the dataflow state.
-        let otherwise = self.targets.last().copied().unwrap();
+        let otherwise = self.targets.otherwise();
         apply_edge_effect(self.exit_state, SwitchIntTarget { value: None, target: otherwise });
         (self.propagate)(otherwise, self.exit_state);
 
diff --git a/compiler/rustc_mir/src/dataflow/framework/engine.rs b/compiler/rustc_mir/src/dataflow/framework/engine.rs
index b836e85c3a7..1b7264f86a2 100644
--- a/compiler/rustc_mir/src/dataflow/framework/engine.rs
+++ b/compiler/rustc_mir/src/dataflow/framework/engine.rs
@@ -2,7 +2,6 @@
 
 use std::borrow::BorrowMut;
 use std::ffi::OsString;
-use std::fs;
 use std::path::PathBuf;
 
 use rustc_ast as ast;
@@ -12,7 +11,7 @@ use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::{self, traversal, BasicBlock};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::{sym, Symbol};
 
 use super::fmt::DebugWithContext;
@@ -21,7 +20,7 @@ use super::{
     visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice,
     ResultsCursor, ResultsVisitor,
 };
-use crate::util::pretty::dump_enabled;
+use crate::util::pretty::{create_dump_file, dump_enabled};
 
 /// A dataflow analysis that has converged to fixpoint.
 pub struct Results<'tcx, A>
@@ -63,15 +62,6 @@ where
         let blocks = mir::traversal::reachable(body);
         visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
     }
-
-    pub fn visit_in_rpo_with(
-        &self,
-        body: &'mir mir::Body<'tcx>,
-        vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>,
-    ) {
-        let blocks = mir::traversal::reverse_postorder(body);
-        visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
-    }
 }
 
 /// A solver for dataflow problems.
@@ -249,7 +239,7 @@ where
 
         let res = write_graphviz_results(tcx, &body, &results, pass_name);
         if let Err(e) = res {
-            warn!("Failed to write graphviz dataflow results: {}", e);
+            error!("Failed to write graphviz dataflow results: {}", e);
         }
 
         results
@@ -270,6 +260,9 @@ where
     A: Analysis<'tcx>,
     A::Domain: DebugWithContext<A>,
 {
+    use std::fs;
+    use std::io::{self, Write};
+
     let def_id = body.source.def_id();
     let attrs = match RustcMirAttrs::parse(tcx, def_id) {
         Ok(attrs) => attrs,
@@ -278,27 +271,29 @@ where
         Err(()) => return Ok(()),
     };
 
-    let path = match attrs.output_path(A::NAME) {
-        Some(path) => path,
+    let mut file = match attrs.output_path(A::NAME) {
+        Some(path) => {
+            debug!("printing dataflow results for {:?} to {}", def_id, path.display());
+            if let Some(parent) = path.parent() {
+                fs::create_dir_all(parent)?;
+            }
+            io::BufWriter::new(fs::File::create(&path)?)
+        }
 
         None if tcx.sess.opts.debugging_opts.dump_mir_dataflow
             && dump_enabled(tcx, A::NAME, def_id) =>
         {
-            // FIXME: Use some variant of `pretty::dump_path` for this
-            let mut path = PathBuf::from(&tcx.sess.opts.debugging_opts.dump_mir_dir);
-
-            let crate_name = tcx.crate_name(def_id.krate);
-            let item_name = ty::print::with_forced_impl_filename_line(|| {
-                tcx.def_path(def_id).to_filename_friendly_no_crate()
-            });
-
-            let pass_name = pass_name.map(|s| format!(".{}", s)).unwrap_or_default();
-
-            path.push(format!("{}.{}.{}{}.dot", crate_name, item_name, A::NAME, pass_name));
-            path
+            create_dump_file(
+                tcx,
+                ".dot",
+                None,
+                A::NAME,
+                &pass_name.unwrap_or("-----"),
+                body.source,
+            )?
         }
 
-        None => return Ok(()),
+        _ => return Ok(()),
     };
 
     let style = match attrs.formatter {
@@ -306,7 +301,6 @@ where
         _ => graphviz::OutputStyle::AfterOnly,
     };
 
-    debug!("printing dataflow results for {:?} to {}", def_id, path.display());
     let mut buf = Vec::new();
 
     let graphviz = graphviz::Formatter::new(body, results, style);
@@ -317,10 +311,7 @@ where
     }
     dot::render_opts(&graphviz, &mut buf, &render_opts)?;
 
-    if let Some(parent) = path.parent() {
-        fs::create_dir_all(parent)?;
-    }
-    fs::write(&path, buf)?;
+    file.write_all(&buf)?;
 
     Ok(())
 }
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index 93da6e3d38a..ec1195d3703 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -477,16 +477,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
         trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
         if let Some(promoted) = promoted {
-            return Ok(&self.tcx.promoted_mir_of_opt_const_arg(def)[promoted]);
+            return Ok(&self.tcx.promoted_mir_opt_const_arg(def)[promoted]);
         }
         match instance {
             ty::InstanceDef::Item(def) => {
                 if self.tcx.is_mir_available(def.did) {
-                    if let Some((did, param_did)) = def.as_const_arg() {
-                        Ok(self.tcx.optimized_mir_of_const_arg((did, param_did)))
-                    } else {
-                        Ok(self.tcx.optimized_mir(def.did))
-                    }
+                    Ok(self.tcx.optimized_mir_opt_const_arg(def))
                 } else {
                     throw_unsup!(NoMirFor(def.did))
                 }
diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs
index 3718da1723b..66dbacb2f9d 100644
--- a/compiler/rustc_mir/src/interpret/machine.rs
+++ b/compiler/rustc_mir/src/interpret/machine.rs
@@ -3,6 +3,7 @@
 //! interpreting common C functions leak into CTFE.
 
 use std::borrow::{Borrow, Cow};
+use std::fmt::Debug;
 use std::hash::Hash;
 
 use rustc_middle::mir;
@@ -79,19 +80,19 @@ pub trait AllocMap<K: Hash + Eq, V> {
 /// and some use case dependent behaviour can instead be applied.
 pub trait Machine<'mir, 'tcx>: Sized {
     /// Additional memory kinds a machine wishes to distinguish from the builtin ones
-    type MemoryKind: ::std::fmt::Debug + ::std::fmt::Display + MayLeak + Eq + 'static;
+    type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static;
 
     /// Tag tracked alongside every pointer. This is used to implement "Stacked Borrows"
     /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
     /// The `default()` is used for pointers to consts, statics, vtables and functions.
     /// The `Debug` formatting is used for displaying pointers; we cannot use `Display`
     /// as `()` does not implement that, but it should be "nice" output.
-    type PointerTag: ::std::fmt::Debug + Copy + Eq + Hash + 'static;
+    type PointerTag: Debug + Copy + Eq + Hash + 'static;
 
     /// Machines can define extra (non-instance) things that represent values of function pointers.
     /// For example, Miri uses this to return a function pointer from `dlsym`
     /// that can later be called to execute the right thing.
-    type ExtraFnVal: ::std::fmt::Debug + Copy;
+    type ExtraFnVal: Debug + Copy;
 
     /// Extra data stored in every call frame.
     type FrameExtra;
diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs
index 735f890a33b..d8f27ec9545 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_mir/src/interpret/operand.rs
@@ -133,7 +133,7 @@ impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> {
     }
 }
 
-impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> {
+impl<'tcx, Tag> std::ops::Deref for ImmTy<'tcx, Tag> {
     type Target = Immediate<Tag>;
     #[inline(always)]
     fn deref(&self) -> &Immediate<Tag> {
@@ -156,7 +156,7 @@ pub struct OpTy<'tcx, Tag = ()> {
     pub layout: TyAndLayout<'tcx>,
 }
 
-impl<'tcx, Tag> ::std::ops::Deref for OpTy<'tcx, Tag> {
+impl<'tcx, Tag> std::ops::Deref for OpTy<'tcx, Tag> {
     type Target = Operand<Tag>;
     #[inline(always)]
     fn deref(&self) -> &Operand<Tag> {
@@ -340,7 +340,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn read_str(&self, mplace: MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> {
         let len = mplace.len(self)?;
         let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len))?;
-        let str = ::std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?;
+        let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?;
         Ok(str)
     }
 
diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs
index 72551b23370..fe25f8ce962 100644
--- a/compiler/rustc_mir/src/interpret/place.rs
+++ b/compiler/rustc_mir/src/interpret/place.rs
@@ -3,6 +3,7 @@
 //! All high-level functions to write to memory work on places as destinations.
 
 use std::convert::TryFrom;
+use std::fmt::Debug;
 use std::hash::Hash;
 
 use rustc_macros::HashStable;
@@ -86,7 +87,7 @@ pub struct PlaceTy<'tcx, Tag = ()> {
     pub layout: TyAndLayout<'tcx>,
 }
 
-impl<'tcx, Tag> ::std::ops::Deref for PlaceTy<'tcx, Tag> {
+impl<'tcx, Tag> std::ops::Deref for PlaceTy<'tcx, Tag> {
     type Target = Place<Tag>;
     #[inline(always)]
     fn deref(&self) -> &Place<Tag> {
@@ -101,7 +102,7 @@ pub struct MPlaceTy<'tcx, Tag = ()> {
     pub layout: TyAndLayout<'tcx>,
 }
 
-impl<'tcx, Tag> ::std::ops::Deref for MPlaceTy<'tcx, Tag> {
+impl<'tcx, Tag> std::ops::Deref for MPlaceTy<'tcx, Tag> {
     type Target = MemPlace<Tag>;
     #[inline(always)]
     fn deref(&self) -> &MemPlace<Tag> {
@@ -226,7 +227,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
 }
 
 // These are defined here because they produce a place.
-impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> {
+impl<'tcx, Tag: Debug + Copy> OpTy<'tcx, Tag> {
     #[inline(always)]
     /// Note: do not call `as_ref` on the resulting place. This function should only be used to
     /// read from the resulting mplace, not to get its address back.
@@ -251,7 +252,7 @@ impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> {
     }
 }
 
-impl<Tag: ::std::fmt::Debug> Place<Tag> {
+impl<Tag: Debug> Place<Tag> {
     #[inline]
     pub fn assert_mem_place(self) -> MemPlace<Tag> {
         match self {
@@ -261,7 +262,7 @@ impl<Tag: ::std::fmt::Debug> Place<Tag> {
     }
 }
 
-impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
+impl<'tcx, Tag: Debug> PlaceTy<'tcx, Tag> {
     #[inline]
     pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> {
         MPlaceTy { mplace: self.place.assert_mem_place(), layout: self.layout }
@@ -272,7 +273,7 @@ impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
 impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M>
 where
     // FIXME: Working around https://github.com/rust-lang/rust/issues/54385
-    Tag: ::std::fmt::Debug + Copy + Eq + Hash + 'static,
+    Tag: Debug + Copy + Eq + Hash + 'static,
     M: Machine<'mir, 'tcx, PointerTag = Tag>,
     // FIXME: Working around https://github.com/rust-lang/rust/issues/24159
     M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKind>, Allocation<Tag, M::AllocExtra>)>,
diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs
index 9f200ca62b8..bb11c2a23bd 100644
--- a/compiler/rustc_mir/src/interpret/terminator.rs
+++ b/compiler/rustc_mir/src/interpret/terminator.rs
@@ -24,16 +24,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
             Goto { target } => self.go_to_block(target),
 
-            SwitchInt { ref discr, ref values, ref targets, switch_ty } => {
+            SwitchInt { ref discr, ref targets, switch_ty } => {
                 let discr = self.read_immediate(self.eval_operand(discr, None)?)?;
                 trace!("SwitchInt({:?})", *discr);
                 assert_eq!(discr.layout.ty, switch_ty);
 
                 // Branch to the `otherwise` case by default, if no match is found.
-                assert!(!targets.is_empty());
-                let mut target_block = targets[targets.len() - 1];
+                assert!(!targets.iter().is_empty());
+                let mut target_block = targets.otherwise();
 
-                for (index, &const_int) in values.iter().enumerate() {
+                for (const_int, target) in targets.iter() {
                     // Compare using binary_op, to also support pointer values
                     let res = self
                         .overflowing_binary_op(
@@ -43,7 +43,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         )?
                         .0;
                     if res.to_bool()? {
-                        target_block = targets[index];
+                        target_block = target;
                         break;
                     }
                 }
diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs
index 7e12cc9176e..417176564b9 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -197,6 +197,7 @@ use rustc_session::config::EntryFnType;
 use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP};
 use smallvec::SmallVec;
 use std::iter;
+use std::ops::Range;
 use std::path::PathBuf;
 
 #[derive(PartialEq)]
@@ -210,9 +211,8 @@ pub enum MonoItemCollectionMode {
 pub struct InliningMap<'tcx> {
     // Maps a source mono item to the range of mono items
     // accessed by it.
-    // The two numbers in the tuple are the start (inclusive) and
-    // end index (exclusive) within the `targets` vecs.
-    index: FxHashMap<MonoItem<'tcx>, (usize, usize)>,
+    // The range selects elements within the `targets` vecs.
+    index: FxHashMap<MonoItem<'tcx>, Range<usize>>,
     targets: Vec<MonoItem<'tcx>>,
 
     // Contains one bit per mono item in the `targets` field. That bit
@@ -245,7 +245,7 @@ impl<'tcx> InliningMap<'tcx> {
         }
 
         let end_index = self.targets.len();
-        assert!(self.index.insert(source, (start_index, end_index)).is_none());
+        assert!(self.index.insert(source, start_index..end_index).is_none());
     }
 
     // Internally iterate over all items referenced by `source` which will be
@@ -254,9 +254,9 @@ impl<'tcx> InliningMap<'tcx> {
     where
         F: FnMut(MonoItem<'tcx>),
     {
-        if let Some(&(start_index, end_index)) = self.index.get(&source) {
-            for (i, candidate) in self.targets[start_index..end_index].iter().enumerate() {
-                if self.inlines.contains(start_index + i) {
+        if let Some(range) = self.index.get(&source) {
+            for (i, candidate) in self.targets[range.clone()].iter().enumerate() {
+                if self.inlines.contains(range.start + i) {
                     f(*candidate);
                 }
             }
@@ -268,8 +268,8 @@ impl<'tcx> InliningMap<'tcx> {
     where
         F: FnMut(MonoItem<'tcx>, &[MonoItem<'tcx>]),
     {
-        for (&accessor, &(start_index, end_index)) in &self.index {
-            f(accessor, &self.targets[start_index..end_index])
+        for (&accessor, range) in &self.index {
+            f(accessor, &self.targets[range.clone()])
         }
     }
 }
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
index 3c89111a659..5083a45b539 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
+++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
@@ -532,7 +532,7 @@ fn mono_item_visibility(
 }
 
 fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility {
-    if !tcx.sess.target.target.options.default_hidden_visibility {
+    if !tcx.sess.target.options.default_hidden_visibility {
         return Visibility::Default;
     }
 
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 4d4e9b98917..fb89b36060a 100644
--- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
+++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
@@ -34,7 +34,6 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
 
     fn is_const_item_without_destructor(&self, local: Local) -> Option<DefId> {
         let def_id = self.is_const_item(local)?;
-        let mut any_dtor = |_tcx, _def_id| Ok(());
 
         // We avoid linting mutation of a const item if the const's type has a
         // Drop impl. The Drop logic observes the mutation which was performed.
@@ -54,7 +53,7 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
         //
         //     #[const_mutation_allowed]
         //     pub const LOG: Log = Log { msg: "" };
-        match self.tcx.calculate_dtor(def_id, &mut any_dtor) {
+        match self.tcx.calculate_dtor(def_id, |_, _| Ok(())) {
             Some(_) => None,
             None => Some(def_id),
         }
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index 9a1b77e994d..63b20c7c027 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -558,12 +558,17 @@ pub mod ty {
     #[derive(Debug)]
     pub struct ImplTrait;
     impl NonConstOp for ImplTrait {
-        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
-            mcf_status_in_item(ccx)
+        fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+            Status::Unstable(sym::const_impl_trait)
         }
 
         fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-            mcf_build_error(ccx, span, "`impl Trait` in const fn is unstable")
+            feature_err(
+                &ccx.tcx.sess.parse_sess,
+                sym::const_impl_trait,
+                span,
+                &format!("`impl Trait` is not allowed in {}s", ccx.const_kind()),
+            )
         }
     }
 
diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
index 237a5c7864b..f97dcf4852d 100644
--- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
+++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
@@ -1,7 +1,7 @@
 use crate::{transform::MirPass, util::patch::MirPatch};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{Ty, TyCtxt};
-use std::{borrow::Cow, fmt::Debug};
+use std::fmt::Debug;
 
 use super::simplify::simplify_cfg;
 
@@ -95,15 +95,17 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
                 StatementKind::Assign(box (Place::from(not_equal_temp), not_equal_rvalue)),
             );
 
-            let (mut targets_to_jump_to, values_to_jump_to): (Vec<_>, Vec<_>) = opt_to_apply
+            let new_targets = opt_to_apply
                 .infos
                 .iter()
                 .flat_map(|x| x.second_switch_info.targets_with_values.iter())
-                .cloned()
-                .unzip();
+                .cloned();
+
+            let targets = SwitchTargets::new(
+                new_targets,
+                opt_to_apply.infos[0].first_switch_info.otherwise_bb,
+            );
 
-            // add otherwise case in the end
-            targets_to_jump_to.push(opt_to_apply.infos[0].first_switch_info.otherwise_bb);
             // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal
             let new_switch_data = BasicBlockData::new(Some(Terminator {
                 source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info,
@@ -111,8 +113,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
                     // the first and second discriminants are equal, so just pick one
                     discr: Operand::Copy(first_descriminant_place),
                     switch_ty: discr_type,
-                    values: Cow::from(values_to_jump_to),
-                    targets: targets_to_jump_to,
+                    targets,
                 },
             }));
 
@@ -176,7 +177,7 @@ struct SwitchDiscriminantInfo<'tcx> {
     /// The basic block that the otherwise branch points to
     otherwise_bb: BasicBlock,
     /// Target along with the value being branched from. Otherwise is not included
-    targets_with_values: Vec<(BasicBlock, u128)>,
+    targets_with_values: Vec<(u128, BasicBlock)>,
     discr_source_info: SourceInfo,
     /// The place of the discriminant used in the switch
     discr_used_in_switch: Place<'tcx>,
@@ -211,7 +212,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> {
         let discr = self.find_switch_discriminant_info(bb, switch)?;
 
         // go through each target, finding a discriminant read, and a switch
-        let results = discr.targets_with_values.iter().map(|(target, value)| {
+        let results = discr.targets_with_values.iter().map(|(value, target)| {
             self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone())
         });
 
@@ -253,7 +254,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> {
             }
 
             // check that the value being matched on is the same. The
-            if this_bb_discr_info.targets_with_values.iter().find(|x| x.1 == value).is_none() {
+            if this_bb_discr_info.targets_with_values.iter().find(|x| x.0 == value).is_none() {
                 trace!("NO: values being matched on are not the same");
                 return None;
             }
@@ -270,7 +271,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> {
             //  ```
             // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch
             if !(this_bb_discr_info.targets_with_values.len() == 1
-                && this_bb_discr_info.targets_with_values[0].1 == value)
+                && this_bb_discr_info.targets_with_values[0].0 == value)
             {
                 trace!(
                     "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here"
@@ -296,18 +297,14 @@ impl<'a, 'tcx> Helper<'a, 'tcx> {
         switch: &Terminator<'tcx>,
     ) -> Option<SwitchDiscriminantInfo<'tcx>> {
         match &switch.kind {
-            TerminatorKind::SwitchInt { discr, targets, values, .. } => {
+            TerminatorKind::SwitchInt { discr, targets, .. } => {
                 let discr_local = discr.place()?.as_local()?;
                 // the declaration of the discriminant read. Place of this read is being used in the switch
                 let discr_decl = &self.body.local_decls()[discr_local];
                 let discr_ty = discr_decl.ty;
                 // the otherwise target lies as the last element
-                let otherwise_bb = targets.get(values.len())?.clone();
-                let targets_with_values = targets
-                    .iter()
-                    .zip(values.iter())
-                    .map(|(t, v)| (t.clone(), v.clone()))
-                    .collect();
+                let otherwise_bb = targets.otherwise();
+                let targets_with_values = targets.iter().collect();
 
                 // find the place of the adt where the discriminant is being read from
                 // assume this is the last statement of the block
diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs
index 924bb4996fc..039d4753a8c 100644
--- a/compiler/rustc_mir/src/transform/generator.rs
+++ b/compiler/rustc_mir/src/transform/generator.rs
@@ -71,7 +71,6 @@ use rustc_middle::ty::GeneratorSubsts;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::PanicStrategy;
-use std::borrow::Cow;
 use std::{iter, ops};
 
 pub struct StateTransform;
@@ -839,11 +838,12 @@ fn insert_switch<'tcx>(
 ) {
     let default_block = insert_term_block(body, default);
     let (assign, discr) = transform.get_discr(body);
+    let switch_targets =
+        SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block);
     let switch = TerminatorKind::SwitchInt {
         discr: Operand::Move(discr),
         switch_ty: transform.discr_ty,
-        values: Cow::from(cases.iter().map(|&(i, _)| i as u128).collect::<Vec<_>>()),
-        targets: cases.iter().map(|&(_, d)| d).chain(iter::once(default_block)).collect(),
+        targets: switch_targets,
     };
 
     let source_info = SourceInfo::outermost(body.span);
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index bec1eb79047..34aaefdcbea 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -771,7 +771,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
                 *target = self.update_target(*target);
             }
             TerminatorKind::SwitchInt { ref mut targets, .. } => {
-                for tgt in targets {
+                for tgt in targets.all_targets_mut() {
                     *tgt = self.update_target(*tgt);
                 }
             }
diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs
index dad3812c5cd..8b2d6b09aa8 100644
--- a/compiler/rustc_mir/src/transform/match_branches.rs
+++ b/compiler/rustc_mir/src/transform/match_branches.rs
@@ -46,10 +46,13 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
                     discr: Operand::Copy(ref place) | Operand::Move(ref place),
                     switch_ty,
                     ref targets,
-                    ref values,
                     ..
-                } if targets.len() == 2 && values.len() == 1 && targets[0] != targets[1] => {
-                    (place, values[0], switch_ty, targets[0], targets[1])
+                } if targets.iter().len() == 1 => {
+                    let (value, target) = targets.iter().next().unwrap();
+                    if target == targets.otherwise() {
+                        continue;
+                    }
+                    (place, value, switch_ty, target, targets.otherwise())
                 }
                 // Only optimize switch int statements
                 _ => continue,
diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs
index b4f5947f5a3..ffb84950fc9 100644
--- a/compiler/rustc_mir/src/transform/mod.rs
+++ b/compiler/rustc_mir/src/transform/mod.rs
@@ -137,7 +137,7 @@ fn mir_keys(tcx: TyCtxt<'_>, krate: CrateNum) -> FxHashSet<LocalDefId> {
 /// Generates a default name for the pass based on the name of the
 /// type `T`.
 pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
-    let name = ::std::any::type_name::<T>();
+    let name = std::any::type_name::<T>();
     if let Some(tail) = name.rfind(':') { Cow::from(&name[tail + 1..]) } else { Cow::from(name) }
 }
 
@@ -287,11 +287,7 @@ fn mir_promoted(
     // this point, before we steal the mir-const result.
     // Also this means promotion can rely on all const checks having been done.
     let _ = tcx.mir_const_qualif_opt_const_arg(def);
-    let _ = if let Some(param_did) = def.const_param_did {
-        tcx.mir_abstract_const_of_const_arg((def.did, param_did))
-    } else {
-        tcx.mir_abstract_const(def.did.to_def_id())
-    };
+    let _ = tcx.mir_abstract_const_opt_const_arg(def.to_global());
     let mut body = tcx.mir_const(def).steal();
 
     let mut required_consts = Vec::new();
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index 7abc998d388..7373abcc820 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -124,6 +124,15 @@ impl Candidate {
             Candidate::Argument { .. } | Candidate::InlineAsm { .. } => true,
         }
     }
+
+    fn source_info(&self, body: &Body<'_>) -> SourceInfo {
+        match self {
+            Candidate::Ref(location) | Candidate::Repeat(location) => *body.source_info(*location),
+            Candidate::Argument { bb, .. } | Candidate::InlineAsm { bb, .. } => {
+                *body.source_info(body.terminator_loc(*bb))
+            }
+        }
+    }
 }
 
 fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Vec<usize>> {
@@ -953,6 +962,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                             from_hir_call,
                             fn_span,
                         },
+                        source_info: SourceInfo::outermost(terminator.source_info.span),
                         ..terminator
                     };
                 }
@@ -1163,12 +1173,13 @@ pub fn promote_candidates<'tcx>(
         // Declare return place local so that `mir::Body::new` doesn't complain.
         let initial_locals = iter::once(LocalDecl::new(tcx.types.never, body.span)).collect();
 
+        let mut scope = body.source_scopes[candidate.source_info(body).scope].clone();
+        scope.parent_scope = None;
+
         let mut promoted = Body::new(
             body.source, // `promoted` gets filled in below
             IndexVec::new(),
-            // FIXME: maybe try to filter this to avoid blowing up
-            // memory usage?
-            body.source_scopes.clone(),
+            IndexVec::from_elem_n(scope, 1),
             initial_locals,
             IndexVec::new(),
             0,
diff --git a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
index b45c533d2c0..31e201c3a5b 100644
--- a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
@@ -43,7 +43,7 @@ impl RemoveNoopLandingPads {
                     // These are all nops in a landing pad
                 }
 
-                StatementKind::Assign(box (place, Rvalue::Use(_))) => {
+                StatementKind::Assign(box (place, Rvalue::Use(_) | Rvalue::Discriminant(_))) => {
                     if place.as_local().is_some() {
                         // Writing to a local (e.g., a drop flag) does not
                         // turn a landing pad to a non-nop
diff --git a/compiler/rustc_mir/src/transform/simplify_branches.rs b/compiler/rustc_mir/src/transform/simplify_branches.rs
index 161856a38ee..5f63c03993d 100644
--- a/compiler/rustc_mir/src/transform/simplify_branches.rs
+++ b/compiler/rustc_mir/src/transform/simplify_branches.rs
@@ -29,17 +29,16 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranches {
                 TerminatorKind::SwitchInt {
                     discr: Operand::Constant(ref c),
                     switch_ty,
-                    ref values,
                     ref targets,
                     ..
                 } => {
                     let constant = c.literal.try_eval_bits(tcx, param_env, switch_ty);
                     if let Some(constant) = constant {
-                        let (otherwise, targets) = targets.split_last().unwrap();
-                        let mut ret = TerminatorKind::Goto { target: *otherwise };
-                        for (&v, t) in values.iter().zip(targets.iter()) {
+                        let otherwise = targets.otherwise();
+                        let mut ret = TerminatorKind::Goto { target: otherwise };
+                        for (v, t) in targets.iter() {
                             if v == constant {
-                                ret = TerminatorKind::Goto { target: *t };
+                                ret = TerminatorKind::Goto { target: t };
                                 break;
                             }
                         }
diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
index 9f837cf78a6..6372f8960dd 100644
--- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
@@ -1,8 +1,10 @@
+use std::iter;
+
 use super::MirPass;
 use rustc_middle::{
     mir::{
         interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement,
-        StatementKind, TerminatorKind,
+        StatementKind, SwitchTargets, TerminatorKind,
     },
     ty::{Ty, TyCtxt},
 };
@@ -43,19 +45,21 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
                 Scalar::Ptr(_) => continue,
             };
             const FALSE: u128 = 0;
-            let mut new_targets = opt.targets.clone();
-            let first_is_false_target = opt.values[0] == FALSE;
+
+            let mut new_targets = opt.targets;
+            let first_value = new_targets.iter().next().unwrap().0;
+            let first_is_false_target = first_value == FALSE;
             match opt.op {
                 BinOp::Eq => {
                     // if the assignment was Eq we want the true case to be first
                     if first_is_false_target {
-                        new_targets.swap(0, 1);
+                        new_targets.all_targets_mut().swap(0, 1);
                     }
                 }
                 BinOp::Ne => {
                     // if the assignment was Ne we want the false case to be first
                     if !first_is_false_target {
-                        new_targets.swap(0, 1);
+                        new_targets.all_targets_mut().swap(0, 1);
                     }
                 }
                 _ => unreachable!(),
@@ -96,7 +100,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
                 }
                 storage_deads_to_remove.push((stmt_idx, opt.bb_idx));
                 // if we have StorageDeads to remove then make sure to insert them at the top of each target
-                for bb_idx in new_targets.iter() {
+                for bb_idx in new_targets.all_targets() {
                     storage_deads_to_insert.push((
                         *bb_idx,
                         Statement {
@@ -107,13 +111,18 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
                 }
             }
 
-            let terminator = bb.terminator_mut();
+            let [bb_cond, bb_otherwise] = match new_targets.all_targets() {
+                [a, b] => [*a, *b],
+                e => bug!("expected 2 switch targets, got: {:?}", e),
+            };
+
+            let targets = SwitchTargets::new(iter::once((new_value, bb_cond)), bb_otherwise);
 
+            let terminator = bb.terminator_mut();
             terminator.kind = TerminatorKind::SwitchInt {
                 discr: Operand::Move(opt.to_switch_on),
                 switch_ty: opt.branch_value_ty,
-                values: vec![new_value].into(),
-                targets: new_targets,
+                targets,
             };
         }
 
@@ -138,15 +147,13 @@ impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> {
             .iter_enumerated()
             .filter_map(|(bb_idx, bb)| {
                 // find switch
-                let (place_switched_on, values, targets, place_switched_on_moved) = match &bb
-                    .terminator()
-                    .kind
-                {
-                    rustc_middle::mir::TerminatorKind::SwitchInt {
-                        discr, values, targets, ..
-                    } => Some((discr.place()?, values, targets, discr.is_move())),
-                    _ => None,
-                }?;
+                let (place_switched_on, targets, place_switched_on_moved) =
+                    match &bb.terminator().kind {
+                        rustc_middle::mir::TerminatorKind::SwitchInt { discr, targets, .. } => {
+                            Some((discr.place()?, targets, discr.is_move()))
+                        }
+                        _ => None,
+                    }?;
 
                 // find the statement that assigns the place being switched on
                 bb.statements.iter().enumerate().rev().find_map(|(stmt_idx, stmt)| {
@@ -167,7 +174,6 @@ impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> {
                                         branch_value_scalar,
                                         branch_value_ty,
                                         op: *op,
-                                        values: values.clone().into_owned(),
                                         targets: targets.clone(),
                                     })
                                 }
@@ -220,8 +226,6 @@ struct OptimizationInfo<'tcx> {
     branch_value_ty: Ty<'tcx>,
     /// Either Eq or Ne
     op: BinOp,
-    /// Current values used in the switch target. This needs to be replaced with the branch_value
-    values: Vec<u128>,
     /// Current targets used in the switch
-    targets: Vec<BasicBlock>,
+    targets: SwitchTargets,
 }
diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs
index a4e7a5a9453..27bb1def726 100644
--- a/compiler/rustc_mir/src/transform/simplify_try.rs
+++ b/compiler/rustc_mir/src/transform/simplify_try.rs
@@ -576,15 +576,13 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
             .iter_enumerated()
             .filter_map(|(bb_idx, bb)| {
                 let (discr_switched_on, targets_and_values) = match &bb.terminator().kind {
-                    TerminatorKind::SwitchInt { targets, discr, values, .. } => {
-                        // if values.len() == targets.len() - 1, we need to include None where no value is present
-                        // such that the zip does not throw away targets. If no `otherwise` case is in targets, the zip will simply throw away the added None
-                        let values_extended = values.iter().map(|x|Some(*x)).chain(once(None));
-                        let targets_and_values:Vec<_> = targets.iter().zip(values_extended)
-                            .map(|(target, value)| SwitchTargetAndValue{target:*target, value})
+                    TerminatorKind::SwitchInt { targets, discr, .. } => {
+                        let targets_and_values: Vec<_> = targets.iter()
+                            .map(|(val, target)| SwitchTargetAndValue { target, value: Some(val) })
+                            .chain(once(SwitchTargetAndValue { target: targets.otherwise(), value: None }))
                             .collect();
-                        assert_eq!(targets.len(), targets_and_values.len());
-                        (discr, targets_and_values)},
+                        (discr, targets_and_values)
+                    },
                     _ => return None,
                 };
 
diff --git a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
index a6bfa0c7409..465832c89fd 100644
--- a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
@@ -1,8 +1,10 @@
 //! A pass that eliminates branches on uninhabited enum variants.
 
 use crate::transform::MirPass;
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_middle::mir::{
-    BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, TerminatorKind,
+    BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets,
+    TerminatorKind,
 };
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{Ty, TyCtxt};
@@ -52,9 +54,13 @@ fn variant_discriminants<'tcx>(
     layout: &TyAndLayout<'tcx>,
     ty: Ty<'tcx>,
     tcx: TyCtxt<'tcx>,
-) -> Vec<u128> {
+) -> FxHashSet<u128> {
     match &layout.variants {
-        Variants::Single { index } => vec![index.as_u32() as u128],
+        Variants::Single { index } => {
+            let mut res = FxHashSet::default();
+            res.insert(index.as_u32() as u128);
+            res
+        }
         Variants::Multiple { variants, .. } => variants
             .iter_enumerated()
             .filter_map(|(idx, layout)| {
@@ -96,21 +102,15 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
 
             trace!("allowed_variants = {:?}", allowed_variants);
 
-            if let TerminatorKind::SwitchInt { values, targets, .. } =
+            if let TerminatorKind::SwitchInt { targets, .. } =
                 &mut body.basic_blocks_mut()[bb].terminator_mut().kind
             {
-                // take otherwise out early
-                let otherwise = targets.pop().unwrap();
-                assert_eq!(targets.len(), values.len());
-                let mut i = 0;
-                targets.retain(|_| {
-                    let keep = allowed_variants.contains(&values[i]);
-                    i += 1;
-                    keep
-                });
-                targets.push(otherwise);
-
-                values.to_mut().retain(|var| allowed_variants.contains(var));
+                let new_targets = SwitchTargets::new(
+                    targets.iter().filter(|(val, _)| allowed_variants.contains(val)),
+                    targets.otherwise(),
+                );
+
+                *targets = new_targets;
             } else {
                 unreachable!()
             }
diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs
index c6426a06ea1..f6d39dae342 100644
--- a/compiler/rustc_mir/src/transform/unreachable_prop.rs
+++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs
@@ -7,7 +7,6 @@ use crate::transform::MirPass;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
-use std::borrow::Cow;
 
 pub struct UnreachablePropagation;
 
@@ -69,14 +68,15 @@ where
 {
     let terminator = match *terminator_kind {
         TerminatorKind::Goto { target } if predicate(target) => TerminatorKind::Unreachable,
-        TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
-            let original_targets_len = targets.len();
-            let (otherwise, targets) = targets.split_last().unwrap();
+        TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => {
+            let otherwise = targets.otherwise();
+
+            let original_targets_len = targets.iter().len() + 1;
             let (mut values, mut targets): (Vec<_>, Vec<_>) =
-                values.iter().zip(targets.iter()).filter(|(_, &t)| !predicate(t)).unzip();
+                targets.iter().filter(|(_, bb)| !predicate(*bb)).unzip();
 
-            if !predicate(*otherwise) {
-                targets.push(*otherwise);
+            if !predicate(otherwise) {
+                targets.push(otherwise);
             } else {
                 values.pop();
             }
@@ -91,8 +91,10 @@ where
                 TerminatorKind::SwitchInt {
                     discr: discr.clone(),
                     switch_ty,
-                    values: Cow::from(values),
-                    targets,
+                    targets: SwitchTargets::new(
+                        values.iter().copied().zip(targets.iter().copied()),
+                        *targets.last().unwrap(),
+                    ),
                 }
             } else {
                 return None;
diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs
index cf51e86c5bc..beffffa727e 100644
--- a/compiler/rustc_mir/src/transform/validate.rs
+++ b/compiler/rustc_mir/src/transform/validate.rs
@@ -8,7 +8,7 @@ use super::MirPass;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
     AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, Rvalue,
-    Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo,
+    SourceScope, Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo,
 };
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
@@ -229,9 +229,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
         }
     }
 
-    fn visit_var_debug_info(&mut self, _var_debug_info: &VarDebugInfo<'tcx>) {
+    fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) {
         // Debuginfo can contain field projections, which count as a use of the base local. Skip
         // debuginfo so that we avoid the storage liveness assertion in that case.
+        self.visit_source_info(&var_debug_info.source_info);
     }
 
     fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
@@ -334,7 +335,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             TerminatorKind::Goto { target } => {
                 self.check_edge(location, *target, EdgeKind::Normal);
             }
-            TerminatorKind::SwitchInt { targets, values, switch_ty, discr } => {
+            TerminatorKind::SwitchInt { targets, switch_ty, discr } => {
                 let ty = discr.ty(&self.body.local_decls, self.tcx);
                 if ty != *switch_ty {
                     self.fail(
@@ -345,19 +346,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         ),
                     );
                 }
-                if targets.len() != values.len() + 1 {
-                    self.fail(
-                        location,
-                        format!(
-                            "encountered `SwitchInt` terminator with {} values, but {} targets (should be values+1)",
-                            values.len(),
-                            targets.len(),
-                        ),
-                    );
-                }
-                for target in targets {
-                    self.check_edge(location, *target, EdgeKind::Normal);
+                for (_, target) in targets.iter() {
+                    self.check_edge(location, target, EdgeKind::Normal);
                 }
+                self.check_edge(location, targets.otherwise(), EdgeKind::Normal);
             }
             TerminatorKind::Drop { target, unwind, .. } => {
                 self.check_edge(location, *target, EdgeKind::Normal);
@@ -441,4 +433,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
             | TerminatorKind::GeneratorDrop => {}
         }
     }
+
+    fn visit_source_scope(&mut self, scope: &SourceScope) {
+        if self.body.source_scopes.get(*scope).is_none() {
+            self.tcx.sess.diagnostic().delay_span_bug(
+                self.body.span,
+                &format!(
+                    "broken MIR in {:?} ({}):\ninvalid source scope {:?}",
+                    self.body.source.instance, self.when, scope,
+                ),
+            );
+        }
+    }
 }
diff --git a/compiler/rustc_mir/src/util/elaborate_drops.rs b/compiler/rustc_mir/src/util/elaborate_drops.rs
index 43fa15d7e49..0e2d8e5495b 100644
--- a/compiler/rustc_mir/src/util/elaborate_drops.rs
+++ b/compiler/rustc_mir/src/util/elaborate_drops.rs
@@ -588,8 +588,10 @@ where
                 kind: TerminatorKind::SwitchInt {
                     discr: Operand::Move(discr),
                     switch_ty: discr_ty,
-                    values: From::from(values.to_owned()),
-                    targets: blocks,
+                    targets: SwitchTargets::new(
+                        values.iter().copied().zip(blocks.iter().copied()),
+                        *blocks.last().unwrap(),
+                    ),
                 },
             }),
             is_cleanup: unwind.is_cleanup(),
@@ -758,8 +760,6 @@ where
         let elem_size = Place::from(self.new_temp(tcx.types.usize));
         let len = Place::from(self.new_temp(tcx.types.usize));
 
-        static USIZE_SWITCH_ZERO: &[u128] = &[0];
-
         let base_block = BasicBlockData {
             statements: vec![
                 self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)),
@@ -771,11 +771,11 @@ where
                 kind: TerminatorKind::SwitchInt {
                     discr: move_(elem_size),
                     switch_ty: tcx.types.usize,
-                    values: From::from(USIZE_SWITCH_ZERO),
-                    targets: vec![
+                    targets: SwitchTargets::static_if(
+                        0,
                         self.drop_loop_pair(ety, false, len),
                         self.drop_loop_pair(ety, true, len),
-                    ],
+                    ),
                 },
             }),
         };
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index a28a181e935..e46274770be 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -28,8 +28,9 @@ use std::mem;
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Simplify a candidate so that all match pairs require a test.
     ///
-    /// This method will also split a candidate where the only match-pair is an
-    /// or-pattern into multiple candidates. This is so that
+    /// This method will also split a candidate, in which the only
+    /// match-pair is an or-pattern, into multiple candidates.
+    /// This is so that
     ///
     /// match x {
     ///     0 | 1 => { ... },
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 02dcf0394f6..c4191900147 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -167,48 +167,42 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let target_blocks = make_target_blocks(self);
                 // Variants is a BitVec of indexes into adt_def.variants.
                 let num_enum_variants = adt_def.variants.len();
-                let used_variants = variants.count();
                 debug_assert_eq!(target_blocks.len(), num_enum_variants + 1);
                 let otherwise_block = *target_blocks.last().unwrap();
-                let mut targets = Vec::with_capacity(used_variants + 1);
-                let mut values = Vec::with_capacity(used_variants);
                 let tcx = self.hir.tcx();
-                for (idx, discr) in adt_def.discriminants(tcx) {
-                    if variants.contains(idx) {
-                        debug_assert_ne!(
-                            target_blocks[idx.index()],
-                            otherwise_block,
-                            "no canididates for tested discriminant: {:?}",
-                            discr,
-                        );
-                        values.push(discr.val);
-                        targets.push(target_blocks[idx.index()]);
-                    } else {
-                        debug_assert_eq!(
-                            target_blocks[idx.index()],
-                            otherwise_block,
-                            "found canididates for untested discriminant: {:?}",
-                            discr,
-                        );
-                    }
-                }
-                targets.push(otherwise_block);
-                debug!(
-                    "num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
-                    num_enum_variants, values, variants
+                let switch_targets = SwitchTargets::new(
+                    adt_def.discriminants(tcx).filter_map(|(idx, discr)| {
+                        if variants.contains(idx) {
+                            debug_assert_ne!(
+                                target_blocks[idx.index()],
+                                otherwise_block,
+                                "no canididates for tested discriminant: {:?}",
+                                discr,
+                            );
+                            Some((discr.val, target_blocks[idx.index()]))
+                        } else {
+                            debug_assert_eq!(
+                                target_blocks[idx.index()],
+                                otherwise_block,
+                                "found canididates for untested discriminant: {:?}",
+                                discr,
+                            );
+                            None
+                        }
+                    }),
+                    otherwise_block,
                 );
+                debug!("num_enum_variants: {}, variants: {:?}", num_enum_variants, variants);
                 let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
                 let discr = self.temp(discr_ty, test.span);
                 self.cfg.push_assign(block, source_info, discr, Rvalue::Discriminant(place));
-                assert_eq!(values.len() + 1, targets.len());
                 self.cfg.terminate(
                     block,
                     source_info,
                     TerminatorKind::SwitchInt {
                         discr: Operand::Move(discr),
                         switch_ty: discr_ty,
-                        values: From::from(values),
-                        targets,
+                        targets: switch_targets,
                     },
                 );
             }
@@ -230,11 +224,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 } else {
                     // The switch may be inexhaustive so we have a catch all block
                     debug_assert_eq!(options.len() + 1, target_blocks.len());
+                    let otherwise_block = *target_blocks.last().unwrap();
+                    let switch_targets = SwitchTargets::new(
+                        options.values().copied().zip(target_blocks),
+                        otherwise_block,
+                    );
                     TerminatorKind::SwitchInt {
                         discr: Operand::Copy(place),
                         switch_ty,
-                        values: options.values().copied().collect(),
-                        targets: target_blocks,
+                        targets: switch_targets,
                     }
                 };
                 self.cfg.terminate(block, source_info, terminator);
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 047bf7db4c8..69de7c7e2ee 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -71,13 +71,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
             hir::LocalSource::AwaitDesugar => ("`await` future binding", None),
         };
         self.check_irrefutable(&loc.pat, msg, sp);
-        self.check_patterns(false, &loc.pat);
+        self.check_patterns(&loc.pat);
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
         intravisit::walk_param(self, param);
         self.check_irrefutable(&param.pat, "function argument", None);
-        self.check_patterns(false, &param.pat);
+        self.check_patterns(&param.pat);
     }
 }
 
@@ -96,14 +96,14 @@ impl PatCtxt<'_, '_> {
                 }
                 PatternError::FloatBug => {
                     // FIXME(#31407) this is only necessary because float parsing is buggy
-                    ::rustc_middle::mir::interpret::struct_error(
+                    rustc_middle::mir::interpret::struct_error(
                         self.tcx.at(pat_span),
                         "could not evaluate float literal (see issue #31407)",
                     )
                     .emit();
                 }
                 PatternError::NonConstPath(span) => {
-                    ::rustc_middle::mir::interpret::struct_error(
+                    rustc_middle::mir::interpret::struct_error(
                         self.tcx.at(span),
                         "runtime values cannot be referenced in patterns",
                     )
@@ -119,10 +119,7 @@ impl PatCtxt<'_, '_> {
 }
 
 impl<'tcx> MatchVisitor<'_, 'tcx> {
-    fn check_patterns(&mut self, has_guard: bool, pat: &Pat<'_>) {
-        if !self.tcx.features().move_ref_pattern {
-            check_legality_of_move_bindings(self, has_guard, pat);
-        }
+    fn check_patterns(&mut self, pat: &Pat<'_>) {
         pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
         if !self.tcx.features().bindings_after_at {
             check_legality_of_bindings_in_at_patterns(self, pat);
@@ -165,7 +162,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
     ) {
         for arm in arms {
             // Check the arm for some things unrelated to exhaustiveness.
-            self.check_patterns(arm.guard.is_some(), &arm.pat);
+            self.check_patterns(&arm.pat);
         }
 
         let mut cx = self.new_cx(scrut.hir_id);
@@ -601,65 +598,6 @@ fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> b
     !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env)
 }
 
-/// Check the legality of legality of by-move bindings.
-fn check_legality_of_move_bindings(cx: &mut MatchVisitor<'_, '_>, has_guard: bool, pat: &Pat<'_>) {
-    let sess = cx.tcx.sess;
-    let typeck_results = cx.typeck_results;
-
-    // Find all by-ref spans.
-    let mut by_ref_spans = Vec::new();
-    pat.each_binding(|_, hir_id, span, _| {
-        if let Some(ty::BindByReference(_)) =
-            typeck_results.extract_binding_mode(sess, hir_id, span)
-        {
-            by_ref_spans.push(span);
-        }
-    });
-
-    // Find bad by-move spans:
-    let by_move_spans = &mut Vec::new();
-    let mut check_move = |p: &Pat<'_>, sub: Option<&Pat<'_>>| {
-        // Check legality of moving out of the enum.
-        //
-        // `x @ Foo(..)` is legal, but `x @ Foo(y)` isn't.
-        if sub.map_or(false, |p| p.contains_bindings()) {
-            struct_span_err!(sess, p.span, E0007, "cannot bind by-move with sub-bindings")
-                .span_label(p.span, "binds an already bound by-move value by moving it")
-                .emit();
-        } else if !has_guard && !by_ref_spans.is_empty() {
-            by_move_spans.push(p.span);
-        }
-    };
-    pat.walk_always(|p| {
-        if let hir::PatKind::Binding(.., sub) = &p.kind {
-            if let Some(ty::BindByValue(_)) =
-                typeck_results.extract_binding_mode(sess, p.hir_id, p.span)
-            {
-                if is_binding_by_move(cx, p.hir_id, p.span) {
-                    check_move(p, sub.as_deref());
-                }
-            }
-        }
-    });
-
-    // Found some bad by-move spans, error!
-    if !by_move_spans.is_empty() {
-        let mut err = feature_err(
-            &sess.parse_sess,
-            sym::move_ref_pattern,
-            by_move_spans.clone(),
-            "binding by-move and by-ref in the same pattern is unstable",
-        );
-        for span in by_ref_spans.iter() {
-            err.span_label(*span, "by-ref pattern here");
-        }
-        for span in by_move_spans.iter() {
-            err.span_label(*span, "by-move pattern here");
-        }
-        err.emit();
-    }
-}
-
 /// Check that there are no borrow or move conflicts in `binding @ subpat` patterns.
 ///
 /// For example, this would reject:
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 718ed78889f..d46e9a98825 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -1060,13 +1060,13 @@ crate fn compare_const_vals<'tcx>(
         use rustc_apfloat::Float;
         return match *ty.kind() {
             ty::Float(ast::FloatTy::F32) => {
-                let l = ::rustc_apfloat::ieee::Single::from_bits(a);
-                let r = ::rustc_apfloat::ieee::Single::from_bits(b);
+                let l = rustc_apfloat::ieee::Single::from_bits(a);
+                let r = rustc_apfloat::ieee::Single::from_bits(b);
                 l.partial_cmp(&r)
             }
             ty::Float(ast::FloatTy::F64) => {
-                let l = ::rustc_apfloat::ieee::Double::from_bits(a);
-                let r = ::rustc_apfloat::ieee::Double::from_bits(b);
+                let l = rustc_apfloat::ieee::Double::from_bits(a);
+                let r = rustc_apfloat::ieee::Double::from_bits(b);
                 l.partial_cmp(&r)
             }
             ty::Int(ity) => {
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index b68d36c9a8e..25deb46e147 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -7,7 +7,7 @@
 #![feature(or_patterns)]
 
 use rustc_ast as ast;
-use rustc_ast::token::{self, Nonterminal, Token, TokenKind};
+use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::{self, TokenStream, TokenTree};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::sync::Lrc;
@@ -114,16 +114,6 @@ pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, sp: Option<Spa
     source_file_to_parser(sess, file_to_source_file(sess, path, sp))
 }
 
-/// Creates a new parser, returning buffered diagnostics if the file doesn't exist,
-/// or from lexing the initial token stream.
-pub fn maybe_new_parser_from_file<'a>(
-    sess: &'a ParseSess,
-    path: &Path,
-) -> Result<Parser<'a>, Vec<Diagnostic>> {
-    let file = try_file_to_source_file(sess, path, None).map_err(|db| vec![db])?;
-    maybe_source_file_to_parser(sess, file)
-}
-
 /// Given a `source_file` and config, returns a parser.
 fn source_file_to_parser(sess: &ParseSess, source_file: Lrc<SourceFile>) -> Parser<'_> {
     panictry_buffer!(&sess.span_diagnostic, maybe_source_file_to_parser(sess, source_file))
@@ -146,12 +136,6 @@ fn maybe_source_file_to_parser(
     Ok(parser)
 }
 
-// Must preserve old name for now, because `quote!` from the *existing*
-// compiler expands into it.
-pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec<TokenTree>) -> Parser<'_> {
-    stream_to_parser(sess, tts.into_iter().collect(), crate::MACRO_ARGUMENTS)
-}
-
 // Base abstractions
 
 /// Given a session and a path and an optional span (for error reporting),
@@ -297,7 +281,11 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
     };
 
     // FIXME(#43081): Avoid this pretty-print + reparse hack
-    let source = pprust::nonterminal_to_string(nt);
+    // Pretty-print the AST struct without inserting any parenthesis
+    // beyond those explicitly written by the user (e.g. `ExpnKind::Paren`).
+    // The resulting stream may have incorrect precedence, but it's only
+    // ever used for a comparison against the capture tokenstream.
+    let source = pprust::nonterminal_to_string_no_extra_parens(nt);
     let filename = FileName::macro_expansion_source_code(&source);
     let reparsed_tokens = parse_stream_from_source_str(filename, source, sess, Some(span));
 
@@ -325,15 +313,43 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
     // modifications, including adding/removing typically non-semantic
     // tokens such as extra braces and commas, don't happen.
     if let Some(tokens) = tokens {
-        if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess) {
+        // Compare with a non-relaxed delim match to start.
+        if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess, false) {
             return tokens;
         }
+
+        // The check failed. This time, we pretty-print the AST struct with parenthesis
+        // inserted to preserve precedence. This may cause `None`-delimiters in the captured
+        // token stream to match up with inserted parenthesis in the reparsed stream.
+        let source_with_parens = pprust::nonterminal_to_string(nt);
+        let filename_with_parens = FileName::macro_expansion_source_code(&source_with_parens);
+        let reparsed_tokens_with_parens = parse_stream_from_source_str(
+            filename_with_parens,
+            source_with_parens,
+            sess,
+            Some(span),
+        );
+
+        // Compare with a relaxed delim match - we want inserted parenthesis in the
+        // reparsed stream to match `None`-delimiters in the original stream.
+        if tokenstream_probably_equal_for_proc_macro(
+            &tokens,
+            &reparsed_tokens_with_parens,
+            sess,
+            true,
+        ) {
+            return tokens;
+        }
+
         info!(
             "cached tokens found, but they're not \"probably equal\", \
                 going with stringified version"
         );
-        info!("cached tokens: {:?}", tokens);
-        info!("reparsed tokens: {:?}", reparsed_tokens);
+        info!("cached   tokens: {}", pprust::tts_to_string(&tokens));
+        info!("reparsed tokens: {}", pprust::tts_to_string(&reparsed_tokens_with_parens));
+
+        info!("cached   tokens debug: {:?}", tokens);
+        info!("reparsed tokens debug: {:?}", reparsed_tokens_with_parens);
     }
     reparsed_tokens
 }
@@ -347,6 +363,7 @@ pub fn tokenstream_probably_equal_for_proc_macro(
     tokens: &TokenStream,
     reparsed_tokens: &TokenStream,
     sess: &ParseSess,
+    relaxed_delim_match: bool,
 ) -> bool {
     // When checking for `probably_eq`, we ignore certain tokens that aren't
     // preserved in the AST. Because they are not preserved, the pretty
@@ -472,7 +489,9 @@ pub fn tokenstream_probably_equal_for_proc_macro(
     let tokens = tokens.trees().flat_map(|t| expand_token(t, sess));
     let reparsed_tokens = reparsed_tokens.trees().flat_map(|t| expand_token(t, sess));
 
-    tokens.eq_by(reparsed_tokens, |t, rt| tokentree_probably_equal_for_proc_macro(&t, &rt, sess))
+    tokens.eq_by(reparsed_tokens, |t, rt| {
+        tokentree_probably_equal_for_proc_macro(&t, &rt, sess, relaxed_delim_match)
+    })
 }
 
 // See comments in `Nonterminal::to_tokenstream` for why we care about
@@ -484,6 +503,7 @@ pub fn tokentree_probably_equal_for_proc_macro(
     token: &TokenTree,
     reparsed_token: &TokenTree,
     sess: &ParseSess,
+    relaxed_delim_match: bool,
 ) -> bool {
     match (token, reparsed_token) {
         (TokenTree::Token(token), TokenTree::Token(reparsed_token)) => {
@@ -492,9 +512,33 @@ pub fn tokentree_probably_equal_for_proc_macro(
         (
             TokenTree::Delimited(_, delim, tokens),
             TokenTree::Delimited(_, reparsed_delim, reparsed_tokens),
-        ) => {
-            delim == reparsed_delim
-                && tokenstream_probably_equal_for_proc_macro(tokens, reparsed_tokens, sess)
+        ) if delim == reparsed_delim => tokenstream_probably_equal_for_proc_macro(
+            tokens,
+            reparsed_tokens,
+            sess,
+            relaxed_delim_match,
+        ),
+        (TokenTree::Delimited(_, DelimToken::NoDelim, tokens), reparsed_token) => {
+            if relaxed_delim_match {
+                if let TokenTree::Delimited(_, DelimToken::Paren, reparsed_tokens) = reparsed_token
+                {
+                    if tokenstream_probably_equal_for_proc_macro(
+                        tokens,
+                        reparsed_tokens,
+                        sess,
+                        relaxed_delim_match,
+                    ) {
+                        return true;
+                    }
+                }
+            }
+            tokens.len() == 1
+                && tokentree_probably_equal_for_proc_macro(
+                    &tokens.trees().next().unwrap(),
+                    reparsed_token,
+                    sess,
+                    relaxed_delim_match,
+                )
         }
         _ => false,
     }
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 9ab13db4b5f..1ea01d95a13 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -5,8 +5,9 @@ use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Lit, LitKind, TokenKind};
 use rustc_ast::util::parser::AssocOp;
 use rustc_ast::{
-    self as ast, AngleBracketedArgs, AttrVec, BinOpKind, BindingMode, BlockCheckMode, Expr,
-    ExprKind, Item, ItemKind, Mutability, Param, Pat, PatKind, PathSegment, QSelf, Ty, TyKind,
+    self as ast, AngleBracketedArgs, AttrVec, BinOpKind, BindingMode, Block, BlockCheckMode, Expr,
+    ExprKind, Item, ItemKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QSelf, Ty,
+    TyKind,
 };
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
@@ -119,6 +120,28 @@ crate enum ConsumeClosingDelim {
     No,
 }
 
+#[derive(Clone, Copy)]
+pub enum AttemptLocalParseRecovery {
+    Yes,
+    No,
+}
+
+impl AttemptLocalParseRecovery {
+    pub fn yes(&self) -> bool {
+        match self {
+            AttemptLocalParseRecovery::Yes => true,
+            AttemptLocalParseRecovery::No => false,
+        }
+    }
+
+    pub fn no(&self) -> bool {
+        match self {
+            AttemptLocalParseRecovery::Yes => false,
+            AttemptLocalParseRecovery::No => true,
+        }
+    }
+}
+
 impl<'a> Parser<'a> {
     pub(super) fn span_fatal_err<S: Into<MultiSpan>>(
         &self,
@@ -321,6 +344,66 @@ impl<'a> Parser<'a> {
         }
     }
 
+    pub fn maybe_suggest_struct_literal(
+        &mut self,
+        lo: Span,
+        s: BlockCheckMode,
+    ) -> Option<PResult<'a, P<Block>>> {
+        if self.token.is_ident() && self.look_ahead(1, |t| t == &token::Colon) {
+            // We might be having a struct literal where people forgot to include the path:
+            // fn foo() -> Foo {
+            //     field: value,
+            // }
+            let mut snapshot = self.clone();
+            let path =
+                Path { segments: vec![], span: self.prev_token.span.shrink_to_lo(), tokens: None };
+            let struct_expr = snapshot.parse_struct_expr(path, AttrVec::new(), false);
+            let block_tail = self.parse_block_tail(lo, s, AttemptLocalParseRecovery::No);
+            return Some(match (struct_expr, block_tail) {
+                (Ok(expr), Err(mut err)) => {
+                    // We have encountered the following:
+                    // fn foo() -> Foo {
+                    //     field: value,
+                    // }
+                    // Suggest:
+                    // fn foo() -> Foo { Path {
+                    //     field: value,
+                    // } }
+                    err.delay_as_bug();
+                    self.struct_span_err(expr.span, "struct literal body without path")
+                        .multipart_suggestion(
+                            "you might have forgotten to add the struct literal inside the block",
+                            vec![
+                                (expr.span.shrink_to_lo(), "{ SomeStruct ".to_string()),
+                                (expr.span.shrink_to_hi(), " }".to_string()),
+                            ],
+                            Applicability::MaybeIncorrect,
+                        )
+                        .emit();
+                    *self = snapshot;
+                    Ok(self.mk_block(
+                        vec![self.mk_stmt_err(expr.span)],
+                        s,
+                        lo.to(self.prev_token.span),
+                    ))
+                }
+                (Err(mut err), Ok(tail)) => {
+                    // We have a block tail that contains a somehow valid type ascription expr.
+                    err.cancel();
+                    Ok(tail)
+                }
+                (Err(mut snapshot_err), Err(err)) => {
+                    // We don't know what went wrong, emit the normal error.
+                    snapshot_err.cancel();
+                    self.consume_block(token::Brace, ConsumeClosingDelim::Yes);
+                    Err(err)
+                }
+                (Ok(_), Ok(tail)) => Ok(tail),
+            });
+        }
+        None
+    }
+
     pub fn maybe_annotate_with_ascription(
         &mut self,
         err: &mut DiagnosticBuilder<'_>,
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 69d13b5cf53..17cbaf65420 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -16,6 +16,7 @@ use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{BytePos, Pos};
 use std::mem;
 use tracing::debug;
 
@@ -245,11 +246,7 @@ impl<'a> Parser<'a> {
                 this.parse_assoc_expr_with(prec + prec_adjustment, LhsExpr::NotYetParsed)
             })?;
 
-            // Make sure that the span of the parent node is larger than the span of lhs and rhs,
-            // including the attributes.
-            let lhs_span =
-                lhs.attrs.iter().find(|a| a.style == AttrStyle::Outer).map_or(lhs_span, |a| a.span);
-            let span = lhs_span.to(rhs.span);
+            let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span);
             lhs = match op {
                 AssocOp::Add
                 | AssocOp::Subtract
@@ -410,7 +407,7 @@ impl<'a> Parser<'a> {
             None
         };
         let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span);
-        let span = lhs.span.to(rhs_span);
+        let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span);
         let limits =
             if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed };
         Ok(self.mk_expr(span, self.mk_range(Some(lhs), rhs, limits)?, AttrVec::new()))
@@ -570,7 +567,11 @@ impl<'a> Parser<'a> {
         expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind,
     ) -> PResult<'a, P<Expr>> {
         let mk_expr = |this: &mut Self, rhs: P<Ty>| {
-            this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs), AttrVec::new())
+            this.mk_expr(
+                this.mk_expr_sp(&lhs, lhs_span, rhs.span),
+                expr_kind(lhs, rhs),
+                AttrVec::new(),
+            )
         };
 
         // Save the state of the parser before parsing type normally, in case there is a
@@ -839,9 +840,10 @@ impl<'a> Parser<'a> {
         }
         use FloatComponent::*;
 
+        let float_str = float.as_str();
         let mut components = Vec::new();
         let mut ident_like = String::new();
-        for c in float.as_str().chars() {
+        for c in float_str.chars() {
             if c == '_' || c.is_ascii_alphanumeric() {
                 ident_like.push(c);
             } else if matches!(c, '.' | '+' | '-') {
@@ -857,8 +859,13 @@ impl<'a> Parser<'a> {
             components.push(IdentLike(ident_like));
         }
 
-        // FIXME: Make the span more precise.
+        // With proc macros the span can refer to anything, the source may be too short,
+        // or too long, or non-ASCII. It only makes sense to break our span into components
+        // if its underlying text is identical to our float literal.
         let span = self.token.span;
+        let can_take_span_apart =
+            || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();
+
         match &*components {
             // 1e2
             [IdentLike(i)] => {
@@ -866,21 +873,40 @@ impl<'a> Parser<'a> {
             }
             // 1.
             [IdentLike(i), Punct('.')] => {
+                let (ident_span, dot_span) = if can_take_span_apart() {
+                    let (span, ident_len) = (span.data(), BytePos::from_usize(i.len()));
+                    let ident_span = span.with_hi(span.lo + ident_len);
+                    let dot_span = span.with_lo(span.lo + ident_len);
+                    (ident_span, dot_span)
+                } else {
+                    (span, span)
+                };
                 assert!(suffix.is_none());
                 let symbol = Symbol::intern(&i);
-                self.token = Token::new(token::Ident(symbol, false), span);
-                let next_token = Token::new(token::Dot, span);
+                self.token = Token::new(token::Ident(symbol, false), ident_span);
+                let next_token = Token::new(token::Dot, dot_span);
                 self.parse_tuple_field_access_expr(lo, base, symbol, None, Some(next_token))
             }
             // 1.2 | 1.2e3
             [IdentLike(i1), Punct('.'), IdentLike(i2)] => {
+                let (ident1_span, dot_span, ident2_span) = if can_take_span_apart() {
+                    let (span, ident1_len) = (span.data(), BytePos::from_usize(i1.len()));
+                    let ident1_span = span.with_hi(span.lo + ident1_len);
+                    let dot_span = span
+                        .with_lo(span.lo + ident1_len)
+                        .with_hi(span.lo + ident1_len + BytePos(1));
+                    let ident2_span = self.token.span.with_lo(span.lo + ident1_len + BytePos(1));
+                    (ident1_span, dot_span, ident2_span)
+                } else {
+                    (span, span, span)
+                };
                 let symbol1 = Symbol::intern(&i1);
-                self.token = Token::new(token::Ident(symbol1, false), span);
-                let next_token1 = Token::new(token::Dot, span);
+                self.token = Token::new(token::Ident(symbol1, false), ident1_span);
+                let next_token1 = Token::new(token::Dot, dot_span);
                 let base1 =
                     self.parse_tuple_field_access_expr(lo, base, symbol1, None, Some(next_token1));
                 let symbol2 = Symbol::intern(&i2);
-                let next_token2 = Token::new(token::Ident(symbol2, false), span);
+                let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span);
                 self.bump_with(next_token2); // `.`
                 self.parse_tuple_field_access_expr(lo, base1, symbol2, suffix, None)
             }
@@ -2015,9 +2041,12 @@ impl<'a> Parser<'a> {
     ) -> Option<PResult<'a, P<Expr>>> {
         let struct_allowed = !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
         if struct_allowed || self.is_certainly_not_a_block() {
-            // This is a struct literal, but we don't can't accept them here.
-            let expr = self.parse_struct_expr(path.clone(), attrs.clone());
+            if let Err(err) = self.expect(&token::OpenDelim(token::Brace)) {
+                return Some(Err(err));
+            }
+            let expr = self.parse_struct_expr(path.clone(), attrs.clone(), true);
             if let (Ok(expr), false) = (&expr, struct_allowed) {
+                // This is a struct literal, but we don't can't accept them here.
                 self.error_struct_lit_not_allowed_here(path.span, expr.span);
             }
             return Some(expr);
@@ -2035,12 +2064,13 @@ impl<'a> Parser<'a> {
             .emit();
     }
 
+    /// Precondition: already parsed the '{'.
     pub(super) fn parse_struct_expr(
         &mut self,
         pth: ast::Path,
         mut attrs: AttrVec,
+        recover: bool,
     ) -> PResult<'a, P<Expr>> {
-        self.bump();
         let mut fields = Vec::new();
         let mut base = None;
         let mut recover_async = false;
@@ -2059,10 +2089,11 @@ impl<'a> Parser<'a> {
                 let exp_span = self.prev_token.span;
                 match self.parse_expr() {
                     Ok(e) => base = Some(e),
-                    Err(mut e) => {
+                    Err(mut e) if recover => {
                         e.emit();
                         self.recover_stmt();
                     }
+                    Err(e) => return Err(e),
                 }
                 self.recover_struct_comma_after_dotdot(exp_span);
                 break;
@@ -2114,6 +2145,9 @@ impl<'a> Parser<'a> {
                             );
                         }
                     }
+                    if !recover {
+                        return Err(e);
+                    }
                     e.emit();
                     self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
                     self.eat(&token::Comma);
@@ -2290,4 +2324,14 @@ impl<'a> Parser<'a> {
     pub(super) fn mk_expr_err(&self, span: Span) -> P<Expr> {
         self.mk_expr(span, ExprKind::Err, AttrVec::new())
     }
+
+    /// Create expression span ensuring the span of the parent node
+    /// is larger than the span of lhs and rhs, including the attributes.
+    fn mk_expr_sp(&self, lhs: &P<Expr>, lhs_span: Span, rhs_span: Span) -> Span {
+        lhs.attrs
+            .iter()
+            .find(|a| a.style == AttrStyle::Outer)
+            .map_or(lhs_span, |a| a.span)
+            .to(rhs_span)
+    }
 }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 26ca9980127..48341f71d33 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1744,7 +1744,7 @@ impl<'a> Parser<'a> {
             }
         };
 
-        let span = lo.to(self.token.span);
+        let span = lo.until(self.token.span);
 
         Ok(Param {
             attrs: attrs.into(),
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 7340c574480..c1094681221 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -10,6 +10,7 @@ mod stmt;
 mod ty;
 
 use crate::lexer::UnmatchedBrace;
+pub use diagnostics::AttemptLocalParseRecovery;
 use diagnostics::Error;
 pub use path::PathStyle;
 
@@ -386,7 +387,7 @@ impl<'a> Parser<'a> {
         next
     }
 
-    crate fn unexpected<T>(&mut self) -> PResult<'a, T> {
+    pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
         match self.expect_one_of(&[], &[]) {
             Err(e) => Err(e),
             // We can get `Ok(true)` from `recover_closing_delimiter`
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index fd1c6b25aec..131ff1ae6b3 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -1,5 +1,5 @@
 use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN;
-use super::diagnostics::Error;
+use super::diagnostics::{AttemptLocalParseRecovery, Error};
 use super::expr::LhsExpr;
 use super::pat::GateOr;
 use super::path::PathStyle;
@@ -79,8 +79,8 @@ impl<'a> Parser<'a> {
             return self.parse_stmt_mac(lo, attrs.into(), path);
         }
 
-        let expr = if self.check(&token::OpenDelim(token::Brace)) {
-            self.parse_struct_expr(path, AttrVec::new())?
+        let expr = if self.eat(&token::OpenDelim(token::Brace)) {
+            self.parse_struct_expr(path, AttrVec::new(), true)?
         } else {
             let hi = self.prev_token.span;
             self.mk_expr(lo.to(hi), ExprKind::Path(None, path), AttrVec::new())
@@ -321,25 +321,37 @@ impl<'a> Parser<'a> {
             return self.error_block_no_opening_brace();
         }
 
-        Ok((self.parse_inner_attributes()?, self.parse_block_tail(lo, blk_mode)?))
+        let attrs = self.parse_inner_attributes()?;
+        let tail = if let Some(tail) = self.maybe_suggest_struct_literal(lo, blk_mode) {
+            tail?
+        } else {
+            self.parse_block_tail(lo, blk_mode, AttemptLocalParseRecovery::Yes)?
+        };
+        Ok((attrs, tail))
     }
 
     /// Parses the rest of a block expression or function body.
     /// Precondition: already parsed the '{'.
-    fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Block>> {
+    crate fn parse_block_tail(
+        &mut self,
+        lo: Span,
+        s: BlockCheckMode,
+        recover: AttemptLocalParseRecovery,
+    ) -> PResult<'a, P<Block>> {
         let mut stmts = vec![];
         while !self.eat(&token::CloseDelim(token::Brace)) {
             if self.token == token::Eof {
                 break;
             }
-            let stmt = match self.parse_full_stmt() {
-                Err(mut err) => {
+            let stmt = match self.parse_full_stmt(recover) {
+                Err(mut err) if recover.yes() => {
                     self.maybe_annotate_with_ascription(&mut err, false);
                     err.emit();
                     self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
                     Some(self.mk_stmt_err(self.token.span))
                 }
                 Ok(stmt) => stmt,
+                Err(err) => return Err(err),
             };
             if let Some(stmt) = stmt {
                 stmts.push(stmt);
@@ -352,7 +364,10 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses a statement, including the trailing semicolon.
-    pub fn parse_full_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
+    pub fn parse_full_stmt(
+        &mut self,
+        recover: AttemptLocalParseRecovery,
+    ) -> PResult<'a, Option<Stmt>> {
         // Skip looking for a trailing semicolon when we have an interpolated statement.
         maybe_whole!(self, NtStmt, |x| Some(x));
 
@@ -391,6 +406,9 @@ impl<'a> Parser<'a> {
                     if let Err(mut e) =
                         self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
                     {
+                        if recover.no() {
+                            return Err(e);
+                        }
                         e.emit();
                         self.recover_stmt();
                     }
@@ -432,7 +450,7 @@ impl<'a> Parser<'a> {
         Stmt { id: DUMMY_NODE_ID, kind, span, tokens: None }
     }
 
-    fn mk_stmt_err(&self, span: Span) -> Stmt {
+    pub(super) fn mk_stmt_err(&self, span: Span) -> Stmt {
         self.mk_stmt(span, StmtKind::Expr(self.mk_expr_err(span)))
     }
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 59955b27334..1acaa4c6eff 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -287,8 +287,9 @@ impl CheckAttrVisitor<'tcx> {
                             self.doc_alias_str_error(meta);
                             return false;
                         }
-                        if let Some(c) =
-                            doc_alias.chars().find(|&c| c == '"' || c == '\'' || c.is_whitespace())
+                        if let Some(c) = doc_alias
+                            .chars()
+                            .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
                         {
                             self.tcx
                                 .sess
@@ -302,6 +303,16 @@ impl CheckAttrVisitor<'tcx> {
                                 .emit();
                             return false;
                         }
+                        if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') {
+                            self.tcx
+                                .sess
+                                .struct_span_err(
+                                    meta.span(),
+                                    "`#[doc(alias = \"...\")]` cannot start or end with ' '",
+                                )
+                                .emit();
+                            return false;
+                        }
                         if let Some(err) = match target {
                             Target::Impl => Some("implementation block"),
                             Target::ForeignMod => Some("extern block"),
diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs
index 79f1c2b9da8..956be925be8 100644
--- a/compiler/rustc_passes/src/intrinsicck.rs
+++ b/compiler/rustc_passes/src/intrinsicck.rs
@@ -143,7 +143,7 @@ impl ExprVisitor<'tcx> {
     ) -> Option<InlineAsmType> {
         // Check the type against the allowed types for inline asm.
         let ty = self.typeck_results.expr_ty_adjusted(expr);
-        let asm_ty_isize = match self.tcx.sess.target.ptr_width {
+        let asm_ty_isize = match self.tcx.sess.target.pointer_width {
             16 => InlineAsmType::I16,
             32 => InlineAsmType::I32,
             64 => InlineAsmType::I64,
@@ -184,7 +184,7 @@ impl ExprVisitor<'tcx> {
                         Some(InlineAsmType::VecI128(fields.len() as u64))
                     }
                     ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => {
-                        Some(match self.tcx.sess.target.ptr_width {
+                        Some(match self.tcx.sess.target.pointer_width {
                             16 => InlineAsmType::VecI16(fields.len() as u64),
                             32 => InlineAsmType::VecI32(fields.len() as u64),
                             64 => InlineAsmType::VecI64(fields.len() as u64),
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index effb25b0224..8650ee05d37 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -26,7 +26,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem
     if items.eh_personality().is_none() {
         items.missing.push(LangItem::EhPersonality);
     }
-    if tcx.sess.target.target.options.is_like_emscripten && items.eh_catch_typeinfo().is_none() {
+    if tcx.sess.target.options.is_like_emscripten && items.eh_catch_typeinfo().is_none() {
         items.missing.push(LangItem::EhCatchTypeinfo);
     }
 
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index e302784cc3e..7808a28dff0 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -165,10 +165,6 @@ impl WorkProductId {
         cgu_name.hash(&mut hasher);
         WorkProductId { hash: hasher.finish() }
     }
-
-    pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId {
-        WorkProductId { hash: fingerprint }
-    }
 }
 
 impl<HCX> HashStable<HCX> for WorkProductId {
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index d70306b4869..85335f0ba50 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -402,11 +402,6 @@ impl<K: DepKind> DepGraph<K> {
         self.data.as_ref().unwrap().previous.fingerprint_of(dep_node)
     }
 
-    #[inline]
-    pub fn prev_dep_node_index_of(&self, dep_node: &DepNode<K>) -> SerializedDepNodeIndex {
-        self.data.as_ref().unwrap().previous.node_to_index(dep_node)
-    }
-
     /// Checks whether a previous work product exists for `v` and, if
     /// so, return the path that leads to it. Used to skip doing work.
     pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> {
diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs
index fb313d2658f..a27b716b95a 100644
--- a/compiler/rustc_query_system/src/dep_graph/query.rs
+++ b/compiler/rustc_query_system/src/dep_graph/query.rs
@@ -1,7 +1,5 @@
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::graph::implementation::{
-    Direction, Graph, NodeIndex, INCOMING, OUTGOING,
-};
+use rustc_data_structures::graph::implementation::{Direction, Graph, NodeIndex, INCOMING};
 
 use super::{DepKind, DepNode};
 
@@ -52,23 +50,8 @@ impl<K: DepKind> DepGraphQuery<K> {
         }
     }
 
-    /// All nodes reachable from `node`. In other words, things that
-    /// will have to be recomputed if `node` changes.
-    pub fn transitive_successors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> {
-        self.reachable_nodes(node, OUTGOING)
-    }
-
     /// All nodes that can reach `node`.
     pub fn transitive_predecessors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> {
         self.reachable_nodes(node, INCOMING)
     }
-
-    /// Just the outgoing edges from `node`.
-    pub fn immediate_successors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> {
-        if let Some(&index) = self.indices.get(&node) {
-            self.graph.successor_nodes(index).map(|s| self.graph.node_data(s)).collect()
-        } else {
-            vec![]
-        }
-    }
 }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index e3cf6d12bd5..774a147c114 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -469,24 +469,17 @@ impl<'a> Resolver<'a> {
             ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => {
                 let mut err = self.session.struct_span_err(
                     span,
-                    "generic parameters must not be used inside of non-trivial constant values",
-                );
-                err.span_label(
-                    span,
-                    &format!(
-                        "non-trivial anonymous constants must not depend on the parameter `{}`",
-                        name
-                    ),
+                    "generic parameters may not be used in const operations",
                 );
+                err.span_label(span, &format!("cannot perform const operation using `{}`", name));
 
                 if is_type {
-                    err.note("type parameters are currently not permitted in anonymous constants");
+                    err.note("type parameters may not be used in const expressions");
                 } else {
-                    err.help(
-                        &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants",
-                                 name
-                        )
-                    );
+                    err.help(&format!(
+                        "const parameters may only be used as standalone arguments, i.e. `{}`",
+                        name
+                    ));
                 }
 
                 err
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 2c01934b490..219517b4ab2 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -384,6 +384,13 @@ struct DiagnosticMetadata<'ast> {
 
     /// Used to detect possible `if let` written without `let` and to provide structured suggestion.
     in_if_condition: Option<&'ast Expr>,
+
+    /// If we are currently in a trait object definition. Used to point at the bounds when
+    /// encountering a struct or enum.
+    current_trait_object: Option<&'ast [ast::GenericBound]>,
+
+    /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
+    current_where_predicate: Option<&'ast WherePredicate>,
 }
 
 struct LateResolutionVisitor<'a, 'b, 'ast> {
@@ -453,6 +460,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         self.diagnostic_metadata.current_let_binding = original;
     }
     fn visit_ty(&mut self, ty: &'ast Ty) {
+        let prev = self.diagnostic_metadata.current_trait_object;
         match ty.kind {
             TyKind::Path(ref qself, ref path) => {
                 self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
@@ -464,9 +472,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
                     .map_or(Res::Err, |d| d.res());
                 self.r.record_partial_res(ty.id, PartialRes::new(res));
             }
+            TyKind::TraitObject(ref bounds, ..) => {
+                self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
+            }
             _ => (),
         }
         visit::walk_ty(self, ty);
+        self.diagnostic_metadata.current_trait_object = prev;
     }
     fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
         self.smart_resolve_path(
@@ -660,6 +672,14 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         }
         self.diagnostic_metadata.currently_processing_generics = prev;
     }
+
+    fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
+        debug!("visit_where_predicate {:?}", p);
+        let previous_value =
+            replace(&mut self.diagnostic_metadata.current_where_predicate, Some(p));
+        visit::walk_where_predicate(self, p);
+        self.diagnostic_metadata.current_where_predicate = previous_value;
+    }
 }
 
 impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 521ea7ad184..bee05e77382 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1,6 +1,6 @@
 use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
 use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext};
-use crate::late::{LateResolutionVisitor, RibKind};
+use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
 use crate::path_names_to_string;
 use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot};
 use crate::{PathResult, PathSource, Segment};
@@ -8,18 +8,19 @@ use crate::{PathResult, PathSource, Segment};
 use rustc_ast::util::lev_distance::find_best_match_for_name;
 use rustc_ast::visit::FnKind;
 use rustc_ast::{self as ast, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind};
+use rustc_ast_pretty::pprust::path_segment_to_string;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def::Namespace::{self, *};
-use rustc_hir::def::{self, CtorKind, DefKind};
+use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_session::config::nightly_options;
 use rustc_session::parse::feature_err;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span, DUMMY_SP};
+use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
 
 use tracing::debug;
 
@@ -439,27 +440,213 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             }
         }
 
-        if !self.type_ascription_suggestion(&mut err, base_span)
-            && !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span)
-        {
-            // Fallback label.
-            err.span_label(base_span, fallback_label);
-
-            match self.diagnostic_metadata.current_let_binding {
-                Some((pat_sp, Some(ty_sp), None)) if ty_sp.contains(base_span) && could_be_expr => {
-                    err.span_suggestion_short(
-                        pat_sp.between(ty_sp),
-                        "use `=` if you meant to assign",
-                        " = ".to_string(),
-                        Applicability::MaybeIncorrect,
+        if !self.type_ascription_suggestion(&mut err, base_span) {
+            let mut fallback = false;
+            if let (
+                PathSource::Trait(AliasPossibility::Maybe),
+                Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)),
+            ) = (source, res)
+            {
+                if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object {
+                    fallback = true;
+                    let spans: Vec<Span> = bounds
+                        .iter()
+                        .map(|bound| bound.span())
+                        .filter(|&sp| sp != base_span)
+                        .collect();
+
+                    let start_span = bounds.iter().map(|bound| bound.span()).next().unwrap();
+                    // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><)
+                    let end_span = bounds.iter().map(|bound| bound.span()).last().unwrap();
+                    // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar)
+                    let last_bound_span = spans.last().cloned().unwrap();
+                    let mut multi_span: MultiSpan = spans.clone().into();
+                    for sp in spans {
+                        let msg = if sp == last_bound_span {
+                            format!(
+                                "...because of {} bound{}",
+                                if bounds.len() <= 2 { "this" } else { "these" },
+                                if bounds.len() <= 2 { "" } else { "s" },
+                            )
+                        } else {
+                            String::new()
+                        };
+                        multi_span.push_span_label(sp, msg);
+                    }
+                    multi_span.push_span_label(
+                        base_span,
+                        "expected this type to be a trait...".to_string(),
+                    );
+                    err.span_help(
+                        multi_span,
+                        "`+` is used to constrain a \"trait object\" type with lifetimes or \
+                         auto-traits; structs and enums can't be bound in that way",
                     );
+                    if bounds.iter().all(|bound| match bound {
+                        ast::GenericBound::Outlives(_) => true,
+                        ast::GenericBound::Trait(tr, _) => tr.span == base_span,
+                    }) {
+                        let mut sugg = vec![];
+                        if base_span != start_span {
+                            sugg.push((start_span.until(base_span), String::new()));
+                        }
+                        if base_span != end_span {
+                            sugg.push((base_span.shrink_to_hi().to(end_span), String::new()));
+                        }
+
+                        err.multipart_suggestion(
+                            "if you meant to use a type and not a trait here, remove the bounds",
+                            sugg,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                 }
-                _ => {}
+            }
+
+            fallback |= self.restrict_assoc_type_in_where_clause(span, &mut err);
+
+            if !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span) {
+                fallback = true;
+                match self.diagnostic_metadata.current_let_binding {
+                    Some((pat_sp, Some(ty_sp), None))
+                        if ty_sp.contains(base_span) && could_be_expr =>
+                    {
+                        err.span_suggestion_short(
+                            pat_sp.between(ty_sp),
+                            "use `=` if you meant to assign",
+                            " = ".to_string(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    _ => {}
+                }
+            }
+            if fallback {
+                // Fallback label.
+                err.span_label(base_span, fallback_label);
             }
         }
         (err, candidates)
     }
 
+    /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`.
+    fn restrict_assoc_type_in_where_clause(
+        &mut self,
+        span: Span,
+        err: &mut DiagnosticBuilder<'_>,
+    ) -> bool {
+        // Detect that we are actually in a `where` predicate.
+        let (bounded_ty, bounds, where_span) =
+            if let Some(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+                bounded_ty,
+                bound_generic_params,
+                bounds,
+                span,
+            })) = self.diagnostic_metadata.current_where_predicate
+            {
+                if !bound_generic_params.is_empty() {
+                    return false;
+                }
+                (bounded_ty, bounds, span)
+            } else {
+                return false;
+            };
+
+        // Confirm that the target is an associated type.
+        let (ty, position, path) = if let ast::TyKind::Path(
+            Some(ast::QSelf { ty, position, .. }),
+            path,
+        ) = &bounded_ty.kind
+        {
+            // use this to verify that ident is a type param.
+            let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
+                bounded_ty.id,
+                None,
+                &Segment::from_path(path),
+                Namespace::TypeNS,
+                span,
+                true,
+                CrateLint::No,
+            ) {
+                partial_res
+            } else {
+                return false;
+            };
+            if !(matches!(
+                partial_res.base_res(),
+                hir::def::Res::Def(hir::def::DefKind::AssocTy, _)
+            ) && partial_res.unresolved_segments() == 0)
+            {
+                return false;
+            }
+            (ty, position, path)
+        } else {
+            return false;
+        };
+
+        if let ast::TyKind::Path(None, type_param_path) = &ty.peel_refs().kind {
+            // Confirm that the `SelfTy` is a type parameter.
+            let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
+                bounded_ty.id,
+                None,
+                &Segment::from_path(type_param_path),
+                Namespace::TypeNS,
+                span,
+                true,
+                CrateLint::No,
+            ) {
+                partial_res
+            } else {
+                return false;
+            };
+            if !(matches!(
+                partial_res.base_res(),
+                hir::def::Res::Def(hir::def::DefKind::TyParam, _)
+            ) && partial_res.unresolved_segments() == 0)
+            {
+                return false;
+            }
+            if let (
+                [ast::PathSegment { ident: constrain_ident, args: None, .. }],
+                [ast::GenericBound::Trait(poly_trait_ref, ast::TraitBoundModifier::None)],
+            ) = (&type_param_path.segments[..], &bounds[..])
+            {
+                if let [ast::PathSegment { ident, args: None, .. }] =
+                    &poly_trait_ref.trait_ref.path.segments[..]
+                {
+                    if ident.span == span {
+                        err.span_suggestion_verbose(
+                            *where_span,
+                            &format!("constrain the associated type to `{}`", ident),
+                            format!(
+                                "{}: {}<{} = {}>",
+                                self.r
+                                    .session
+                                    .source_map()
+                                    .span_to_snippet(ty.span) // Account for `<&'a T as Foo>::Bar`.
+                                    .unwrap_or_else(|_| constrain_ident.to_string()),
+                                path.segments[..*position]
+                                    .iter()
+                                    .map(|segment| path_segment_to_string(segment))
+                                    .collect::<Vec<_>>()
+                                    .join("::"),
+                                path.segments[*position..]
+                                    .iter()
+                                    .map(|segment| path_segment_to_string(segment))
+                                    .collect::<Vec<_>>()
+                                    .join("::"),
+                                ident,
+                            ),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    return true;
+                }
+            }
+        }
+        false
+    }
+
     /// Check if the source is call expression and the first argument is `self`. If true,
     /// return the span of whole call and the span for all arguments expect the first one (`self`).
     fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> {
@@ -726,24 +913,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
                     // We already suggested changing `:` into `::` during parsing.
                     return false;
                 }
-                if let Some(variants) = self.collect_enum_variants(def_id) {
-                    if !variants.is_empty() {
-                        let msg = if variants.len() == 1 {
-                            "try using the enum's variant"
-                        } else {
-                            "try using one of the enum's variants"
-                        };
 
-                        err.span_suggestions(
-                            span,
-                            msg,
-                            variants.iter().map(path_names_to_string),
-                            Applicability::MaybeIncorrect,
-                        );
-                    }
-                } else {
-                    err.note("you might have meant to use one of the enum's variants");
-                }
+                self.suggest_using_enum_variant(err, source, def_id, span);
             }
             (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
                 if let Some((ctor_def, ctor_vis, fields)) =
@@ -1126,20 +1297,139 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         result
     }
 
-    fn collect_enum_variants(&mut self, def_id: DefId) -> Option<Vec<Path>> {
+    fn collect_enum_ctors(&mut self, def_id: DefId) -> Option<Vec<(Path, DefId, CtorKind)>> {
         self.find_module(def_id).map(|(enum_module, enum_import_suggestion)| {
             let mut variants = Vec::new();
             enum_module.for_each_child(self.r, |_, ident, _, name_binding| {
-                if let Res::Def(DefKind::Variant, _) = name_binding.res() {
+                if let Res::Def(DefKind::Ctor(CtorOf::Variant, kind), def_id) = name_binding.res() {
                     let mut segms = enum_import_suggestion.path.segments.clone();
                     segms.push(ast::PathSegment::from_ident(ident));
-                    variants.push(Path { span: name_binding.span, segments: segms, tokens: None });
+                    let path = Path { span: name_binding.span, segments: segms, tokens: None };
+                    variants.push((path, def_id, kind));
                 }
             });
             variants
         })
     }
 
+    /// Adds a suggestion for using an enum's variant when an enum is used instead.
+    fn suggest_using_enum_variant(
+        &mut self,
+        err: &mut DiagnosticBuilder<'a>,
+        source: PathSource<'_>,
+        def_id: DefId,
+        span: Span,
+    ) {
+        let variants = match self.collect_enum_ctors(def_id) {
+            Some(variants) => variants,
+            None => {
+                err.note("you might have meant to use one of the enum's variants");
+                return;
+            }
+        };
+
+        let suggest_only_tuple_variants =
+            matches!(source, PathSource::TupleStruct(..)) || source.is_call();
+        let mut suggestable_variants = if suggest_only_tuple_variants {
+            // Suggest only tuple variants regardless of whether they have fields and do not
+            // suggest path with added parenthesis.
+            variants
+                .iter()
+                .filter(|(.., kind)| *kind == CtorKind::Fn)
+                .map(|(variant, ..)| path_names_to_string(variant))
+                .collect::<Vec<_>>()
+        } else {
+            variants
+                .iter()
+                .filter(|(_, def_id, kind)| {
+                    // Suggest only variants that have no fields (these can definitely
+                    // be constructed).
+                    let has_fields =
+                        self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false);
+                    match kind {
+                        CtorKind::Const => true,
+                        CtorKind::Fn | CtorKind::Fictive if has_fields => true,
+                        _ => false,
+                    }
+                })
+                .map(|(variant, _, kind)| (path_names_to_string(variant), kind))
+                .map(|(variant_str, kind)| {
+                    // Add constructor syntax where appropriate.
+                    match kind {
+                        CtorKind::Const => variant_str,
+                        CtorKind::Fn => format!("({}())", variant_str),
+                        CtorKind::Fictive => format!("({} {{}})", variant_str),
+                    }
+                })
+                .collect::<Vec<_>>()
+        };
+
+        let non_suggestable_variant_count = variants.len() - suggestable_variants.len();
+
+        if !suggestable_variants.is_empty() {
+            let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 {
+                "try using the enum's variant"
+            } else {
+                "try using one of the enum's variants"
+            };
+
+            err.span_suggestions(
+                span,
+                msg,
+                suggestable_variants.drain(..),
+                Applicability::MaybeIncorrect,
+            );
+        }
+
+        if suggest_only_tuple_variants {
+            let source_msg = if source.is_call() {
+                "to construct"
+            } else if matches!(source, PathSource::TupleStruct(..)) {
+                "to match against"
+            } else {
+                unreachable!()
+            };
+
+            // If the enum has no tuple variants..
+            if non_suggestable_variant_count == variants.len() {
+                err.help(&format!("the enum has no tuple variants {}", source_msg));
+            }
+
+            // If there are also non-tuple variants..
+            if non_suggestable_variant_count == 1 {
+                err.help(&format!(
+                    "you might have meant {} the enum's non-tuple variant",
+                    source_msg
+                ));
+            } else if non_suggestable_variant_count >= 1 {
+                err.help(&format!(
+                    "you might have meant {} one of the enum's non-tuple variants",
+                    source_msg
+                ));
+            }
+        } else {
+            let made_suggestion = non_suggestable_variant_count != variants.len();
+            if made_suggestion {
+                if non_suggestable_variant_count == 1 {
+                    err.help(
+                        "you might have meant to use the enum's other variant that has fields",
+                    );
+                } else if non_suggestable_variant_count >= 1 {
+                    err.help(
+                        "you might have meant to use one of the enum's other variants that \
+                         have fields",
+                    );
+                }
+            } else {
+                if non_suggestable_variant_count == 1 {
+                    err.help("you might have meant to use the enum's variant");
+                } else if non_suggestable_variant_count >= 1 {
+                    err.help("you might have meant to use one of the enum's variants");
+                }
+            }
+        }
+    }
+
     crate fn report_missing_type_error(
         &self,
         path: &[Segment],
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index fe8f5926385..6677a5ffe28 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -218,7 +218,7 @@ enum ResolutionError<'a> {
     ParamInTyOfConstParam(Symbol),
     /// constant values inside of type parameter defaults must not depend on generic parameters.
     ParamInAnonConstInTyDefault(Symbol),
-    /// generic parameters must not be used inside of non-trivial constant values.
+    /// generic parameters must not be used inside const evaluations.
     ///
     /// This error is only emitted when using `min_const_generics`.
     ParamInNonTrivialAnonConst { name: Symbol, is_type: bool },
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index fa4423e261d..8b79c93e760 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -107,7 +107,7 @@ impl serialize::Encoder for Encoder {
 
     #[inline]
     fn emit_i8(&mut self, v: i8) -> EncodeResult {
-        let as_u8: u8 = unsafe { ::std::mem::transmute(v) };
+        let as_u8: u8 = unsafe { std::mem::transmute(v) };
         self.emit_u8(as_u8)
     }
 
@@ -300,13 +300,13 @@ impl<'a> serialize::Decoder for Decoder<'a> {
     #[inline]
     fn read_char(&mut self) -> Result<char, Self::Error> {
         let bits = self.read_u32()?;
-        Ok(::std::char::from_u32(bits).unwrap())
+        Ok(std::char::from_u32(bits).unwrap())
     }
 
     #[inline]
     fn read_str(&mut self) -> Result<Cow<'_, str>, Self::Error> {
         let len = self.read_usize()?;
-        let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
+        let s = std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
         self.position += len;
         Ok(Cow::Borrowed(s))
     }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 231e315a22f..f33bebf99d6 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -34,11 +34,6 @@ use std::iter::{self, FromIterator};
 use std::path::{Path, PathBuf};
 use std::str::{self, FromStr};
 
-pub struct Config {
-    pub target: Target,
-    pub ptr_width: u32,
-}
-
 bitflags! {
     #[derive(Default, Encodable, Decodable)]
     pub struct SanitizerSet: u8 {
@@ -740,16 +735,16 @@ pub const fn default_lib_output() -> CrateType {
 }
 
 pub fn default_configuration(sess: &Session) -> CrateConfig {
-    let end = &sess.target.target.target_endian;
-    let arch = &sess.target.target.arch;
-    let wordsz = &sess.target.target.target_pointer_width;
-    let os = &sess.target.target.target_os;
-    let env = &sess.target.target.target_env;
-    let vendor = &sess.target.target.target_vendor;
-    let min_atomic_width = sess.target.target.min_atomic_width();
-    let max_atomic_width = sess.target.target.max_atomic_width();
-    let atomic_cas = sess.target.target.options.atomic_cas;
-    let layout = TargetDataLayout::parse(&sess.target.target).unwrap_or_else(|err| {
+    let end = &sess.target.target_endian;
+    let arch = &sess.target.arch;
+    let wordsz = sess.target.pointer_width.to_string();
+    let os = &sess.target.target_os;
+    let env = &sess.target.target_env;
+    let vendor = &sess.target.target_vendor;
+    let min_atomic_width = sess.target.min_atomic_width();
+    let max_atomic_width = sess.target.max_atomic_width();
+    let atomic_cas = sess.target.options.atomic_cas;
+    let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
         sess.fatal(&err);
     });
 
@@ -757,7 +752,7 @@ pub fn default_configuration(sess: &Session) -> CrateConfig {
     ret.reserve(6); // the minimum number of insertions
     // Target bindings.
     ret.insert((sym::target_os, Some(Symbol::intern(os))));
-    if let Some(ref fam) = sess.target.target.options.target_family {
+    if let Some(ref fam) = sess.target.options.target_family {
         ret.insert((sym::target_family, Some(Symbol::intern(fam))));
         if fam == "windows" {
             ret.insert((sym::windows, None));
@@ -767,10 +762,10 @@ pub fn default_configuration(sess: &Session) -> CrateConfig {
     }
     ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
     ret.insert((sym::target_endian, Some(Symbol::intern(end))));
-    ret.insert((sym::target_pointer_width, Some(Symbol::intern(wordsz))));
+    ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
     ret.insert((sym::target_env, Some(Symbol::intern(env))));
     ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
-    if sess.target.target.options.has_elf_tls {
+    if sess.target.options.has_elf_tls {
         ret.insert((sym::target_thread_local, None));
     }
     for &(i, align) in &[
@@ -792,7 +787,7 @@ pub fn default_configuration(sess: &Session) -> CrateConfig {
             };
             let s = i.to_string();
             insert_atomic(&s, align);
-            if &s == wordsz {
+            if s == wordsz {
                 insert_atomic("ptr", layout.pointer_align.abi);
             }
         }
@@ -831,7 +826,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo
     user_cfg
 }
 
-pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Config {
+pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
     let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
     let target = target_result.unwrap_or_else(|e| {
         early_error(
@@ -844,21 +839,18 @@ pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> C
         )
     });
 
-    let ptr_width = match &target.target_pointer_width[..] {
-        "16" => 16,
-        "32" => 32,
-        "64" => 64,
-        w => early_error(
+    if !matches!(target.pointer_width, 16 | 32 | 64) {
+        early_error(
             opts.error_format,
             &format!(
                 "target specification was invalid: \
              unrecognized target-pointer-width {}",
-                w
+                target.pointer_width
             ),
-        ),
-    };
+        )
+    }
 
-    Config { target, ptr_width }
+    target
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs
index 3e899e00d11..fef3164de59 100644
--- a/compiler/rustc_session/src/lint/builtin.rs
+++ b/compiler/rustc_session/src/lint/builtin.rs
@@ -1882,6 +1882,16 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `invalid_html_tags` lint detects invalid HTML tags. This is a
+    /// `rustdoc` only lint, see the documentation in the [rustdoc book].
+    ///
+    /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_html_tags
+    pub INVALID_HTML_TAGS,
+    Allow,
+    "detects invalid HTML tags in doc comments"
+}
+
+declare_lint! {
     /// The `where_clauses_object_safety` lint detects for [object safety] of
     /// [where clauses].
     ///
@@ -2699,6 +2709,7 @@ declare_lint_pass! {
         INVALID_CODEBLOCK_ATTRIBUTES,
         MISSING_CRATE_LEVEL_DOCS,
         MISSING_DOC_CODE_EXAMPLES,
+        INVALID_HTML_TAGS,
         PRIVATE_DOC_TESTS,
         WHERE_CLAUSES_OBJECT_SAFETY,
         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index a106007c274..627adcceb3f 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1078,6 +1078,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "show extended diagnostic help (default: no)"),
     terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
         "set the current terminal width"),
+    tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
+        "select processor to schedule for (`rustc --print target-cpus` for details)"),
     thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "enable ThinLTO when possible"),
     // We default to 1 here since we want to behave like
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index bf9c96c6c94..0766c55da74 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -151,18 +151,16 @@ pub fn filename_for_input(
         CrateType::Rlib => outputs.out_directory.join(&format!("lib{}.rlib", libname)),
         CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => {
             let (prefix, suffix) =
-                (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix);
+                (&sess.target.options.dll_prefix, &sess.target.options.dll_suffix);
             outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix))
         }
         CrateType::Staticlib => {
-            let (prefix, suffix) = (
-                &sess.target.target.options.staticlib_prefix,
-                &sess.target.target.options.staticlib_suffix,
-            );
+            let (prefix, suffix) =
+                (&sess.target.options.staticlib_prefix, &sess.target.options.staticlib_suffix);
             outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix))
         }
         CrateType::Executable => {
-            let suffix = &sess.target.target.options.exe_suffix;
+            let suffix = &sess.target.options.exe_suffix;
             let out_filename = outputs.path(OutputType::Exe);
             if suffix.is_empty() { out_filename } else { out_filename.with_extension(&suffix[1..]) }
         }
@@ -179,35 +177,29 @@ pub fn filename_for_input(
 /// interaction with Rust code through static library is the only
 /// option for now
 pub fn default_output_for_target(sess: &Session) -> CrateType {
-    if !sess.target.target.options.executables {
-        CrateType::Staticlib
-    } else {
-        CrateType::Executable
-    }
+    if !sess.target.options.executables { CrateType::Staticlib } else { CrateType::Executable }
 }
 
 /// Checks if target supports crate_type as output
 pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool {
     match crate_type {
         CrateType::Cdylib | CrateType::Dylib | CrateType::ProcMacro => {
-            if !sess.target.target.options.dynamic_linking {
+            if !sess.target.options.dynamic_linking {
                 return true;
             }
-            if sess.crt_static(Some(crate_type))
-                && !sess.target.target.options.crt_static_allows_dylibs
-            {
+            if sess.crt_static(Some(crate_type)) && !sess.target.options.crt_static_allows_dylibs {
                 return true;
             }
         }
         _ => {}
     }
-    if sess.target.target.options.only_cdylib {
+    if sess.target.options.only_cdylib {
         match crate_type {
             CrateType::ProcMacro | CrateType::Dylib => return true,
             _ => {}
         }
     }
-    if !sess.target.target.options.executables {
+    if !sess.target.options.executables {
         if crate_type == CrateType::Executable {
             return true;
         }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index ff5e6156d84..8312f89b271 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -102,7 +102,7 @@ impl Mul<usize> for Limit {
 /// Represents the data associated with a compilation
 /// session for a single crate.
 pub struct Session {
-    pub target: config::Config,
+    pub target: Target,
     pub host: Target,
     pub opts: config::Options,
     pub host_tlib_path: SearchPath,
@@ -614,7 +614,7 @@ impl Session {
     /// Calculates the flavor of LTO to use for this compilation.
     pub fn lto(&self) -> config::Lto {
         // If our target has codegen requirements ignore the command line
-        if self.target.target.options.requires_lto {
+        if self.target.options.requires_lto {
             return config::Lto::Fat;
         }
 
@@ -682,7 +682,7 @@ impl Session {
     /// Returns the panic strategy for this compile session. If the user explicitly selected one
     /// using '-C panic', use that, otherwise use the panic strategy defined by the target.
     pub fn panic_strategy(&self) -> PanicStrategy {
-        self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy)
+        self.opts.cg.panic.unwrap_or(self.target.options.panic_strategy)
     }
     pub fn fewer_names(&self) -> bool {
         let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
@@ -706,9 +706,9 @@ impl Session {
 
     /// Check whether this compile session and crate type use static crt.
     pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool {
-        if !self.target.target.options.crt_static_respected {
+        if !self.target.options.crt_static_respected {
             // If the target does not opt in to crt-static support, use its default.
-            return self.target.target.options.crt_static_default;
+            return self.target.options.crt_static_default;
         }
 
         let requested_features = self.opts.cg.target_feature.split(',');
@@ -725,20 +725,20 @@ impl Session {
             // We can't check `#![crate_type = "proc-macro"]` here.
             false
         } else {
-            self.target.target.options.crt_static_default
+            self.target.options.crt_static_default
         }
     }
 
     pub fn relocation_model(&self) -> RelocModel {
-        self.opts.cg.relocation_model.unwrap_or(self.target.target.options.relocation_model)
+        self.opts.cg.relocation_model.unwrap_or(self.target.options.relocation_model)
     }
 
     pub fn code_model(&self) -> Option<CodeModel> {
-        self.opts.cg.code_model.or(self.target.target.options.code_model)
+        self.opts.cg.code_model.or(self.target.options.code_model)
     }
 
     pub fn tls_model(&self) -> TlsModel {
-        self.opts.debugging_opts.tls_model.unwrap_or(self.target.target.options.tls_model)
+        self.opts.debugging_opts.tls_model.unwrap_or(self.target.options.tls_model)
     }
 
     pub fn must_not_eliminate_frame_pointers(&self) -> bool {
@@ -749,7 +749,7 @@ impl Session {
         } else if let Some(x) = self.opts.cg.force_frame_pointers {
             x
         } else {
-            !self.target.target.options.eliminate_frame_pointer
+            !self.target.options.eliminate_frame_pointer
         }
     }
 
@@ -773,7 +773,7 @@ impl Session {
         // value, if it is provided, or disable them, if not.
         if self.panic_strategy() == PanicStrategy::Unwind {
             true
-        } else if self.target.target.options.requires_uwtable {
+        } else if self.target.options.requires_uwtable {
             true
         } else {
             self.opts.cg.force_unwind_tables.unwrap_or(false)
@@ -944,7 +944,7 @@ impl Session {
         if let Some(n) = self.opts.cli_forced_codegen_units {
             return n;
         }
-        if let Some(n) = self.target.target.options.default_codegen_units {
+        if let Some(n) = self.target.options.default_codegen_units {
             return n as usize;
         }
 
@@ -1029,11 +1029,11 @@ impl Session {
     pub fn needs_plt(&self) -> bool {
         // Check if the current target usually needs PLT to be enabled.
         // The user can use the command line flag to override it.
-        let needs_plt = self.target.target.options.needs_plt;
+        let needs_plt = self.target.options.needs_plt;
 
         let dbg_opts = &self.opts.debugging_opts;
 
-        let relro_level = dbg_opts.relro_level.unwrap_or(self.target.target.options.relro_level);
+        let relro_level = dbg_opts.relro_level.unwrap_or(self.target.options.relro_level);
 
         // Only enable this optimization by default if full relro is also enabled.
         // In this case, lazy binding was already unavailable, so nothing is lost.
@@ -1057,8 +1057,7 @@ impl Session {
         match self.opts.cg.link_dead_code {
             Some(explicitly_set) => explicitly_set,
             None => {
-                self.opts.debugging_opts.instrument_coverage
-                    && !self.target.target.options.is_like_msvc
+                self.opts.debugging_opts.instrument_coverage && !self.target.options.is_like_msvc
                 // Issue #76038: (rustc `-Clink-dead-code` causes MSVC linker to produce invalid
                 // binaries when LLVM InstrProf counters are enabled). As described by this issue,
                 // the "link dead code" option produces incorrect binaries when compiled and linked
@@ -1259,7 +1258,7 @@ pub fn build_session(
 
     let loader = file_loader.unwrap_or(Box::new(RealFileLoader));
     let hash_kind = sopts.debugging_opts.src_hash_algorithm.unwrap_or_else(|| {
-        if target_cfg.target.options.is_like_msvc {
+        if target_cfg.options.is_like_msvc {
             SourceFileHashAlgorithm::Sha1
         } else {
             SourceFileHashAlgorithm::Md5
@@ -1369,8 +1368,8 @@ pub fn build_session(
         if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
     };
 
-    let asm_arch = if target_cfg.target.options.allow_asm {
-        InlineAsmArch::from_str(&target_cfg.target.arch).ok()
+    let asm_arch = if target_cfg.options.allow_asm {
+        InlineAsmArch::from_str(&target_cfg.arch).ok()
     } else {
         None
     };
@@ -1438,7 +1437,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     // the `dllimport` attributes and `__imp_` symbols in that case.
     if sess.opts.cg.linker_plugin_lto.enabled()
         && sess.opts.cg.prefer_dynamic
-        && sess.target.target.options.is_like_windows
+        && sess.target.options.is_like_windows
     {
         sess.err(
             "Linker plugin based LTO is not supported together with \
@@ -1466,7 +1465,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             );
         }
 
-        if sess.target.target.options.requires_uwtable && !include_uwtables {
+        if sess.target.options.requires_uwtable && !include_uwtables {
             sess.err(
                 "target requires unwind tables, they cannot be disabled with \
                      `-C force-unwind-tables=no`.",
@@ -1481,7 +1480,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     // We should only display this error if we're actually going to run PGO.
     // If we're just supposed to print out some data, don't show the error (#61002).
     if sess.opts.cg.profile_generate.enabled()
-        && sess.target.target.options.is_like_msvc
+        && sess.target.options.is_like_msvc
         && sess.panic_strategy() == PanicStrategy::Unwind
         && sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs)
     {
@@ -1586,5 +1585,3 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
     let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
     handler.struct_warn(msg).emit();
 }
-
-pub type CompileResult = Result<(), ErrorReported>;
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index fb80dcb7561..31f3d8e3791 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -619,14 +619,6 @@ impl SyntaxContext {
         HygieneData::with(|data| data.outer_mark(self))
     }
 
-    #[inline]
-    pub fn outer_mark_with_data(self) -> (ExpnId, Transparency, ExpnData) {
-        HygieneData::with(|data| {
-            let (expn_id, transparency) = data.outer_mark(self);
-            (expn_id, transparency, data.expn_data(expn_id).clone())
-        })
-    }
-
     pub fn dollar_crate_name(self) -> Symbol {
         HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name)
     }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index e7cb8cb6e88..d036c078049 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -223,12 +223,6 @@ impl FileName {
         }
     }
 
-    pub fn quote_expansion_source_code(src: &str) -> FileName {
-        let mut hasher = StableHasher::new();
-        src.hash(&mut hasher);
-        FileName::QuoteExpansion(hasher.finish())
-    }
-
     pub fn macro_expansion_source_code(src: &str) -> FileName {
         let mut hasher = StableHasher::new();
         src.hash(&mut hasher);
@@ -1861,7 +1855,7 @@ where
         }
 
         if *self == DUMMY_SP {
-            std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
+            Hash::hash(&TAG_INVALID_SPAN, hasher);
             return;
         }
 
@@ -1872,28 +1866,28 @@ where
         let (file_lo, line_lo, col_lo) = match ctx.byte_pos_to_line_and_col(span.lo) {
             Some(pos) => pos,
             None => {
-                std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
+                Hash::hash(&TAG_INVALID_SPAN, hasher);
                 span.ctxt.hash_stable(ctx, hasher);
                 return;
             }
         };
 
         if !file_lo.contains(span.hi) {
-            std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
+            Hash::hash(&TAG_INVALID_SPAN, hasher);
             span.ctxt.hash_stable(ctx, hasher);
             return;
         }
 
-        std::hash::Hash::hash(&TAG_VALID_SPAN, hasher);
+        Hash::hash(&TAG_VALID_SPAN, hasher);
         // We truncate the stable ID hash and line and column numbers. The chances
         // of causing a collision this way should be minimal.
-        std::hash::Hash::hash(&(file_lo.name_hash as u64), hasher);
+        Hash::hash(&(file_lo.name_hash as u64), hasher);
 
         let col = (col_lo.0 as u64) & 0xFF;
         let line = ((line_lo as u64) & 0xFF_FF_FF) << 8;
         let len = ((span.hi - span.lo).0 as u64) << 32;
         let line_col_len = col | line | len;
-        std::hash::Hash::hash(&line_col_len, hasher);
+        Hash::hash(&line_col_len, hasher);
         span.ctxt.hash_stable(ctx, hasher);
     }
 }
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index fdb031fd9b3..3b929c4acb9 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -451,15 +451,6 @@ impl SourceMap {
         }
     }
 
-    /// Returns a new `Span` covering the start and end `BytePos`s of the file containing the given
-    /// `pos`. This can be used to quickly determine if another `BytePos` or `Span` is from the same
-    /// file.
-    pub fn lookup_file_span(&self, pos: BytePos) -> Span {
-        let idx = self.lookup_source_file_idx(pos);
-        let SourceFile { start_pos, end_pos, .. } = *(*self.files.borrow().source_files)[idx];
-        Span::with_root_ctxt(start_pos, end_pos)
-    }
-
     /// Returns `Some(span)`, a union of the LHS and RHS span. The LHS must precede the RHS. If
     /// there are gaps between LHS and RHS, the resulting union will cross these gaps.
     /// For this to work,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 6309b00f5f5..28fef65da07 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -212,6 +212,7 @@ symbols! {
         _d,
         _e,
         _task_context,
+        a32,
         aarch64_target_feature,
         abi,
         abi_amdgpu_kernel,
@@ -256,6 +257,7 @@ symbols! {
         arbitrary_enum_discriminant,
         arbitrary_self_types,
         arith_offset,
+        arm,
         arm_target_feature,
         array,
         arrays,
@@ -359,6 +361,7 @@ symbols! {
         const_fn_union,
         const_generics,
         const_if_match,
+        const_impl_trait,
         const_in_array_repeat_expressions,
         const_indexing,
         const_let,
@@ -591,11 +594,13 @@ symbols! {
         inlateout,
         inline,
         inout,
+        instruction_set,
         intel,
         into_iter,
         into_result,
         intrinsics,
         irrefutable_let_patterns,
+        isa_attribute,
         isize,
         issue,
         issue_5723_bootstrap,
@@ -1064,6 +1069,7 @@ symbols! {
         sym,
         sync,
         sync_trait,
+        t32,
         target_arch,
         target_endian,
         target_env,
@@ -1108,6 +1114,7 @@ symbols! {
         try_trait,
         tt,
         tuple,
+        tuple_from_req,
         tuple_indexing,
         two_phase,
         ty,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index b96e318bd3e..2c9caf73b8e 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -115,7 +115,6 @@ fn get_symbol_hash<'tcx>(
         }
 
         // also include any type parameters (for generic items)
-        assert!(!substs.has_erasable_regions());
         substs.hash_stable(&mut hcx, &mut hasher);
 
         if let Some(instantiating_crate) = instantiating_crate {
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 75150a56c43..28b4a78929e 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -201,7 +201,7 @@ fn compute_symbol_name(
     //
     // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316
     if is_foreign {
-        if tcx.sess.target.target.arch != "wasm32"
+        if tcx.sess.target.arch != "wasm32"
             || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id)
         {
             if let Some(name) = attrs.link_name {
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index d2c9b05c560..822a8352934 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -6,7 +6,7 @@
 
 use rustc_hir as hir;
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{Instance, TyCtxt};
+use rustc_middle::ty::{subst::InternalSubsts, Instance, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 
 const SYMBOL_NAME: Symbol = sym::rustc_symbol_name;
@@ -36,8 +36,11 @@ impl SymbolNamesTest<'tcx> {
         let def_id = tcx.hir().local_def_id(hir_id);
         for attr in tcx.get_attrs(def_id.to_def_id()).iter() {
             if tcx.sess.check_name(attr, SYMBOL_NAME) {
-                // for now, can only use on monomorphic names
-                let instance = Instance::mono(tcx, def_id.to_def_id());
+                let def_id = def_id.to_def_id();
+                let instance = Instance::new(
+                    def_id,
+                    tcx.erase_regions(&InternalSubsts::identity_for_item(tcx, def_id)),
+                );
                 let mangled = tcx.symbol_name(instance);
                 tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled));
                 if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index da9c93143bf..16d0b86903e 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -132,7 +132,7 @@ impl SymbolMangler<'tcx> {
             self.push("u");
 
             // FIXME(eddyb) we should probably roll our own punycode implementation.
-            let mut punycode_bytes = match ::punycode::encode(ident) {
+            let mut punycode_bytes = match punycode::encode(ident) {
                 Ok(s) => s.into_bytes(),
                 Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident),
             };
@@ -259,7 +259,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
     }
 
     fn print_impl_path(
-        self,
+        mut self,
         impl_def_id: DefId,
         substs: &'tcx [GenericArg<'tcx>],
         mut self_ty: Ty<'tcx>,
@@ -284,12 +284,37 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
             }
         }
 
-        self.path_append_impl(
-            |cx| cx.print_def_path(parent_def_id, &[]),
-            &key.disambiguated_data,
-            self_ty,
-            impl_trait_ref,
-        )
+        self.push(match impl_trait_ref {
+            Some(_) => "X",
+            None => "M",
+        });
+
+        // Encode impl generic params if the substitutions contain parameters (implying
+        // polymorphization is enabled) and this isn't an inherent impl.
+        if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) {
+            self = self.path_generic_args(
+                |this| {
+                    this.path_append_ns(
+                        |cx| cx.print_def_path(parent_def_id, &[]),
+                        'I',
+                        key.disambiguated_data.disambiguator as u64,
+                        "",
+                    )
+                },
+                substs,
+            )?;
+        } else {
+            self.push_disambiguator(key.disambiguated_data.disambiguator as u64);
+            self = self.print_def_path(parent_def_id, &[])?;
+        }
+
+        self = self_ty.print(self)?;
+
+        if let Some(trait_ref) = impl_trait_ref {
+            self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?;
+        }
+
+        Ok(self)
     }
 
     fn print_region(mut self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
@@ -538,6 +563,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
         self.push_ident(&name);
         Ok(self)
     }
+
     fn path_qualified(
         mut self,
         self_ty: Ty<'tcx>,
@@ -552,24 +578,16 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
     }
 
     fn path_append_impl(
-        mut self,
-        print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
-        disambiguated_data: &DisambiguatedDefPathData,
-        self_ty: Ty<'tcx>,
-        trait_ref: Option<ty::TraitRef<'tcx>>,
+        self,
+        _: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+        _: &DisambiguatedDefPathData,
+        _: Ty<'tcx>,
+        _: Option<ty::TraitRef<'tcx>>,
     ) -> Result<Self::Path, Self::Error> {
-        self.push(match trait_ref {
-            Some(_) => "X",
-            None => "M",
-        });
-        self.push_disambiguator(disambiguated_data.disambiguator as u64);
-        self = print_prefix(self)?;
-        self = self_ty.print(self)?;
-        if let Some(trait_ref) = trait_ref {
-            self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?;
-        }
-        Ok(self)
+        // Inlined into `print_impl_path`
+        unreachable!()
     }
+
     fn path_append(
         self,
         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
@@ -603,6 +621,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
             name.as_ref().map_or("", |s| &s[..]),
         )
     }
+
     fn path_generic_args(
         mut self,
         print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 3c1a2ea39d3..047b8cf5cdb 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -164,12 +164,12 @@ impl TargetDataLayout {
             ));
         }
 
-        if dl.pointer_size.bits().to_string() != target.target_pointer_width {
+        if dl.pointer_size.bits() != target.pointer_width.into() {
             return Err(format!(
                 "inconsistent target specification: \"data-layout\" claims \
                                 pointers are {}-bit, while \"target-pointer-width\" is `{}`",
                 dl.pointer_size.bits(),
-                target.target_pointer_width
+                target.pointer_width
             ));
         }
 
diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs
index 638c52d97f1..b19489aa439 100644
--- a/compiler/rustc_target/src/asm/mips.rs
+++ b/compiler/rustc_target/src/asm/mips.rs
@@ -32,11 +32,12 @@ impl MipsInlineAsmRegClass {
 
     pub fn supported_types(
         self,
-        _arch: InlineAsmArch,
+        arch: InlineAsmArch,
     ) -> &'static [(InlineAsmType, Option<&'static str>)] {
-        match self {
-            Self::reg => types! { _: I8, I16, I32, F32; },
-            Self::freg => types! { _: F32; },
+        match (self, arch) {
+            (Self::reg, InlineAsmArch::Mips64) => types! { _: I8, I16, I32, I64, F32, F64; },
+            (Self::reg, _) => types! { _: I8, I16, I32, F32; },
+            (Self::freg, _) => types! { _: F32, F64; },
         }
     }
 }
@@ -44,31 +45,31 @@ impl MipsInlineAsmRegClass {
 // The reserved registers are somewhat taken from <https://git.io/JUR1k#L150>.
 def_regs! {
     Mips MipsInlineAsmReg MipsInlineAsmRegClass {
-        v0: reg = ["$2", "$v0"],
-        v1: reg = ["$3", "$v1"],
-        a0: reg = ["$4", "$a0"],
-        a1: reg = ["$5", "$a1"],
-        a2: reg = ["$6", "$a2"],
-        a3: reg = ["$7", "$a3"],
+        r2: reg = ["$2"],
+        r3: reg = ["$3"],
+        r4: reg = ["$4"],
+        r5: reg = ["$5"],
+        r6: reg = ["$6"],
+        r7: reg = ["$7"],
         // FIXME: Reserve $t0, $t1 if in mips16 mode.
-        t0: reg = ["$8", "$t0"],
-        t1: reg = ["$9", "$t1"],
-        t2: reg = ["$10", "$t2"],
-        t3: reg = ["$11", "$t3"],
-        t4: reg = ["$12", "$t4"],
-        t5: reg = ["$13", "$t5"],
-        t6: reg = ["$14", "$t6"],
-        t7: reg = ["$15", "$t7"],
-        s0: reg = ["$16", "$s0"],
-        s1: reg = ["$17", "$s1"],
-        s2: reg = ["$18", "$s2"],
-        s3: reg = ["$19", "$s3"],
-        s4: reg = ["$20", "$s4"],
-        s5: reg = ["$21", "$s5"],
-        s6: reg = ["$22", "$s6"],
-        s7: reg = ["$23", "$s7"],
-        t8: reg = ["$24", "$t8"],
-        t9: reg = ["$25", "$t9"],
+        r8: reg = ["$8"],
+        r9: reg = ["$9"],
+        r10: reg = ["$10"],
+        r11: reg = ["$11"],
+        r12: reg = ["$12"],
+        r13: reg = ["$13"],
+        r14: reg = ["$14"],
+        r15: reg = ["$15"],
+        r16: reg = ["$16"],
+        r17: reg = ["$17"],
+        r18: reg = ["$18"],
+        r19: reg = ["$19"],
+        r20: reg = ["$20"],
+        r21: reg = ["$21"],
+        r22: reg = ["$22"],
+        r23: reg = ["$23"],
+        r24: reg = ["$24"],
+        r25: reg = ["$25"],
         f0: freg = ["$f0"],
         f1: freg = ["$f1"],
         f2: freg = ["$f2"],
@@ -101,21 +102,21 @@ def_regs! {
         f29: freg = ["$f29"],
         f30: freg = ["$f30"],
         f31: freg = ["$f31"],
-        #error = ["$0", "$zero"] =>
+        #error = ["$0"] =>
             "constant zero cannot be used as an operand for inline asm",
-        #error = ["$1", "$at"] =>
+        #error = ["$1"] =>
             "reserved for assembler (Assembler Temp)",
-        #error = ["$26", "$k0"] =>
+        #error = ["$26"] =>
             "OS-reserved register cannot be used as an operand for inline asm",
-        #error = ["$27", "$k1"] =>
+        #error = ["$27"] =>
             "OS-reserved register cannot be used as an operand for inline asm",
-        #error = ["$28", "$gp"] =>
+        #error = ["$28"] =>
             "the global pointer cannot be used as an operand for inline asm",
-        #error = ["$29", "$sp"] =>
+        #error = ["$29"] =>
             "the stack pointer cannot be used as an operand for inline asm",
-        #error = ["$30", "$s8", "$fp"] =>
+        #error = ["$30"] =>
             "the frame pointer cannot be used as an operand for inline asm",
-        #error = ["$31", "$ra"] =>
+        #error = ["$31"] =>
             "the return address register cannot be used as an operand for inline asm",
     }
 }
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index e2f8e91fa95..0d691dc441e 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -176,6 +176,7 @@ pub enum InlineAsmArch {
     Nvptx64,
     Hexagon,
     Mips,
+    Mips64,
 }
 
 impl FromStr for InlineAsmArch {
@@ -192,6 +193,7 @@ impl FromStr for InlineAsmArch {
             "nvptx64" => Ok(Self::Nvptx64),
             "hexagon" => Ok(Self::Hexagon),
             "mips" => Ok(Self::Mips),
+            "mips64" => Ok(Self::Mips64),
             _ => Err(()),
         }
     }
@@ -259,7 +261,7 @@ impl InlineAsmReg {
             InlineAsmArch::Hexagon => {
                 Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
             }
-            InlineAsmArch::Mips => {
+            InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
                 Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?)
             }
         })
@@ -409,7 +411,9 @@ impl InlineAsmRegClass {
                 InlineAsmArch::Hexagon => {
                     Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?)
                 }
-                InlineAsmArch::Mips => Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?),
+                InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
+                    Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?)
+                }
             })
         })
     }
@@ -565,7 +569,7 @@ pub fn allocatable_registers(
             hexagon::fill_reg_map(arch, has_feature, target, &mut map);
             map
         }
-        InlineAsmArch::Mips => {
+        InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
             let mut map = mips::regclass_map();
             mips::fill_reg_map(arch, has_feature, target, &mut map);
             map
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
index 60daf10b36a..c15bd9a08fc 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::apple_base::opts();
     base.cpu = "apple-a12".to_string();
     base.max_atomic_width = Some(128);
@@ -14,10 +14,10 @@ pub fn target() -> TargetResult {
     let arch = "aarch64";
     let llvm_target = super::apple_base::macos_llvm_target(&arch);
 
-    Ok(Target {
+    Target {
         llvm_target,
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -26,5 +26,5 @@ pub fn target() -> TargetResult {
         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 168cd01878e..0019fc4492d 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
@@ -1,12 +1,12 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = opts(Arch::Arm64);
-    Ok(Target {
+    Target {
         llvm_target: "arm64-apple-ios".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -33,5 +33,5 @@ pub fn target() -> TargetResult {
                 .to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
index 5e2cab0df1e..276682c591d 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
@@ -1,12 +1,12 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = opts(Arch::Arm64);
-    Ok(Target {
+    Target {
         llvm_target: "arm64-apple-tvos".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -22,5 +22,5 @@ pub fn target() -> TargetResult {
             forces_embed_bitcode: true,
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
index aabfe458ca3..1f81a03c4a5 100644
--- a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::fuchsia_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-fuchsia".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -16,5 +16,5 @@ pub fn target() -> TargetResult {
         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 e4ecc7ac2dc..1ed4f0da79c 100644
--- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs
@@ -1,18 +1,18 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // See https://developer.android.com/ndk/guides/abis.html#arm64-v8a
 // for target ABI requirements.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::android_base::opts();
     base.max_atomic_width = Some(128);
     // As documented in http://developer.android.com/ndk/guides/cpu-features.html
     // the neon (ASIMD) and FP must exist on all android aarch64 targets.
     base.features = "+neon,+fp-armv8".to_string();
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-linux-android".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
         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 8c03f1e8a7e..32fa2d69540 100644
--- a/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
     base.features = "+neon,+fp-armv8".to_string();
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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 1278b89c7fd..f9d62519bd9 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::cloudabi_base::opts();
     base.max_atomic_width = Some(128);
     base.unsupported_abis = super::arm_base::unsupported_abis();
     base.linker = Some("aarch64-unknown-cloudabi-cc".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-cloudabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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 5ae592c5139..3d008290240 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-freebsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -16,5 +16,5 @@ pub fn target() -> TargetResult {
         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 e07b8f7a756..a7050cbee9e 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::hermit_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-hermit".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -16,5 +16,5 @@ pub fn target() -> TargetResult {
         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 036162248c7..10255012e41 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}_mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
index dc613f35d1d..f530163faf7 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}_mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
index 8c2f6fcff73..dcb157d7aab 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.max_atomic_width = Some(128);
     base.unsupported_abis = super::arm_base::unsupported_abis();
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-netbsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -17,5 +17,5 @@ pub fn target() -> TargetResult {
         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 e012dce73fe..6d3e72906d5 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
@@ -8,7 +8,7 @@
 
 use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let opts = TargetOptions {
         linker: Some("rust-lld".to_owned()),
         features: "+strict-align,+neon,+fp-armv8".to_string(),
@@ -21,10 +21,10 @@ pub fn target() -> Result<Target, String> {
         unsupported_abis: super::arm_base::unsupported_abis(),
         ..Default::default()
     };
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-none".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -33,5 +33,5 @@ pub fn target() -> Result<Target, 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 e2aa6e3b8f5..784cd7eb3c9 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
@@ -8,7 +8,7 @@
 
 use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let opts = TargetOptions {
         linker: Some("rust-lld".to_owned()),
         features: "+strict-align,-neon,-fp-armv8".to_string(),
@@ -21,10 +21,10 @@ pub fn target() -> Result<Target, String> {
         unsupported_abis: super::arm_base::unsupported_abis(),
         ..Default::default()
     };
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-none".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -33,5 +33,5 @@ pub fn target() -> Result<Target, 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 fd726c70f49..e03690e86b8 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
     base.max_atomic_width = Some(128);
     base.unsupported_abis = super::arm_base::unsupported_abis();
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-openbsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -17,5 +17,5 @@ pub fn target() -> TargetResult {
         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 f347a2dba53..13adec9d4c4 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::redox_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-redox".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -16,5 +16,5 @@ pub fn target() -> TargetResult {
         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 6a8d148259a..d6af5dd3628 100644
--- a/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_uwp_msvc_base::opts();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -17,5 +17,5 @@ pub fn target() -> TargetResult {
         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 05f5d7d3a8b..6fce200a96e 100644
--- a/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs
@@ -1,13 +1,13 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.max_atomic_width = Some(128);
 
-    Ok(Target {
+    Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -16,5 +16,5 @@ pub fn target() -> TargetResult {
         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 bb11ce8ef28..0824bc30358 100644
--- a/compiler/rustc_target/src/spec/android_base.rs
+++ b/compiler/rustc_target/src/spec/android_base.rs
@@ -9,6 +9,7 @@ pub fn opts() -> TargetOptions {
         .unwrap()
         .push("-Wl,--allow-multiple-definition".to_string());
     base.is_like_android = true;
+    base.dwarf_version = Some(2);
     base.position_independent_executables = true;
     base.has_elf_tls = false;
     base.requires_uwtable = true;
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index e7b565ae9ca..2e3c835c0e5 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -23,6 +23,7 @@ pub fn opts() -> TargetOptions {
         executables: true,
         target_family: Some("unix".to_string()),
         is_like_osx: true,
+        dwarf_version: Some(2),
         has_rpath: true,
         dll_prefix: "lib".to_string(),
         dll_suffix: ".dylib".to_string(),
diff --git a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
index 7109d043f51..f9c69217460 100644
--- a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::android_base::opts();
     // https://developer.android.com/ndk/guides/abis.html#armeabi
     base.features = "+strict-align,+v5te".to_string();
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "arm-linux-androideabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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 2e3bad83e25..96a444fc465 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs
@@ -1,12 +1,12 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         llvm_target: "arm-unknown-linux-gnueabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
index f8e357cce66..534b98cc607 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs
@@ -1,12 +1,12 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         llvm_target: "arm-unknown-linux-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
index 75753af9f30..e5fa3e3a1cb 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs
@@ -1,19 +1,19 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
 
     // Most of these settings are copied from the arm_unknown_linux_gnueabi
     // target.
     base.features = "+strict-align,+v6".to_string();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
         // 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(),
-        target_pointer_width: "32".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(),
@@ -26,5 +26,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
index c74c88e3612..b631a0010a0 100644
--- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs
@@ -1,19 +1,19 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
 
     // Most of these settings are copied from the arm_unknown_linux_gnueabihf
     // target.
     base.features = "+strict-align,+v6,+vfp2,-d32".to_string();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
         // 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(),
-        target_pointer_width: "32".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(),
@@ -26,5 +26,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
index e0d1f2653ce..86d0cd57af3 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
@@ -1,13 +1,13 @@
 // Targets the Big endian Cortex-R4/R5 processor (ARMv7-R)
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "armebv7r-unknown-none-eabi".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -26,5 +26,5 @@ pub fn target() -> TargetResult {
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
index e2d37d45bf1..9ea44b3b25e 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
@@ -1,13 +1,13 @@
 // Targets the Cortex-R4F/R5F processor (ARMv7-R)
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "armebv7r-unknown-none-eabihf".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -27,5 +27,5 @@ pub fn target() -> TargetResult {
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
-    })
+    }
 }
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 2580e8b0f85..be32731a869 100644
--- a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv4t-unknown-linux-gnueabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -20,7 +20,8 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
             unsupported_abis: super::arm_base::unsupported_abis(),
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            has_thumb_interworking: true,
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
index f28421dc775..4ea4b650623 100644
--- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv5te-unknown-linux-gnueabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -20,7 +20,8 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
             unsupported_abis: super::arm_base::unsupported_abis(),
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
+            has_thumb_interworking: true,
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
index fe1fa88883d..a41a5409ac9 100644
--- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_musl_base::opts();
-    Ok(Target {
+    Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
         // 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(),
-        target_pointer_width: "32".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(),
@@ -23,7 +23,8 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
             unsupported_abis: super::arm_base::unsupported_abis(),
             target_mcount: "\u{1}mcount".to_string(),
+            has_thumb_interworking: true,
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
index 1e06f837997..68f6502133a 100644
--- a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::freebsd_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv6-unknown-freebsd-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
index ef40085888c..23a20ca1c9f 100644
--- a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs
@@ -1,12 +1,12 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         llvm_target: "armv6-unknown-netbsdelf-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
             target_mcount: "__mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_apple_ios.rs b/compiler/rustc_target/src/spec/armv7_apple_ios.rs
index 6dafcc2c345..24a47dd56a9 100644
--- a/compiler/rustc_target/src/spec/armv7_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/armv7_apple_ios.rs
@@ -1,12 +1,12 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = opts(Arch::Armv7);
-    Ok(Target {
+    Target {
         llvm_target: "armv7-apple-ios".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
             unsupported_abis: super::arm_base::unsupported_abis(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
index 38c6c31bd10..342959883cb 100644
--- a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target if is for the baseline of the Android v7a ABI
 // in thumb mode. It's named armv7-* instead of thumbv7-*
@@ -8,16 +8,16 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
 // See https://developer.android.com/ndk/guides/abis.html#v7a
 // for target ABI requirements.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::android_base::opts();
     base.features = "+v7,+thumb-mode,+thumb2,+vfp3,-d32,-neon".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "armv7-none-linux-android".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -26,5 +26,5 @@ pub fn target() -> TargetResult {
         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 e3f4fe0b2ef..d4bb4e963fb 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::cloudabi_base::opts();
     base.cpu = "cortex-a8".to_string();
     base.max_atomic_width = Some(64);
@@ -8,10 +8,10 @@ pub fn target() -> TargetResult {
     base.unsupported_abis = super::arm_base::unsupported_abis();
     base.linker = Some("armv7-unknown-cloudabi-eabihf-cc".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
         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 80a9e6d7e3c..c32e2d4376e 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::freebsd_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-freebsd-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
index 0f175e9aef5..66d3b3e5d07 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target is for glibc Linux on ARMv7 without thumb-mode, NEON or
 // hardfloat.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-linux-gnueabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -25,5 +25,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
index 27923457cd1..c1ef540a01d 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target is for glibc Linux on ARMv7 without NEON or
 // thumb-mode. See the thumbv7neon variant for enabling both.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -26,5 +26,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}__gnu_mcount_nc".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
index 3d1bf05237f..d4d26b14556 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs
@@ -1,19 +1,19 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target is for musl Linux on ARMv7 without thumb-mode, NEON or
 // hardfloat.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_musl_base::opts();
     // Most of these settings are copied from the armv7_unknown_linux_gnueabi
     // target.
-    Ok(Target {
+    Target {
         // It's important we use "gnueabi" and not "musleabi" here. LLVM uses it
         // 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(),
-        target_pointer_width: "32".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(),
@@ -30,5 +30,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
index 03d7d88b0d6..88db04a74e2 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target is for musl Linux on ARMv7 without thumb-mode or NEON.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_musl_base::opts();
-    Ok(Target {
+    Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
         // 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(),
-        target_pointer_width: "32".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(),
@@ -29,5 +29,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}mcount".to_string(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
index 18fc9ed2ec6..fe2471ab0d0 100644
--- a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::netbsd_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-netbsdelf-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -22,5 +22,5 @@ pub fn target() -> TargetResult {
             target_mcount: "__mcount".to_string(),
             ..base
         },
-    })
+    }
 }
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 04d8702471a..9b8cefdfa9e 100644
--- a/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::vxworks_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
             unsupported_abis: super::arm_base::unsupported_abis(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
index 1db279defff..4199ac4569a 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs
@@ -19,7 +19,7 @@
 
 use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let opts = TargetOptions {
         linker: Some("rust-lld".to_owned()),
         features: "+v7,+thumb2,+soft-float,-neon,+strict-align".to_string(),
@@ -32,10 +32,10 @@ pub fn target() -> Result<Target, String> {
         emit_debug_gdb_scripts: false,
         ..Default::default()
     };
-    Ok(Target {
+    Target {
         llvm_target: "armv7a-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -44,5 +44,5 @@ pub fn target() -> Result<Target, 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 22c2b306b43..99a06590097 100644
--- a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs
@@ -7,7 +7,7 @@
 
 use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let opts = TargetOptions {
         linker: Some("rust-lld".to_owned()),
         features: "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align".to_string(),
@@ -20,10 +20,10 @@ pub fn target() -> Result<Target, String> {
         emit_debug_gdb_scripts: false,
         ..Default::default()
     };
-    Ok(Target {
+    Target {
         llvm_target: "armv7a-none-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -32,5 +32,5 @@ pub fn target() -> Result<Target, 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 fed83997190..f0e79072bc1 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
@@ -1,13 +1,13 @@
 // Targets the Little-endian Cortex-R4/R5 processor (ARMv7-R)
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "armv7r-unknown-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -26,5 +26,5 @@ pub fn target() -> TargetResult {
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
index 769ac13e515..4c464d2b256 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
@@ -1,13 +1,13 @@
 // Targets the Little-endian Cortex-R4F/R5F processor (ARMv7-R)
 
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "armv7r-unknown-none-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -27,5 +27,5 @@ pub fn target() -> TargetResult {
             emit_debug_gdb_scripts: false,
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
index d6c99c4ade6..4c2d70ae34b 100644
--- a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs
@@ -1,12 +1,12 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = opts(Arch::Armv7s);
-    Ok(Target {
+    Target {
         llvm_target: "armv7s-apple-ios".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
             unsupported_abis: super::arm_base::unsupported_abis(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
index d3dbc39c99d..1c3f5c4f9e8 100644
--- a/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs
@@ -1,12 +1,12 @@
 use super::{wasm32_unknown_emscripten, LinkerFlavor, Target};
 
-pub fn target() -> Result<Target, String> {
-    let mut target = wasm32_unknown_emscripten::target()?;
+pub fn target() -> Target {
+    let mut target = wasm32_unknown_emscripten::target();
     target
         .options
         .post_link_args
         .entry(LinkerFlavor::Em)
         .or_default()
         .extend(vec!["-s".to_string(), "WASM=0".to_string()]);
-    Ok(target)
+    target
 }
diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs
index 527a322d56a..01445dc3898 100644
--- a/compiler/rustc_target/src/spec/avr_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 /// A base target for AVR devices using the GNU toolchain.
 ///
 /// Requires GNU avr-gcc and avr-binutils on the host system.
-pub fn target(target_cpu: String) -> TargetResult {
-    Ok(Target {
+pub fn target(target_cpu: String) -> Target {
+    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(),
-        target_pointer_width: "16".to_string(),
+        pointer_width: 16,
         linker_flavor: LinkerFlavor::Gcc,
         target_os: "unknown".to_string(),
         target_env: "".to_string(),
@@ -49,5 +49,5 @@ pub fn target(target_cpu: String) -> TargetResult {
             atomic_cas: false,
             ..TargetOptions::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs b/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs
index 5d22598b57b..7e63ae9c5aa 100644
--- a/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs
+++ b/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs
@@ -1,5 +1,5 @@
-use crate::spec::TargetResult;
+use crate::spec::Target;
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     super::avr_gnu_base::target("atmega328".to_owned())
 }
diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs
index c7062e1ca51..82dc5f54659 100644
--- a/compiler/rustc_target/src/spec/dragonfly_base.rs
+++ b/compiler/rustc_target/src/spec/dragonfly_base.rs
@@ -24,6 +24,7 @@ pub fn opts() -> TargetOptions {
         pre_link_args: args,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
+        dwarf_version: Some(2),
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs
index d2a087ab62f..051325a8df6 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -26,6 +26,7 @@ pub fn opts() -> TargetOptions {
         eliminate_frame_pointer: false, // FIXME 43575
         relro_level: RelroLevel::Full,
         abi_return_struct_as_int: true,
+        dwarf_version: Some(2),
         ..Default::default()
     }
 }
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 0976acb4fb0..143b93dfeef 100644
--- a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkArgs, LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkArgs, LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "hexagonv60".to_string();
     base.max_atomic_width = Some(32);
@@ -17,10 +17,10 @@ pub fn target() -> TargetResult {
     base.pre_link_args = LinkArgs::new();
     base.post_link_args = LinkArgs::new();
 
-    Ok(Target {
+    Target {
         llvm_target: "hexagon-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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",
@@ -35,5 +35,5 @@ pub fn target() -> TargetResult {
         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 6cb209ab1c0..21421497965 100644
--- a/compiler/rustc_target/src/spec/i386_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs
@@ -1,12 +1,12 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = opts(Arch::I386);
-    Ok(Target {
+    Target {
         llvm_target: "i386-apple-ios".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -17,5 +17,5 @@ pub fn target() -> TargetResult {
         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/i586_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs
index ba712aced84..664b9d5d515 100644
--- a/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs
@@ -1,8 +1,8 @@
-use crate::spec::TargetResult;
+use crate::spec::Target;
 
-pub fn target() -> TargetResult {
-    let mut base = super::i686_pc_windows_msvc::target()?;
+pub fn target() -> Target {
+    let mut base = super::i686_pc_windows_msvc::target();
     base.options.cpu = "pentium".to_string();
     base.llvm_target = "i586-pc-windows-msvc".to_string();
-    Ok(base)
+    base
 }
diff --git a/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs
index 49f4f2cb6b9..3276f1d0094 100644
--- a/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs
@@ -1,8 +1,8 @@
-use crate::spec::TargetResult;
+use crate::spec::Target;
 
-pub fn target() -> TargetResult {
-    let mut base = super::i686_unknown_linux_gnu::target()?;
+pub fn target() -> Target {
+    let mut base = super::i686_unknown_linux_gnu::target();
     base.options.cpu = "pentium".to_string();
     base.llvm_target = "i586-unknown-linux-gnu".to_string();
-    Ok(base)
+    base
 }
diff --git a/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs
index 0f2ccebd6da..5fbf0487226 100644
--- a/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs
@@ -1,8 +1,8 @@
-use crate::spec::TargetResult;
+use crate::spec::Target;
 
-pub fn target() -> TargetResult {
-    let mut base = super::i686_unknown_linux_musl::target()?;
+pub fn target() -> Target {
+    let mut base = super::i686_unknown_linux_musl::target();
     base.options.cpu = "pentium".to_string();
     base.llvm_target = "i586-unknown-linux-musl".to_string();
-    Ok(base)
+    base
 }
diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
index b7a34f9740a..9c7e7241b57 100644
--- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::apple_base::opts();
     base.cpu = "yonah".to_string();
     base.max_atomic_width = Some(64);
@@ -15,10 +15,10 @@ pub fn target() -> TargetResult {
     let arch = "i686";
     let llvm_target = super::apple_base::macos_llvm_target(&arch);
 
-    Ok(Target {
+    Target {
         llvm_target,
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -29,5 +29,5 @@ pub fn target() -> TargetResult {
         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 79242f24026..d116ae62e0f 100644
--- a/compiler/rustc_target/src/spec/i686_linux_android.rs
+++ b/compiler/rustc_target/src/spec/i686_linux_android.rs
@@ -1,9 +1,9 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
 // See https://developer.android.com/ndk/guides/abis.html#x86
 // for target ABI requirements.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::android_base::opts();
 
     base.max_atomic_width = Some(64);
@@ -13,10 +13,10 @@ pub fn target() -> TargetResult {
     base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string();
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-linux-android".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -27,5 +27,5 @@ pub fn target() -> TargetResult {
         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 33c9008bb14..84585bd515a 100644
--- a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_gnu_base::opts();
     base.cpu = "pentium4".to_string();
     base.pre_link_args
@@ -16,10 +16,10 @@ pub fn target() -> TargetResult {
         .unwrap()
         .push("-Wl,--large-address-aware".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-pc-windows-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -30,5 +30,5 @@ pub fn target() -> TargetResult {
         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 9d0922b8ce5..db20b6094b7 100644
--- a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
@@ -20,10 +20,10 @@ pub fn target() -> TargetResult {
         .unwrap()
         .extend(pre_link_args_msvc);
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -34,5 +34,5 @@ pub fn target() -> TargetResult {
         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 729b1f68e00..d9365d59e0e 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::cloudabi_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
@@ -8,10 +8,10 @@ pub fn target() -> TargetResult {
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-cloudabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -22,5 +22,5 @@ pub fn target() -> TargetResult {
         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 60f2188514e..ba379a40f50 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
@@ -9,10 +9,10 @@ pub fn target() -> TargetResult {
     pre_link_args.push("-Wl,-znotext".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-freebsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -23,5 +23,5 @@ pub fn target() -> TargetResult {
         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 4dc27af30da..02754b39fa7 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::haiku_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]);
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-haiku".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
         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 0d578f22f98..b7ceaefef93 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
         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 699a0ab45e8..9240b56aeaf 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
@@ -22,10 +22,10 @@ pub fn target() -> TargetResult {
     // https://llvm.org/bugs/show_bug.cgi?id=30879
     base.eliminate_frame_pointer = false;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -36,5 +36,5 @@ pub fn target() -> TargetResult {
         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 88b1ae7d53c..a4421924a7b 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-netbsdelf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
         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 829cd1ac1a3..fe5030f661b 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
@@ -8,10 +8,10 @@ pub fn target() -> TargetResult {
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-fuse-ld=lld".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-openbsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -22,5 +22,5 @@ pub fn target() -> TargetResult {
         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 221d5f0785c..676a8ca0acc 100644
--- a/compiler/rustc_target/src/spec/i686_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/i686_unknown_uefi.rs
@@ -5,9 +5,9 @@
 // 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, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::uefi_msvc_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
@@ -76,10 +76,10 @@ pub fn target() -> TargetResult {
     // As a result, we choose -gnu for i686 version before those intrisics are implemented in
     // compiler-builtins. After compiler-builtins implements all required intrinsics, we may
     // remove -gnu and use the default one.
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-windows-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -91,5 +91,5 @@ pub fn target() -> TargetResult {
         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 1c6d2e061bc..ec5a9cc68ce 100644
--- a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_uwp_gnu_base::opts();
     base.cpu = "pentium4".to_string();
     base.pre_link_args
@@ -15,10 +15,10 @@ pub fn target() -> TargetResult {
         .unwrap()
         .push("-Wl,--large-address-aware".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-pc-windows-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -29,5 +29,5 @@ pub fn target() -> TargetResult {
         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 ed2dba53589..d960a130351 100644
--- a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_uwp_msvc_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
         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 f5f66cabb2c..0e5c7b6143e 100644
--- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.cpu = "pentium4".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "i686-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
         target_vendor: "wrs".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
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 b2ea8a6f388..5cbd6bcd3d8 100644
--- a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mips64-unknown-linux-gnuabi64".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
index 17584de1144..3ca92dd1d04 100644
--- a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "mips64r2".to_string();
     base.features = "+mips64r2".to_string();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64-unknown-linux-musl".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
index 48aea4a39b0..4761be5b7ef 100644
--- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mips64el-unknown-linux-gnuabi64".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
index c7a849a1641..d87170b6868 100644
--- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
+++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "mips64r2".to_string();
     base.features = "+mips64r2".to_string();
     base.max_atomic_width = Some(64);
-    Ok(Target {
+    Target {
         // LLVM doesn't recognize "muslabi64" yet.
         llvm_target: "mips64el-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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 e360abdb38d..e51cf3c59f6 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mips-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
index c8d97e600d4..44d136ee7e9 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "mips32r2".to_string();
     base.features = "+mips32r2,+soft-float".to_string();
     base.max_atomic_width = Some(32);
     base.crt_static_default = false;
-    Ok(Target {
+    Target {
         llvm_target: "mips-unknown-linux-musl".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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_uclibc.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
index 8116b8c9cc8..7e168836dc7 100644
--- a/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mips-unknown-linux-uclibc".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
 
             ..super::linux_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 b3bda97c8a5..9897b0093fc 100644
--- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
+++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
@@ -1,17 +1,17 @@
 use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
 // The PSP has custom linker requirements.
 const LINKER_SCRIPT: &str = include_str!("./mipsel_sony_psp_linker_script.ld");
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut pre_link_args = LinkArgs::new();
     pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["--emit-relocs".to_string()]);
 
-    Ok(Target {
+    Target {
         llvm_target: "mipsel-sony-psp".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -36,5 +36,5 @@ pub fn target() -> TargetResult {
             link_script: Some(LINKER_SCRIPT.to_string()),
             ..Default::default()
         },
-    })
+    }
 }
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 7e9d8cd942a..509f3e04ba7 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mipsel-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs
index f70cc13224f..0d3691dd5b9 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "mips32r2".to_string();
     base.features = "+mips32r2,+soft-float".to_string();
     base.max_atomic_width = Some(32);
     base.crt_static_default = false;
-    Ok(Target {
+    Target {
         llvm_target: "mipsel-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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 a8152011efa..6d50d9ba81e 100644
--- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs
+++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mipsel-unknown-linux-uclibc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
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 36b83c63fca..d6e71d2922f 100644
--- a/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mipsisa32r6-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs
index 717ae3f1d20..67e97fd2f0f 100644
--- a/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mipsisa32r6el-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
index 3f7d233e55f..c3a7ae8b11f 100644
--- a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mipsisa64r6-unknown-linux-gnuabi64".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
index 4f41b8323a9..467e05a00d4 100644
--- a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
+++ b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "mipsisa64r6el-unknown-linux-gnuabi64".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
 
             ..super::linux_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index f1e8330425e..1d3e61c4992 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -430,48 +430,23 @@ impl fmt::Display for LinkOutputKind {
     }
 }
 
-pub enum LoadTargetError {
-    BuiltinTargetNotFound(String),
-    Other(String),
-}
-
 pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<String>>;
-pub type TargetResult = Result<Target, String>;
 
 macro_rules! supported_targets {
     ( $(($( $triple:literal, )+ $module:ident ),)+ ) => {
         $(mod $module;)+
 
         /// List of supported targets
-        const TARGETS: &[&str] = &[$($($triple),+),+];
-
-        fn load_specific(target: &str) -> Result<Target, LoadTargetError> {
-            match target {
-                $(
-                    $($triple)|+ => {
-                        let mut t = $module::target()
-                            .map_err(LoadTargetError::Other)?;
-                        t.options.is_builtin = true;
-
-                        // round-trip through the JSON parser to ensure at
-                        // run-time that the parser works correctly
-                        t = Target::from_json(t.to_json())
-                            .map_err(LoadTargetError::Other)?;
-                        debug!("got builtin target: {:?}", t);
-                        Ok(t)
-                    },
-                )+
-                    _ => Err(LoadTargetError::BuiltinTargetNotFound(
-                        format!("Unable to find target: {}", target)))
-            }
-        }
-
-        pub fn get_targets() -> impl Iterator<Item = String> {
-            TARGETS.iter().filter_map(|t| -> Option<String> {
-                load_specific(t)
-                    .and(Ok(t.to_string()))
-                    .ok()
-            })
+        pub const TARGETS: &[&str] = &[$($($triple),+),+];
+
+        fn load_builtin(target: &str) -> Option<Target> {
+            let mut t = match target {
+                $( $($triple)|+ => $module::target(), )+
+                _ => return None,
+            };
+            t.options.is_builtin = true;
+            debug!("got builtin target: {:?}", t);
+            Some(t)
         }
 
         #[cfg(test)]
@@ -690,8 +665,8 @@ pub struct Target {
     pub llvm_target: String,
     /// String to use as the `target_endian` `cfg` variable.
     pub target_endian: String,
-    /// String to use as the `target_pointer_width` `cfg` variable.
-    pub target_pointer_width: 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.
@@ -841,6 +816,9 @@ pub struct TargetOptions {
     pub is_like_emscripten: bool,
     /// Whether the target toolchain is like Fuchsia's.
     pub is_like_fuchsia: bool,
+    /// Version of DWARF to use if not using the default.
+    /// Useful because some platforms (osx, bsd) only want up to DWARF2.
+    pub dwarf_version: Option<u32>,
     /// Whether the linker support GNU-like arguments such as -O. Defaults to false.
     pub linker_is_gnu: bool,
     /// The MinGW toolchain has a known issue that prevents it from correctly
@@ -994,6 +972,10 @@ pub struct TargetOptions {
     /// used to locate unwinding information is passed
     /// (only has effect if the linker is `ld`-like).
     pub eh_frame_header: bool,
+
+    /// Is true if the target is an ARM architecture using thumb v1 which allows for
+    /// thumb and arm interworking.
+    pub has_thumb_interworking: bool,
 }
 
 impl Default for TargetOptions {
@@ -1033,6 +1015,7 @@ impl Default for TargetOptions {
             is_like_emscripten: false,
             is_like_msvc: false,
             is_like_fuchsia: false,
+            dwarf_version: None,
             linker_is_gnu: false,
             allows_weak_linkage: true,
             has_rpath: false,
@@ -1086,6 +1069,7 @@ impl Default for TargetOptions {
             llvm_args: vec![],
             use_ctors_section: false,
             eh_frame_header: true,
+            has_thumb_interworking: false,
         }
     }
 }
@@ -1127,7 +1111,7 @@ impl Target {
     /// Maximum integer size in bits that this target can perform atomic
     /// operations on.
     pub fn max_atomic_width(&self) -> u64 {
-        self.options.max_atomic_width.unwrap_or_else(|| self.target_pointer_width.parse().unwrap())
+        self.options.max_atomic_width.unwrap_or_else(|| self.pointer_width.into())
     }
 
     pub fn is_abi_supported(&self, abi: Abi) -> bool {
@@ -1135,7 +1119,7 @@ impl Target {
     }
 
     /// Loads a target descriptor from a JSON object.
-    pub fn from_json(obj: Json) -> TargetResult {
+    pub fn from_json(obj: Json) -> Result<Target, String> {
         // While ugly, this code must remain this way to retain
         // compatibility with existing JSON fields and the internal
         // expected naming of the Target and TargetOptions structs.
@@ -1160,7 +1144,9 @@ impl Target {
         let mut base = Target {
             llvm_target: get_req_field("llvm-target")?,
             target_endian: get_req_field("target-endian")?,
-            target_pointer_width: get_req_field("target-pointer-width")?,
+            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")?,
@@ -1185,6 +1171,15 @@ impl Target {
                     base.options.$key_name = s;
                 }
             } );
+            ($key_name:ident, Option<u32>) => ( {
+                let name = (stringify!($key_name)).replace("_", "-");
+                if let Some(s) = obj.find(&name).and_then(Json::as_u64) {
+                    if s < 1 || s > 5 {
+                        return Err("Not a valid DWARF version number".to_string());
+                    }
+                    base.options.$key_name = Some(s as u32);
+                }
+            } );
             ($key_name:ident, Option<u64>) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(s) = obj.find(&name).and_then(Json::as_u64) {
@@ -1437,6 +1432,7 @@ impl Target {
         key!(is_like_emscripten, bool);
         key!(is_like_android, bool);
         key!(is_like_fuchsia, bool);
+        key!(dwarf_version, Option<u32>);
         key!(linker_is_gnu, bool);
         key!(allows_weak_linkage, bool);
         key!(has_rpath, bool);
@@ -1479,6 +1475,7 @@ impl Target {
         key!(llvm_args, list);
         key!(use_ctors_section, bool);
         key!(eh_frame_header, bool);
+        key!(has_thumb_interworking, bool);
 
         // NB: The old name is deprecated, but support for it is retained for
         // compatibility.
@@ -1531,11 +1528,9 @@ impl Target {
 
         match *target_triple {
             TargetTriple::TargetTriple(ref target_triple) => {
-                // check if triple is in list of supported targets
-                match load_specific(target_triple) {
-                    Ok(t) => return Ok(t),
-                    Err(LoadTargetError::BuiltinTargetNotFound(_)) => (),
-                    Err(LoadTargetError::Other(e)) => return Err(e),
+                // check if triple is in list of built-in targets
+                if let Some(t) = load_builtin(target_triple) {
+                    return Ok(t);
                 }
 
                 // search for a file named `target_triple`.json in RUST_TARGET_PATH
@@ -1624,7 +1619,7 @@ impl ToJson for Target {
 
         target_val!(llvm_target);
         target_val!(target_endian);
-        target_val!(target_pointer_width);
+        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");
@@ -1675,6 +1670,7 @@ impl ToJson for Target {
         target_option_val!(is_like_emscripten);
         target_option_val!(is_like_android);
         target_option_val!(is_like_fuchsia);
+        target_option_val!(dwarf_version);
         target_option_val!(linker_is_gnu);
         target_option_val!(allows_weak_linkage);
         target_option_val!(has_rpath);
@@ -1717,6 +1713,7 @@ impl ToJson for Target {
         target_option_val!(llvm_args);
         target_option_val!(use_ctors_section);
         target_option_val!(eh_frame_header);
+        target_option_val!(has_thumb_interworking);
 
         if default.unsupported_abis != self.options.unsupported_abis {
             d.insert(
diff --git a/compiler/rustc_target/src/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs
index f75697996ac..5bb8109ce26 100644
--- a/compiler/rustc_target/src/spec/msp430_none_elf.rs
+++ b/compiler/rustc_target/src/spec/msp430_none_elf.rs
@@ -1,10 +1,10 @@
-use crate::spec::{LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "msp430-none-elf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "16".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(),
@@ -60,5 +60,5 @@ pub fn target() -> TargetResult {
 
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs
index 988346af2d7..d7baf81fce3 100644
--- a/compiler/rustc_target/src/spec/netbsd_base.rs
+++ b/compiler/rustc_target/src/spec/netbsd_base.rs
@@ -24,6 +24,7 @@ pub fn opts() -> TargetOptions {
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
         use_ctors_section: true,
+        dwarf_version: Some(2),
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
index 0c8f2a34301..86360c181d1 100644
--- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
@@ -1,10 +1,8 @@
 use crate::spec::abi::Abi;
-use crate::spec::{
-    LinkerFlavor, MergeFunctions, PanicStrategy, Target, TargetOptions, TargetResult,
-};
+use crate::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> 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(),
@@ -16,7 +14,7 @@ pub fn target() -> TargetResult {
         linker_flavor: LinkerFlavor::PtxLinker,
 
         target_endian: "little".to_string(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
 
         options: TargetOptions {
@@ -71,5 +69,5 @@ pub fn target() -> TargetResult {
 
             ..Default::default()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs
index cadd14df693..92a382e826b 100644
--- a/compiler/rustc_target/src/spec/openbsd_base.rs
+++ b/compiler/rustc_target/src/spec/openbsd_base.rs
@@ -26,6 +26,7 @@ pub fn opts() -> TargetOptions {
         position_independent_executables: true,
         eliminate_frame_pointer: false, // FIXME 43575
         relro_level: RelroLevel::Full,
+        dwarf_version: Some(2),
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
index 60c15d6b7d2..563ff96a403 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.cpu = "ppc64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc64-unknown-freebsd".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
index 5306d905c5d..7d37670e5b0 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, RelroLevel, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, RelroLevel, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "ppc64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
@@ -10,10 +10,10 @@ pub fn target() -> TargetResult {
     // for now. https://github.com/rust-lang/rust/pull/43170#issuecomment-315411474
     base.relro_level = RelroLevel::Partial;
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".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(),
@@ -22,5 +22,5 @@ pub fn target() -> TargetResult {
         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/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
index c3b956effae..e108d75f337 100644
--- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "ppc64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc64-unknown-linux-musl".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
index e00a927c3a4..9784c637c7e 100644
--- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.cpu = "ppc64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         target_vendor: "wrs".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { ..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 90737994612..46d847f6e5f 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "ppc64le".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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 1a1fccfab02..e04ee013701 100644
--- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "ppc64le".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc64le-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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 2d4c5986637..80fc63e78e4 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -17,5 +17,5 @@ pub fn target() -> TargetResult {
         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_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
index fabc4313bee..612d2967ee0 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mspe".to_string());
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -17,5 +17,5 @@ pub fn target() -> TargetResult {
         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_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
index 240cbcbfe6e..fd89262e464 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc-unknown-linux-musl".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -17,5 +17,5 @@ pub fn target() -> TargetResult {
         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_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
index 6ca7053ced5..d33258d1859 100644
--- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc-unknown-netbsd".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -17,5 +17,5 @@ pub fn target() -> TargetResult {
         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_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
index 2211dc29a5d..6a12f4c59f6 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("--secure-plt".to_string());
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         target_vendor: "wrs".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: TargetOptions { 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 b10182c09ad..5fee61fa0bd 100644
--- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
+++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mspe".to_string());
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("--secure-plt".to_string());
     base.max_atomic_width = Some(32);
 
-    Ok(Target {
+    Target {
         llvm_target: "powerpc-unknown-linux-gnuspe".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -22,5 +22,5 @@ pub fn target() -> TargetResult {
             features: "+secure-plt,+msync".to_string(),
             ..base
         },
-    })
+    }
 }
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 28710c60175..415d7c5607d 100644
--- a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs
@@ -1,10 +1,10 @@
-use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "riscv32-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
             ..super::linux_base::opts()
         },
-    })
+    }
 }
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 5b5e342000b..022768f6ab8 100644
--- a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs
@@ -1,12 +1,12 @@
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+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(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -28,5 +28,5 @@ pub fn target() -> TargetResult {
             eh_frame_header: false,
             ..Default::default()
         },
-    })
+    }
 }
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 4cef5c42d8d..13f0d42d6fd 100644
--- a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs
@@ -1,12 +1,12 @@
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+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(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -28,5 +28,5 @@ pub fn target() -> TargetResult {
             eh_frame_header: false,
             ..Default::default()
         },
-    })
+    }
 }
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 8ad563e441d..86189c27bbd 100644
--- a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs
@@ -1,12 +1,12 @@
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+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(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -28,5 +28,5 @@ pub fn target() -> TargetResult {
             eh_frame_header: false,
             ..Default::default()
         },
-    })
+    }
 }
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 f7a93c916d1..808d7159f82 100644
--- a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs
@@ -1,10 +1,10 @@
-use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "riscv64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(64),
             ..super::linux_base::opts()
         },
-    })
+    }
 }
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 3aeb3f3ca72..0211bc02d2d 100644
--- a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs
@@ -1,12 +1,12 @@
 use crate::spec::{CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
-use crate::spec::{Target, TargetOptions, TargetResult};
+use crate::spec::{Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+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(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -29,5 +29,5 @@ pub fn target() -> TargetResult {
             eh_frame_header: false,
             ..Default::default()
         },
-    })
+    }
 }
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 d8144964dc9..1050ce5ba74 100644
--- a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
+++ b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs
@@ -1,12 +1,12 @@
-use crate::spec::{CodeModel, Target, TargetOptions, TargetResult};
+use crate::spec::{CodeModel, Target, TargetOptions};
 use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+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(),
-        target_pointer_width: "64".to_string(),
+        pointer_width: 64,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: String::new(),
@@ -29,5 +29,5 @@ pub fn target() -> TargetResult {
             eh_frame_header: false,
             ..Default::default()
         },
-    })
+    }
 }
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 f259787e1d5..653b83646ce 100644
--- a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     // z10 is the oldest CPU supported by LLVM
     base.cpu = "z10".to_string();
@@ -11,10 +11,10 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(64);
     base.min_global_align = Some(16);
 
-    Ok(Target {
+    Target {
         llvm_target: "s390x-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".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(),
@@ -23,5 +23,5 @@ pub fn target() -> TargetResult {
         target_vendor: "unknown".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
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 c842b22d4e1..e50c114fcfa 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs
@@ -1,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "v9".to_string();
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "sparc64-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".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(),
@@ -17,5 +17,5 @@ pub fn target() -> TargetResult {
         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 aad85e852f0..6d8e433949b 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.cpu = "v9".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "sparc64-unknown-netbsd".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
index 229e0621e0d..45700e14c53 100644
--- a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
     base.cpu = "v9".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "sparc64-unknown-openbsd".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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 162cd311a38..fc400dd3446 100644
--- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "v9".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mv8plus".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "sparc-unknown-linux-gnu".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "32".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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 acc03fd0d79..0878e7fd21e 100644
--- a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::solaris_base::opts();
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
     // llvm calls this "v9"
     base.cpu = "v9".to_string();
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "sparcv9-sun-solaris".to_string(),
         target_endian: "big".to_string(),
-        target_pointer_width: "64".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
@@ -23,5 +23,5 @@ pub fn target() -> TargetResult {
         target_vendor: "sun".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs
index b2c2b8254d8..d06ab368e1c 100644
--- a/compiler/rustc_target/src/spec/tests/tests_impl.rs
+++ b/compiler/rustc_target/src/spec/tests/tests_impl.rs
@@ -1,16 +1,9 @@
 use super::super::*;
 
-pub(super) fn test_target(target: TargetResult) {
-    // Grab the TargetResult struct. If we successfully retrieved
-    // a Target, then the test JSON encoding/decoding can run for this
-    // Target on this testing platform (i.e., checking the iOS targets
-    // only on a Mac test platform).
-    if let Ok(original) = target {
-        original.check_consistency();
-        let as_json = original.to_json();
-        let parsed = Target::from_json(as_json).unwrap();
-        assert_eq!(original, parsed);
-    }
+// Test target self-consistency and JSON encoding/decoding roundtrip.
+pub(super) fn test_target(target: Target) {
+    target.check_consistency();
+    assert_eq!(Target::from_json(target.to_json()), Ok(target));
 }
 
 impl Target {
diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
index a8c78f057fc..d5ce62d8c1c 100644
--- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
@@ -8,13 +8,13 @@
 //!
 //! **Important:** This target profile **does not** specify a linker script. You just get the default link script when you build a binary for this target. The default link script is very likely wrong, so you should use `-Clink-arg=-Tmy_script.ld` to override that with a correct linker script.
 
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv4t-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "none".to_string(),
         target_env: "".to_string(),
@@ -55,8 +55,9 @@ pub fn target() -> TargetResult {
 
             // don't have atomic compare-and-swap
             atomic_cas: false,
+            has_thumb_interworking: true,
 
             ..super::thumb_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
index 953d60fcc22..407fa6116c5 100644
--- a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
@@ -1,12 +1,12 @@
 // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture)
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv6m-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -24,5 +24,5 @@ pub fn target() -> TargetResult {
             atomic_cas: false,
             ..super::thumb_base::opts()
         },
-    })
+    }
 }
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 37828026fe1..d34f42cdc61 100644
--- a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
 
     // Prevent error LNK2013: BRANCH24(T) fixup overflow
@@ -21,10 +21,10 @@ pub fn target() -> TargetResult {
     // implemented for windows/arm in LLVM
     base.panic_strategy = PanicStrategy::Abort;
 
-    Ok(Target {
+    Target {
         llvm_target: "thumbv7a-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -40,5 +40,5 @@ pub fn target() -> TargetResult {
             unsupported_abis: super::arm_base::unsupported_abis(),
             ..base
         },
-    })
+    }
 }
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 29a4a9875e5..143a9a48a4a 100644
--- a/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_uwp_msvc_base::opts();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
@@ -9,10 +9,10 @@ pub fn target() -> TargetResult {
     // implemented for windows/arm in LLVM
     base.panic_strategy = PanicStrategy::Abort;
 
-    Ok(Target {
+    Target {
         llvm_target: "thumbv7a-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -26,5 +26,5 @@ pub fn target() -> TargetResult {
             unsupported_abis: super::arm_base::unsupported_abis(),
             ..base
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs
index 9e085381953..e0b00460e08 100644
--- a/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs
@@ -9,13 +9,13 @@
 // 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, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv7em-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -25,5 +25,5 @@ pub fn target() -> TargetResult {
         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 95b9b9d5b56..eecd75e4614 100644
--- a/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs
@@ -8,13 +8,13 @@
 //
 // To opt into double precision hardware support, use the `-C target-feature=+fp64` flag.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv7em-none-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -37,5 +37,5 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
             ..super::thumb_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs
index 528359ffad3..a02100ee199 100644
--- a/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs
@@ -1,12 +1,12 @@
 // Targets the Cortex-M3 processor (ARMv7-M)
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv7m-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -16,5 +16,5 @@ pub fn target() -> TargetResult {
         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 c52f077f6f1..35e7d480f3f 100644
--- a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs
@@ -1,4 +1,4 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target if is for the Android v7a ABI in thumb mode with
 // NEON unconditionally enabled and, therefore, with 32 FPU registers
@@ -8,16 +8,16 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
 // See https://developer.android.com/ndk/guides/abis.html#v7a
 // for target ABI requirements.
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::android_base::opts();
     base.features = "+v7,+thumb-mode,+thumb2,+vfp3,+neon".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "armv7-none-linux-android".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -26,5 +26,5 @@ pub fn target() -> TargetResult {
         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 78936948e64..946b0db4c22 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, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target is for glibc Linux on ARMv7 with thumb mode enabled
 // (for consistency with Android and Debian-based distributions)
@@ -6,12 +6,12 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
 // registers enabled as well. See section A2.6.2 on page A2-56 in
 // https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_base::opts();
-    Ok(Target {
+    Target {
         llvm_target: "armv7-unknown-linux-gnueabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -28,5 +28,5 @@ pub fn target() -> TargetResult {
             unsupported_abis: super::arm_base::unsupported_abis(),
             ..base
         },
-    })
+    }
 }
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 f759c3eeb01..91945f9dcdc 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, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
 // This target is for musl Linux on ARMv7 with thumb mode enabled
 // (for consistency with Android and Debian-based distributions)
@@ -6,15 +6,15 @@ use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
 // registers enabled as well. See section A2.6.2 on page A2-56 in
 // https://static.docs.arm.com/ddi0406/cd/DDI0406C_d_armv7ar_arm.pdf
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = super::linux_musl_base::opts();
-    Ok(Target {
+    Target {
         // It's important we use "gnueabihf" and not "musleabihf" here. LLVM
         // 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(),
-        target_pointer_width: "32".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(),
@@ -33,5 +33,5 @@ pub fn target() -> TargetResult {
             target_mcount: "\u{1}mcount".to_string(),
             ..base
         },
-    })
+    }
 }
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 3f67c67b7bc..383346400b5 100644
--- a/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs
@@ -1,12 +1,12 @@
 // Targets the Cortex-M23 processor (Baseline ARMv8-M)
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv8m.base-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -22,5 +22,5 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
             ..super::thumb_base::opts()
         },
-    })
+    }
 }
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 2f8103f0c70..3d0fb664cf6 100644
--- a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs
@@ -1,13 +1,13 @@
 // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile),
 // without the Floating Point extension.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv8m.main-none-eabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -17,5 +17,5 @@ pub fn target() -> TargetResult {
         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 53a340230d6..82368cb59b2 100644
--- a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs
@@ -1,13 +1,13 @@
 // Targets the Cortex-M33 processor (Armv8-M Mainline architecture profile),
 // with the Floating Point extension.
 
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
-    Ok(Target {
+pub fn target() -> Target {
+    Target {
         llvm_target: "thumbv8m.main-none-eabihf".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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(),
@@ -26,5 +26,5 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
             ..super::thumb_base::opts()
         },
-    })
+    }
 }
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index 1916639170e..aea06412aa2 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -1,7 +1,7 @@
 use super::wasm32_base;
 use super::{LinkArgs, LinkerFlavor, PanicStrategy, Target, TargetOptions};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let mut post_link_args = LinkArgs::new();
     post_link_args.insert(
         LinkerFlavor::Em,
@@ -28,10 +28,10 @@ pub fn target() -> Result<Target, String> {
         target_family: Some("unix".to_string()),
         ..wasm32_base::options()
     };
-    Ok(Target {
+    Target {
         llvm_target: "wasm32-unknown-emscripten".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "emscripten".to_string(),
         target_env: String::new(),
@@ -40,5 +40,5 @@ pub fn target() -> Result<Target, 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 ded95a34d55..19609b0d496 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
@@ -13,7 +13,7 @@
 use super::wasm32_base;
 use super::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let mut options = wasm32_base::options();
     let clang_args = options.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
 
@@ -30,10 +30,10 @@ pub fn target() -> Result<Target, String> {
         .unwrap()
         .push("--no-entry".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "wasm32-unknown-unknown".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "unknown".to_string(),
         target_env: String::new(),
@@ -42,5 +42,5 @@ pub fn target() -> Result<Target, 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 351167105ec..26e0722fcf0 100644
--- a/compiler/rustc_target/src/spec/wasm32_wasi.rs
+++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs
@@ -75,7 +75,7 @@
 use super::wasm32_base;
 use super::{crt_objects, LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     let mut options = wasm32_base::options();
 
     options
@@ -104,10 +104,10 @@ pub fn target() -> Result<Target, String> {
     // `args::args()` makes the WASI API calls itself.
     options.main_needs_argc_argv = false;
 
-    Ok(Target {
+    Target {
         llvm_target: "wasm32-wasi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".to_string(),
+        pointer_width: 32,
         target_c_int_width: "32".to_string(),
         target_os: "wasi".to_string(),
         target_env: String::new(),
@@ -116,5 +116,5 @@ pub fn target() -> Result<Target, 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 0234ff55f01..98e42f6c37c 100644
--- a/compiler/rustc_target/src/spec/windows_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs
@@ -11,6 +11,10 @@ pub fn opts() -> TargetOptions {
             "-fno-use-linker-plugin".to_string(),
             // Always enable DEP (NX bit) when it is available
             "-Wl,--nxcompat".to_string(),
+            // Enable ASLR
+            "-Wl,--dynamicbase".to_string(),
+            // ASLR will rebase it anyway so leaving that option enabled only leads to confusion
+            "-Wl,--disable-auto-image-base".to_string(),
         ],
     );
 
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 909aebec70b..2b39fec594a 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::apple_base::opts();
     base.cpu = "core2".to_string();
     base.max_atomic_width = Some(128); // core2 support cmpxchg16b
@@ -18,10 +18,10 @@ pub fn target() -> TargetResult {
     let arch = "x86_64";
     let llvm_target = super::apple_base::macos_llvm_target(&arch);
 
-    Ok(Target {
+    Target {
         llvm_target,
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -31,5 +31,5 @@ pub fn target() -> TargetResult {
         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 fd3e4e2f57b..685e046b64b 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs
@@ -1,12 +1,12 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = opts(Arch::X86_64);
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-apple-ios".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -16,5 +16,5 @@ pub fn target() -> TargetResult {
         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 4cfbd9eba06..ff7331560ed 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,12 +1,12 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = opts(Arch::X86_64_macabi);
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-apple-ios13.0-macabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -16,5 +16,5 @@ pub fn target() -> TargetResult {
         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 664a3ed8816..7c0a819f5dd 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs
@@ -1,12 +1,12 @@
 use super::apple_sdk_base::{opts, Arch};
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let base = opts(Arch::X86_64);
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-apple-tvos".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -15,5 +15,5 @@ pub fn target() -> TargetResult {
         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 3b5233a3e67..8f1627d4a29 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
@@ -2,7 +2,7 @@ use std::iter;
 
 use super::{LinkerFlavor, LldFlavor, PanicStrategy, Target, TargetOptions};
 
-pub fn target() -> Result<Target, String> {
+pub fn target() -> Target {
     const PRE_LINK_ARGS: &[&str] = &[
         "--as-needed",
         "-z",
@@ -74,10 +74,10 @@ pub fn target() -> Result<Target, String> {
         relax_elf_relocations: true,
         ..Default::default()
     };
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-elf".into(),
         target_endian: "little".into(),
-        target_pointer_width: "64".into(),
+        pointer_width: 64,
         target_c_int_width: "32".into(),
         target_os: "unknown".into(),
         target_env: "sgx".into(),
@@ -87,5 +87,5 @@ pub fn target() -> Result<Target, String> {
         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 37b6d57366c..71add0a6c0a 100644
--- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs
@@ -1,15 +1,15 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::fuchsia_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-fuchsia".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -19,5 +19,5 @@ pub fn target() -> TargetResult {
         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 74097f5bf6f..aa5e48cee07 100644
--- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::android_base::opts();
     base.cpu = "x86-64".to_string();
     // https://developer.android.com/ndk/guides/abis.html#86-64
@@ -9,10 +9,10 @@ pub fn target() -> TargetResult {
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-linux-android".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -22,5 +22,5 @@ pub fn target() -> TargetResult {
         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 65bb97d84aa..243167558be 100644
--- a/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs
+++ b/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs
@@ -1,9 +1,9 @@
 // This defines the amd64 target for the Linux Kernel. See the linux-kernel-base module for
 // generic Linux kernel options.
 
-use crate::spec::{CodeModel, LinkerFlavor, Target, TargetResult};
+use crate::spec::{CodeModel, LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_kernel_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -13,11 +13,11 @@ pub fn target() -> TargetResult {
     base.code_model = Some(CodeModel::Kernel);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
 
-    Ok(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(),
-        target_pointer_width: "64".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(),
@@ -28,5 +28,5 @@ pub fn target() -> TargetResult {
         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 99af483f1d4..3b2edc91bc2 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
@@ -1,18 +1,21 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_gnu_base::opts();
     base.cpu = "x86-64".to_string();
-    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
+    let gcc_pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
+    gcc_pre_link_args.push("-m64".to_string());
+    // Use high-entropy 64 bit address space for ASLR
+    gcc_pre_link_args.push("-Wl,--high-entropy-va".to_string());
     base.pre_link_args
         .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pep".to_string()]);
     base.max_atomic_width = Some(64);
     base.linker = Some("x86_64-w64-mingw32-gcc".to_string());
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-pc-windows-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -22,5 +25,5 @@ pub fn target() -> TargetResult {
         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 75ff6b97a2e..f21b059551d 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,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_msvc_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -19,5 +19,5 @@ pub fn target() -> TargetResult {
         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 fbade02c556..2e009d7abbf 100644
--- a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
@@ -13,10 +13,10 @@ pub fn target() -> TargetResult {
     base.disable_redzone = true;
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-rumprun-netbsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -26,5 +26,5 @@ pub fn target() -> TargetResult {
         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 53f4df96518..aef06157cdd 100644
--- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
+++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::solaris_base::opts();
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-pc-solaris".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
         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 dbc5f965020..bdaab883d90 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::cloudabi_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -8,10 +8,10 @@ pub fn target() -> TargetResult {
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-cloudabi".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
         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 fd1871b1a57..13a62d5081c 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::dragonfly_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-dragonfly".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
         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 a124f582bf3..145983022e8 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::freebsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-freebsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
         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 51237697714..d88812e4248 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::haiku_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -9,10 +9,10 @@ pub fn target() -> TargetResult {
     // This option is required to build executables on Haiku x86_64
     base.position_independent_executables = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-haiku".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -22,5 +22,5 @@ pub fn target() -> TargetResult {
         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 4a526f90ed5..a5002091d07 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::hermit_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.features = "+rdrnd,+rdseed".to_string();
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-hermit".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
         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 c25cd0809ee..91d7b0eaefc 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,6 +1,6 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::hermit_kernel_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -9,10 +9,10 @@ pub fn target() -> TargetResult {
             .to_string();
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-hermit".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -22,5 +22,5 @@ pub fn target() -> TargetResult {
         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 2567ca47ef9..e49f009be0f 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs
@@ -1,17 +1,17 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::illumos_base::opts();
     base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string(), "-std=c99".to_string()]);
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
 
-    Ok(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(),
-        target_pointer_width: "64".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
         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 cab19f149a7..fc5b1ba60ec 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,14 +1,14 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::l4re_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-l4re-uclibc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -18,5 +18,5 @@ pub fn target() -> TargetResult {
         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 29cbb777db5..9d9f99c9b59 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
         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 0a37399e2fa..e4a0d913bab 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -11,10 +11,10 @@ pub fn target() -> TargetResult {
     // breaks code gen. See LLVM bug 36743
     base.needs_plt = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-linux-gnux32".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "32".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"
@@ -25,5 +25,5 @@ pub fn target() -> TargetResult {
         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 3a22290da68..a7d3324b2c7 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
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::linux_musl_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -8,10 +8,10 @@ pub fn target() -> TargetResult {
     base.stack_probes = true;
     base.static_position_independent_executables = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-linux-musl".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
         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 adf09c89c42..a8106c0c770 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+use crate::spec::{LinkerFlavor, Target, TargetOptions};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::netbsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-netbsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
         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 dbd163db36b..5afe73ea713 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::openbsd_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-openbsd".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
         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 3d40bafbe1f..e21148887d9 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs
@@ -1,16 +1,16 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::redox_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
     base.stack_probes = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-redox".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -20,5 +20,5 @@ pub fn target() -> TargetResult {
         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 849227a574a..894bd334169 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs
@@ -5,9 +5,9 @@
 // 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, TargetResult};
+use crate::spec::{CodeModel, LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::uefi_msvc_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -28,10 +28,10 @@ pub fn target() -> TargetResult {
     // places no locality-restrictions, so it fits well here.
     base.code_model = Some(CodeModel::Large);
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-windows".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -42,5 +42,5 @@ pub fn target() -> TargetResult {
         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 3bd18f23f6f..a4fa0d03546 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
@@ -1,17 +1,20 @@
-use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, LldFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_uwp_gnu_base::opts();
     base.cpu = "x86-64".to_string();
-    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
+    let gcc_pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap();
+    gcc_pre_link_args.push("-m64".to_string());
+    // Use high-entropy 64 bit address space for ASLR
+    gcc_pre_link_args.push("-Wl,--high-entropy-va".to_string());
     base.pre_link_args
         .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pep".to_string()]);
     base.max_atomic_width = Some(64);
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-pc-windows-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -21,5 +24,5 @@ pub fn target() -> TargetResult {
         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 258df010aae..aaf85bbce81 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,15 +1,15 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::windows_uwp_msvc_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
     base.has_elf_tls = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-pc-windows-msvc".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -19,5 +19,5 @@ pub fn target() -> TargetResult {
         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 f1e27f4d8be..5edf7e7af51 100644
--- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs
@@ -1,6 +1,6 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LinkerFlavor, Target};
 
-pub fn target() -> TargetResult {
+pub fn target() -> Target {
     let mut base = super::vxworks_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
@@ -8,10 +8,10 @@ pub fn target() -> TargetResult {
     base.stack_probes = true;
     base.disable_redzone = true;
 
-    Ok(Target {
+    Target {
         llvm_target: "x86_64-unknown-linux-gnu".to_string(),
         target_endian: "little".to_string(),
-        target_pointer_width: "64".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(),
@@ -21,5 +21,5 @@ pub fn target() -> TargetResult {
         target_vendor: "wrs".to_string(),
         linker_flavor: LinkerFlavor::Gcc,
         options: base,
-    })
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 610c6fd7e35..ecaafee77e2 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -717,6 +717,8 @@ where
             ty::Closure(_, ref substs) => {
                 // Skip lifetime parameters of the enclosing item(s)
 
+                substs.as_closure().tupled_upvars_ty().visit_with(self);
+
                 for upvar_ty in substs.as_closure().upvar_tys() {
                     upvar_ty.visit_with(self);
                 }
@@ -728,6 +730,8 @@ where
                 // Skip lifetime parameters of the enclosing item(s)
                 // Also skip the witness type, because that has no free regions.
 
+                substs.as_generator().tupled_upvars_ty().visit_with(self);
+
                 for upvar_ty in substs.as_generator().upvar_tys() {
                     upvar_ty.visit_with(self);
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 3828cf4d302..1e1eb16faf4 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -147,11 +147,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
     if concrete.is_ok() && substs.has_param_types_or_consts() {
         match infcx.tcx.def_kind(def.did) {
             DefKind::AnonConst => {
-                let mir_body = if let Some(def) = def.as_const_arg() {
-                    infcx.tcx.optimized_mir_of_const_arg(def)
-                } else {
-                    infcx.tcx.optimized_mir(def.did)
-                };
+                let mir_body = infcx.tcx.optimized_mir_opt_const_arg(def);
 
                 if mir_body.is_polymorphic {
                     future_compat_lint();
@@ -212,13 +208,7 @@ impl AbstractConst<'tcx> {
         def: ty::WithOptConstParam<DefId>,
         substs: SubstsRef<'tcx>,
     ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
-        let inner = match (def.did.as_local(), def.const_param_did) {
-            (Some(did), Some(param_did)) => {
-                tcx.mir_abstract_const_of_const_arg((did, param_did))?
-            }
-            _ => tcx.mir_abstract_const(def.did)?,
-        };
-
+        let inner = tcx.mir_abstract_const_opt_const_arg(def)?;
         Ok(inner.map(|inner| AbstractConst { inner, substs }))
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index cb3de57cfed..05e3ed34351 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1384,17 +1384,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
         trait_ref: &ty::PolyTraitRef<'tcx>,
     ) {
         let get_trait_impl = |trait_def_id| {
-            let mut trait_impl = None;
-            self.tcx.for_each_relevant_impl(
+            self.tcx.find_map_relevant_impl(
                 trait_def_id,
                 trait_ref.skip_binder().self_ty(),
-                |impl_def_id| {
-                    if trait_impl.is_none() {
-                        trait_impl = Some(impl_def_id);
-                    }
-                },
-            );
-            trait_impl
+                |impl_def_id| Some(impl_def_id),
+            )
         };
         let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
         let all_traits = self.tcx.all_traits(LOCAL_CRATE);
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 967374ffdc2..efa9bd633ba 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -22,6 +22,7 @@ use rustc_middle::ty::{
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
+use rustc_target::spec::abi;
 use std::fmt;
 
 use super::InferCtxtPrivExt;
@@ -1157,15 +1158,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
                     false,
                     hir::Unsafety::Normal,
-                    ::rustc_target::spec::abi::Abi::Rust,
+                    abi::Abi::Rust,
                 )
             } else {
                 tcx.mk_fn_sig(
-                    ::std::iter::once(inputs),
+                    std::iter::once(inputs),
                     tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })),
                     false,
                     hir::Unsafety::Normal,
-                    ::rustc_target::spec::abi::Abi::Rust,
+                    abi::Abi::Rust,
                 )
             };
             ty::Binder::bind(sig).to_string()
@@ -1307,6 +1308,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let mut generator = None;
         let mut outer_generator = None;
         let mut next_code = Some(&obligation.cause.code);
+
+        let mut seen_upvar_tys_infer_tuple = false;
+
         while let Some(code) = next_code {
             debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
             match code {
@@ -1327,6 +1331,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             outer_generator = Some(did);
                         }
                         ty::GeneratorWitness(..) => {}
+                        ty::Tuple(_) if !seen_upvar_tys_infer_tuple => {
+                            // By introducing a tuple of upvar types into the chain of obligations
+                            // of a generator, the first non-generator item is now the tuple itself,
+                            // we shall ignore this.
+
+                            seen_upvar_tys_infer_tuple = true;
+                        }
                         _ if generator.is_none() => {
                             trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder());
                             target_ty = Some(ty);
@@ -1912,7 +1923,29 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     return;
                 }
 
-                err.note(&format!("required because it appears within the type `{}`", ty));
+                // If the obligation for a tuple is set directly by a Generator or Closure,
+                // then the tuple must be the one containing capture types.
+                let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) {
+                    false
+                } else {
+                    if let ObligationCauseCode::BuiltinDerivedObligation(ref data) =
+                        *data.parent_code
+                    {
+                        let parent_trait_ref =
+                            self.resolve_vars_if_possible(&data.parent_trait_ref);
+                        let ty = parent_trait_ref.skip_binder().self_ty();
+                        matches!(ty.kind(), ty::Generator(..))
+                            || matches!(ty.kind(), ty::Closure(..))
+                    } else {
+                        false
+                    }
+                };
+
+                // Don't print the tuple of capture types
+                if !is_upvar_tys_infer_tuple {
+                    err.note(&format!("required because it appears within the type `{}`", ty));
+                }
+
                 obligated_types.push(ty);
 
                 let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 27751eb554d..97dd180b27b 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -120,7 +120,8 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
         &mut self,
         selcx: &mut SelectionContext<'a, 'tcx>,
     ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
-        debug!("select(obligation-forest-size={})", self.predicates.len());
+        let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
+        let _enter = span.enter();
 
         let mut errors = Vec::new();
 
@@ -173,7 +174,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         projection_ty: ty::ProjectionTy<'tcx>,
         cause: ObligationCause<'tcx>,
     ) -> Ty<'tcx> {
-        debug!("normalize_projection_type(projection_ty={:?})", projection_ty);
+        debug!(?projection_ty, "normalize_projection_type");
 
         debug_assert!(!projection_ty.has_escaping_bound_vars());
 
@@ -191,7 +192,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         );
         self.register_predicate_obligations(infcx, obligations);
 
-        debug!("normalize_projection_type: result={:?}", normalized_ty);
+        debug!(?normalized_ty);
 
         normalized_ty
     }
@@ -205,7 +206,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         // debug output much nicer to read and so on.
         let obligation = infcx.resolve_vars_if_possible(&obligation);
 
-        debug!("register_predicate_obligation(obligation={:?})", obligation);
+        debug!(?obligation, "register_predicate_obligation");
 
         assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
 
@@ -342,7 +343,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate);
         }
 
-        debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause);
+        debug!(?obligation, ?obligation.cause, "process_obligation");
 
         let infcx = self.selcx.infcx();
 
@@ -509,7 +510,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 }
 
                 ty::PredicateAtom::ConstEquate(c1, c2) => {
-                    debug!("equating consts: c1={:?} c2={:?}", c1, c2);
+                    debug!(?c1, ?c2, "equating consts");
                     if self.selcx.tcx().features().const_evaluatable_checked {
                         // FIXME: we probably should only try to unify abstract constants
                         // if the constants depend on generic parameters.
@@ -601,6 +602,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
         }
     }
 
+    #[instrument(level = "debug", skip(self, obligation, stalled_on))]
     fn process_trait_obligation(
         &mut self,
         obligation: &PredicateObligation<'tcx>,
@@ -613,8 +615,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
             // FIXME: consider caching errors too.
             if infcx.predicate_must_hold_considering_regions(obligation) {
                 debug!(
-                    "selecting trait `{:?}` at depth {} evaluated to holds",
-                    obligation.predicate, obligation.recursion_depth
+                    "selecting trait at depth {} evaluated to holds",
+                    obligation.recursion_depth
                 );
                 return ProcessResult::Changed(vec![]);
             }
@@ -622,17 +624,11 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
 
         match self.selcx.select(&trait_obligation) {
             Ok(Some(impl_source)) => {
-                debug!(
-                    "selecting trait `{:?}` at depth {} yielded Ok(Some)",
-                    trait_obligation.predicate, obligation.recursion_depth
-                );
+                debug!("selecting trait at depth {} yielded Ok(Some)", obligation.recursion_depth);
                 ProcessResult::Changed(mk_pending(impl_source.nested_obligations()))
             }
             Ok(None) => {
-                debug!(
-                    "selecting trait `{:?}` at depth {} yielded Ok(None)",
-                    trait_obligation.predicate, obligation.recursion_depth
-                );
+                debug!("selecting trait at depth {} yielded Ok(None)", obligation.recursion_depth);
 
                 // This is a bit subtle: for the most part, the
                 // only reason we can fail to make progress on
@@ -652,10 +648,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 ProcessResult::Unchanged
             }
             Err(selection_err) => {
-                info!(
-                    "selecting trait `{:?}` at depth {} yielded Err",
-                    trait_obligation.predicate, obligation.recursion_depth
-                );
+                info!("selecting trait at depth {} yielded Err", obligation.recursion_depth);
 
                 ProcessResult::Error(CodeSelectionError(selection_err))
             }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index de42aa0e6b7..8dbf7ec51c6 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -157,6 +157,7 @@ impl<'tcx> ProjectionTyCandidateSet<'tcx> {
 ///    the given obligations. If the projection cannot be normalized because
 ///    the required trait bound doesn't hold this returned with `obligations`
 ///    being a predicate that cannot be proven.
+#[instrument(level = "debug", skip(selcx))]
 pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &PolyProjectionObligation<'tcx>,
@@ -164,8 +165,6 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
     Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
     MismatchedProjectionTypes<'tcx>,
 > {
-    debug!("poly_project_and_unify_type(obligation={:?})", obligation);
-
     let infcx = selcx.infcx();
     infcx.commit_if_ok(|_snapshot| {
         let placeholder_predicate =
@@ -191,7 +190,7 @@ fn project_and_unify_type<'cx, 'tcx>(
     Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
     MismatchedProjectionTypes<'tcx>,
 > {
-    debug!("project_and_unify_type(obligation={:?})", obligation);
+    debug!(?obligation, "project_and_unify_type");
 
     let mut obligations = vec![];
     let normalized_ty = match opt_normalize_projection_type(
@@ -207,10 +206,7 @@ fn project_and_unify_type<'cx, 'tcx>(
         Err(InProgress) => return Ok(Err(InProgress)),
     };
 
-    debug!(
-        "project_and_unify_type: normalized_ty={:?} obligations={:?}",
-        normalized_ty, obligations
-    );
+    debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
 
     let infcx = selcx.infcx();
     match infcx
@@ -275,6 +271,7 @@ where
     Normalized { value, obligations }
 }
 
+#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
 pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
     selcx: &'a mut SelectionContext<'b, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -286,16 +283,10 @@ pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>(
 where
     T: TypeFoldable<'tcx>,
 {
-    debug!("normalize_with_depth(depth={}, value={:?})", depth, value);
     let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations);
     let result = ensure_sufficient_stack(|| normalizer.fold(value));
-    debug!(
-        "normalize_with_depth: depth={} result={:?} with {} obligations",
-        depth,
-        result,
-        normalizer.obligations.len()
-    );
-    debug!("normalize_with_depth: depth={} obligations={:?}", depth, normalizer.obligations);
+    debug!(?result, obligations.len = normalizer.obligations.len());
+    debug!(?normalizer.obligations,);
     result
 }
 
@@ -396,12 +387,11 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
                     &mut self.obligations,
                 );
                 debug!(
-                    "AssocTypeNormalizer: depth={} normalized {:?} to {:?}, \
-                     now with {} obligations",
-                    self.depth,
-                    ty,
-                    normalized_ty,
-                    self.obligations.len()
+                    ?self.depth,
+                    ?ty,
+                    ?normalized_ty,
+                    obligations.len = ?self.obligations.len(),
+                    "AssocTypeNormalizer: normalized type"
                 );
                 normalized_ty
             }
@@ -473,6 +463,7 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>(
 /// often immediately appended to another obligations vector. So now this
 /// function takes an obligations vector and appends to it directly, which is
 /// slightly uglier but avoids the need for an extra short-lived allocation.
+#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
 fn opt_normalize_projection_type<'a, 'b, 'tcx>(
     selcx: &'a mut SelectionContext<'b, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
@@ -486,13 +477,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
     let projection_ty = infcx.resolve_vars_if_possible(&projection_ty);
     let cache_key = ProjectionCacheKey::new(projection_ty);
 
-    debug!(
-        "opt_normalize_projection_type(\
-         projection_ty={:?}, \
-         depth={})",
-        projection_ty, depth
-    );
-
     // FIXME(#20304) For now, I am caching here, which is good, but it
     // means we don't capture the type variables that are created in
     // the case of ambiguity. Which means we may create a large stream
@@ -508,10 +492,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             // If we found ambiguity the last time, that means we will continue
             // to do so until some type in the key changes (and we know it
             // hasn't, because we just fully resolved it).
-            debug!(
-                "opt_normalize_projection_type: \
-                 found cache entry: ambiguous"
-            );
+            debug!("found cache entry: ambiguous");
             return Ok(None);
         }
         Err(ProjectionCacheEntry::InProgress) => {
@@ -529,10 +510,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             // with `A::B`, which can trigger a recursive
             // normalization.
 
-            debug!(
-                "opt_normalize_projection_type: \
-                 found cache entry: in-progress"
-            );
+            debug!("found cache entry: in-progress");
 
             return Err(InProgress);
         }
@@ -548,11 +526,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             // discarded as duplicated). But when doing trait
             // evaluation this is not the case, and dropping the trait
             // evaluations can causes ICEs (e.g., #43132).
-            debug!(
-                "opt_normalize_projection_type: \
-                 found normalized ty `{:?}`",
-                ty
-            );
+            debug!(?ty, "found normalized ty");
 
             // Once we have inferred everything we need to know, we
             // can ignore the `obligations` from that point on.
@@ -565,10 +539,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             return Ok(Some(ty.value));
         }
         Err(ProjectionCacheEntry::Error) => {
-            debug!(
-                "opt_normalize_projection_type: \
-                 found error"
-            );
+            debug!("opt_normalize_projection_type: found error");
             let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
             obligations.extend(result.obligations);
             return Ok(Some(result.value));
@@ -586,13 +557,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             // an impl, where-clause etc) and hence we must
             // re-normalize it
 
-            debug!(
-                "opt_normalize_projection_type: \
-                 projected_ty={:?} \
-                 depth={} \
-                 projected_obligations={:?}",
-                projected_ty, depth, projected_obligations
-            );
+            debug!(?projected_ty, ?depth, ?projected_obligations);
 
             let result = if projected_ty.has_projections() {
                 let mut normalizer = AssocTypeNormalizer::new(
@@ -604,11 +569,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
                 );
                 let normalized_ty = normalizer.fold(&projected_ty);
 
-                debug!(
-                    "opt_normalize_projection_type: \
-                     normalized_ty={:?} depth={}",
-                    normalized_ty, depth
-                );
+                debug!(?normalized_ty, ?depth);
 
                 Normalized { value: normalized_ty, obligations: projected_obligations }
             } else {
@@ -621,21 +582,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             Ok(Some(result.value))
         }
         Ok(ProjectedTy::NoProgress(projected_ty)) => {
-            debug!(
-                "opt_normalize_projection_type: \
-                 projected_ty={:?} no progress",
-                projected_ty
-            );
+            debug!(?projected_ty, "opt_normalize_projection_type: no progress");
             let result = Normalized { value: projected_ty, obligations: vec![] };
             infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone());
             // No need to extend `obligations`.
             Ok(Some(result.value))
         }
         Err(ProjectionTyError::TooManyCandidates) => {
-            debug!(
-                "opt_normalize_projection_type: \
-                 too many candidates"
-            );
+            debug!("opt_normalize_projection_type: too many candidates");
             infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key);
             Ok(None)
         }
@@ -755,15 +709,12 @@ impl<'tcx> Progress<'tcx> {
 
     fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self {
         debug!(
-            "with_addl_obligations: self.obligations.len={} obligations.len={}",
-            self.obligations.len(),
-            obligations.len()
+            self.obligations.len = ?self.obligations.len(),
+            obligations.len = obligations.len(),
+            "with_addl_obligations"
         );
 
-        debug!(
-            "with_addl_obligations: self.obligations={:?} obligations={:?}",
-            self.obligations, obligations
-        );
+        debug!(?self.obligations, ?obligations, "with_addl_obligations");
 
         self.obligations.append(&mut obligations);
         self
@@ -778,7 +729,7 @@ fn project_type<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
 ) -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> {
-    debug!("project(obligation={:?})", obligation);
+    debug!(?obligation, "project_type");
 
     if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) {
         debug!("project: overflow!");
@@ -787,7 +738,7 @@ fn project_type<'cx, 'tcx>(
 
     let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx());
 
-    debug!("project: obligation_trait_ref={:?}", obligation_trait_ref);
+    debug!(?obligation_trait_ref);
 
     if obligation_trait_ref.references_error() {
         return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
@@ -951,10 +902,11 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
     env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
     potentially_unnormalized_candidates: bool,
 ) {
-    debug!("assemble_candidates_from_predicates(obligation={:?})", obligation);
+    debug!(?obligation, "assemble_candidates_from_predicates");
+
     let infcx = selcx.infcx();
     for predicate in env_predicates {
-        debug!("assemble_candidates_from_predicates: predicate={:?}", predicate);
+        debug!(?predicate);
         if let ty::PredicateAtom::Projection(data) = predicate.skip_binders() {
             let data = ty::Binder::bind(data);
             let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id;
@@ -969,11 +921,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
                     )
                 });
 
-            debug!(
-                "assemble_candidates_from_predicates: candidate={:?} \
-                 is_match={} same_def_id={}",
-                data, is_match, same_def_id
-            );
+            debug!(?data, ?is_match, ?same_def_id);
 
             if is_match {
                 candidate_set.push_candidate(ctor(data));
@@ -997,6 +945,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
     obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
+    debug!("assemble_candidates_from_impls");
+
     // If we are resolving `<T as TraitRef<...>>::Item == Type`,
     // start out by selecting the predicate `T as TraitRef<...>`:
     let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
@@ -1009,7 +959,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                 return Err(());
             }
             Err(e) => {
-                debug!("assemble_candidates_from_impls: selection error {:?}", e);
+                debug!(error = ?e, "selection error");
                 candidate_set.mark_error(e);
                 return Err(());
             }
@@ -1020,7 +970,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
             | super::ImplSource::Generator(_)
             | super::ImplSource::FnPointer(_)
             | super::ImplSource::TraitAlias(_) => {
-                debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source);
+                debug!(?impl_source);
                 true
             }
             super::ImplSource::UserDefined(impl_data) => {
@@ -1066,10 +1016,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                         !poly_trait_ref.still_further_specializable()
                     } else {
                         debug!(
-                            "assemble_candidates_from_impls: not eligible due to default: \
-                             assoc_ty={} predicate={}",
-                            selcx.tcx().def_path_str(node_item.item.def_id),
-                            obligation.predicate,
+                            assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id),
+                            ?obligation.predicate,
+                            "assemble_candidates_from_impls: not eligible due to default",
                         );
                         false
                     }
@@ -1176,8 +1125,7 @@ fn confirm_candidate<'cx, 'tcx>(
     obligation: &ProjectionTyObligation<'tcx>,
     candidate: ProjectionTyCandidate<'tcx>,
 ) -> Progress<'tcx> {
-    debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation);
-
+    debug!(?obligation, ?candidate, "confirm_candidate");
     let mut progress = match candidate {
         ProjectionTyCandidate::ParamEnv(poly_projection)
         | ProjectionTyCandidate::Object(poly_projection) => {
@@ -1220,9 +1168,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
         | super::ImplSource::AutoImpl(..)
         | super::ImplSource::Param(..)
         | super::ImplSource::Builtin(..)
-        | super::ImplSource::TraitAlias(..) =>
-        // we don't create Select candidates with this kind of resolution
-        {
+        | super::ImplSource::TraitAlias(..) => {
+            // we don't create Select candidates with this kind of resolution
             span_bug!(
                 obligation.cause.span,
                 "Cannot project an associated type from `{:?}`",
@@ -1246,10 +1193,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
         &gen_sig,
     );
 
-    debug!(
-        "confirm_generator_candidate: obligation={:?},gen_sig={:?},obligations={:?}",
-        obligation, gen_sig, obligations
-    );
+    debug!(?obligation, ?gen_sig, ?obligations, "confirm_generator_candidate");
 
     let tcx = selcx.tcx();
 
@@ -1339,10 +1283,7 @@ fn confirm_closure_candidate<'cx, 'tcx>(
         &closure_sig,
     );
 
-    debug!(
-        "confirm_closure_candidate: obligation={:?},closure_sig={:?},obligations={:?}",
-        obligation, closure_sig, obligations
-    );
+    debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
 
     confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No)
         .with_addl_obligations(impl_source.nested)
@@ -1357,7 +1298,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
 
-    debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig);
+    debug!(?obligation, ?fn_sig, "confirm_callable_candidate");
 
     let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, None);
     let fn_once_output_def_id = tcx.require_lang_item(LangItem::FnOnceOutput, None);
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 424b3bd67ff..8212823a6db 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -110,7 +110,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         // check if *any* of those are trivial.
         ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())),
         ty::Closure(_, ref substs) => {
-            substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t))
+            trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty())
         }
 
         ty::Adt(def, _) => {
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index bdbf45f78a2..d748fc8235e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -44,7 +44,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
     {
         debug!(
             "normalize::<{}>(value={:?}, param_env={:?})",
-            ::std::any::type_name::<T>(),
+            std::any::type_name::<T>(),
             value,
             self.param_env,
         );
@@ -65,13 +65,13 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
         let result = value.fold_with(&mut normalizer);
         debug!(
             "normalize::<{}>: result={:?} with {} obligations",
-            ::std::any::type_name::<T>(),
+            std::any::type_name::<T>(),
             result,
             normalizer.obligations.len(),
         );
         debug!(
             "normalize::<{}>: obligations={:?}",
-            ::std::any::type_name::<T>(),
+            std::any::type_name::<T>(),
             normalizer.obligations,
         );
         if normalizer.error {
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 038ba431c47..fdf1641c986 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -22,6 +22,7 @@ use super::SelectionCandidate::{self, *};
 use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack};
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
+    #[instrument(level = "debug", skip(self))]
     pub(super) fn candidate_from_obligation<'o>(
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
@@ -35,16 +36,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // this is because we want the unbound variables to be
         // replaced with fresh types starting from index 0.
         let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate);
-        debug!(
-            "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})",
-            cache_fresh_trait_pred, stack
-        );
+        debug!(?cache_fresh_trait_pred);
         debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars());
 
         if let Some(c) =
             self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred)
         {
-            debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c);
+            debug!(candidate = ?c, "CACHE HIT");
             return c;
         }
 
@@ -57,7 +55,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let (candidate, dep_node) =
             self.in_task(|this| this.candidate_from_obligation_no_cache(stack));
 
-        debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate);
+        debug!(?candidate, "CACHE MISS");
         self.insert_candidate_cache(
             stack.obligation.param_env,
             cache_fresh_trait_pred,
@@ -103,7 +101,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         } else {
                             IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
                         };
-                        debug!("evaluate_stack: pushing cause = {:?}", cause);
+                        debug!(?cause, "evaluate_stack: pushing cause");
                         self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
                     }
                 }
@@ -120,7 +118,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let mut candidates = candidate_set.vec;
 
-        debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates);
+        debug!(?stack, ?candidates, "assembled {} candidates", candidates.len());
 
         // At this point, we know that each of the entries in the
         // candidate set is *individually* applicable. Now we have to
@@ -163,7 +161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .flat_map(Result::transpose)
             .collect::<Result<Vec<_>, _>>()?;
 
-        debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates);
+        debug!(?stack, ?candidates, "winnowed to {} candidates", candidates.len());
 
         let needs_infer = stack.obligation.predicate.has_infer_types_or_consts();
 
@@ -181,10 +179,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     )
                 });
                 if is_dup {
-                    debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]);
+                    debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len());
                     candidates.swap_remove(i);
                 } else {
-                    debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]);
+                    debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len());
                     i += 1;
 
                     // If there are *STILL* multiple candidates, give up
@@ -257,7 +255,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let lang_items = self.tcx().lang_items();
 
         if lang_items.copy_trait() == Some(def_id) {
-            debug!("obligation self ty is {:?}", obligation.predicate.skip_binder().self_ty());
+            debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
 
             // User-defined copy impls are permitted, but only for
             // structs and enums.
@@ -308,7 +306,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
-        debug!("assemble_candidates_for_projected_tys({:?})", obligation);
+        debug!(?obligation, "assemble_candidates_from_projected_tys");
 
         // Before we go into the whole placeholder thing, just
         // quickly check if the self-type is a projection at all.
@@ -341,7 +339,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         stack: &TraitObligationStack<'o, 'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) -> Result<(), SelectionError<'tcx>> {
-        debug!("assemble_candidates_from_caller_bounds({:?})", stack.obligation);
+        debug!(?stack.obligation, "assemble_candidates_from_caller_bounds");
 
         let all_bounds = stack
             .obligation
@@ -383,10 +381,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let self_ty = obligation.self_ty().skip_binder();
         match self_ty.kind() {
             ty::Generator(..) => {
-                debug!(
-                    "assemble_generator_candidates: self_ty={:?} obligation={:?}",
-                    self_ty, obligation
-                );
+                debug!(?self_ty, ?obligation, "assemble_generator_candidates",);
 
                 candidates.vec.push(GeneratorCandidate);
             }
@@ -423,10 +418,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // type/region parameters
         match *obligation.self_ty().skip_binder().kind() {
             ty::Closure(_, closure_substs) => {
-                debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation);
+                debug!(?kind, ?obligation, "assemble_unboxed_candidates");
                 match self.infcx.closure_kind(closure_substs) {
                     Some(closure_kind) => {
-                        debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
+                        debug!(?closure_kind, "assemble_unboxed_candidates");
                         if closure_kind.extends(kind) {
                             candidates.vec.push(ClosureCandidate);
                         }
@@ -503,7 +498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) -> Result<(), SelectionError<'tcx>> {
-        debug!("assemble_candidates_from_impls(obligation={:?})", obligation);
+        debug!(?obligation, "assemble_candidates_from_impls");
 
         // Essentially any user-written impl will match with an error type,
         // so creating `ImplCandidates` isn't useful. However, we might
@@ -537,7 +532,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Result<(), SelectionError<'tcx>> {
         // Okay to skip binder here because the tests we do below do not involve bound regions.
         let self_ty = obligation.self_ty().skip_binder();
-        debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty);
+        debug!(?self_ty, "assemble_candidates_from_auto_impls");
 
         let def_id = obligation.predicate.def_id();
 
@@ -604,8 +599,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
         debug!(
-            "assemble_candidates_from_object_ty(self_ty={:?})",
-            obligation.self_ty().skip_binder()
+            self_ty = ?obligation.self_ty().skip_binder(),
+            "assemble_candidates_from_object_ty",
         );
 
         self.infcx.probe(|_snapshot| {
@@ -645,7 +640,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 _ => return,
             };
 
-            debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref);
+            debug!(?poly_trait_ref, "assemble_candidates_from_object_ty");
 
             // Count only those upcast versions that match the trait-ref
             // we are looking for. Specifically, do not only check for the
@@ -697,7 +692,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         };
         let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
 
-        debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target);
+        debug!(?source, ?target, "assemble_candidates_for_unsizing");
 
         let may_apply = match (source.kind(), target.kind()) {
             // Trait+Kx+'a -> Trait+Ky+'b (upcasts).
@@ -758,7 +753,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Result<(), SelectionError<'tcx>> {
         // Okay to skip binder here because the tests we do below do not involve bound regions.
         let self_ty = obligation.self_ty().skip_binder();
-        debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty);
+        debug!(?self_ty, "assemble_candidates_for_trait_alias");
 
         let def_id = obligation.predicate.def_id();
 
@@ -778,7 +773,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Result<(), SelectionError<'tcx>> {
         match conditions {
             BuiltinImplConditions::Where(nested) => {
-                debug!("builtin_bound: nested={:?}", nested);
+                debug!(?nested, "builtin_bound");
                 candidates
                     .vec
                     .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() });
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 96f0bedf6f1..37d619d5942 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -42,13 +42,12 @@ use super::SelectionContext;
 use std::iter;
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
+    #[instrument(level = "debug", skip(self))]
     pub(super) fn confirm_candidate(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         candidate: SelectionCandidate<'tcx>,
     ) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
-        debug!("confirm_candidate({:?}, {:?})", obligation, candidate);
-
         match candidate {
             BuiltinCandidate { has_nested } => {
                 let data = self.confirm_builtin_candidate(obligation, has_nested);
@@ -191,7 +190,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         param: ty::PolyTraitRef<'tcx>,
     ) -> Vec<PredicateObligation<'tcx>> {
-        debug!("confirm_param_candidate({:?},{:?})", obligation, param);
+        debug!(?obligation, ?param, "confirm_param_candidate");
 
         // During evaluation, we already checked that this
         // where-clause trait-ref could be unified with the obligation
@@ -214,7 +213,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         has_nested: bool,
     ) -> ImplSourceBuiltinData<PredicateObligation<'tcx>> {
-        debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested);
+        debug!(?obligation, ?has_nested, "confirm_builtin_candidate");
 
         let lang_items = self.tcx().lang_items();
         let obligations = if has_nested {
@@ -247,7 +246,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             vec![]
         };
 
-        debug!("confirm_builtin_candidate: obligations={:?}", obligations);
+        debug!(?obligations);
 
         ImplSourceBuiltinData { nested: obligations }
     }
@@ -262,7 +261,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         trait_def_id: DefId,
     ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> {
-        debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id);
+        debug!(?obligation, ?trait_def_id, "confirm_auto_impl_candidate");
 
         let types = obligation.predicate.map_bound(|inner| {
             let self_ty = self.infcx.shallow_resolve(inner.self_ty());
@@ -278,7 +277,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         trait_def_id: DefId,
         nested: ty::Binder<Vec<Ty<'tcx>>>,
     ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> {
-        debug!("vtable_auto_impl: nested={:?}", nested);
+        debug!(?nested, "vtable_auto_impl");
         ensure_sufficient_stack(|| {
             let cause = obligation.derived_cause(BuiltinDerivedObligation);
             let mut obligations = self.collect_predicates_for_types(
@@ -308,7 +307,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // predicate as usual.  It won't have any effect since auto traits are coinductive.
             obligations.extend(trait_obligations);
 
-            debug!("vtable_auto_impl: obligations={:?}", obligations);
+            debug!(?obligations, "vtable_auto_impl");
 
             ImplSourceAutoImplData { trait_def_id, nested: obligations }
         })
@@ -319,13 +318,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         impl_def_id: DefId,
     ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
-        debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id);
+        debug!(?obligation, ?impl_def_id, "confirm_impl_candidate");
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
         self.infcx.commit_unconditionally(|_| {
             let substs = self.rematch_impl(impl_def_id, obligation);
-            debug!("confirm_impl_candidate: substs={:?}", substs);
+            debug!(?substs, "impl substs");
             let cause = obligation.derived_cause(ImplDerivedObligation);
             ensure_sufficient_stack(|| {
                 self.vtable_impl(
@@ -347,10 +346,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         recursion_depth: usize,
         param_env: ty::ParamEnv<'tcx>,
     ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> {
-        debug!(
-            "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})",
-            impl_def_id, substs, recursion_depth,
-        );
+        debug!(?impl_def_id, ?substs, ?recursion_depth, "vtable_impl");
 
         let mut impl_obligations = self.impl_or_trait_obligations(
             cause,
@@ -360,10 +356,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             &substs.value,
         );
 
-        debug!(
-            "vtable_impl: impl_def_id={:?} impl_obligations={:?}",
-            impl_def_id, impl_obligations
-        );
+        debug!(?impl_obligations, "vtable_impl");
 
         // Because of RFC447, the impl-trait-ref and obligations
         // are sufficient to determine the impl substs, without
@@ -379,8 +372,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> ImplSourceObjectData<'tcx, PredicateObligation<'tcx>> {
+        debug!(?obligation, "confirm_object_candidate");
         let tcx = self.tcx();
-        debug!("confirm_object_candidate({:?})", obligation);
 
         let trait_predicate =
             self.infcx.replace_bound_vars_with_placeholders(&obligation.predicate);
@@ -507,7 +500,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
         }
 
-        debug!("confirm_object_candidate: nested: {:?}", nested);
+        debug!(?nested, "object nested obligations");
         ImplSourceObjectData { upcast_trait_ref, vtable_base, nested }
     }
 
@@ -516,7 +509,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
     ) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
     {
-        debug!("confirm_fn_pointer_candidate({:?})", obligation);
+        debug!(?obligation, "confirm_fn_pointer_candidate");
 
         // Okay to skip binder; it is reintroduced below.
         let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
@@ -554,7 +547,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         alias_def_id: DefId,
     ) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> {
-        debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id);
+        debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate");
 
         self.infcx.commit_unconditionally(|_| {
             let predicate =
@@ -571,10 +564,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 &substs,
             );
 
-            debug!(
-                "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}",
-                trait_def_id, trait_obligations
-            );
+            debug!(?trait_def_id, ?trait_obligations, "trait alias obligations");
 
             ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations }
         })
@@ -594,7 +584,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => bug!("closure candidate for non-closure {:?}", obligation),
         };
 
-        debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs);
+        debug!(?obligation, ?generator_def_id, ?substs, "confirm_generator_candidate");
 
         let trait_ref = self.generator_trait_ref_unnormalized(obligation, substs);
         let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| {
@@ -607,11 +597,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             )
         });
 
-        debug!(
-            "confirm_generator_candidate(generator_def_id={:?}, \
-             trait_ref={:?}, obligations={:?})",
-            generator_def_id, trait_ref, obligations
-        );
+        debug!(?trait_ref, ?obligations, "generator candidate obligations");
 
         obligations.extend(self.confirm_poly_trait_refs(
             obligation.cause.clone(),
@@ -627,7 +613,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> Result<ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> {
-        debug!("confirm_closure_candidate({:?})", obligation);
+        debug!(?obligation, "confirm_closure_candidate");
 
         let kind = self
             .tcx()
@@ -654,10 +640,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             )
         });
 
-        debug!(
-            "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})",
-            closure_def_id, trait_ref, obligations
-        );
+        debug!(?closure_def_id, ?trait_ref, ?obligations, "confirm closure candidate obligations");
 
         obligations.extend(self.confirm_poly_trait_refs(
             obligation.cause.clone(),
@@ -731,7 +714,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
         let target = self.infcx.shallow_resolve(target);
 
-        debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target);
+        debug!(?source, ?target, "confirm_builtin_unsize_candidate");
 
         let mut nested = vec![];
         match (source.kind(), target.kind()) {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index a142ba58a69..4d347380c6c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -236,7 +236,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         infcx: &'cx InferCtxt<'cx, 'tcx>,
         allow_negative_impls: bool,
     ) -> SelectionContext<'cx, 'tcx> {
-        debug!("with_negative({:?})", allow_negative_impls);
+        debug!(?allow_negative_impls, "with_negative");
         SelectionContext {
             infcx,
             freshener: infcx.freshener(),
@@ -251,7 +251,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         infcx: &'cx InferCtxt<'cx, 'tcx>,
         query_mode: TraitQueryMode,
     ) -> SelectionContext<'cx, 'tcx> {
-        debug!("with_query_mode({:?})", query_mode);
+        debug!(?query_mode, "with_query_mode");
         SelectionContext {
             infcx,
             freshener: infcx.freshener(),
@@ -290,10 +290,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         self.infcx.tcx
     }
 
-    pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> {
-        self.infcx
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // Selection
     //
@@ -311,11 +307,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     /// Attempts to satisfy the obligation. If successful, this will affect the surrounding
     /// type environment by performing unification.
+    #[instrument(level = "debug", skip(self))]
     pub fn select(
         &mut self,
         obligation: &TraitObligation<'tcx>,
     ) -> SelectionResult<'tcx, Selection<'tcx>> {
-        debug!("select({:?})", obligation);
         debug_assert!(!obligation.predicate.has_escaping_bound_vars());
 
         let pec = &ProvisionalEvaluationCache::default();
@@ -344,7 +340,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
             Err(e) => Err(e),
             Ok(candidate) => {
-                debug!("select: candidate = {:?}", candidate);
+                debug!(?candidate);
                 Ok(Some(candidate))
             }
         }
@@ -362,7 +358,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     /// Evaluates whether the obligation `obligation` can be satisfied (by any means).
     pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool {
-        debug!("predicate_may_hold_fatal({:?})", obligation);
+        debug!(?obligation, "predicate_may_hold_fatal");
 
         // This fatal query is a stopgap that should only be used in standard mode,
         // where we do not expect overflow to be propagated.
@@ -419,10 +415,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
     {
         let mut result = EvaluatedToOk;
-        debug!("evaluate_predicates_recursively({:?})", predicates);
+        debug!(?predicates, "evaluate_predicates_recursively");
         for obligation in predicates {
             let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
-            debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval);
             if let EvaluatedToErr = eval {
                 // fast-path - EvaluatedToErr is the top of the lattice,
                 // so we don't need to look on the other predicates.
@@ -434,17 +429,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         Ok(result)
     }
 
+    #[instrument(
+        level = "debug",
+        skip(self, previous_stack),
+        fields(previous_stack = ?previous_stack.head())
+    )]
     fn evaluate_predicate_recursively<'o>(
         &mut self,
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         obligation: PredicateObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        debug!(
-            "evaluate_predicate_recursively(obligation={:?}, previous_stack={:?})",
-            obligation,
-            previous_stack.head()
-        );
-
         // `previous_stack` stores a `TraitObligation`, while `obligation` is
         // a `PredicateObligation`. These are distinct types, so we can't
         // use any `Option` combinator method that would force them to be
@@ -454,7 +448,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             None => self.check_recursion_limit(&obligation, &obligation)?,
         }
 
-        ensure_sufficient_stack(|| {
+        let result = ensure_sufficient_stack(|| {
             match obligation.predicate.skip_binders() {
                 ty::PredicateAtom::Trait(t, _) => {
                     let t = ty::Binder::bind(t);
@@ -561,10 +555,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 }
 
                 ty::PredicateAtom::ConstEquate(c1, c2) => {
-                    debug!(
-                        "evaluate_predicate_recursively: equating consts c1={:?} c2={:?}",
-                        c1, c2
-                    );
+                    debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
 
                     let evaluate = |c: &'tcx ty::Const<'tcx>| {
                         if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val {
@@ -610,7 +601,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     bug!("TypeWellFormedFromEnv is only used for chalk")
                 }
             }
-        })
+        });
+
+        debug!(?result);
+
+        result
     }
 
     fn evaluate_trait_predicate_recursively<'o>(
@@ -618,7 +613,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         previous_stack: TraitObligationStackList<'o, 'tcx>,
         mut obligation: TraitObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        debug!("evaluate_trait_predicate_recursively({:?})", obligation);
+        debug!(?obligation, "evaluate_trait_predicate_recursively");
 
         if !self.intercrate
             && obligation.is_global()
@@ -627,19 +622,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // If a param env has no global bounds, global obligations do not
             // depend on its particular value in order to work, so we can clear
             // out the param env and get better caching.
-            debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation);
+            debug!("evaluate_trait_predicate_recursively - in global");
             obligation.param_env = obligation.param_env.without_caller_bounds();
         }
 
         let stack = self.push_stack(previous_stack, &obligation);
         let fresh_trait_ref = stack.fresh_trait_ref;
+
+        debug!(?fresh_trait_ref);
+
         if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) {
-            debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result);
+            debug!(?result, "CACHE HIT");
             return Ok(result);
         }
 
         if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) {
-            debug!("PROVISIONAL CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result);
+            debug!(?result, "PROVISIONAL CACHE HIT");
             stack.update_reached_depth(stack.cache().current_reached_depth());
             return Ok(result);
         }
@@ -662,7 +660,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         let reached_depth = stack.reached_depth.get();
         if reached_depth >= stack.depth {
-            debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result);
+            debug!(?result, "CACHE MISS");
             self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
 
             stack.cache().on_completion(stack.depth, |fresh_trait_ref, provisional_result| {
@@ -674,7 +672,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 );
             });
         } else {
-            debug!("PROVISIONAL: {:?}={:?}", fresh_trait_ref, result);
+            debug!(?result, "PROVISIONAL");
             debug!(
                 "evaluate_trait_predicate_recursively: caching provisionally because {:?} \
                  is a cycle participant (at depth {}, reached depth {})",
@@ -719,10 +717,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             })
             .map(|stack| stack.depth)
         {
-            debug!(
-                "evaluate_stack({:?}) --> recursive at depth {}",
-                stack.fresh_trait_ref, cycle_depth,
-            );
+            debug!("evaluate_stack --> recursive at depth {}", cycle_depth);
 
             // If we have a stack like `A B C D E A`, where the top of
             // the stack is the final `A`, then this will iterate over
@@ -742,10 +737,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             let cycle =
                 cycle.map(|stack| stack.obligation.predicate.without_const().to_predicate(tcx));
             if self.coinductive_match(cycle) {
-                debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref);
+                debug!("evaluate_stack --> recursive, coinductive");
                 Some(EvaluatedToOk)
             } else {
-                debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref);
+                debug!("evaluate_stack --> recursive, inductive");
                 Some(EvaluatedToRecur)
             }
         } else {
@@ -786,10 +781,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // This check was an imperfect workaround for a bug in the old
         // intercrate mode; it should be removed when that goes away.
         if unbound_input_types && self.intercrate {
-            debug!(
-                "evaluate_stack({:?}) --> unbound argument, intercrate -->  ambiguous",
-                stack.fresh_trait_ref
-            );
+            debug!("evaluate_stack --> unbound argument, intercrate -->  ambiguous",);
             // Heuristics: show the diagnostics when there are no candidates in crate.
             if self.intercrate_ambiguity_causes.is_some() {
                 debug!("evaluate_stack: intercrate_ambiguity_causes is some");
@@ -807,7 +799,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 },
                             });
 
-                        debug!("evaluate_stack: pushing cause = {:?}", cause);
+                        debug!(?cause, "evaluate_stack: pushing cause");
                         self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
                     }
                 }
@@ -824,10 +816,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     )
             })
         {
-            debug!(
-                "evaluate_stack({:?}) --> unbound argument, recursive --> giving up",
-                stack.fresh_trait_ref
-            );
+            debug!("evaluate_stack --> unbound argument, recursive --> giving up",);
             return Ok(EvaluatedToUnknown);
         }
 
@@ -860,27 +849,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             ty::PredicateAtom::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()),
             _ => false,
         };
-        debug!("coinductive_predicate({:?}) = {:?}", predicate, result);
+        debug!(?predicate, ?result, "coinductive_predicate");
         result
     }
 
     /// Further evaluates `candidate` to decide whether all type parameters match and whether nested
     /// obligations are met. Returns whether `candidate` remains viable after this further
     /// scrutiny.
+    #[instrument(
+        level = "debug",
+        skip(self, stack),
+        fields(depth = stack.obligation.recursion_depth)
+    )]
     fn evaluate_candidate<'o>(
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
         candidate: &SelectionCandidate<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
-        debug!(
-            "evaluate_candidate: depth={} candidate={:?}",
-            stack.obligation.recursion_depth, candidate
-        );
         let result = self.evaluation_probe(|this| {
             let candidate = (*candidate).clone();
             match this.confirm_candidate(stack.obligation, candidate) {
                 Ok(selection) => {
-                    debug!("evaluate_candidate: selection = {:?}", selection);
+                    debug!(?selection);
                     this.evaluate_predicates_recursively(
                         stack.list(),
                         selection.nested_obligations().into_iter(),
@@ -889,10 +879,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Err(..) => Ok(EvaluatedToErr),
             }
         })?;
-        debug!(
-            "evaluate_candidate: depth={} result={:?}",
-            stack.obligation.recursion_depth, result
-        );
+        debug!(?result);
         Ok(result)
     }
 
@@ -925,10 +912,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         if self.can_use_global_caches(param_env) {
             if !trait_ref.needs_infer() {
-                debug!(
-                    "insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global",
-                    trait_ref, result,
-                );
+                debug!(?trait_ref, ?result, "insert_evaluation_cache global");
                 // This may overwrite the cache with the same value
                 // FIXME: Due to #50507 this overwrites the different values
                 // This should be changed to use HashMapExt::insert_same
@@ -938,7 +922,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
         }
 
-        debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,);
+        debug!(?trait_ref, ?result, "insert_evaluation_cache");
         self.infcx.evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
     }
 
@@ -1127,11 +1111,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref;
 
         if !self.can_cache_candidate(&candidate) {
-            debug!(
-                "insert_candidate_cache(trait_ref={:?}, candidate={:?} -\
-                 candidate is not cacheable",
-                trait_ref, candidate
-            );
+            debug!(?trait_ref, ?candidate, "insert_candidate_cache - candidate is not cacheable");
             return;
         }
 
@@ -1140,10 +1120,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 // Don't cache overflow globally; we only produce this in certain modes.
             } else if !trait_ref.needs_infer() {
                 if !candidate.needs_infer() {
-                    debug!(
-                        "insert_candidate_cache(trait_ref={:?}, candidate={:?}) global",
-                        trait_ref, candidate,
-                    );
+                    debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
                     // This may overwrite the cache with the same value.
                     tcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate);
                     return;
@@ -1151,10 +1128,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
         }
 
-        debug!(
-            "insert_candidate_cache(trait_ref={:?}, candidate={:?}) local",
-            trait_ref, candidate,
-        );
+        debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
         self.infcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate);
     }
 
@@ -1172,9 +1146,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let placeholder_trait_predicate =
             self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate);
         debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             placeholder_trait_predicate={:?}",
-            placeholder_trait_predicate,
+            ?placeholder_trait_predicate,
+            "match_projection_obligation_against_definition_bounds"
         );
 
         let tcx = self.infcx.tcx;
@@ -1225,11 +1198,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             })
             .collect();
 
-        debug!(
-            "match_projection_obligation_against_definition_bounds: \
-             matching_bounds={:?}",
-            matching_bounds
-        );
+        debug!(?matching_bounds, "match_projection_obligation_against_definition_bounds");
         matching_bounds
     }
 
@@ -1631,7 +1600,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             ty::Closure(_, substs) => {
                 // (*) binder moved here
-                Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect()))
+                let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
+                if let ty::Infer(ty::TyVar(_)) = ty.kind() {
+                    // Not yet resolved.
+                    Ambiguous
+                } else {
+                    Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect()))
+                }
             }
 
             ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => {
@@ -1700,11 +1675,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 tys.iter().map(|k| k.expect_ty()).collect()
             }
 
-            ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().collect(),
+            ty::Closure(_, ref substs) => {
+                let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty());
+                vec![ty]
+            }
 
             ty::Generator(_, ref substs, _) => {
+                let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
                 let witness = substs.as_generator().witness();
-                substs.as_generator().upvar_tys().chain(iter::once(witness)).collect()
+                vec![ty].into_iter().chain(iter::once(witness)).collect()
             }
 
             ty::GeneratorWitness(types) => {
@@ -1816,6 +1795,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         impl_def_id: DefId,
         obligation: &TraitObligation<'tcx>,
     ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> {
+        debug!(?impl_def_id, ?obligation, "match_impl");
         let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
 
         // Before we create the substitutions and everything, first
@@ -1844,11 +1824,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 )
             });
 
-        debug!(
-            "match_impl(impl_def_id={:?}, obligation={:?}, \
-             impl_trait_ref={:?}, placeholder_obligation_trait_ref={:?})",
-            impl_def_id, obligation, impl_trait_ref, placeholder_obligation_trait_ref
-        );
+        debug!(?impl_trait_ref, ?placeholder_obligation_trait_ref);
 
         let InferOk { obligations, .. } = self
             .infcx
@@ -1864,7 +1840,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return Err(());
         }
 
-        debug!("match_impl: success impl_substs={:?}", impl_substs);
+        debug!(?impl_substs, "match_impl: success");
         Ok(Normalized { value: impl_substs, obligations: nested_obligations })
     }
 
@@ -1926,10 +1902,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Result<Vec<PredicateObligation<'tcx>>, ()> {
-        debug!(
-            "match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}",
-            obligation, poly_trait_ref
-        );
+        debug!(?obligation, ?poly_trait_ref, "match_poly_trait_ref");
 
         self.infcx
             .at(&obligation.cause, obligation.param_env)
@@ -1976,10 +1949,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligation: &TraitObligation<'tcx>,
         substs: SubstsRef<'tcx>,
     ) -> ty::PolyTraitRef<'tcx> {
-        debug!("closure_trait_ref_unnormalized(obligation={:?}, substs={:?})", obligation, substs);
+        debug!(?obligation, ?substs, "closure_trait_ref_unnormalized");
         let closure_sig = substs.as_closure().sig();
 
-        debug!("closure_trait_ref_unnormalized: closure_sig = {:?}", closure_sig);
+        debug!(?closure_sig);
 
         // (1) Feels icky to skip the binder here, but OTOH we know
         // that the self-type is an unboxed closure type and hence is
@@ -2030,7 +2003,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         def_id: DefId,           // of impl or trait
         substs: SubstsRef<'tcx>, // for impl or trait
     ) -> Vec<PredicateObligation<'tcx>> {
-        debug!("impl_or_trait_obligations(def_id={:?})", def_id);
+        debug!(?def_id, "impl_or_trait_obligations");
         let tcx = self.tcx();
 
         // To allow for one-pass evaluation of the nested obligation,
@@ -2152,10 +2125,10 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
             self.depth,
             reached_depth,
         );
-        debug!("update_reached_depth(reached_depth={})", reached_depth);
+        debug!(reached_depth, "update_reached_depth");
         let mut p = self;
         while reached_depth < p.depth {
-            debug!("update_reached_depth: marking {:?} as cycle participant", p.fresh_trait_ref);
+            debug!(?p.fresh_trait_ref, "update_reached_depth: marking as cycle participant");
             p.reached_depth.set(p.reached_depth.get().min(reached_depth));
             p = p.previous.head.unwrap();
         }
@@ -2282,10 +2255,10 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
     /// `self.current_reached_depth()` and above.
     fn get_provisional(&self, fresh_trait_ref: ty::PolyTraitRef<'tcx>) -> Option<EvaluationResult> {
         debug!(
-            "get_provisional(fresh_trait_ref={:?}) = {:#?} with reached-depth {}",
-            fresh_trait_ref,
+            ?fresh_trait_ref,
+            reached_depth = ?self.reached_depth.get(),
+            "get_provisional = {:#?}",
             self.map.borrow().get(&fresh_trait_ref),
-            self.reached_depth.get(),
         );
         Some(self.map.borrow().get(&fresh_trait_ref)?.result)
     }
@@ -2308,14 +2281,11 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
         fresh_trait_ref: ty::PolyTraitRef<'tcx>,
         result: EvaluationResult,
     ) {
-        debug!(
-            "insert_provisional(from_dfn={}, reached_depth={}, fresh_trait_ref={:?}, result={:?})",
-            from_dfn, reached_depth, fresh_trait_ref, result,
-        );
+        debug!(?from_dfn, ?reached_depth, ?fresh_trait_ref, ?result, "insert_provisional");
         let r_d = self.reached_depth.get();
         self.reached_depth.set(r_d.min(reached_depth));
 
-        debug!("insert_provisional: reached_depth={:?}", self.reached_depth.get());
+        debug!(reached_depth = self.reached_depth.get());
 
         self.map.borrow_mut().insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, result });
     }
@@ -2329,7 +2299,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
     /// these provisional entries must either depend on it or some
     /// ancestor of it.
     fn on_failure(&self, dfn: usize) {
-        debug!("on_failure(dfn={:?})", dfn,);
+        debug!(?dfn, "on_failure");
         self.map.borrow_mut().retain(|key, eval| {
             if !eval.from_dfn >= dfn {
                 debug!("on_failure: removing {:?}", key);
@@ -2350,7 +2320,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
         depth: usize,
         mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult),
     ) {
-        debug!("on_completion(depth={}, reached_depth={})", depth, self.reached_depth.get(),);
+        debug!(?depth, reached_depth = ?self.reached_depth.get(), "on_completion");
 
         if self.reached_depth.get() < depth {
             debug!("on_completion: did not yet reach depth to complete");
@@ -2358,7 +2328,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
         }
 
         for (fresh_trait_ref, eval) in self.map.borrow_mut().drain() {
-            debug!("on_completion: fresh_trait_ref={:?} eval={:?}", fresh_trait_ref, eval,);
+            debug!(?fresh_trait_ref, ?eval, "on_completion");
 
             op(fresh_trait_ref, eval.result);
         }
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index d66bfd48206..496dff6c5b2 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -592,10 +592,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     // anyway, except via auto trait matching (which
                     // only inspects the upvar types).
                     walker.skip_current_subtree(); // subtree handled below
-                    for upvar_ty in substs.as_closure().upvar_tys() {
-                        // FIXME(eddyb) add the type to `walker` instead of recursing.
-                        self.compute(upvar_ty.into());
-                    }
+                    // FIXME(eddyb) add the type to `walker` instead of recursing.
+                    self.compute(substs.as_closure().tupled_upvars_ty().into());
                 }
 
                 ty::FnPtr(_) => {
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml
index b176b150cd3..a54fe08394e 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.31.0"
-chalk-solve = "0.31.0"
-chalk-engine = "0.31.0"
+chalk-ir = "0.32.0"
+chalk-solve = "0.32.0"
+chalk-engine = "0.32.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/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 3ee391d6dc7..6cffa6d02a4 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -210,12 +210,25 @@ fn dtorck_constraint_for_ty<'tcx>(
             Ok::<_, NoSolution>(())
         })?,
 
-        ty::Closure(_, substs) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
-            for ty in substs.as_closure().upvar_tys() {
-                dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
+        ty::Closure(_, substs) => {
+            if !substs.as_closure().is_valid() {
+                // By the time this code runs, all type variables ought to
+                // be fully resolved.
+
+                tcx.sess.delay_span_bug(
+                    span,
+                    &format!("upvar_tys for closure not found. Expected capture information for closure {}", ty,),
+                );
+                return Err(NoSolution);
             }
-            Ok::<_, NoSolution>(())
-        })?,
+
+            rustc_data_structures::stack::ensure_sufficient_stack(|| {
+                for ty in substs.as_closure().upvar_tys() {
+                    dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
+                }
+                Ok::<_, NoSolution>(())
+            })?
+        }
 
         ty::Generator(_, substs, _movability) => {
             // rust-lang/rust#49918: types can be constructed, stored
@@ -241,6 +254,16 @@ fn dtorck_constraint_for_ty<'tcx>(
             // derived from lifetimes attached to the upvars and resume
             // argument, and we *do* incorporate those here.
 
+            if !substs.as_generator().is_valid() {
+                // By the time this code runs, all type variables ought to
+                // be fully resolved.
+                tcx.sess.delay_span_bug(
+                    span,
+                    &format!("upvar_tys for generator not found. Expected capture information for generator {}", ty,),
+                );
+                return Err(NoSolution);
+            }
+
             constraints.outlives.extend(
                 substs
                     .as_generator()
diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs
index 80f39051c58..683707470f4 100644
--- a/compiler/rustc_typeck/src/bounds.rs
+++ b/compiler/rustc_typeck/src/bounds.rs
@@ -72,7 +72,7 @@ impl<'tcx> Bounds<'tcx> {
                     .iter()
                     .map(|&(region_bound, span)| {
                         let outlives = ty::OutlivesPredicate(param_ty, region_bound);
-                        (ty::Binder::dummy(outlives).to_predicate(tcx), span)
+                        (ty::Binder::bind(outlives).to_predicate(tcx), span)
                     })
                     .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
                         let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index 740783aeb9d..a38fb9642b9 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -285,10 +285,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         arg_exprs: &'tcx [hir::Expr<'tcx>],
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
-        let (fn_sig, def_span) = match *callee_ty.kind() {
-            ty::FnDef(def_id, _) => {
-                (callee_ty.fn_sig(self.tcx), self.tcx.hir().span_if_local(def_id))
-            }
+        let (fn_sig, def_id) = match *callee_ty.kind() {
+            ty::FnDef(def_id, _) => (callee_ty.fn_sig(self.tcx), Some(def_id)),
             ty::FnPtr(sig) => (sig, None),
             ref t => {
                 let mut unit_variant = None;
@@ -427,7 +425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             arg_exprs,
             fn_sig.c_variadic,
             TupleArgumentsFlag::DontTupleArguments,
-            def_span,
+            def_id,
         );
 
         fn_sig.output()
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index d319ac2cba6..b9a5db47855 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -29,7 +29,7 @@ pub fn check_wf_new(tcx: TyCtxt<'_>) {
 }
 
 pub(super) fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) {
-    if !tcx.sess.target.target.is_abi_supported(abi) {
+    if !tcx.sess.target.is_abi_supported(abi) {
         struct_span_err!(
             tcx.sess,
             span,
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index 8898a545228..8bdd933644a 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -81,19 +81,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
         );
 
-        let tupled_upvars_ty =
-            self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map(|upvars| {
-                upvars.iter().map(|(&var_hir_id, _)| {
-                    // Create type variables (for now) to represent the transformed
-                    // types of upvars. These will be unified during the upvar
-                    // inference phase (`upvar.rs`).
-                    self.infcx.next_ty_var(TypeVariableOrigin {
-                        // FIXME(eddyb) distinguish upvar inference variables from the rest.
-                        kind: TypeVariableOriginKind::ClosureSynthetic,
-                        span: self.tcx.hir().span(var_hir_id),
-                    })
-                })
-            }));
+        let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
+            kind: TypeVariableOriginKind::ClosureSynthetic,
+            span: self.tcx.hir().span(expr.hir_id),
+        });
 
         if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types
         {
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 4addee1a4c9..db32a736181 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -39,6 +39,7 @@ use crate::astconv::AstConv;
 use crate::check::FnCtxt;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{Coercion, InferOk, InferResult};
 use rustc_middle::ty::adjustment::{
@@ -221,11 +222,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
                 // unsafe qualifier.
                 self.coerce_from_fn_pointer(a, a_f, b)
             }
-            ty::Closure(_, substs_a) => {
+            ty::Closure(closure_def_id_a, substs_a) => {
                 // Non-capturing closures are coercible to
                 // function pointers or unsafe function pointers.
                 // It cannot convert closures that require unsafe.
-                self.coerce_closure_to_fn(a, substs_a, b)
+                self.coerce_closure_to_fn(a, closure_def_id_a, substs_a, b)
             }
             _ => {
                 // Otherwise, just use unification rules.
@@ -762,6 +763,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
     fn coerce_closure_to_fn(
         &self,
         a: Ty<'tcx>,
+        closure_def_id_a: DefId,
         substs_a: SubstsRef<'tcx>,
         b: Ty<'tcx>,
     ) -> CoerceResult<'tcx> {
@@ -772,7 +774,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         let b = self.shallow_resolve(b);
 
         match b.kind() {
-            ty::FnPtr(fn_ty) if substs_a.as_closure().upvar_tys().next().is_none() => {
+            // At this point we haven't done capture analysis, which means
+            // that the ClosureSubsts just contains an inference variable instead
+            // of tuple of captured types.
+            //
+            // All we care here is if any variable is being captured and not the exact paths,
+            // so we check `upvars_mentioned` for root variables being captured.
+            ty::FnPtr(fn_ty)
+                if self
+                    .tcx
+                    .upvars_mentioned(closure_def_id_a.expect_local())
+                    .map_or(true, |u| u.is_empty()) =>
+            {
                 // We coerce the closure, which has fn type
                 //     `extern "rust-call" fn((arg0,arg1,...)) -> _`
                 // to
@@ -906,8 +919,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Function items or non-capturing closures of differing IDs or InternalSubsts.
         let (a_sig, b_sig) = {
             let is_capturing_closure = |ty| {
-                if let &ty::Closure(_, substs) = ty {
-                    substs.as_closure().upvar_tys().next().is_some()
+                if let &ty::Closure(closure_def_id, _substs) = ty {
+                    self.tcx.upvars_mentioned(closure_def_id.expect_local()).is_some()
                 } else {
                     false
                 }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs
deleted file mode 100644
index 79d6c7dbfda..00000000000
--- a/compiler/rustc_typeck/src/check/fn_ctxt.rs
+++ /dev/null
@@ -1,3200 +0,0 @@
-// ignore-tidy-filelength
-// FIXME: This file seems to have too much functionality wrapped into it,
-// leading to it being too long.
-// Splitting this file may involve abstracting functionality into other files.
-
-use super::callee::{self, DeferredCallResolution};
-use super::coercion::{CoerceMany, DynamicCoerceMany};
-use super::method::{self, MethodCallee, SelfSource};
-use super::Expectation::*;
-use super::TupleArgumentsFlag::*;
-use super::{
-    potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, EnclosingBreakables,
-    Expectation, FallbackMode, Inherited, LocalTy, Needs, TupleArgumentsFlag, UnsafetyState,
-};
-use crate::astconv::{
-    AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg,
-};
-
-use rustc_ast as ast;
-use rustc_ast::util::parser::ExprPrecedence;
-use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::ErrorReported;
-use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
-use rustc_hir as hir;
-use rustc_hir::def::{CtorOf, DefKind, Res};
-use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ExprKind, GenericArg, ItemKind, Node, QPath};
-use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
-use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_infer::infer::{self, InferOk, InferResult};
-use rustc_middle::hir::map::blocks::FnLikeNode;
-use rustc_middle::ty::adjustment::{
-    Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
-};
-use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::subst::{
-    self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts,
-};
-use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind, ToPolyTraitRef,
-    ToPredicate, Ty, TyCtxt, UserType,
-};
-use rustc_session::{lint, Session};
-use rustc_span::hygiene::DesugaringKind;
-use rustc_span::source_map::{original_sp, DUMMY_SP};
-use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{self, BytePos, MultiSpan, Span};
-use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_trait_selection::traits::{
-    self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
-};
-
-use std::cell::{Cell, RefCell};
-use std::collections::hash_map::Entry;
-use std::iter;
-use std::mem::replace;
-use std::ops::Deref;
-use std::slice;
-
-pub struct FnCtxt<'a, 'tcx> {
-    pub(super) body_id: hir::HirId,
-
-    /// The parameter environment used for proving trait obligations
-    /// in this function. This can change when we descend into
-    /// closures (as they bring new things into scope), hence it is
-    /// not part of `Inherited` (as of the time of this writing,
-    /// closures do not yet change the environment, but they will
-    /// eventually).
-    pub(super) param_env: ty::ParamEnv<'tcx>,
-
-    /// Number of errors that had been reported when we started
-    /// checking this function. On exit, if we find that *more* errors
-    /// have been reported, we will skip regionck and other work that
-    /// expects the types within the function to be consistent.
-    // FIXME(matthewjasper) This should not exist, and it's not correct
-    // if type checking is run in parallel.
-    err_count_on_creation: usize,
-
-    /// If `Some`, this stores coercion information for returned
-    /// expressions. If `None`, this is in a context where return is
-    /// inappropriate, such as a const expression.
-    ///
-    /// This is a `RefCell<DynamicCoerceMany>`, which means that we
-    /// can track all the return expressions and then use them to
-    /// compute a useful coercion from the set, similar to a match
-    /// expression or other branching context. You can use methods
-    /// like `expected_ty` to access the declared return type (if
-    /// any).
-    pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
-
-    pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>,
-
-    pub(super) ret_type_span: Option<Span>,
-
-    /// Used exclusively to reduce cost of advanced evaluation used for
-    /// more helpful diagnostics.
-    pub(super) in_tail_expr: bool,
-
-    /// First span of a return site that we find. Used in error messages.
-    pub(super) ret_coercion_span: RefCell<Option<Span>>,
-
-    pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
-
-    pub(super) ps: RefCell<UnsafetyState>,
-
-    /// Whether the last checked node generates a divergence (e.g.,
-    /// `return` will set this to `Always`). In general, when entering
-    /// an expression or other node in the tree, the initial value
-    /// indicates whether prior parts of the containing expression may
-    /// have diverged. It is then typically set to `Maybe` (and the
-    /// old value remembered) for processing the subparts of the
-    /// current expression. As each subpart is processed, they may set
-    /// the flag to `Always`, etc. Finally, at the end, we take the
-    /// result and "union" it with the original value, so that when we
-    /// return the flag indicates if any subpart of the parent
-    /// expression (up to and including this part) has diverged. So,
-    /// if you read it after evaluating a subexpression `X`, the value
-    /// you get indicates whether any subexpression that was
-    /// evaluating up to and including `X` diverged.
-    ///
-    /// We currently use this flag only for diagnostic purposes:
-    ///
-    /// - To warn about unreachable code: if, after processing a
-    ///   sub-expression but before we have applied the effects of the
-    ///   current node, we see that the flag is set to `Always`, we
-    ///   can issue a warning. This corresponds to something like
-    ///   `foo(return)`; we warn on the `foo()` expression. (We then
-    ///   update the flag to `WarnedAlways` to suppress duplicate
-    ///   reports.) Similarly, if we traverse to a fresh statement (or
-    ///   tail expression) from a `Always` setting, we will issue a
-    ///   warning. This corresponds to something like `{return;
-    ///   foo();}` or `{return; 22}`, where we would warn on the
-    ///   `foo()` or `22`.
-    ///
-    /// An expression represents dead code if, after checking it,
-    /// the diverges flag is set to something other than `Maybe`.
-    pub(super) diverges: Cell<Diverges>,
-
-    /// Whether any child nodes have any type errors.
-    pub(super) has_errors: Cell<bool>,
-
-    pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
-
-    pub(super) inh: &'a Inherited<'a, 'tcx>,
-}
-
-impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub fn new(
-        inh: &'a Inherited<'a, 'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        body_id: hir::HirId,
-    ) -> FnCtxt<'a, 'tcx> {
-        FnCtxt {
-            body_id,
-            param_env,
-            err_count_on_creation: inh.tcx.sess.err_count(),
-            ret_coercion: None,
-            ret_coercion_impl_trait: None,
-            ret_type_span: None,
-            in_tail_expr: false,
-            ret_coercion_span: RefCell::new(None),
-            resume_yield_tys: None,
-            ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
-            diverges: Cell::new(Diverges::Maybe),
-            has_errors: Cell::new(false),
-            enclosing_breakables: RefCell::new(EnclosingBreakables {
-                stack: Vec::new(),
-                by_id: Default::default(),
-            }),
-            inh,
-        }
-    }
-
-    pub fn sess(&self) -> &Session {
-        &self.tcx.sess
-    }
-
-    pub fn errors_reported_since_creation(&self) -> bool {
-        self.tcx.sess.err_count() > self.err_count_on_creation
-    }
-
-    /// Produces warning on the given node, if the current point in the
-    /// function is unreachable, and there hasn't been another warning.
-    pub(super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) {
-        // FIXME: Combine these two 'if' expressions into one once
-        // let chains are implemented
-        if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() {
-            // If span arose from a desugaring of `if` or `while`, then it is the condition itself,
-            // which diverges, that we are about to lint on. This gives suboptimal diagnostics.
-            // Instead, stop here so that the `if`- or `while`-expression's block is linted instead.
-            if !span.is_desugaring(DesugaringKind::CondTemporary)
-                && !span.is_desugaring(DesugaringKind::Async)
-                && !orig_span.is_desugaring(DesugaringKind::Await)
-            {
-                self.diverges.set(Diverges::WarnedAlways);
-
-                debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
-
-                self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
-                    let msg = format!("unreachable {}", kind);
-                    lint.build(&msg)
-                        .span_label(span, &msg)
-                        .span_label(
-                            orig_span,
-                            custom_note
-                                .unwrap_or("any code following this expression is unreachable"),
-                        )
-                        .emit();
-                })
-            }
-        }
-    }
-
-    pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> {
-        ObligationCause::new(span, self.body_id, code)
-    }
-
-    pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
-        self.cause(span, ObligationCauseCode::MiscObligation)
-    }
-
-    /// Resolves type and const variables in `ty` if possible. Unlike the infcx
-    /// version (resolve_vars_if_possible), this version will
-    /// also select obligations if it seems useful, in an effort
-    /// to get more type information.
-    pub(super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
-        debug!("resolve_vars_with_obligations(ty={:?})", ty);
-
-        // No Infer()? Nothing needs doing.
-        if !ty.has_infer_types_or_consts() {
-            debug!("resolve_vars_with_obligations: ty={:?}", ty);
-            return ty;
-        }
-
-        // If `ty` is a type variable, see whether we already know what it is.
-        ty = self.resolve_vars_if_possible(&ty);
-        if !ty.has_infer_types_or_consts() {
-            debug!("resolve_vars_with_obligations: ty={:?}", ty);
-            return ty;
-        }
-
-        // If not, try resolving pending obligations as much as
-        // possible. This can help substantially when there are
-        // indirect dependencies that don't seem worth tracking
-        // precisely.
-        self.select_obligations_where_possible(false, |_| {});
-        ty = self.resolve_vars_if_possible(&ty);
-
-        debug!("resolve_vars_with_obligations: ty={:?}", ty);
-        ty
-    }
-
-    pub(super) fn record_deferred_call_resolution(
-        &self,
-        closure_def_id: DefId,
-        r: DeferredCallResolution<'tcx>,
-    ) {
-        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
-        deferred_call_resolutions.entry(closure_def_id).or_default().push(r);
-    }
-
-    pub(super) fn remove_deferred_call_resolutions(
-        &self,
-        closure_def_id: DefId,
-    ) -> Vec<DeferredCallResolution<'tcx>> {
-        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
-        deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![])
-    }
-
-    pub fn tag(&self) -> String {
-        format!("{:p}", self)
-    }
-
-    pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> {
-        self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| {
-            span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid))
-        })
-    }
-
-    #[inline]
-    pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) {
-        debug!(
-            "write_ty({:?}, {:?}) in fcx {}",
-            id,
-            self.resolve_vars_if_possible(&ty),
-            self.tag()
-        );
-        self.typeck_results.borrow_mut().node_types_mut().insert(id, ty);
-
-        if ty.references_error() {
-            self.has_errors.set(true);
-            self.set_tainted_by_errors();
-        }
-    }
-
-    pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) {
-        self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
-    }
-
-    fn write_resolution(&self, hir_id: hir::HirId, r: Result<(DefKind, DefId), ErrorReported>) {
-        self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r);
-    }
-
-    pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) {
-        debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method);
-        self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
-        self.write_substs(hir_id, method.substs);
-
-        // When the method is confirmed, the `method.substs` includes
-        // parameters from not just the method, but also the impl of
-        // the method -- in particular, the `Self` type will be fully
-        // resolved. However, those are not something that the "user
-        // specified" -- i.e., those types come from the inferred type
-        // of the receiver, not something the user wrote. So when we
-        // create the user-substs, we want to replace those earlier
-        // types with just the types that the user actually wrote --
-        // that is, those that appear on the *method itself*.
-        //
-        // As an example, if the user wrote something like
-        // `foo.bar::<u32>(...)` -- the `Self` type here will be the
-        // type of `foo` (possibly adjusted), but we don't want to
-        // include that. We want just the `[_, u32]` part.
-        if !method.substs.is_noop() {
-            let method_generics = self.tcx.generics_of(method.def_id);
-            if !method_generics.params.is_empty() {
-                let user_type_annotation = self.infcx.probe(|_| {
-                    let user_substs = UserSubsts {
-                        substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| {
-                            let i = param.index as usize;
-                            if i < method_generics.parent_count {
-                                self.infcx.var_for_def(DUMMY_SP, param)
-                            } else {
-                                method.substs[i]
-                            }
-                        }),
-                        user_self_ty: None, // not relevant here
-                    };
-
-                    self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
-                        method.def_id,
-                        user_substs,
-                    ))
-                });
-
-                debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
-                self.write_user_type_annotation(hir_id, user_type_annotation);
-            }
-        }
-    }
-
-    pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
-        if !substs.is_noop() {
-            debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag());
-
-            self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs);
-        }
-    }
-
-    /// Given the substs that we just converted from the HIR, try to
-    /// canonicalize them and store them as user-given substitutions
-    /// (i.e., substitutions that must be respected by the NLL check).
-    ///
-    /// This should be invoked **before any unifications have
-    /// occurred**, so that annotations like `Vec<_>` are preserved
-    /// properly.
-    pub fn write_user_type_annotation_from_substs(
-        &self,
-        hir_id: hir::HirId,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
-        user_self_ty: Option<UserSelfTy<'tcx>>,
-    ) {
-        debug!(
-            "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \
-             user_self_ty={:?} in fcx {}",
-            hir_id,
-            def_id,
-            substs,
-            user_self_ty,
-            self.tag(),
-        );
-
-        if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
-            let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
-                def_id,
-                UserSubsts { substs, user_self_ty },
-            ));
-            debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized);
-            self.write_user_type_annotation(hir_id, canonicalized);
-        }
-    }
-
-    pub fn write_user_type_annotation(
-        &self,
-        hir_id: hir::HirId,
-        canonical_user_type_annotation: CanonicalUserType<'tcx>,
-    ) {
-        debug!(
-            "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}",
-            hir_id,
-            canonical_user_type_annotation,
-            self.tag(),
-        );
-
-        if !canonical_user_type_annotation.is_identity() {
-            self.typeck_results
-                .borrow_mut()
-                .user_provided_types_mut()
-                .insert(hir_id, canonical_user_type_annotation);
-        } else {
-            debug!("write_user_type_annotation: skipping identity substs");
-        }
-    }
-
-    pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) {
-        debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj);
-
-        if adj.is_empty() {
-            return;
-        }
-
-        let autoborrow_mut = adj.iter().any(|adj| {
-            matches!(adj, &Adjustment {
-                kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })),
-                ..
-            })
-        });
-
-        match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) {
-            Entry::Vacant(entry) => {
-                entry.insert(adj);
-            }
-            Entry::Occupied(mut entry) => {
-                debug!(" - composing on top of {:?}", entry.get());
-                match (&entry.get()[..], &adj[..]) {
-                    // Applying any adjustment on top of a NeverToAny
-                    // is a valid NeverToAny adjustment, because it can't
-                    // be reached.
-                    (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return,
-                    (&[
-                        Adjustment { kind: Adjust::Deref(_), .. },
-                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
-                    ], &[
-                        Adjustment { kind: Adjust::Deref(_), .. },
-                        .. // Any following adjustments are allowed.
-                    ]) => {
-                        // A reborrow has no effect before a dereference.
-                    }
-                    // FIXME: currently we never try to compose autoderefs
-                    // and ReifyFnPointer/UnsafeFnPointer, but we could.
-                    _ =>
-                        bug!("while adjusting {:?}, can't compose {:?} and {:?}",
-                             expr, entry.get(), adj)
-                };
-                *entry.get_mut() = adj;
-            }
-        }
-
-        // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`.
-        // In this case implicit use of `Deref` and `Index` within `<expr>` should
-        // instead be `DerefMut` and `IndexMut`, so fix those up.
-        if autoborrow_mut {
-            self.convert_place_derefs_to_mutable(expr);
-        }
-    }
-
-    /// Basically whenever we are converting from a type scheme into
-    /// the fn body space, we always want to normalize associated
-    /// types as well. This function combines the two.
-    fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        let value = value.subst(self.tcx, substs);
-        let result = self.normalize_associated_types_in(span, &value);
-        debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result);
-        result
-    }
-
-    /// As `instantiate_type_scheme`, but for the bounds found in a
-    /// generic type scheme.
-    fn instantiate_bounds(
-        &self,
-        span: Span,
-        def_id: DefId,
-        substs: SubstsRef<'tcx>,
-    ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) {
-        let bounds = self.tcx.predicates_of(def_id);
-        let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect();
-        let result = bounds.instantiate(self.tcx, substs);
-        let result = self.normalize_associated_types_in(span, &result);
-        debug!(
-            "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
-            bounds, substs, result, spans,
-        );
-        (result, spans)
-    }
-
-    /// Replaces the opaque types from the given value with type variables,
-    /// and records the `OpaqueTypeMap` for later use during writeback. See
-    /// `InferCtxt::instantiate_opaque_types` for more details.
-    pub(super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
-        &self,
-        parent_id: hir::HirId,
-        value: &T,
-        value_span: Span,
-    ) -> T {
-        let parent_def_id = self.tcx.hir().local_def_id(parent_id);
-        debug!(
-            "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})",
-            parent_def_id, value
-        );
-
-        let (value, opaque_type_map) =
-            self.register_infer_ok_obligations(self.instantiate_opaque_types(
-                parent_def_id,
-                self.body_id,
-                self.param_env,
-                value,
-                value_span,
-            ));
-
-        let mut opaque_types = self.opaque_types.borrow_mut();
-        let mut opaque_types_vars = self.opaque_types_vars.borrow_mut();
-        for (ty, decl) in opaque_type_map {
-            let _ = opaque_types.insert(ty, decl);
-            let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
-        }
-
-        value
-    }
-
-    pub(super) fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value)
-    }
-
-    pub(super) fn normalize_associated_types_in_as_infer_ok<T>(
-        &self,
-        span: Span,
-        value: &T,
-    ) -> InferOk<'tcx, T>
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value)
-    }
-
-    pub fn require_type_meets(
-        &self,
-        ty: Ty<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-        def_id: DefId,
-    ) {
-        self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code));
-    }
-
-    pub fn require_type_is_sized(
-        &self,
-        ty: Ty<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-    ) {
-        if !ty.references_error() {
-            let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
-            self.require_type_meets(ty, span, code, lang_item);
-        }
-    }
-
-    pub fn require_type_is_sized_deferred(
-        &self,
-        ty: Ty<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-    ) {
-        if !ty.references_error() {
-            self.deferred_sized_obligations.borrow_mut().push((ty, span, code));
-        }
-    }
-
-    pub fn register_bound(
-        &self,
-        ty: Ty<'tcx>,
-        def_id: DefId,
-        cause: traits::ObligationCause<'tcx>,
-    ) {
-        if !ty.references_error() {
-            self.fulfillment_cx.borrow_mut().register_bound(
-                self,
-                self.param_env,
-                ty,
-                def_id,
-                cause,
-            );
-        }
-    }
-
-    pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> {
-        let t = AstConv::ast_ty_to_ty(self, ast_t);
-        self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation);
-        t
-    }
-
-    pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
-        let ty = self.to_ty(ast_ty);
-        debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
-
-        if Self::can_contain_user_lifetime_bounds(ty) {
-            let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty));
-            debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
-            self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
-        }
-
-        ty
-    }
-
-    pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
-        let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
-        let c = ty::Const::from_anon_const(self.tcx, const_def_id);
-        self.register_wf_obligation(
-            c.into(),
-            self.tcx.hir().span(ast_c.hir_id),
-            ObligationCauseCode::MiscObligation,
-        );
-        c
-    }
-
-    pub fn const_arg_to_const(
-        &self,
-        ast_c: &hir::AnonConst,
-        param_def_id: DefId,
-    ) -> &'tcx ty::Const<'tcx> {
-        let const_def = ty::WithOptConstParam {
-            did: self.tcx.hir().local_def_id(ast_c.hir_id),
-            const_param_did: Some(param_def_id),
-        };
-        let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def);
-        self.register_wf_obligation(
-            c.into(),
-            self.tcx.hir().span(ast_c.hir_id),
-            ObligationCauseCode::MiscObligation,
-        );
-        c
-    }
-
-    // If the type given by the user has free regions, save it for later, since
-    // NLL would like to enforce those. Also pass in types that involve
-    // projections, since those can resolve to `'static` bounds (modulo #54940,
-    // which hopefully will be fixed by the time you see this comment, dear
-    // reader, although I have my doubts). Also pass in types with inference
-    // types, because they may be repeated. Other sorts of things are already
-    // sufficiently enforced with erased regions. =)
-    fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
-    where
-        T: TypeFoldable<'tcx>,
-    {
-        t.has_free_regions() || t.has_projections() || t.has_infer_types()
-    }
-
-    pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
-        match self.typeck_results.borrow().node_types().get(id) {
-            Some(&t) => t,
-            None if self.is_tainted_by_errors() => self.tcx.ty_error(),
-            None => {
-                bug!(
-                    "no type for node {}: {} in fcx {}",
-                    id,
-                    self.tcx.hir().node_to_string(id),
-                    self.tag()
-                );
-            }
-        }
-    }
-
-    /// Registers an obligation for checking later, during regionck, that `arg` is well-formed.
-    pub fn register_wf_obligation(
-        &self,
-        arg: subst::GenericArg<'tcx>,
-        span: Span,
-        code: traits::ObligationCauseCode<'tcx>,
-    ) {
-        // WF obligations never themselves fail, so no real need to give a detailed cause:
-        let cause = traits::ObligationCause::new(span, self.body_id, code);
-        self.register_predicate(traits::Obligation::new(
-            cause,
-            self.param_env,
-            ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx),
-        ));
-    }
-
-    /// Registers obligations that all `substs` are well-formed.
-    pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) {
-        for arg in substs.iter().filter(|arg| {
-            matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
-        }) {
-            self.register_wf_obligation(arg, expr.span, traits::MiscObligation);
-        }
-    }
-
-    /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each
-    /// type/region parameter was instantiated (`substs`), creates and registers suitable
-    /// trait/region obligations.
-    ///
-    /// For example, if there is a function:
-    ///
-    /// ```
-    /// fn foo<'a,T:'a>(...)
-    /// ```
-    ///
-    /// and a reference:
-    ///
-    /// ```
-    /// let f = foo;
-    /// ```
-    ///
-    /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a`
-    /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally.
-    pub fn add_obligations_for_parameters(
-        &self,
-        cause: traits::ObligationCause<'tcx>,
-        predicates: ty::InstantiatedPredicates<'tcx>,
-    ) {
-        assert!(!predicates.has_escaping_bound_vars());
-
-        debug!("add_obligations_for_parameters(predicates={:?})", predicates);
-
-        for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) {
-            self.register_predicate(obligation);
-        }
-    }
-
-    // FIXME(arielb1): use this instead of field.ty everywhere
-    // Only for fields! Returns <none> for methods>
-    // Indifferent to privacy flags
-    pub fn field_ty(
-        &self,
-        span: Span,
-        field: &'tcx ty::FieldDef,
-        substs: SubstsRef<'tcx>,
-    ) -> Ty<'tcx> {
-        self.normalize_associated_types_in(span, &field.ty(self.tcx, substs))
-    }
-
-    pub(super) fn check_casts(&self) {
-        let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
-        for cast in deferred_cast_checks.drain(..) {
-            cast.check(self);
-        }
-    }
-
-    pub(super) fn resolve_generator_interiors(&self, def_id: DefId) {
-        let mut generators = self.deferred_generator_interiors.borrow_mut();
-        for (body_id, interior, kind) in generators.drain(..) {
-            self.select_obligations_where_possible(false, |_| {});
-            super::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
-        }
-    }
-
-    // Tries to apply a fallback to `ty` if it is an unsolved variable.
-    //
-    // - Unconstrained ints are replaced with `i32`.
-    //
-    // - Unconstrained floats are replaced with with `f64`.
-    //
-    // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
-    //   is enabled. Otherwise, they are replaced with `()`.
-    //
-    // Fallback becomes very dubious if we have encountered type-checking errors.
-    // In that case, fallback to Error.
-    // The return value indicates whether fallback has occurred.
-    pub(super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool {
-        use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
-        use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
-
-        assert!(ty.is_ty_infer());
-        let fallback = match self.type_is_unconstrained_numeric(ty) {
-            _ if self.is_tainted_by_errors() => self.tcx().ty_error(),
-            UnconstrainedInt => self.tcx.types.i32,
-            UnconstrainedFloat => self.tcx.types.f64,
-            Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
-            Neither => {
-                // This type variable was created from the instantiation of an opaque
-                // type. The fact that we're attempting to perform fallback for it
-                // means that the function neither constrained it to a concrete
-                // type, nor to the opaque type itself.
-                //
-                // For example, in this code:
-                //
-                //```
-                // type MyType = impl Copy;
-                // fn defining_use() -> MyType { true }
-                // fn other_use() -> MyType { defining_use() }
-                // ```
-                //
-                // `defining_use` will constrain the instantiated inference
-                // variable to `bool`, while `other_use` will constrain
-                // the instantiated inference variable to `MyType`.
-                //
-                // When we process opaque types during writeback, we
-                // will handle cases like `other_use`, and not count
-                // them as defining usages
-                //
-                // However, we also need to handle cases like this:
-                //
-                // ```rust
-                // pub type Foo = impl Copy;
-                // fn produce() -> Option<Foo> {
-                //     None
-                //  }
-                //  ```
-                //
-                // In the above snippet, the inference variable created by
-                // instantiating `Option<Foo>` will be completely unconstrained.
-                // We treat this as a non-defining use by making the inference
-                // variable fall back to the opaque type itself.
-                if let FallbackMode::All = mode {
-                    if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) {
-                        debug!(
-                            "fallback_if_possible: falling back opaque type var {:?} to {:?}",
-                            ty, opaque_ty
-                        );
-                        *opaque_ty
-                    } else {
-                        return false;
-                    }
-                } else {
-                    return false;
-                }
-            }
-        };
-        debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback);
-        self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback);
-        true
-    }
-
-    pub(super) fn select_all_obligations_or_error(&self) {
-        debug!("select_all_obligations_or_error");
-        if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {
-            self.report_fulfillment_errors(&errors, self.inh.body_id, false);
-        }
-    }
-
-    /// Select as many obligations as we can at present.
-    pub(super) fn select_obligations_where_possible(
-        &self,
-        fallback_has_occurred: bool,
-        mutate_fullfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
-    ) {
-        let result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
-        if let Err(mut errors) = result {
-            mutate_fullfillment_errors(&mut errors);
-            self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
-        }
-    }
-
-    /// For the overloaded place expressions (`*x`, `x[3]`), the trait
-    /// returns a type of `&T`, but the actual type we assign to the
-    /// *expression* is `T`. So this function just peels off the return
-    /// type by one layer to yield `T`.
-    pub(super) fn make_overloaded_place_return_type(
-        &self,
-        method: MethodCallee<'tcx>,
-    ) -> ty::TypeAndMut<'tcx> {
-        // extract method return type, which will be &T;
-        let ret_ty = method.sig.output();
-
-        // method returns &T, but the type as visible to user is T, so deref
-        ret_ty.builtin_deref(true).unwrap()
-    }
-
-    pub(super) fn check_method_argument_types(
-        &self,
-        sp: Span,
-        expr: &'tcx hir::Expr<'tcx>,
-        method: Result<MethodCallee<'tcx>, ()>,
-        args_no_rcvr: &'tcx [hir::Expr<'tcx>],
-        tuple_arguments: TupleArgumentsFlag,
-        expected: Expectation<'tcx>,
-    ) -> Ty<'tcx> {
-        let has_error = match method {
-            Ok(method) => method.substs.references_error() || method.sig.references_error(),
-            Err(_) => true,
-        };
-        if has_error {
-            let err_inputs = self.err_args(args_no_rcvr.len());
-
-            let err_inputs = match tuple_arguments {
-                DontTupleArguments => err_inputs,
-                TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])],
-            };
-
-            self.check_argument_types(
-                sp,
-                expr,
-                &err_inputs[..],
-                &[],
-                args_no_rcvr,
-                false,
-                tuple_arguments,
-                None,
-            );
-            return self.tcx.ty_error();
-        }
-
-        let method = method.unwrap();
-        // HACK(eddyb) ignore self in the definition (see above).
-        let expected_arg_tys = self.expected_inputs_for_expected_output(
-            sp,
-            expected,
-            method.sig.output(),
-            &method.sig.inputs()[1..],
-        );
-        self.check_argument_types(
-            sp,
-            expr,
-            &method.sig.inputs()[1..],
-            &expected_arg_tys[..],
-            args_no_rcvr,
-            method.sig.c_variadic,
-            tuple_arguments,
-            self.tcx.hir().span_if_local(method.def_id),
-        );
-        method.sig.output()
-    }
-
-    fn self_type_matches_expected_vid(
-        &self,
-        trait_ref: ty::PolyTraitRef<'tcx>,
-        expected_vid: ty::TyVid,
-    ) -> bool {
-        let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
-        debug!(
-            "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})",
-            trait_ref, self_ty, expected_vid
-        );
-        match *self_ty.kind() {
-            ty::Infer(ty::TyVar(found_vid)) => {
-                // FIXME: consider using `sub_root_var` here so we
-                // can see through subtyping.
-                let found_vid = self.root_var(found_vid);
-                debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid);
-                expected_vid == found_vid
-            }
-            _ => false,
-        }
-    }
-
-    pub(super) fn obligations_for_self_ty<'b>(
-        &'b self,
-        self_ty: ty::TyVid,
-    ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
-    + Captures<'tcx>
-    + 'b {
-        // FIXME: consider using `sub_root_var` here so we
-        // can see through subtyping.
-        let ty_var_root = self.root_var(self_ty);
-        debug!(
-            "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}",
-            self_ty,
-            ty_var_root,
-            self.fulfillment_cx.borrow().pending_obligations()
-        );
-
-        self.fulfillment_cx
-            .borrow()
-            .pending_obligations()
-            .into_iter()
-            .filter_map(move |obligation| {
-                match obligation.predicate.skip_binders() {
-                    ty::PredicateAtom::Projection(data) => {
-                        Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation))
-                    }
-                    ty::PredicateAtom::Trait(data, _) => {
-                        Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation))
-                    }
-                    ty::PredicateAtom::Subtype(..) => None,
-                    ty::PredicateAtom::RegionOutlives(..) => None,
-                    ty::PredicateAtom::TypeOutlives(..) => None,
-                    ty::PredicateAtom::WellFormed(..) => None,
-                    ty::PredicateAtom::ObjectSafe(..) => None,
-                    ty::PredicateAtom::ConstEvaluatable(..) => None,
-                    ty::PredicateAtom::ConstEquate(..) => None,
-                    // N.B., this predicate is created by breaking down a
-                    // `ClosureType: FnFoo()` predicate, where
-                    // `ClosureType` represents some `Closure`. It can't
-                    // possibly be referring to the current closure,
-                    // because we haven't produced the `Closure` for
-                    // this closure yet; this is exactly why the other
-                    // code is looking for a self type of a unresolved
-                    // inference variable.
-                    ty::PredicateAtom::ClosureKind(..) => None,
-                    ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
-                }
-            })
-            .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
-    }
-
-    pub(super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
-        self.obligations_for_self_ty(self_ty)
-            .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait())
-    }
-
-    /// Generic function that factors out common logic from function calls,
-    /// method calls and overloaded operators.
-    pub(super) fn check_argument_types(
-        &self,
-        sp: Span,
-        expr: &'tcx hir::Expr<'tcx>,
-        fn_inputs: &[Ty<'tcx>],
-        expected_arg_tys: &[Ty<'tcx>],
-        args: &'tcx [hir::Expr<'tcx>],
-        c_variadic: bool,
-        tuple_arguments: TupleArgumentsFlag,
-        def_span: Option<Span>,
-    ) {
-        let tcx = self.tcx;
-        // Grab the argument types, supplying fresh type variables
-        // if the wrong number of arguments were supplied
-        let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 };
-
-        // All the input types from the fn signature must outlive the call
-        // so as to validate implied bounds.
-        for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) {
-            self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
-        }
-
-        let expected_arg_count = fn_inputs.len();
-
-        let param_count_error = |expected_count: usize,
-                                 arg_count: usize,
-                                 error_code: &str,
-                                 c_variadic: bool,
-                                 sugg_unit: bool| {
-            let (span, start_span, args) = match &expr.kind {
-                hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]),
-                hir::ExprKind::MethodCall(path_segment, span, args, _) => (
-                    *span,
-                    // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
-                    path_segment
-                        .args
-                        .and_then(|args| args.args.iter().last())
-                        // Account for `foo.bar::<T>()`.
-                        .map(|arg| {
-                            // Skip the closing `>`.
-                            tcx.sess
-                                .source_map()
-                                .next_point(tcx.sess.source_map().next_point(arg.span()))
-                        })
-                        .unwrap_or(*span),
-                    &args[1..], // Skip the receiver.
-                ),
-                k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k),
-            };
-            let arg_spans = if args.is_empty() {
-                // foo()
-                // ^^^-- supplied 0 arguments
-                // |
-                // expected 2 arguments
-                vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())]
-            } else {
-                // foo(1, 2, 3)
-                // ^^^ -  -  - supplied 3 arguments
-                // |
-                // expected 2 arguments
-                args.iter().map(|arg| arg.span).collect::<Vec<Span>>()
-            };
-
-            let mut err = tcx.sess.struct_span_err_with_code(
-                span,
-                &format!(
-                    "this function takes {}{} but {} {} supplied",
-                    if c_variadic { "at least " } else { "" },
-                    potentially_plural_count(expected_count, "argument"),
-                    potentially_plural_count(arg_count, "argument"),
-                    if arg_count == 1 { "was" } else { "were" }
-                ),
-                DiagnosticId::Error(error_code.to_owned()),
-            );
-            let label = format!("supplied {}", potentially_plural_count(arg_count, "argument"));
-            for (i, span) in arg_spans.into_iter().enumerate() {
-                err.span_label(
-                    span,
-                    if arg_count == 0 || i + 1 == arg_count { &label } else { "" },
-                );
-            }
-
-            if let Some(def_s) = def_span.map(|sp| tcx.sess.source_map().guess_head_span(sp)) {
-                err.span_label(def_s, "defined here");
-            }
-            if sugg_unit {
-                let sugg_span = tcx.sess.source_map().end_point(expr.span);
-                // remove closing `)` from the span
-                let sugg_span = sugg_span.shrink_to_lo();
-                err.span_suggestion(
-                    sugg_span,
-                    "expected the unit value `()`; create it with empty parentheses",
-                    String::from("()"),
-                    Applicability::MachineApplicable,
-                );
-            } else {
-                err.span_label(
-                    span,
-                    format!(
-                        "expected {}{}",
-                        if c_variadic { "at least " } else { "" },
-                        potentially_plural_count(expected_count, "argument")
-                    ),
-                );
-            }
-            err.emit();
-        };
-
-        let mut expected_arg_tys = expected_arg_tys.to_vec();
-
-        let formal_tys = if tuple_arguments == TupleArguments {
-            let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
-            match tuple_type.kind() {
-                ty::Tuple(arg_types) if arg_types.len() != args.len() => {
-                    param_count_error(arg_types.len(), args.len(), "E0057", false, false);
-                    expected_arg_tys = vec![];
-                    self.err_args(args.len())
-                }
-                ty::Tuple(arg_types) => {
-                    expected_arg_tys = match expected_arg_tys.get(0) {
-                        Some(&ty) => match ty.kind() {
-                            ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
-                            _ => vec![],
-                        },
-                        None => vec![],
-                    };
-                    arg_types.iter().map(|k| k.expect_ty()).collect()
-                }
-                _ => {
-                    struct_span_err!(
-                        tcx.sess,
-                        sp,
-                        E0059,
-                        "cannot use call notation; the first type parameter \
-                         for the function trait is neither a tuple nor unit"
-                    )
-                    .emit();
-                    expected_arg_tys = vec![];
-                    self.err_args(args.len())
-                }
-            }
-        } else if expected_arg_count == supplied_arg_count {
-            fn_inputs.to_vec()
-        } else if c_variadic {
-            if supplied_arg_count >= expected_arg_count {
-                fn_inputs.to_vec()
-            } else {
-                param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
-                expected_arg_tys = vec![];
-                self.err_args(supplied_arg_count)
-            }
-        } else {
-            // is the missing argument of type `()`?
-            let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit()
-            } else if fn_inputs.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(&fn_inputs[0]).is_unit()
-            } else {
-                false
-            };
-            param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
-
-            expected_arg_tys = vec![];
-            self.err_args(supplied_arg_count)
-        };
-
-        debug!(
-            "check_argument_types: formal_tys={:?}",
-            formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
-        );
-
-        // If there is no expectation, expect formal_tys.
-        let expected_arg_tys =
-            if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() };
-
-        let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
-
-        // Check the arguments.
-        // We do this in a pretty awful way: first we type-check any arguments
-        // that are not closures, then we type-check the closures. This is so
-        // that we have more information about the types of arguments when we
-        // type-check the functions. This isn't really the right way to do this.
-        for &check_closures in &[false, true] {
-            debug!("check_closures={}", check_closures);
-
-            // More awful hacks: before we check argument types, try to do
-            // an "opportunistic" trait resolution of any trait bounds on
-            // the call. This helps coercions.
-            if check_closures {
-                self.select_obligations_where_possible(false, |errors| {
-                    self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
-                    self.point_at_arg_instead_of_call_if_possible(
-                        errors,
-                        &final_arg_types[..],
-                        sp,
-                        &args,
-                    );
-                })
-            }
-
-            // For C-variadic functions, we don't have a declared type for all of
-            // the arguments hence we only do our usual type checking with
-            // the arguments who's types we do know.
-            let t = if c_variadic {
-                expected_arg_count
-            } else if tuple_arguments == TupleArguments {
-                args.len()
-            } else {
-                supplied_arg_count
-            };
-            for (i, arg) in args.iter().take(t).enumerate() {
-                // Warn only for the first loop (the "no closures" one).
-                // Closure arguments themselves can't be diverging, but
-                // a previous argument can, e.g., `foo(panic!(), || {})`.
-                if !check_closures {
-                    self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
-                }
-
-                let is_closure = match arg.kind {
-                    ExprKind::Closure(..) => true,
-                    _ => false,
-                };
-
-                if is_closure != check_closures {
-                    continue;
-                }
-
-                debug!("checking the argument");
-                let formal_ty = formal_tys[i];
-
-                // The special-cased logic below has three functions:
-                // 1. Provide as good of an expected type as possible.
-                let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]);
-
-                let checked_ty = self.check_expr_with_expectation(&arg, expected);
-
-                // 2. Coerce to the most detailed type that could be coerced
-                //    to, which is `expected_ty` if `rvalue_hint` returns an
-                //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
-                let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
-                // We're processing function arguments so we definitely want to use
-                // two-phase borrows.
-                self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
-                final_arg_types.push((i, checked_ty, coerce_ty));
-
-                // 3. Relate the expected type and the formal one,
-                //    if the expected type was used for the coercion.
-                self.demand_suptype(arg.span, formal_ty, coerce_ty);
-            }
-        }
-
-        // We also need to make sure we at least write the ty of the other
-        // arguments which we skipped above.
-        if c_variadic {
-            fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) {
-                use crate::structured_errors::{StructuredDiagnostic, VariadicError};
-                VariadicError::new(s, span, t, cast_ty).diagnostic().emit();
-            }
-
-            for arg in args.iter().skip(expected_arg_count) {
-                let arg_ty = self.check_expr(&arg);
-
-                // There are a few types which get autopromoted when passed via varargs
-                // in C but we just error out instead and require explicit casts.
-                let arg_ty = self.structurally_resolved_type(arg.span, arg_ty);
-                match arg_ty.kind() {
-                    ty::Float(ast::FloatTy::F32) => {
-                        variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
-                    }
-                    ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => {
-                        variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
-                    }
-                    ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => {
-                        variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
-                    }
-                    ty::FnDef(..) => {
-                        let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx));
-                        let ptr_ty = self.resolve_vars_if_possible(&ptr_ty);
-                        variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string());
-                    }
-                    _ => {}
-                }
-            }
-        }
-    }
-
-    pub(super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
-        vec![self.tcx.ty_error(); len]
-    }
-
-    /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk
-    /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s
-    /// reference a type argument. The reason to walk also the checked type is that the coerced type
-    /// can be not easily comparable with predicate type (because of coercion). If the types match
-    /// for either checked or coerced type, and there's only *one* argument that does, we point at
-    /// the corresponding argument's expression span instead of the `fn` call path span.
-    fn point_at_arg_instead_of_call_if_possible(
-        &self,
-        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
-        final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
-        call_sp: Span,
-        args: &'tcx [hir::Expr<'tcx>],
-    ) {
-        // We *do not* do this for desugared call spans to keep good diagnostics when involving
-        // the `?` operator.
-        if call_sp.desugaring_kind().is_some() {
-            return;
-        }
-
-        for error in errors {
-            // Only if the cause is somewhere inside the expression we want try to point at arg.
-            // Otherwise, it means that the cause is somewhere else and we should not change
-            // anything because we can break the correct span.
-            if !call_sp.contains(error.obligation.cause.span) {
-                continue;
-            }
-
-            if let ty::PredicateAtom::Trait(predicate, _) =
-                error.obligation.predicate.skip_binders()
-            {
-                // Collect the argument position for all arguments that could have caused this
-                // `FulfillmentError`.
-                let mut referenced_in = final_arg_types
-                    .iter()
-                    .map(|&(i, checked_ty, _)| (i, checked_ty))
-                    .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
-                    .flat_map(|(i, ty)| {
-                        let ty = self.resolve_vars_if_possible(&ty);
-                        // We walk the argument type because the argument's type could have
-                        // been `Option<T>`, but the `FulfillmentError` references `T`.
-                        if ty.walk().any(|arg| arg == predicate.self_ty().into()) {
-                            Some(i)
-                        } else {
-                            None
-                        }
-                    })
-                    .collect::<Vec<usize>>();
-
-                // Both checked and coerced types could have matched, thus we need to remove
-                // duplicates.
-
-                // We sort primitive type usize here and can use unstable sort
-                referenced_in.sort_unstable();
-                referenced_in.dedup();
-
-                if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
-                    // We make sure that only *one* argument matches the obligation failure
-                    // and we assign the obligation's span to its expression's.
-                    error.obligation.cause.make_mut().span = args[ref_in].span;
-                    error.points_at_arg_span = true;
-                }
-            }
-        }
-    }
-
-    /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the
-    /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s
-    /// were caused by them. If they were, we point at the corresponding type argument's span
-    /// instead of the `fn` call path span.
-    fn point_at_type_arg_instead_of_call_if_possible(
-        &self,
-        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
-        call_expr: &'tcx hir::Expr<'tcx>,
-    ) {
-        if let hir::ExprKind::Call(path, _) = &call_expr.kind {
-            if let hir::ExprKind::Path(qpath) = &path.kind {
-                if let hir::QPath::Resolved(_, path) = &qpath {
-                    for error in errors {
-                        if let ty::PredicateAtom::Trait(predicate, _) =
-                            error.obligation.predicate.skip_binders()
-                        {
-                            // If any of the type arguments in this path segment caused the
-                            // `FullfillmentError`, point at its span (#61860).
-                            for arg in path
-                                .segments
-                                .iter()
-                                .filter_map(|seg| seg.args.as_ref())
-                                .flat_map(|a| a.args.iter())
-                            {
-                                if let hir::GenericArg::Type(hir_ty) = &arg {
-                                    if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
-                                        &hir_ty.kind
-                                    {
-                                        // Avoid ICE with associated types. As this is best
-                                        // effort only, it's ok to ignore the case. It
-                                        // would trigger in `is_send::<T::AssocType>();`
-                                        // from `typeck-default-trait-impl-assoc-type.rs`.
-                                    } else {
-                                        let ty = AstConv::ast_ty_to_ty(self, hir_ty);
-                                        let ty = self.resolve_vars_if_possible(&ty);
-                                        if ty == predicate.self_ty() {
-                                            error.obligation.cause.make_mut().span = hir_ty.span;
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // AST fragment checking
-    pub(super) fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> {
-        let tcx = self.tcx;
-
-        match lit.node {
-            ast::LitKind::Str(..) => tcx.mk_static_str(),
-            ast::LitKind::ByteStr(ref v) => {
-                tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64))
-            }
-            ast::LitKind::Byte(_) => tcx.types.u8,
-            ast::LitKind::Char(_) => tcx.types.char,
-            ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t),
-            ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t),
-            ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
-                let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
-                    ty::Int(_) | ty::Uint(_) => Some(ty),
-                    ty::Char => Some(tcx.types.u8),
-                    ty::RawPtr(..) => Some(tcx.types.usize),
-                    ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize),
-                    _ => None,
-                });
-                opt_ty.unwrap_or_else(|| self.next_int_var())
-            }
-            ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t),
-            ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
-                let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
-                    ty::Float(_) => Some(ty),
-                    _ => None,
-                });
-                opt_ty.unwrap_or_else(|| self.next_float_var())
-            }
-            ast::LitKind::Bool(_) => tcx.types.bool,
-            ast::LitKind::Err(_) => tcx.ty_error(),
-        }
-    }
-
-    /// Unifies the output type with the expected type early, for more coercions
-    /// and forward type information on the input expressions.
-    pub(super) fn expected_inputs_for_expected_output(
-        &self,
-        call_span: Span,
-        expected_ret: Expectation<'tcx>,
-        formal_ret: Ty<'tcx>,
-        formal_args: &[Ty<'tcx>],
-    ) -> Vec<Ty<'tcx>> {
-        let formal_ret = self.resolve_vars_with_obligations(formal_ret);
-        let ret_ty = match expected_ret.only_has_type(self) {
-            Some(ret) => ret,
-            None => return Vec::new(),
-        };
-        let expect_args = self
-            .fudge_inference_if_ok(|| {
-                // Attempt to apply a subtyping relationship between the formal
-                // return type (likely containing type variables if the function
-                // is polymorphic) and the expected return type.
-                // No argument expectations are produced if unification fails.
-                let origin = self.misc(call_span);
-                let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret);
-
-                // FIXME(#27336) can't use ? here, Try::from_error doesn't default
-                // to identity so the resulting type is not constrained.
-                match ures {
-                    Ok(ok) => {
-                        // Process any obligations locally as much as
-                        // we can.  We don't care if some things turn
-                        // out unconstrained or ambiguous, as we're
-                        // just trying to get hints here.
-                        self.save_and_restore_in_snapshot_flag(|_| {
-                            let mut fulfill = TraitEngine::new(self.tcx);
-                            for obligation in ok.obligations {
-                                fulfill.register_predicate_obligation(self, obligation);
-                            }
-                            fulfill.select_where_possible(self)
-                        })
-                        .map_err(|_| ())?;
-                    }
-                    Err(_) => return Err(()),
-                }
-
-                // Record all the argument types, with the substitutions
-                // produced from the above subtyping unification.
-                Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect())
-            })
-            .unwrap_or_default();
-        debug!(
-            "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})",
-            formal_args, formal_ret, expect_args, expected_ret
-        );
-        expect_args
-    }
-
-    pub fn check_struct_path(
-        &self,
-        qpath: &QPath<'_>,
-        hir_id: hir::HirId,
-    ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> {
-        let path_span = qpath.qself_span();
-        let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
-        let variant = match def {
-            Res::Err => {
-                self.set_tainted_by_errors();
-                return None;
-            }
-            Res::Def(DefKind::Variant, _) => match ty.kind() {
-                ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)),
-                _ => bug!("unexpected type: {:?}", ty),
-            },
-            Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
-            | Res::SelfTy(..) => match ty.kind() {
-                ty::Adt(adt, substs) if !adt.is_enum() => {
-                    Some((adt.non_enum_variant(), adt.did, substs))
-                }
-                _ => None,
-            },
-            _ => bug!("unexpected definition: {:?}", def),
-        };
-
-        if let Some((variant, did, substs)) = variant {
-            debug!("check_struct_path: did={:?} substs={:?}", did, substs);
-            self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
-
-            // Check bounds on type arguments used in the path.
-            let (bounds, _) = self.instantiate_bounds(path_span, did, substs);
-            let cause =
-                traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did));
-            self.add_obligations_for_parameters(cause, bounds);
-
-            Some((variant, ty))
-        } else {
-            struct_span_err!(
-                self.tcx.sess,
-                path_span,
-                E0071,
-                "expected struct, variant or union type, found {}",
-                ty.sort_string(self.tcx)
-            )
-            .span_label(path_span, "not a struct")
-            .emit();
-            None
-        }
-    }
-
-    // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
-    // The newly resolved definition is written into `type_dependent_defs`.
-    fn finish_resolving_struct_path(
-        &self,
-        qpath: &QPath<'_>,
-        path_span: Span,
-        hir_id: hir::HirId,
-    ) -> (Res, Ty<'tcx>) {
-        match *qpath {
-            QPath::Resolved(ref maybe_qself, ref path) => {
-                let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
-                let ty = AstConv::res_to_ty(self, self_ty, path, true);
-                (path.res, ty)
-            }
-            QPath::TypeRelative(ref qself, ref segment) => {
-                let ty = self.to_ty(qself);
-
-                let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind {
-                    path.res
-                } else {
-                    Res::Err
-                };
-                let result =
-                    AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true);
-                let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
-                let result = result.map(|(_, kind, def_id)| (kind, def_id));
-
-                // Write back the new resolution.
-                self.write_resolution(hir_id, result);
-
-                (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty)
-            }
-            QPath::LangItem(lang_item, span) => {
-                self.resolve_lang_item_path(lang_item, span, hir_id)
-            }
-        }
-    }
-
-    pub(super) fn resolve_lang_item_path(
-        &self,
-        lang_item: hir::LangItem,
-        span: Span,
-        hir_id: hir::HirId,
-    ) -> (Res, Ty<'tcx>) {
-        let def_id = self.tcx.require_lang_item(lang_item, Some(span));
-        let def_kind = self.tcx.def_kind(def_id);
-
-        let item_ty = if let DefKind::Variant = def_kind {
-            self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent"))
-        } else {
-            self.tcx.type_of(def_id)
-        };
-        let substs = self.infcx.fresh_substs_for_item(span, def_id);
-        let ty = item_ty.subst(self.tcx, substs);
-
-        self.write_resolution(hir_id, Ok((def_kind, def_id)));
-        self.add_required_obligations(span, def_id, &substs);
-        (Res::Def(def_kind, def_id), ty)
-    }
-
-    /// Resolves an associated value path into a base type and associated constant, or method
-    /// resolution. The newly resolved definition is written into `type_dependent_defs`.
-    pub fn resolve_ty_and_res_ufcs<'b>(
-        &self,
-        qpath: &'b QPath<'b>,
-        hir_id: hir::HirId,
-        span: Span,
-    ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) {
-        debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span);
-        let (ty, qself, item_segment) = match *qpath {
-            QPath::Resolved(ref opt_qself, ref path) => {
-                return (
-                    path.res,
-                    opt_qself.as_ref().map(|qself| self.to_ty(qself)),
-                    &path.segments[..],
-                );
-            }
-            QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
-            QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"),
-        };
-        if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
-        {
-            // Return directly on cache hit. This is useful to avoid doubly reporting
-            // errors with default match binding modes. See #44614.
-            let def =
-                cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err);
-            return (def, Some(ty), slice::from_ref(&**item_segment));
-        }
-        let item_name = item_segment.ident;
-        let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| {
-            let result = match error {
-                method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
-                _ => Err(ErrorReported),
-            };
-            if item_name.name != kw::Invalid {
-                if let Some(mut e) = self.report_method_error(
-                    span,
-                    ty,
-                    item_name,
-                    SelfSource::QPath(qself),
-                    error,
-                    None,
-                ) {
-                    e.emit();
-                }
-            }
-            result
-        });
-
-        // Write back the new resolution.
-        self.write_resolution(hir_id, result);
-        (
-            result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err),
-            Some(ty),
-            slice::from_ref(&**item_segment),
-        )
-    }
-
-    pub fn check_decl_initializer(
-        &self,
-        local: &'tcx hir::Local<'tcx>,
-        init: &'tcx hir::Expr<'tcx>,
-    ) -> Ty<'tcx> {
-        // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed
-        // for #42640 (default match binding modes).
-        //
-        // See #44848.
-        let ref_bindings = local.pat.contains_explicit_ref_binding();
-
-        let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty;
-        if let Some(m) = ref_bindings {
-            // Somewhat subtle: if we have a `ref` binding in the pattern,
-            // we want to avoid introducing coercions for the RHS. This is
-            // both because it helps preserve sanity and, in the case of
-            // ref mut, for soundness (issue #23116). In particular, in
-            // the latter case, we need to be clear that the type of the
-            // referent for the reference that results is *equal to* the
-            // type of the place it is referencing, and not some
-            // supertype thereof.
-            let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m));
-            self.demand_eqtype(init.span, local_ty, init_ty);
-            init_ty
-        } else {
-            self.check_expr_coercable_to_type(init, local_ty, None)
-        }
-    }
-
-    /// Type check a `let` statement.
-    pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
-        // Determine and write the type which we'll check the pattern against.
-        let ty = self.local_ty(local.span, local.hir_id).decl_ty;
-        self.write_ty(local.hir_id, ty);
-
-        // Type check the initializer.
-        if let Some(ref init) = local.init {
-            let init_ty = self.check_decl_initializer(local, &init);
-            self.overwrite_local_ty_if_err(local, ty, init_ty);
-        }
-
-        // Does the expected pattern type originate from an expression and what is the span?
-        let (origin_expr, ty_span) = match (local.ty, local.init) {
-            (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type.
-            (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee.
-            _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained.
-        };
-
-        // Type check the pattern. Override if necessary to avoid knock-on errors.
-        self.check_pat_top(&local.pat, ty, ty_span, origin_expr);
-        let pat_ty = self.node_ty(local.pat.hir_id);
-        self.overwrite_local_ty_if_err(local, ty, pat_ty);
-    }
-
-    fn overwrite_local_ty_if_err(
-        &self,
-        local: &'tcx hir::Local<'tcx>,
-        decl_ty: Ty<'tcx>,
-        ty: Ty<'tcx>,
-    ) {
-        if ty.references_error() {
-            // Override the types everywhere with `err()` to avoid knock on errors.
-            self.write_ty(local.hir_id, ty);
-            self.write_ty(local.pat.hir_id, ty);
-            let local_ty = LocalTy { decl_ty, revealed_ty: ty };
-            self.locals.borrow_mut().insert(local.hir_id, local_ty);
-            self.locals.borrow_mut().insert(local.pat.hir_id, local_ty);
-        }
-    }
-
-    pub(super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) {
-        err.span_suggestion_short(
-            span.shrink_to_hi(),
-            "consider using a semicolon here",
-            ";".to_string(),
-            Applicability::MachineApplicable,
-        );
-    }
-
-    pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) {
-        // Don't do all the complex logic below for `DeclItem`.
-        match stmt.kind {
-            hir::StmtKind::Item(..) => return,
-            hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
-        }
-
-        self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement");
-
-        // Hide the outer diverging and `has_errors` flags.
-        let old_diverges = self.diverges.replace(Diverges::Maybe);
-        let old_has_errors = self.has_errors.replace(false);
-
-        match stmt.kind {
-            hir::StmtKind::Local(ref l) => {
-                self.check_decl_local(&l);
-            }
-            // Ignore for now.
-            hir::StmtKind::Item(_) => {}
-            hir::StmtKind::Expr(ref expr) => {
-                // Check with expected type of `()`.
-                self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
-                    self.suggest_semicolon_at_end(expr.span, err);
-                });
-            }
-            hir::StmtKind::Semi(ref expr) => {
-                self.check_expr(&expr);
-            }
-        }
-
-        // Combine the diverging and `has_error` flags.
-        self.diverges.set(self.diverges.get() | old_diverges);
-        self.has_errors.set(self.has_errors.get() | old_has_errors);
-    }
-
-    pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
-        let unit = self.tcx.mk_unit();
-        let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
-
-        // if the block produces a `!` value, that can always be
-        // (effectively) coerced to unit.
-        if !ty.is_never() {
-            self.demand_suptype(blk.span, unit, ty);
-        }
-    }
-
-    /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
-    /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors
-    /// when given code like the following:
-    /// ```text
-    /// if false { return 0i32; } else { 1u32 }
-    /// //                               ^^^^ point at this instead of the whole `if` expression
-    /// ```
-    fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span {
-        if let hir::ExprKind::Match(_, arms, _) = &expr.kind {
-            let arm_spans: Vec<Span> = arms
-                .iter()
-                .filter_map(|arm| {
-                    self.in_progress_typeck_results
-                        .and_then(|typeck_results| {
-                            typeck_results.borrow().node_type_opt(arm.body.hir_id)
-                        })
-                        .and_then(|arm_ty| {
-                            if arm_ty.is_never() {
-                                None
-                            } else {
-                                Some(match &arm.body.kind {
-                                    // Point at the tail expression when possible.
-                                    hir::ExprKind::Block(block, _) => {
-                                        block.expr.as_ref().map(|e| e.span).unwrap_or(block.span)
-                                    }
-                                    _ => arm.body.span,
-                                })
-                            }
-                        })
-                })
-                .collect();
-            if arm_spans.len() == 1 {
-                return arm_spans[0];
-            }
-        }
-        expr.span
-    }
-
-    pub(super) fn check_block_with_expected(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected: Expectation<'tcx>,
-    ) -> Ty<'tcx> {
-        let prev = {
-            let mut fcx_ps = self.ps.borrow_mut();
-            let unsafety_state = fcx_ps.recurse(blk);
-            replace(&mut *fcx_ps, unsafety_state)
-        };
-
-        // In some cases, blocks have just one exit, but other blocks
-        // can be targeted by multiple breaks. This can happen both
-        // with labeled blocks as well as when we desugar
-        // a `try { ... }` expression.
-        //
-        // Example 1:
-        //
-        //    'a: { if true { break 'a Err(()); } Ok(()) }
-        //
-        // Here we would wind up with two coercions, one from
-        // `Err(())` and the other from the tail expression
-        // `Ok(())`. If the tail expression is omitted, that's a
-        // "forced unit" -- unless the block diverges, in which
-        // case we can ignore the tail expression (e.g., `'a: {
-        // break 'a 22; }` would not force the type of the block
-        // to be `()`).
-        let tail_expr = blk.expr.as_ref();
-        let coerce_to_ty = expected.coercion_target_type(self, blk.span);
-        let coerce = if blk.targeted_by_break {
-            CoerceMany::new(coerce_to_ty)
-        } else {
-            let tail_expr: &[&hir::Expr<'_>] = match tail_expr {
-                Some(e) => slice::from_ref(e),
-                None => &[],
-            };
-            CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr)
-        };
-
-        let prev_diverges = self.diverges.get();
-        let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false };
-
-        let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || {
-            for s in blk.stmts {
-                self.check_stmt(s);
-            }
-
-            // check the tail expression **without** holding the
-            // `enclosing_breakables` lock below.
-            let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
-
-            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-            let ctxt = enclosing_breakables.find_breakable(blk.hir_id);
-            let coerce = ctxt.coerce.as_mut().unwrap();
-            if let Some(tail_expr_ty) = tail_expr_ty {
-                let tail_expr = tail_expr.unwrap();
-                let span = self.get_expr_coercion_span(tail_expr);
-                let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
-                coerce.coerce(self, &cause, tail_expr, tail_expr_ty);
-            } else {
-                // Subtle: if there is no explicit tail expression,
-                // that is typically equivalent to a tail expression
-                // of `()` -- except if the block diverges. In that
-                // case, there is no value supplied from the tail
-                // expression (assuming there are no other breaks,
-                // this implies that the type of the block will be
-                // `!`).
-                //
-                // #41425 -- label the implicit `()` as being the
-                // "found type" here, rather than the "expected type".
-                if !self.diverges.get().is_always() {
-                    // #50009 -- Do not point at the entire fn block span, point at the return type
-                    // span, as it is the cause of the requirement, and
-                    // `consider_hint_about_removing_semicolon` will point at the last expression
-                    // if it were a relevant part of the error. This improves usability in editors
-                    // that highlight errors inline.
-                    let mut sp = blk.span;
-                    let mut fn_span = None;
-                    if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) {
-                        let ret_sp = decl.output.span();
-                        if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
-                            // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
-                            // output would otherwise be incorrect and even misleading. Make sure
-                            // the span we're aiming at correspond to a `fn` body.
-                            if block_sp == blk.span {
-                                sp = ret_sp;
-                                fn_span = Some(ident.span);
-                            }
-                        }
-                    }
-                    coerce.coerce_forced_unit(
-                        self,
-                        &self.misc(sp),
-                        &mut |err| {
-                            if let Some(expected_ty) = expected.only_has_type(self) {
-                                self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
-                            }
-                            if let Some(fn_span) = fn_span {
-                                err.span_label(
-                                    fn_span,
-                                    "implicitly returns `()` as its body has no tail or `return` \
-                                     expression",
-                                );
-                            }
-                        },
-                        false,
-                    );
-                }
-            }
-        });
-
-        if ctxt.may_break {
-            // If we can break from the block, then the block's exit is always reachable
-            // (... as long as the entry is reachable) - regardless of the tail of the block.
-            self.diverges.set(prev_diverges);
-        }
-
-        let mut ty = ctxt.coerce.unwrap().complete(self);
-
-        if self.has_errors.get() || ty.references_error() {
-            ty = self.tcx.ty_error()
-        }
-
-        self.write_ty(blk.hir_id, ty);
-
-        *self.ps.borrow_mut() = prev;
-        ty
-    }
-
-    fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
-        let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id));
-        match node {
-            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })
-            | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
-                let body = self.tcx.hir().body(body_id);
-                if let ExprKind::Block(block, _) = &body.value.kind {
-                    return Some(block.span);
-                }
-            }
-            _ => {}
-        }
-        None
-    }
-
-    /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
-    fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
-        let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id));
-        self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
-    }
-
-    /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
-    pub(super) fn get_node_fn_decl(
-        &self,
-        node: Node<'tcx>,
-    ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> {
-        match node {
-            Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => {
-                // This is less than ideal, it will not suggest a return type span on any
-                // method called `main`, regardless of whether it is actually the entry point,
-                // but it will still present it as the reason for the expected type.
-                Some((&sig.decl, ident, ident.name != sym::main))
-            }
-            Node::TraitItem(&hir::TraitItem {
-                ident,
-                kind: hir::TraitItemKind::Fn(ref sig, ..),
-                ..
-            }) => Some((&sig.decl, ident, true)),
-            Node::ImplItem(&hir::ImplItem {
-                ident,
-                kind: hir::ImplItemKind::Fn(ref sig, ..),
-                ..
-            }) => Some((&sig.decl, ident, false)),
-            _ => None,
-        }
-    }
-
-    /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a
-    /// suggestion can be made, `None` otherwise.
-    pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> {
-        // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
-        // `while` before reaching it, as block tail returns are not available in them.
-        self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
-            let parent = self.tcx.hir().get(blk_id);
-            self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
-        })
-    }
-
-    /// On implicit return expressions with mismatched types, provides the following suggestions:
-    ///
-    /// - Points out the method's return type as the reason for the expected type.
-    /// - Possible missing semicolon.
-    /// - Possible missing return type if the return type is the default, and not `fn main()`.
-    pub fn suggest_mismatched_types_on_tail(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &'tcx hir::Expr<'tcx>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-        cause_span: Span,
-        blk_id: hir::HirId,
-    ) -> bool {
-        let expr = expr.peel_drop_temps();
-        self.suggest_missing_semicolon(err, expr, expected, cause_span);
-        let mut pointing_at_return_type = false;
-        if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
-            pointing_at_return_type =
-                self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
-        }
-        pointing_at_return_type
-    }
-
-    /// When encountering an fn-like ctor that needs to unify with a value, check whether calling
-    /// the ctor would successfully solve the type mismatch and if so, suggest it:
-    /// ```
-    /// fn foo(x: usize) -> usize { x }
-    /// let x: usize = foo;  // suggest calling the `foo` function: `foo(42)`
-    /// ```
-    fn suggest_fn_call(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) -> bool {
-        let hir = self.tcx.hir();
-        let (def_id, sig) = match *found.kind() {
-            ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
-            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()),
-            _ => return false,
-        };
-
-        let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0;
-        let sig = self.normalize_associated_types_in(expr.span, &sig);
-        if self.can_coerce(sig.output(), expected) {
-            let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
-                (String::new(), Applicability::MachineApplicable)
-            } else {
-                ("...".to_string(), Applicability::HasPlaceholders)
-            };
-            let mut msg = "call this function";
-            match hir.get_if_local(def_id) {
-                Some(
-                    Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. })
-                    | Node::ImplItem(hir::ImplItem {
-                        kind: hir::ImplItemKind::Fn(_, body_id), ..
-                    })
-                    | Node::TraitItem(hir::TraitItem {
-                        kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)),
-                        ..
-                    }),
-                ) => {
-                    let body = hir.body(*body_id);
-                    sugg_call = body
-                        .params
-                        .iter()
-                        .map(|param| match &param.pat.kind {
-                            hir::PatKind::Binding(_, _, ident, None)
-                                if ident.name != kw::SelfLower =>
-                            {
-                                ident.to_string()
-                            }
-                            _ => "_".to_string(),
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ");
-                }
-                Some(Node::Expr(hir::Expr {
-                    kind: ExprKind::Closure(_, _, body_id, _, _),
-                    span: full_closure_span,
-                    ..
-                })) => {
-                    if *full_closure_span == expr.span {
-                        return false;
-                    }
-                    msg = "call this closure";
-                    let body = hir.body(*body_id);
-                    sugg_call = body
-                        .params
-                        .iter()
-                        .map(|param| match &param.pat.kind {
-                            hir::PatKind::Binding(_, _, ident, None)
-                                if ident.name != kw::SelfLower =>
-                            {
-                                ident.to_string()
-                            }
-                            _ => "_".to_string(),
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ");
-                }
-                Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
-                    sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
-                    match def_id.as_local().map(|def_id| hir.def_kind(def_id)) {
-                        Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
-                            msg = "instantiate this tuple variant";
-                        }
-                        Some(DefKind::Ctor(CtorOf::Struct, _)) => {
-                            msg = "instantiate this tuple struct";
-                        }
-                        _ => {}
-                    }
-                }
-                Some(Node::ForeignItem(hir::ForeignItem {
-                    kind: hir::ForeignItemKind::Fn(_, idents, _),
-                    ..
-                })) => {
-                    sugg_call = idents
-                        .iter()
-                        .map(|ident| {
-                            if ident.name != kw::SelfLower {
-                                ident.to_string()
-                            } else {
-                                "_".to_string()
-                            }
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ")
-                }
-                Some(Node::TraitItem(hir::TraitItem {
-                    kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)),
-                    ..
-                })) => {
-                    sugg_call = idents
-                        .iter()
-                        .map(|ident| {
-                            if ident.name != kw::SelfLower {
-                                ident.to_string()
-                            } else {
-                                "_".to_string()
-                            }
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ")
-                }
-                _ => {}
-            }
-            err.span_suggestion_verbose(
-                expr.span.shrink_to_hi(),
-                &format!("use parentheses to {}", msg),
-                format!("({})", sugg_call),
-                applicability,
-            );
-            return true;
-        }
-        false
-    }
-
-    pub fn suggest_deref_ref_or_into(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
-    ) {
-        if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) {
-            err.span_suggestion(sp, msg, suggestion, applicability);
-        } else if let (ty::FnDef(def_id, ..), true) =
-            (&found.kind(), self.suggest_fn_call(err, expr, expected, found))
-        {
-            if let Some(sp) = self.tcx.hir().span_if_local(*def_id) {
-                let sp = self.sess().source_map().guess_head_span(sp);
-                err.span_label(sp, &format!("{} defined here", found));
-            }
-        } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
-            let is_struct_pat_shorthand_field =
-                self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
-            let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
-            if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
-                let mut suggestions = iter::repeat(&expr_text)
-                    .zip(methods.iter())
-                    .filter_map(|(receiver, method)| {
-                        let method_call = format!(".{}()", method.ident);
-                        if receiver.ends_with(&method_call) {
-                            None // do not suggest code that is already there (#53348)
-                        } else {
-                            let method_call_list = [".to_vec()", ".to_string()"];
-                            let sugg = if receiver.ends_with(".clone()")
-                                && method_call_list.contains(&method_call.as_str())
-                            {
-                                let max_len = receiver.rfind('.').unwrap();
-                                format!("{}{}", &receiver[..max_len], method_call)
-                            } else {
-                                if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
-                                    format!("({}){}", receiver, method_call)
-                                } else {
-                                    format!("{}{}", receiver, method_call)
-                                }
-                            };
-                            Some(if is_struct_pat_shorthand_field {
-                                format!("{}: {}", receiver, sugg)
-                            } else {
-                                sugg
-                            })
-                        }
-                    })
-                    .peekable();
-                if suggestions.peek().is_some() {
-                    err.span_suggestions(
-                        expr.span,
-                        "try using a conversion method",
-                        suggestions,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            }
-        }
-    }
-
-    /// When encountering the expected boxed value allocated in the stack, suggest allocating it
-    /// in the heap by calling `Box::new()`.
-    pub(super) fn suggest_boxing_when_appropriate(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
-            // Do not suggest `Box::new` in const context.
-            return;
-        }
-        if !expected.is_box() || found.is_box() {
-            return;
-        }
-        let boxed_found = self.tcx.mk_box(found);
-        if let (true, Ok(snippet)) = (
-            self.can_coerce(boxed_found, expected),
-            self.sess().source_map().span_to_snippet(expr.span),
-        ) {
-            err.span_suggestion(
-                expr.span,
-                "store this in the heap by calling `Box::new`",
-                format!("Box::new({})", snippet),
-                Applicability::MachineApplicable,
-            );
-            err.note(
-                "for more on the distinction between the stack and the heap, read \
-                 https://doc.rust-lang.org/book/ch15-01-box.html, \
-                 https://doc.rust-lang.org/rust-by-example/std/box.html, and \
-                 https://doc.rust-lang.org/std/boxed/index.html",
-            );
-        }
-    }
-
-    pub(super) fn note_internal_mutation_in_method(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        if found != self.tcx.types.unit {
-            return;
-        }
-        if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind {
-            if self
-                .typeck_results
-                .borrow()
-                .expr_ty_adjusted_opt(rcvr)
-                .map_or(true, |ty| expected.peel_refs() != ty.peel_refs())
-            {
-                return;
-            }
-            let mut sp = MultiSpan::from_span(path_segment.ident.span);
-            sp.push_span_label(
-                path_segment.ident.span,
-                format!(
-                    "this call modifies {} in-place",
-                    match rcvr.kind {
-                        ExprKind::Path(QPath::Resolved(
-                            None,
-                            hir::Path { segments: [segment], .. },
-                        )) => format!("`{}`", segment.ident),
-                        _ => "its receiver".to_string(),
-                    }
-                ),
-            );
-            sp.push_span_label(
-                rcvr.span,
-                "you probably want to use this value after calling the method...".to_string(),
-            );
-            err.span_note(
-                sp,
-                &format!("method `{}` modifies its receiver in-place", path_segment.ident),
-            );
-            err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident));
-        }
-    }
-
-    /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
-    pub(super) fn suggest_calling_boxed_future_when_appropriate(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) -> bool {
-        // Handle #68197.
-
-        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
-            // Do not suggest `Box::new` in const context.
-            return false;
-        }
-        let pin_did = self.tcx.lang_items().pin_type();
-        match expected.kind() {
-            ty::Adt(def, _) if Some(def.did) != pin_did => return false,
-            // This guards the `unwrap` and `mk_box` below.
-            _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false,
-            _ => {}
-        }
-        let boxed_found = self.tcx.mk_box(found);
-        let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap();
-        if let (true, Ok(snippet)) = (
-            self.can_coerce(new_found, expected),
-            self.sess().source_map().span_to_snippet(expr.span),
-        ) {
-            match found.kind() {
-                ty::Adt(def, _) if def.is_box() => {
-                    err.help("use `Box::pin`");
-                }
-                _ => {
-                    err.span_suggestion(
-                        expr.span,
-                        "you need to pin and box this expression",
-                        format!("Box::pin({})", snippet),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-            true
-        } else {
-            false
-        }
-    }
-
-    /// A common error is to forget to add a semicolon at the end of a block, e.g.,
-    ///
-    /// ```
-    /// fn foo() {
-    ///     bar_that_returns_u32()
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the return expression in a block would make sense on its own as a
-    /// statement and the return type has been left as default or has been specified as `()`. If so,
-    /// it suggests adding a semicolon.
-    fn suggest_missing_semicolon(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expression: &'tcx hir::Expr<'tcx>,
-        expected: Ty<'tcx>,
-        cause_span: Span,
-    ) {
-        if expected.is_unit() {
-            // `BlockTailExpression` only relevant if the tail expr would be
-            // useful on its own.
-            match expression.kind {
-                ExprKind::Call(..)
-                | ExprKind::MethodCall(..)
-                | ExprKind::Loop(..)
-                | ExprKind::Match(..)
-                | ExprKind::Block(..) => {
-                    err.span_suggestion(
-                        cause_span.shrink_to_hi(),
-                        "try adding a semicolon",
-                        ";".to_string(),
-                        Applicability::MachineApplicable,
-                    );
-                }
-                _ => (),
-            }
-        }
-    }
-
-    /// A possible error is to forget to add a return type that is needed:
-    ///
-    /// ```
-    /// fn foo() {
-    ///     bar_that_returns_u32()
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the return type is left as default, the method is not part of an
-    /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
-    /// type.
-    pub(super) fn suggest_missing_return_type(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        fn_decl: &hir::FnDecl<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-        can_suggest: bool,
-    ) -> bool {
-        // Only suggest changing the return type for methods that
-        // haven't set a return type at all (and aren't `fn main()` or an impl).
-        match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
-            (&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
-                err.span_suggestion(
-                    span,
-                    "try adding a return type",
-                    format!("-> {} ", self.resolve_vars_with_obligations(found)),
-                    Applicability::MachineApplicable,
-                );
-                true
-            }
-            (&hir::FnRetTy::DefaultReturn(span), false, true, true) => {
-                err.span_label(span, "possibly return type missing here?");
-                true
-            }
-            (&hir::FnRetTy::DefaultReturn(span), _, false, true) => {
-                // `fn main()` must return `()`, do not suggest changing return type
-                err.span_label(span, "expected `()` because of default return type");
-                true
-            }
-            // expectation was caused by something else, not the default return
-            (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false,
-            (&hir::FnRetTy::Return(ref ty), _, _, _) => {
-                // Only point to return type if the expected type is the return type, as if they
-                // are not, the expectation must have been caused by something else.
-                debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
-                let sp = ty.span;
-                let ty = AstConv::ast_ty_to_ty(self, ty);
-                debug!("suggest_missing_return_type: return type {:?}", ty);
-                debug!("suggest_missing_return_type: expected type {:?}", ty);
-                if ty.kind() == expected.kind() {
-                    err.span_label(sp, format!("expected `{}` because of return type", expected));
-                    return true;
-                }
-                false
-            }
-        }
-    }
-
-    /// A possible error is to forget to add `.await` when using futures:
-    ///
-    /// ```
-    /// async fn make_u32() -> u32 {
-    ///     22
-    /// }
-    ///
-    /// fn take_u32(x: u32) {}
-    ///
-    /// async fn foo() {
-    ///     let x = make_u32();
-    ///     take_u32(x);
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
-    /// expected type. If this is the case, and we are inside of an async body, it suggests adding
-    /// `.await` to the tail of the expression.
-    pub(super) fn suggest_missing_await(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found);
-        // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the
-        // body isn't `async`.
-        let item_id = self.tcx().hir().get_parent_node(self.body_id);
-        if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) {
-            let body = self.tcx().hir().body(body_id);
-            if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
-                let sp = expr.span;
-                // Check for `Future` implementations by constructing a predicate to
-                // prove: `<T as Future>::Output == U`
-                let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp));
-                let item_def_id = self
-                    .tcx
-                    .associated_items(future_trait)
-                    .in_definition_order()
-                    .next()
-                    .unwrap()
-                    .def_id;
-                // `<T as Future>::Output`
-                let projection_ty = ty::ProjectionTy {
-                    // `T`
-                    substs: self
-                        .tcx
-                        .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)),
-                    // `Future::Output`
-                    item_def_id,
-                };
-
-                let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate {
-                    projection_ty,
-                    ty: expected,
-                })
-                .potentially_quantified(self.tcx, ty::PredicateKind::ForAll);
-                let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
-
-                debug!("suggest_missing_await: trying obligation {:?}", obligation);
-
-                if self.infcx.predicate_may_hold(&obligation) {
-                    debug!("suggest_missing_await: obligation held: {:?}", obligation);
-                    if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
-                        err.span_suggestion(
-                            sp,
-                            "consider using `.await` here",
-                            format!("{}.await", code),
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        debug!("suggest_missing_await: no snippet for {:?}", sp);
-                    }
-                } else {
-                    debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
-                }
-            }
-        }
-    }
-
-    pub(super) fn suggest_missing_parentheses(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-    ) {
-        let sp = self.tcx.sess.source_map().start_point(expr.span);
-        if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
-            // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
-            self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None);
-        }
-    }
-
-    pub(super) fn note_need_for_fn_pointer(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expected: Ty<'tcx>,
-        found: Ty<'tcx>,
-    ) {
-        let (sig, did, substs) = match (&expected.kind(), &found.kind()) {
-            (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
-                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
-                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
-                if sig1 != sig2 {
-                    return;
-                }
-                err.note(
-                    "different `fn` items always have unique types, even if their signatures are \
-                     the same",
-                );
-                (sig1, *did1, substs1)
-            }
-            (ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
-                let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs);
-                if sig1 != *sig2 {
-                    return;
-                }
-                (sig1, *did, substs)
-            }
-            _ => return,
-        };
-        err.help(&format!("change the expected type to be function pointer `{}`", sig));
-        err.help(&format!(
-            "if the expected type is due to type inference, cast the expected `fn` to a function \
-             pointer: `{} as {}`",
-            self.tcx.def_path_str_with_substs(did, substs),
-            sig
-        ));
-    }
-
-    /// A common error is to add an extra semicolon:
-    ///
-    /// ```
-    /// fn foo() -> usize {
-    ///     22;
-    /// }
-    /// ```
-    ///
-    /// This routine checks if the final statement in a block is an
-    /// expression with an explicit semicolon whose type is compatible
-    /// with `expected_ty`. If so, it suggests removing the semicolon.
-    fn consider_hint_about_removing_semicolon(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected_ty: Ty<'tcx>,
-        err: &mut DiagnosticBuilder<'_>,
-    ) {
-        if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) {
-            err.span_suggestion(
-                span_semi,
-                "consider removing this semicolon",
-                String::new(),
-                Applicability::MachineApplicable,
-            );
-        }
-    }
-
-    pub(super) fn could_remove_semicolon(
-        &self,
-        blk: &'tcx hir::Block<'tcx>,
-        expected_ty: Ty<'tcx>,
-    ) -> Option<Span> {
-        // Be helpful when the user wrote `{... expr;}` and
-        // taking the `;` off is enough to fix the error.
-        let last_stmt = blk.stmts.last()?;
-        let last_expr = match last_stmt.kind {
-            hir::StmtKind::Semi(ref e) => e,
-            _ => return None,
-        };
-        let last_expr_ty = self.node_ty(last_expr.hir_id);
-        if matches!(last_expr_ty.kind(), ty::Error(_))
-            || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()
-        {
-            return None;
-        }
-        let original_span = original_sp(last_stmt.span, blk.span);
-        Some(original_span.with_lo(original_span.hi() - BytePos(1)))
-    }
-
-    // Instantiates the given path, which must refer to an item with the given
-    // number of type parameters and type.
-    pub fn instantiate_value_path(
-        &self,
-        segments: &[hir::PathSegment<'_>],
-        self_ty: Option<Ty<'tcx>>,
-        res: Res,
-        span: Span,
-        hir_id: hir::HirId,
-    ) -> (Ty<'tcx>, Res) {
-        debug!(
-            "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})",
-            segments, self_ty, res, hir_id,
-        );
-
-        let tcx = self.tcx;
-
-        let path_segs = match res {
-            Res::Local(_) | Res::SelfCtor(_) => vec![],
-            Res::Def(kind, def_id) => {
-                AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id)
-            }
-            _ => bug!("instantiate_value_path on {:?}", res),
-        };
-
-        let mut user_self_ty = None;
-        let mut is_alias_variant_ctor = false;
-        match res {
-            Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => {
-                if let Some(self_ty) = self_ty {
-                    let adt_def = self_ty.ty_adt_def().unwrap();
-                    user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty });
-                    is_alias_variant_ctor = true;
-                }
-            }
-            Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
-                let container = tcx.associated_item(def_id).container;
-                debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container);
-                match container {
-                    ty::TraitContainer(trait_did) => {
-                        callee::check_legal_trait_for_method_call(tcx, span, None, trait_did)
-                    }
-                    ty::ImplContainer(impl_def_id) => {
-                        if segments.len() == 1 {
-                            // `<T>::assoc` will end up here, and so
-                            // can `T::assoc`. It this came from an
-                            // inherent impl, we need to record the
-                            // `T` for posterity (see `UserSelfTy` for
-                            // details).
-                            let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
-                            user_self_ty = Some(UserSelfTy { impl_def_id, self_ty });
-                        }
-                    }
-                }
-            }
-            _ => {}
-        }
-
-        // Now that we have categorized what space the parameters for each
-        // segment belong to, let's sort out the parameters that the user
-        // provided (if any) into their appropriate spaces. We'll also report
-        // errors if type parameters are provided in an inappropriate place.
-
-        let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect();
-        let generics_has_err = AstConv::prohibit_generics(
-            self,
-            segments.iter().enumerate().filter_map(|(index, seg)| {
-                if !generic_segs.contains(&index) || is_alias_variant_ctor {
-                    Some(seg)
-                } else {
-                    None
-                }
-            }),
-        );
-
-        if let Res::Local(hid) = res {
-            let ty = self.local_ty(span, hid).decl_ty;
-            let ty = self.normalize_associated_types_in(span, &ty);
-            self.write_ty(hir_id, ty);
-            return (ty, res);
-        }
-
-        if generics_has_err {
-            // Don't try to infer type parameters when prohibited generic arguments were given.
-            user_self_ty = None;
-        }
-
-        // Now we have to compare the types that the user *actually*
-        // provided against the types that were *expected*. If the user
-        // did not provide any types, then we want to substitute inference
-        // variables. If the user provided some types, we may still need
-        // to add defaults. If the user provided *too many* types, that's
-        // a problem.
-
-        let mut infer_args_for_err = FxHashSet::default();
-        for &PathSeg(def_id, index) in &path_segs {
-            let seg = &segments[index];
-            let generics = tcx.generics_of(def_id);
-            // Argument-position `impl Trait` is treated as a normal generic
-            // parameter internally, but we don't allow users to specify the
-            // parameter's value explicitly, so we have to do some error-
-            // checking here.
-            if let GenericArgCountResult {
-                correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }),
-                ..
-            } = AstConv::check_generic_arg_count_for_call(
-                tcx, span, &generics, &seg, false, // `is_method_call`
-            ) {
-                infer_args_for_err.insert(index);
-                self.set_tainted_by_errors(); // See issue #53251.
-            }
-        }
-
-        let has_self = path_segs
-            .last()
-            .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self)
-            .unwrap_or(false);
-
-        let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
-            let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id));
-            match *ty.kind() {
-                ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
-                    let variant = adt_def.non_enum_variant();
-                    let ctor_def_id = variant.ctor_def_id.unwrap();
-                    (
-                        Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id),
-                        Some(substs),
-                    )
-                }
-                _ => {
-                    let mut err = tcx.sess.struct_span_err(
-                        span,
-                        "the `Self` constructor can only be used with tuple or unit structs",
-                    );
-                    if let Some(adt_def) = ty.ty_adt_def() {
-                        match adt_def.adt_kind() {
-                            AdtKind::Enum => {
-                                err.help("did you mean to use one of the enum's variants?");
-                            }
-                            AdtKind::Struct | AdtKind::Union => {
-                                err.span_suggestion(
-                                    span,
-                                    "use curly brackets",
-                                    String::from("Self { /* fields */ }"),
-                                    Applicability::HasPlaceholders,
-                                );
-                            }
-                        }
-                    }
-                    err.emit();
-
-                    return (tcx.ty_error(), res);
-                }
-            }
-        } else {
-            (res, None)
-        };
-        let def_id = res.def_id();
-
-        // The things we are substituting into the type should not contain
-        // escaping late-bound regions, and nor should the base type scheme.
-        let ty = tcx.type_of(def_id);
-
-        let arg_count = GenericArgCountResult {
-            explicit_late_bound: ExplicitLateBound::No,
-            correct: if infer_args_for_err.is_empty() {
-                Ok(())
-            } else {
-                Err(GenericArgCountMismatch::default())
-            },
-        };
-
-        let substs = self_ctor_substs.unwrap_or_else(|| {
-            AstConv::create_substs_for_generic_args(
-                tcx,
-                def_id,
-                &[][..],
-                has_self,
-                self_ty,
-                arg_count,
-                // Provide the generic args, and whether types should be inferred.
-                |def_id| {
-                    if let Some(&PathSeg(_, index)) =
-                        path_segs.iter().find(|&PathSeg(did, _)| *did == def_id)
-                    {
-                        // If we've encountered an `impl Trait`-related error, we're just
-                        // going to infer the arguments for better error messages.
-                        if !infer_args_for_err.contains(&index) {
-                            // Check whether the user has provided generic arguments.
-                            if let Some(ref data) = segments[index].args {
-                                return (Some(data), segments[index].infer_args);
-                            }
-                        }
-                        return (None, segments[index].infer_args);
-                    }
-
-                    (None, true)
-                },
-                // Provide substitutions for parameters for which (valid) arguments have been provided.
-                |param, arg| match (&param.kind, arg) {
-                    (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                        AstConv::ast_region_to_region(self, lt, Some(param)).into()
-                    }
-                    (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
-                        self.to_ty(ty).into()
-                    }
-                    (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
-                        self.const_arg_to_const(&ct.value, param.def_id).into()
-                    }
-                    _ => unreachable!(),
-                },
-                // Provide substitutions for parameters for which arguments are inferred.
-                |substs, param, infer_args| {
-                    match param.kind {
-                        GenericParamDefKind::Lifetime => {
-                            self.re_infer(Some(param), span).unwrap().into()
-                        }
-                        GenericParamDefKind::Type { has_default, .. } => {
-                            if !infer_args && has_default {
-                                // If we have a default, then we it doesn't matter that we're not
-                                // inferring the type arguments: we provide the default where any
-                                // is missing.
-                                let default = tcx.type_of(param.def_id);
-                                self.normalize_ty(
-                                    span,
-                                    default.subst_spanned(tcx, substs.unwrap(), Some(span)),
-                                )
-                                .into()
-                            } else {
-                                // If no type arguments were provided, we have to infer them.
-                                // This case also occurs as a result of some malformed input, e.g.
-                                // a lifetime argument being given instead of a type parameter.
-                                // Using inference instead of `Error` gives better error messages.
-                                self.var_for_def(span, param)
-                            }
-                        }
-                        GenericParamDefKind::Const => {
-                            // FIXME(const_generics:defaults)
-                            // No const parameters were provided, we have to infer them.
-                            self.var_for_def(span, param)
-                        }
-                    }
-                },
-            )
-        });
-        assert!(!substs.has_escaping_bound_vars());
-        assert!(!ty.has_escaping_bound_vars());
-
-        // First, store the "user substs" for later.
-        self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty);
-
-        self.add_required_obligations(span, def_id, &substs);
-
-        // Substitute the values for the type parameters into the type of
-        // the referenced item.
-        let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty);
-
-        if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
-            // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
-            // is inherent, there is no `Self` parameter; instead, the impl needs
-            // type parameters, which we can infer by unifying the provided `Self`
-            // with the substituted impl type.
-            // This also occurs for an enum variant on a type alias.
-            let ty = tcx.type_of(impl_def_id);
-
-            let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
-            match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
-                Ok(ok) => self.register_infer_ok_obligations(ok),
-                Err(_) => {
-                    self.tcx.sess.delay_span_bug(
-                        span,
-                        &format!(
-                        "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
-                        self_ty,
-                        impl_ty,
-                    ),
-                    );
-                }
-            }
-        }
-
-        self.check_rustc_args_require_const(def_id, hir_id, span);
-
-        debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted);
-        self.write_substs(hir_id, substs);
-
-        (ty_substituted, res)
-    }
-
-    /// Add all the obligations that are required, substituting and normalized appropriately.
-    fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
-        let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs);
-
-        for (i, mut obligation) in traits::predicates_for_generics(
-            traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)),
-            self.param_env,
-            bounds,
-        )
-        .enumerate()
-        {
-            // This makes the error point at the bound, but we want to point at the argument
-            if let Some(span) = spans.get(i) {
-                obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span);
-            }
-            self.register_predicate(obligation);
-        }
-    }
-
-    fn check_rustc_args_require_const(&self, def_id: DefId, hir_id: hir::HirId, span: Span) {
-        // We're only interested in functions tagged with
-        // #[rustc_args_required_const], so ignore anything that's not.
-        if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
-            return;
-        }
-
-        // If our calling expression is indeed the function itself, we're good!
-        // If not, generate an error that this can only be called directly.
-        if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) {
-            if let ExprKind::Call(ref callee, ..) = expr.kind {
-                if callee.hir_id == hir_id {
-                    return;
-                }
-            }
-        }
-
-        self.tcx.sess.span_err(
-            span,
-            "this function can only be invoked directly, not through a function pointer",
-        );
-    }
-
-    /// Resolves `typ` by a single level if `typ` is a type variable.
-    /// If no resolution is possible, then an error is reported.
-    /// Numeric inference variables may be left unresolved.
-    pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let ty = self.resolve_vars_with_obligations(ty);
-        if !ty.is_ty_var() {
-            ty
-        } else {
-            if !self.is_tainted_by_errors() {
-                self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282)
-                    .note("type must be known at this point")
-                    .emit();
-            }
-            let err = self.tcx.ty_error();
-            self.demand_suptype(sp, err, ty);
-            err
-        }
-    }
-
-    pub(super) fn with_breakable_ctxt<F: FnOnce() -> R, R>(
-        &self,
-        id: hir::HirId,
-        ctxt: BreakableCtxt<'tcx>,
-        f: F,
-    ) -> (BreakableCtxt<'tcx>, R) {
-        let index;
-        {
-            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-            index = enclosing_breakables.stack.len();
-            enclosing_breakables.by_id.insert(id, index);
-            enclosing_breakables.stack.push(ctxt);
-        }
-        let result = f();
-        let ctxt = {
-            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
-            debug_assert!(enclosing_breakables.stack.len() == index + 1);
-            enclosing_breakables.by_id.remove(&id).expect("missing breakable context");
-            enclosing_breakables.stack.pop().expect("missing breakable context")
-        };
-        (ctxt, result)
-    }
-
-    /// Instantiate a QueryResponse in a probe context, without a
-    /// good ObligationCause.
-    pub(super) fn probe_instantiate_query_response(
-        &self,
-        span: Span,
-        original_values: &OriginalQueryValues<'tcx>,
-        query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
-    ) -> InferResult<'tcx, Ty<'tcx>> {
-        self.instantiate_query_response_and_region_obligations(
-            &traits::ObligationCause::misc(span, self.body_id),
-            self.param_env,
-            original_values,
-            query_result,
-        )
-    }
-
-    /// Returns `true` if an expression is contained inside the LHS of an assignment expression.
-    pub(super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool {
-        let mut contained_in_place = false;
-
-        while let hir::Node::Expr(parent_expr) =
-            self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id))
-        {
-            match &parent_expr.kind {
-                hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
-                    if lhs.hir_id == expr_id {
-                        contained_in_place = true;
-                        break;
-                    }
-                }
-                _ => (),
-            }
-            expr_id = parent_expr.hir_id;
-        }
-
-        contained_in_place
-    }
-}
-impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
-    type Target = Inherited<'a, 'tcx>;
-    fn deref(&self) -> &Self::Target {
-        &self.inh
-    }
-}
-
-impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn item_def_id(&self) -> Option<DefId> {
-        None
-    }
-
-    fn default_constness_for_trait_bounds(&self) -> hir::Constness {
-        // FIXME: refactor this into a method
-        let node = self.tcx.hir().get(self.body_id);
-        if let Some(fn_like) = FnLikeNode::from_node(node) {
-            fn_like.constness()
-        } else {
-            hir::Constness::NotConst
-        }
-    }
-
-    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
-        let tcx = self.tcx;
-        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-        let item_id = tcx.hir().ty_param_owner(hir_id);
-        let item_def_id = tcx.hir().local_def_id(item_id);
-        let generics = tcx.generics_of(item_def_id);
-        let index = generics.param_def_id_to_index[&def_id];
-        ty::GenericPredicates {
-            parent: None,
-            predicates: tcx.arena.alloc_from_iter(
-                self.param_env.caller_bounds().iter().filter_map(|predicate| {
-                    match predicate.skip_binders() {
-                        ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => {
-                            // HACK(eddyb) should get the original `Span`.
-                            let span = tcx.def_span(def_id);
-                            Some((predicate, span))
-                        }
-                        _ => None,
-                    }
-                }),
-            ),
-        }
-    }
-
-    fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
-        let v = match def {
-            Some(def) => infer::EarlyBoundRegion(span, def.name),
-            None => infer::MiscVariable(span),
-        };
-        Some(self.next_region_var(v))
-    }
-
-    fn allow_ty_infer(&self) -> bool {
-        true
-    }
-
-    fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
-        if let Some(param) = param {
-            if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
-                return ty;
-            }
-            unreachable!()
-        } else {
-            self.next_ty_var(TypeVariableOrigin {
-                kind: TypeVariableOriginKind::TypeInference,
-                span,
-            })
-        }
-    }
-
-    fn ct_infer(
-        &self,
-        ty: Ty<'tcx>,
-        param: Option<&ty::GenericParamDef>,
-        span: Span,
-    ) -> &'tcx Const<'tcx> {
-        if let Some(param) = param {
-            if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
-                return ct;
-            }
-            unreachable!()
-        } else {
-            self.next_const_var(
-                ty,
-                ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
-            )
-        }
-    }
-
-    fn projected_ty_from_poly_trait_ref(
-        &self,
-        span: Span,
-        item_def_id: DefId,
-        item_segment: &hir::PathSegment<'_>,
-        poly_trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Ty<'tcx> {
-        let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars(
-            span,
-            infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
-            &poly_trait_ref,
-        );
-
-        let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
-            self,
-            self.tcx,
-            span,
-            item_def_id,
-            item_segment,
-            trait_ref.substs,
-        );
-
-        self.tcx().mk_projection(item_def_id, item_substs)
-    }
-
-    fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if ty.has_escaping_bound_vars() {
-            ty // FIXME: normalization and escaping regions
-        } else {
-            self.normalize_associated_types_in(span, &ty)
-        }
-    }
-
-    fn set_tainted_by_errors(&self) {
-        self.infcx.set_tainted_by_errors()
-    }
-
-    fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
-        self.write_ty(hir_id, ty)
-    }
-}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
new file mode 100644
index 00000000000..017b0abd1d6
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -0,0 +1,1469 @@
+use crate::astconv::{
+    AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg,
+};
+use crate::check::callee::{self, DeferredCallResolution};
+use crate::check::method::{self, MethodCallee, SelfSource};
+use crate::check::{BreakableCtxt, Diverges, Expectation, FallbackMode, FnCtxt, LocalTy};
+
+use rustc_data_structures::captures::Captures;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
+use rustc_hir as hir;
+use rustc_hir::def::{CtorOf, DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ExprKind, GenericArg, Node, QPath};
+use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
+use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
+use rustc_infer::infer::{InferOk, InferResult};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::subst::{
+    self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts,
+};
+use rustc_middle::ty::{
+    self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
+    Ty, UserType,
+};
+use rustc_session::lint;
+use rustc_span::hygiene::DesugaringKind;
+use rustc_span::source_map::{original_sp, DUMMY_SP};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::{self, BytePos, MultiSpan, Span};
+use rustc_trait_selection::infer::InferCtxtExt as _;
+use rustc_trait_selection::opaque_types::InferCtxtExt as _;
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
+use rustc_trait_selection::traits::{self, ObligationCauseCode, TraitEngine, TraitEngineExt};
+
+use std::collections::hash_map::Entry;
+use std::slice;
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    /// Produces warning on the given node, if the current point in the
+    /// function is unreachable, and there hasn't been another warning.
+    pub(in super::super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) {
+        // FIXME: Combine these two 'if' expressions into one once
+        // let chains are implemented
+        if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() {
+            // If span arose from a desugaring of `if` or `while`, then it is the condition itself,
+            // which diverges, that we are about to lint on. This gives suboptimal diagnostics.
+            // Instead, stop here so that the `if`- or `while`-expression's block is linted instead.
+            if !span.is_desugaring(DesugaringKind::CondTemporary)
+                && !span.is_desugaring(DesugaringKind::Async)
+                && !orig_span.is_desugaring(DesugaringKind::Await)
+            {
+                self.diverges.set(Diverges::WarnedAlways);
+
+                debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
+
+                self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
+                    let msg = format!("unreachable {}", kind);
+                    lint.build(&msg)
+                        .span_label(span, &msg)
+                        .span_label(
+                            orig_span,
+                            custom_note
+                                .unwrap_or("any code following this expression is unreachable"),
+                        )
+                        .emit();
+                })
+            }
+        }
+    }
+
+    /// Resolves type and const variables in `ty` if possible. Unlike the infcx
+    /// version (resolve_vars_if_possible), this version will
+    /// also select obligations if it seems useful, in an effort
+    /// to get more type information.
+    pub(in super::super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> {
+        debug!("resolve_vars_with_obligations(ty={:?})", ty);
+
+        // No Infer()? Nothing needs doing.
+        if !ty.has_infer_types_or_consts() {
+            debug!("resolve_vars_with_obligations: ty={:?}", ty);
+            return ty;
+        }
+
+        // If `ty` is a type variable, see whether we already know what it is.
+        ty = self.resolve_vars_if_possible(&ty);
+        if !ty.has_infer_types_or_consts() {
+            debug!("resolve_vars_with_obligations: ty={:?}", ty);
+            return ty;
+        }
+
+        // If not, try resolving pending obligations as much as
+        // possible. This can help substantially when there are
+        // indirect dependencies that don't seem worth tracking
+        // precisely.
+        self.select_obligations_where_possible(false, |_| {});
+        ty = self.resolve_vars_if_possible(&ty);
+
+        debug!("resolve_vars_with_obligations: ty={:?}", ty);
+        ty
+    }
+
+    pub(in super::super) fn record_deferred_call_resolution(
+        &self,
+        closure_def_id: DefId,
+        r: DeferredCallResolution<'tcx>,
+    ) {
+        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
+        deferred_call_resolutions.entry(closure_def_id).or_default().push(r);
+    }
+
+    pub(in super::super) fn remove_deferred_call_resolutions(
+        &self,
+        closure_def_id: DefId,
+    ) -> Vec<DeferredCallResolution<'tcx>> {
+        let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut();
+        deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![])
+    }
+
+    pub fn tag(&self) -> String {
+        format!("{:p}", self)
+    }
+
+    pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> {
+        self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| {
+            span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid))
+        })
+    }
+
+    #[inline]
+    pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) {
+        debug!(
+            "write_ty({:?}, {:?}) in fcx {}",
+            id,
+            self.resolve_vars_if_possible(&ty),
+            self.tag()
+        );
+        self.typeck_results.borrow_mut().node_types_mut().insert(id, ty);
+
+        if ty.references_error() {
+            self.has_errors.set(true);
+            self.set_tainted_by_errors();
+        }
+    }
+
+    pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) {
+        self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
+    }
+
+    pub(in super::super) fn write_resolution(
+        &self,
+        hir_id: hir::HirId,
+        r: Result<(DefKind, DefId), ErrorReported>,
+    ) {
+        self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r);
+    }
+
+    pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) {
+        debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method);
+        self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id)));
+        self.write_substs(hir_id, method.substs);
+
+        // When the method is confirmed, the `method.substs` includes
+        // parameters from not just the method, but also the impl of
+        // the method -- in particular, the `Self` type will be fully
+        // resolved. However, those are not something that the "user
+        // specified" -- i.e., those types come from the inferred type
+        // of the receiver, not something the user wrote. So when we
+        // create the user-substs, we want to replace those earlier
+        // types with just the types that the user actually wrote --
+        // that is, those that appear on the *method itself*.
+        //
+        // As an example, if the user wrote something like
+        // `foo.bar::<u32>(...)` -- the `Self` type here will be the
+        // type of `foo` (possibly adjusted), but we don't want to
+        // include that. We want just the `[_, u32]` part.
+        if !method.substs.is_noop() {
+            let method_generics = self.tcx.generics_of(method.def_id);
+            if !method_generics.params.is_empty() {
+                let user_type_annotation = self.infcx.probe(|_| {
+                    let user_substs = UserSubsts {
+                        substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| {
+                            let i = param.index as usize;
+                            if i < method_generics.parent_count {
+                                self.infcx.var_for_def(DUMMY_SP, param)
+                            } else {
+                                method.substs[i]
+                            }
+                        }),
+                        user_self_ty: None, // not relevant here
+                    };
+
+                    self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
+                        method.def_id,
+                        user_substs,
+                    ))
+                });
+
+                debug!("write_method_call: user_type_annotation={:?}", user_type_annotation);
+                self.write_user_type_annotation(hir_id, user_type_annotation);
+            }
+        }
+    }
+
+    pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
+        if !substs.is_noop() {
+            debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag());
+
+            self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs);
+        }
+    }
+
+    /// Given the substs that we just converted from the HIR, try to
+    /// canonicalize them and store them as user-given substitutions
+    /// (i.e., substitutions that must be respected by the NLL check).
+    ///
+    /// This should be invoked **before any unifications have
+    /// occurred**, so that annotations like `Vec<_>` are preserved
+    /// properly.
+    pub fn write_user_type_annotation_from_substs(
+        &self,
+        hir_id: hir::HirId,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+        user_self_ty: Option<UserSelfTy<'tcx>>,
+    ) {
+        debug!(
+            "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \
+             user_self_ty={:?} in fcx {}",
+            hir_id,
+            def_id,
+            substs,
+            user_self_ty,
+            self.tag(),
+        );
+
+        if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
+            let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf(
+                def_id,
+                UserSubsts { substs, user_self_ty },
+            ));
+            debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized);
+            self.write_user_type_annotation(hir_id, canonicalized);
+        }
+    }
+
+    pub fn write_user_type_annotation(
+        &self,
+        hir_id: hir::HirId,
+        canonical_user_type_annotation: CanonicalUserType<'tcx>,
+    ) {
+        debug!(
+            "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}",
+            hir_id,
+            canonical_user_type_annotation,
+            self.tag(),
+        );
+
+        if !canonical_user_type_annotation.is_identity() {
+            self.typeck_results
+                .borrow_mut()
+                .user_provided_types_mut()
+                .insert(hir_id, canonical_user_type_annotation);
+        } else {
+            debug!("write_user_type_annotation: skipping identity substs");
+        }
+    }
+
+    pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) {
+        debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj);
+
+        if adj.is_empty() {
+            return;
+        }
+
+        let autoborrow_mut = adj.iter().any(|adj| {
+            matches!(adj, &Adjustment {
+                kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })),
+                ..
+            })
+        });
+
+        match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) {
+            Entry::Vacant(entry) => {
+                entry.insert(adj);
+            }
+            Entry::Occupied(mut entry) => {
+                debug!(" - composing on top of {:?}", entry.get());
+                match (&entry.get()[..], &adj[..]) {
+                    // Applying any adjustment on top of a NeverToAny
+                    // is a valid NeverToAny adjustment, because it can't
+                    // be reached.
+                    (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return,
+                    (&[
+                        Adjustment { kind: Adjust::Deref(_), .. },
+                        Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. },
+                    ], &[
+                        Adjustment { kind: Adjust::Deref(_), .. },
+                        .. // Any following adjustments are allowed.
+                    ]) => {
+                        // A reborrow has no effect before a dereference.
+                    }
+                    // FIXME: currently we never try to compose autoderefs
+                    // and ReifyFnPointer/UnsafeFnPointer, but we could.
+                    _ =>
+                        bug!("while adjusting {:?}, can't compose {:?} and {:?}",
+                             expr, entry.get(), adj)
+                };
+                *entry.get_mut() = adj;
+            }
+        }
+
+        // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`.
+        // In this case implicit use of `Deref` and `Index` within `<expr>` should
+        // instead be `DerefMut` and `IndexMut`, so fix those up.
+        if autoborrow_mut {
+            self.convert_place_derefs_to_mutable(expr);
+        }
+    }
+
+    /// Basically whenever we are converting from a type scheme into
+    /// the fn body space, we always want to normalize associated
+    /// types as well. This function combines the two.
+    fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        let value = value.subst(self.tcx, substs);
+        let result = self.normalize_associated_types_in(span, &value);
+        debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result);
+        result
+    }
+
+    /// As `instantiate_type_scheme`, but for the bounds found in a
+    /// generic type scheme.
+    pub(in super::super) fn instantiate_bounds(
+        &self,
+        span: Span,
+        def_id: DefId,
+        substs: SubstsRef<'tcx>,
+    ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) {
+        let bounds = self.tcx.predicates_of(def_id);
+        let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect();
+        let result = bounds.instantiate(self.tcx, substs);
+        let result = self.normalize_associated_types_in(span, &result);
+        debug!(
+            "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}",
+            bounds, substs, result, spans,
+        );
+        (result, spans)
+    }
+
+    /// Replaces the opaque types from the given value with type variables,
+    /// and records the `OpaqueTypeMap` for later use during writeback. See
+    /// `InferCtxt::instantiate_opaque_types` for more details.
+    pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>(
+        &self,
+        parent_id: hir::HirId,
+        value: &T,
+        value_span: Span,
+    ) -> T {
+        let parent_def_id = self.tcx.hir().local_def_id(parent_id);
+        debug!(
+            "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})",
+            parent_def_id, value
+        );
+
+        let (value, opaque_type_map) =
+            self.register_infer_ok_obligations(self.instantiate_opaque_types(
+                parent_def_id,
+                self.body_id,
+                self.param_env,
+                value,
+                value_span,
+            ));
+
+        let mut opaque_types = self.opaque_types.borrow_mut();
+        let mut opaque_types_vars = self.opaque_types_vars.borrow_mut();
+        for (ty, decl) in opaque_type_map {
+            let _ = opaque_types.insert(ty, decl);
+            let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type);
+        }
+
+        value
+    }
+
+    pub(in super::super) fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value)
+    }
+
+    pub(in super::super) fn normalize_associated_types_in_as_infer_ok<T>(
+        &self,
+        span: Span,
+        value: &T,
+    ) -> InferOk<'tcx, T>
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value)
+    }
+
+    pub fn require_type_meets(
+        &self,
+        ty: Ty<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+        def_id: DefId,
+    ) {
+        self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code));
+    }
+
+    pub fn require_type_is_sized(
+        &self,
+        ty: Ty<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+    ) {
+        if !ty.references_error() {
+            let lang_item = self.tcx.require_lang_item(LangItem::Sized, None);
+            self.require_type_meets(ty, span, code, lang_item);
+        }
+    }
+
+    pub fn require_type_is_sized_deferred(
+        &self,
+        ty: Ty<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+    ) {
+        if !ty.references_error() {
+            self.deferred_sized_obligations.borrow_mut().push((ty, span, code));
+        }
+    }
+
+    pub fn register_bound(
+        &self,
+        ty: Ty<'tcx>,
+        def_id: DefId,
+        cause: traits::ObligationCause<'tcx>,
+    ) {
+        if !ty.references_error() {
+            self.fulfillment_cx.borrow_mut().register_bound(
+                self,
+                self.param_env,
+                ty,
+                def_id,
+                cause,
+            );
+        }
+    }
+
+    pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> {
+        let t = AstConv::ast_ty_to_ty(self, ast_t);
+        self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation);
+        t
+    }
+
+    pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
+        let ty = self.to_ty(ast_ty);
+        debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
+
+        if Self::can_contain_user_lifetime_bounds(ty) {
+            let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty));
+            debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
+            self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
+        }
+
+        ty
+    }
+
+    pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
+        let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
+        let c = ty::Const::from_anon_const(self.tcx, const_def_id);
+        self.register_wf_obligation(
+            c.into(),
+            self.tcx.hir().span(ast_c.hir_id),
+            ObligationCauseCode::MiscObligation,
+        );
+        c
+    }
+
+    pub fn const_arg_to_const(
+        &self,
+        ast_c: &hir::AnonConst,
+        param_def_id: DefId,
+    ) -> &'tcx ty::Const<'tcx> {
+        let const_def = ty::WithOptConstParam {
+            did: self.tcx.hir().local_def_id(ast_c.hir_id),
+            const_param_did: Some(param_def_id),
+        };
+        let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def);
+        self.register_wf_obligation(
+            c.into(),
+            self.tcx.hir().span(ast_c.hir_id),
+            ObligationCauseCode::MiscObligation,
+        );
+        c
+    }
+
+    // If the type given by the user has free regions, save it for later, since
+    // NLL would like to enforce those. Also pass in types that involve
+    // projections, since those can resolve to `'static` bounds (modulo #54940,
+    // which hopefully will be fixed by the time you see this comment, dear
+    // reader, although I have my doubts). Also pass in types with inference
+    // types, because they may be repeated. Other sorts of things are already
+    // sufficiently enforced with erased regions. =)
+    fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
+    where
+        T: TypeFoldable<'tcx>,
+    {
+        t.has_free_regions() || t.has_projections() || t.has_infer_types()
+    }
+
+    pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
+        match self.typeck_results.borrow().node_types().get(id) {
+            Some(&t) => t,
+            None if self.is_tainted_by_errors() => self.tcx.ty_error(),
+            None => {
+                bug!(
+                    "no type for node {}: {} in fcx {}",
+                    id,
+                    self.tcx.hir().node_to_string(id),
+                    self.tag()
+                );
+            }
+        }
+    }
+
+    /// Registers an obligation for checking later, during regionck, that `arg` is well-formed.
+    pub fn register_wf_obligation(
+        &self,
+        arg: subst::GenericArg<'tcx>,
+        span: Span,
+        code: traits::ObligationCauseCode<'tcx>,
+    ) {
+        // WF obligations never themselves fail, so no real need to give a detailed cause:
+        let cause = traits::ObligationCause::new(span, self.body_id, code);
+        self.register_predicate(traits::Obligation::new(
+            cause,
+            self.param_env,
+            ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx),
+        ));
+    }
+
+    /// Registers obligations that all `substs` are well-formed.
+    pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) {
+        for arg in substs.iter().filter(|arg| {
+            matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
+        }) {
+            self.register_wf_obligation(arg, expr.span, traits::MiscObligation);
+        }
+    }
+
+    /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each
+    /// type/region parameter was instantiated (`substs`), creates and registers suitable
+    /// trait/region obligations.
+    ///
+    /// For example, if there is a function:
+    ///
+    /// ```
+    /// fn foo<'a,T:'a>(...)
+    /// ```
+    ///
+    /// and a reference:
+    ///
+    /// ```
+    /// let f = foo;
+    /// ```
+    ///
+    /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a`
+    /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally.
+    pub fn add_obligations_for_parameters(
+        &self,
+        cause: traits::ObligationCause<'tcx>,
+        predicates: ty::InstantiatedPredicates<'tcx>,
+    ) {
+        assert!(!predicates.has_escaping_bound_vars());
+
+        debug!("add_obligations_for_parameters(predicates={:?})", predicates);
+
+        for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) {
+            self.register_predicate(obligation);
+        }
+    }
+
+    // FIXME(arielb1): use this instead of field.ty everywhere
+    // Only for fields! Returns <none> for methods>
+    // Indifferent to privacy flags
+    pub fn field_ty(
+        &self,
+        span: Span,
+        field: &'tcx ty::FieldDef,
+        substs: SubstsRef<'tcx>,
+    ) -> Ty<'tcx> {
+        self.normalize_associated_types_in(span, &field.ty(self.tcx, substs))
+    }
+
+    pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
+        let mut generators = self.deferred_generator_interiors.borrow_mut();
+        for (body_id, interior, kind) in generators.drain(..) {
+            self.select_obligations_where_possible(false, |_| {});
+            crate::check::generator_interior::resolve_interior(
+                self, def_id, body_id, interior, kind,
+            );
+        }
+    }
+
+    // Tries to apply a fallback to `ty` if it is an unsolved variable.
+    //
+    // - Unconstrained ints are replaced with `i32`.
+    //
+    // - Unconstrained floats are replaced with with `f64`.
+    //
+    // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
+    //   is enabled. Otherwise, they are replaced with `()`.
+    //
+    // Fallback becomes very dubious if we have encountered type-checking errors.
+    // In that case, fallback to Error.
+    // The return value indicates whether fallback has occurred.
+    pub(in super::super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool {
+        use rustc_middle::ty::error::UnconstrainedNumeric::Neither;
+        use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt};
+
+        assert!(ty.is_ty_infer());
+        let fallback = match self.type_is_unconstrained_numeric(ty) {
+            _ if self.is_tainted_by_errors() => self.tcx().ty_error(),
+            UnconstrainedInt => self.tcx.types.i32,
+            UnconstrainedFloat => self.tcx.types.f64,
+            Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
+            Neither => {
+                // This type variable was created from the instantiation of an opaque
+                // type. The fact that we're attempting to perform fallback for it
+                // means that the function neither constrained it to a concrete
+                // type, nor to the opaque type itself.
+                //
+                // For example, in this code:
+                //
+                //```
+                // type MyType = impl Copy;
+                // fn defining_use() -> MyType { true }
+                // fn other_use() -> MyType { defining_use() }
+                // ```
+                //
+                // `defining_use` will constrain the instantiated inference
+                // variable to `bool`, while `other_use` will constrain
+                // the instantiated inference variable to `MyType`.
+                //
+                // When we process opaque types during writeback, we
+                // will handle cases like `other_use`, and not count
+                // them as defining usages
+                //
+                // However, we also need to handle cases like this:
+                //
+                // ```rust
+                // pub type Foo = impl Copy;
+                // fn produce() -> Option<Foo> {
+                //     None
+                //  }
+                //  ```
+                //
+                // In the above snippet, the inference variable created by
+                // instantiating `Option<Foo>` will be completely unconstrained.
+                // We treat this as a non-defining use by making the inference
+                // variable fall back to the opaque type itself.
+                if let FallbackMode::All = mode {
+                    if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) {
+                        debug!(
+                            "fallback_if_possible: falling back opaque type var {:?} to {:?}",
+                            ty, opaque_ty
+                        );
+                        *opaque_ty
+                    } else {
+                        return false;
+                    }
+                } else {
+                    return false;
+                }
+            }
+        };
+        debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback);
+        self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback);
+        true
+    }
+
+    pub(in super::super) fn select_all_obligations_or_error(&self) {
+        debug!("select_all_obligations_or_error");
+        if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) {
+            self.report_fulfillment_errors(&errors, self.inh.body_id, false);
+        }
+    }
+
+    /// Select as many obligations as we can at present.
+    pub(in super::super) fn select_obligations_where_possible(
+        &self,
+        fallback_has_occurred: bool,
+        mutate_fullfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
+    ) {
+        let result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
+        if let Err(mut errors) = result {
+            mutate_fullfillment_errors(&mut errors);
+            self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
+        }
+    }
+
+    /// For the overloaded place expressions (`*x`, `x[3]`), the trait
+    /// returns a type of `&T`, but the actual type we assign to the
+    /// *expression* is `T`. So this function just peels off the return
+    /// type by one layer to yield `T`.
+    pub(in super::super) fn make_overloaded_place_return_type(
+        &self,
+        method: MethodCallee<'tcx>,
+    ) -> ty::TypeAndMut<'tcx> {
+        // extract method return type, which will be &T;
+        let ret_ty = method.sig.output();
+
+        // method returns &T, but the type as visible to user is T, so deref
+        ret_ty.builtin_deref(true).unwrap()
+    }
+
+    fn self_type_matches_expected_vid(
+        &self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        expected_vid: ty::TyVid,
+    ) -> bool {
+        let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
+        debug!(
+            "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})",
+            trait_ref, self_ty, expected_vid
+        );
+        match *self_ty.kind() {
+            ty::Infer(ty::TyVar(found_vid)) => {
+                // FIXME: consider using `sub_root_var` here so we
+                // can see through subtyping.
+                let found_vid = self.root_var(found_vid);
+                debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid);
+                expected_vid == found_vid
+            }
+            _ => false,
+        }
+    }
+
+    pub(in super::super) fn obligations_for_self_ty<'b>(
+        &'b self,
+        self_ty: ty::TyVid,
+    ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
+    + Captures<'tcx>
+    + 'b {
+        // FIXME: consider using `sub_root_var` here so we
+        // can see through subtyping.
+        let ty_var_root = self.root_var(self_ty);
+        debug!(
+            "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}",
+            self_ty,
+            ty_var_root,
+            self.fulfillment_cx.borrow().pending_obligations()
+        );
+
+        self.fulfillment_cx
+            .borrow()
+            .pending_obligations()
+            .into_iter()
+            .filter_map(move |obligation| {
+                match obligation.predicate.skip_binders() {
+                    ty::PredicateAtom::Projection(data) => {
+                        Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation))
+                    }
+                    ty::PredicateAtom::Trait(data, _) => {
+                        Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation))
+                    }
+                    ty::PredicateAtom::Subtype(..) => None,
+                    ty::PredicateAtom::RegionOutlives(..) => None,
+                    ty::PredicateAtom::TypeOutlives(..) => None,
+                    ty::PredicateAtom::WellFormed(..) => None,
+                    ty::PredicateAtom::ObjectSafe(..) => None,
+                    ty::PredicateAtom::ConstEvaluatable(..) => None,
+                    ty::PredicateAtom::ConstEquate(..) => None,
+                    // N.B., this predicate is created by breaking down a
+                    // `ClosureType: FnFoo()` predicate, where
+                    // `ClosureType` represents some `Closure`. It can't
+                    // possibly be referring to the current closure,
+                    // because we haven't produced the `Closure` for
+                    // this closure yet; this is exactly why the other
+                    // code is looking for a self type of a unresolved
+                    // inference variable.
+                    ty::PredicateAtom::ClosureKind(..) => None,
+                    ty::PredicateAtom::TypeWellFormedFromEnv(..) => None,
+                }
+            })
+            .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
+    }
+
+    pub(in super::super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
+        self.obligations_for_self_ty(self_ty)
+            .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait())
+    }
+
+    pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
+        vec![self.tcx.ty_error(); len]
+    }
+
+    /// Unifies the output type with the expected type early, for more coercions
+    /// and forward type information on the input expressions.
+    pub(in super::super) fn expected_inputs_for_expected_output(
+        &self,
+        call_span: Span,
+        expected_ret: Expectation<'tcx>,
+        formal_ret: Ty<'tcx>,
+        formal_args: &[Ty<'tcx>],
+    ) -> Vec<Ty<'tcx>> {
+        let formal_ret = self.resolve_vars_with_obligations(formal_ret);
+        let ret_ty = match expected_ret.only_has_type(self) {
+            Some(ret) => ret,
+            None => return Vec::new(),
+        };
+        let expect_args = self
+            .fudge_inference_if_ok(|| {
+                // Attempt to apply a subtyping relationship between the formal
+                // return type (likely containing type variables if the function
+                // is polymorphic) and the expected return type.
+                // No argument expectations are produced if unification fails.
+                let origin = self.misc(call_span);
+                let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret);
+
+                // FIXME(#27336) can't use ? here, Try::from_error doesn't default
+                // to identity so the resulting type is not constrained.
+                match ures {
+                    Ok(ok) => {
+                        // Process any obligations locally as much as
+                        // we can.  We don't care if some things turn
+                        // out unconstrained or ambiguous, as we're
+                        // just trying to get hints here.
+                        self.save_and_restore_in_snapshot_flag(|_| {
+                            let mut fulfill = TraitEngine::new(self.tcx);
+                            for obligation in ok.obligations {
+                                fulfill.register_predicate_obligation(self, obligation);
+                            }
+                            fulfill.select_where_possible(self)
+                        })
+                        .map_err(|_| ())?;
+                    }
+                    Err(_) => return Err(()),
+                }
+
+                // Record all the argument types, with the substitutions
+                // produced from the above subtyping unification.
+                Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect())
+            })
+            .unwrap_or_default();
+        debug!(
+            "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})",
+            formal_args, formal_ret, expect_args, expected_ret
+        );
+        expect_args
+    }
+
+    pub(in super::super) fn resolve_lang_item_path(
+        &self,
+        lang_item: hir::LangItem,
+        span: Span,
+        hir_id: hir::HirId,
+    ) -> (Res, Ty<'tcx>) {
+        let def_id = self.tcx.require_lang_item(lang_item, Some(span));
+        let def_kind = self.tcx.def_kind(def_id);
+
+        let item_ty = if let DefKind::Variant = def_kind {
+            self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent"))
+        } else {
+            self.tcx.type_of(def_id)
+        };
+        let substs = self.infcx.fresh_substs_for_item(span, def_id);
+        let ty = item_ty.subst(self.tcx, substs);
+
+        self.write_resolution(hir_id, Ok((def_kind, def_id)));
+        self.add_required_obligations(span, def_id, &substs);
+        (Res::Def(def_kind, def_id), ty)
+    }
+
+    /// Resolves an associated value path into a base type and associated constant, or method
+    /// resolution. The newly resolved definition is written into `type_dependent_defs`.
+    pub fn resolve_ty_and_res_ufcs<'b>(
+        &self,
+        qpath: &'b QPath<'b>,
+        hir_id: hir::HirId,
+        span: Span,
+    ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) {
+        debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span);
+        let (ty, qself, item_segment) = match *qpath {
+            QPath::Resolved(ref opt_qself, ref path) => {
+                return (
+                    path.res,
+                    opt_qself.as_ref().map(|qself| self.to_ty(qself)),
+                    &path.segments[..],
+                );
+            }
+            QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
+            QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"),
+        };
+        if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
+        {
+            // Return directly on cache hit. This is useful to avoid doubly reporting
+            // errors with default match binding modes. See #44614.
+            let def =
+                cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err);
+            return (def, Some(ty), slice::from_ref(&**item_segment));
+        }
+        let item_name = item_segment.ident;
+        let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| {
+            let result = match error {
+                method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
+                _ => Err(ErrorReported),
+            };
+            if item_name.name != kw::Invalid {
+                if let Some(mut e) = self.report_method_error(
+                    span,
+                    ty,
+                    item_name,
+                    SelfSource::QPath(qself),
+                    error,
+                    None,
+                ) {
+                    e.emit();
+                }
+            }
+            result
+        });
+
+        // Write back the new resolution.
+        self.write_resolution(hir_id, result);
+        (
+            result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err),
+            Some(ty),
+            slice::from_ref(&**item_segment),
+        )
+    }
+
+    /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
+    pub(in super::super) fn get_node_fn_decl(
+        &self,
+        node: Node<'tcx>,
+    ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> {
+        match node {
+            Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => {
+                // This is less than ideal, it will not suggest a return type span on any
+                // method called `main`, regardless of whether it is actually the entry point,
+                // but it will still present it as the reason for the expected type.
+                Some((&sig.decl, ident, ident.name != sym::main))
+            }
+            Node::TraitItem(&hir::TraitItem {
+                ident,
+                kind: hir::TraitItemKind::Fn(ref sig, ..),
+                ..
+            }) => Some((&sig.decl, ident, true)),
+            Node::ImplItem(&hir::ImplItem {
+                ident,
+                kind: hir::ImplItemKind::Fn(ref sig, ..),
+                ..
+            }) => Some((&sig.decl, ident, false)),
+            _ => None,
+        }
+    }
+
+    /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a
+    /// suggestion can be made, `None` otherwise.
+    pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> {
+        // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
+        // `while` before reaching it, as block tail returns are not available in them.
+        self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
+            let parent = self.tcx.hir().get(blk_id);
+            self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
+        })
+    }
+
+    pub(in super::super) fn note_internal_mutation_in_method(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        if found != self.tcx.types.unit {
+            return;
+        }
+        if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind {
+            if self
+                .typeck_results
+                .borrow()
+                .expr_ty_adjusted_opt(rcvr)
+                .map_or(true, |ty| expected.peel_refs() != ty.peel_refs())
+            {
+                return;
+            }
+            let mut sp = MultiSpan::from_span(path_segment.ident.span);
+            sp.push_span_label(
+                path_segment.ident.span,
+                format!(
+                    "this call modifies {} in-place",
+                    match rcvr.kind {
+                        ExprKind::Path(QPath::Resolved(
+                            None,
+                            hir::Path { segments: [segment], .. },
+                        )) => format!("`{}`", segment.ident),
+                        _ => "its receiver".to_string(),
+                    }
+                ),
+            );
+            sp.push_span_label(
+                rcvr.span,
+                "you probably want to use this value after calling the method...".to_string(),
+            );
+            err.span_note(
+                sp,
+                &format!("method `{}` modifies its receiver in-place", path_segment.ident),
+            );
+            err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident));
+        }
+    }
+
+    pub(in super::super) fn note_need_for_fn_pointer(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        let (sig, did, substs) = match (&expected.kind(), &found.kind()) {
+            (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
+                let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1);
+                let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2);
+                if sig1 != sig2 {
+                    return;
+                }
+                err.note(
+                    "different `fn` items always have unique types, even if their signatures are \
+                     the same",
+                );
+                (sig1, *did1, substs1)
+            }
+            (ty::FnDef(did, substs), ty::FnPtr(sig2)) => {
+                let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs);
+                if sig1 != *sig2 {
+                    return;
+                }
+                (sig1, *did, substs)
+            }
+            _ => return,
+        };
+        err.help(&format!("change the expected type to be function pointer `{}`", sig));
+        err.help(&format!(
+            "if the expected type is due to type inference, cast the expected `fn` to a function \
+             pointer: `{} as {}`",
+            self.tcx.def_path_str_with_substs(did, substs),
+            sig
+        ));
+    }
+
+    pub(in super::super) fn could_remove_semicolon(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected_ty: Ty<'tcx>,
+    ) -> Option<Span> {
+        // Be helpful when the user wrote `{... expr;}` and
+        // taking the `;` off is enough to fix the error.
+        let last_stmt = blk.stmts.last()?;
+        let last_expr = match last_stmt.kind {
+            hir::StmtKind::Semi(ref e) => e,
+            _ => return None,
+        };
+        let last_expr_ty = self.node_ty(last_expr.hir_id);
+        if matches!(last_expr_ty.kind(), ty::Error(_))
+            || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err()
+        {
+            return None;
+        }
+        let original_span = original_sp(last_stmt.span, blk.span);
+        Some(original_span.with_lo(original_span.hi() - BytePos(1)))
+    }
+
+    // Instantiates the given path, which must refer to an item with the given
+    // number of type parameters and type.
+    pub fn instantiate_value_path(
+        &self,
+        segments: &[hir::PathSegment<'_>],
+        self_ty: Option<Ty<'tcx>>,
+        res: Res,
+        span: Span,
+        hir_id: hir::HirId,
+    ) -> (Ty<'tcx>, Res) {
+        debug!(
+            "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})",
+            segments, self_ty, res, hir_id,
+        );
+
+        let tcx = self.tcx;
+
+        let path_segs = match res {
+            Res::Local(_) | Res::SelfCtor(_) => vec![],
+            Res::Def(kind, def_id) => {
+                AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id)
+            }
+            _ => bug!("instantiate_value_path on {:?}", res),
+        };
+
+        let mut user_self_ty = None;
+        let mut is_alias_variant_ctor = false;
+        match res {
+            Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => {
+                if let Some(self_ty) = self_ty {
+                    let adt_def = self_ty.ty_adt_def().unwrap();
+                    user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty });
+                    is_alias_variant_ctor = true;
+                }
+            }
+            Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => {
+                let container = tcx.associated_item(def_id).container;
+                debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container);
+                match container {
+                    ty::TraitContainer(trait_did) => {
+                        callee::check_legal_trait_for_method_call(tcx, span, None, trait_did)
+                    }
+                    ty::ImplContainer(impl_def_id) => {
+                        if segments.len() == 1 {
+                            // `<T>::assoc` will end up here, and so
+                            // can `T::assoc`. It this came from an
+                            // inherent impl, we need to record the
+                            // `T` for posterity (see `UserSelfTy` for
+                            // details).
+                            let self_ty = self_ty.expect("UFCS sugared assoc missing Self");
+                            user_self_ty = Some(UserSelfTy { impl_def_id, self_ty });
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+
+        // Now that we have categorized what space the parameters for each
+        // segment belong to, let's sort out the parameters that the user
+        // provided (if any) into their appropriate spaces. We'll also report
+        // errors if type parameters are provided in an inappropriate place.
+
+        let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect();
+        let generics_has_err = AstConv::prohibit_generics(
+            self,
+            segments.iter().enumerate().filter_map(|(index, seg)| {
+                if !generic_segs.contains(&index) || is_alias_variant_ctor {
+                    Some(seg)
+                } else {
+                    None
+                }
+            }),
+        );
+
+        if let Res::Local(hid) = res {
+            let ty = self.local_ty(span, hid).decl_ty;
+            let ty = self.normalize_associated_types_in(span, &ty);
+            self.write_ty(hir_id, ty);
+            return (ty, res);
+        }
+
+        if generics_has_err {
+            // Don't try to infer type parameters when prohibited generic arguments were given.
+            user_self_ty = None;
+        }
+
+        // Now we have to compare the types that the user *actually*
+        // provided against the types that were *expected*. If the user
+        // did not provide any types, then we want to substitute inference
+        // variables. If the user provided some types, we may still need
+        // to add defaults. If the user provided *too many* types, that's
+        // a problem.
+
+        let mut infer_args_for_err = FxHashSet::default();
+        for &PathSeg(def_id, index) in &path_segs {
+            let seg = &segments[index];
+            let generics = tcx.generics_of(def_id);
+            // Argument-position `impl Trait` is treated as a normal generic
+            // parameter internally, but we don't allow users to specify the
+            // parameter's value explicitly, so we have to do some error-
+            // checking here.
+            if let GenericArgCountResult {
+                correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }),
+                ..
+            } = AstConv::check_generic_arg_count_for_call(
+                tcx, span, &generics, &seg, false, // `is_method_call`
+            ) {
+                infer_args_for_err.insert(index);
+                self.set_tainted_by_errors(); // See issue #53251.
+            }
+        }
+
+        let has_self = path_segs
+            .last()
+            .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self)
+            .unwrap_or(false);
+
+        let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
+            let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id));
+            match *ty.kind() {
+                ty::Adt(adt_def, substs) if adt_def.has_ctor() => {
+                    let variant = adt_def.non_enum_variant();
+                    let ctor_def_id = variant.ctor_def_id.unwrap();
+                    (
+                        Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id),
+                        Some(substs),
+                    )
+                }
+                _ => {
+                    let mut err = tcx.sess.struct_span_err(
+                        span,
+                        "the `Self` constructor can only be used with tuple or unit structs",
+                    );
+                    if let Some(adt_def) = ty.ty_adt_def() {
+                        match adt_def.adt_kind() {
+                            AdtKind::Enum => {
+                                err.help("did you mean to use one of the enum's variants?");
+                            }
+                            AdtKind::Struct | AdtKind::Union => {
+                                err.span_suggestion(
+                                    span,
+                                    "use curly brackets",
+                                    String::from("Self { /* fields */ }"),
+                                    Applicability::HasPlaceholders,
+                                );
+                            }
+                        }
+                    }
+                    err.emit();
+
+                    return (tcx.ty_error(), res);
+                }
+            }
+        } else {
+            (res, None)
+        };
+        let def_id = res.def_id();
+
+        // The things we are substituting into the type should not contain
+        // escaping late-bound regions, and nor should the base type scheme.
+        let ty = tcx.type_of(def_id);
+
+        let arg_count = GenericArgCountResult {
+            explicit_late_bound: ExplicitLateBound::No,
+            correct: if infer_args_for_err.is_empty() {
+                Ok(())
+            } else {
+                Err(GenericArgCountMismatch::default())
+            },
+        };
+
+        let substs = self_ctor_substs.unwrap_or_else(|| {
+            AstConv::create_substs_for_generic_args(
+                tcx,
+                def_id,
+                &[][..],
+                has_self,
+                self_ty,
+                arg_count,
+                // Provide the generic args, and whether types should be inferred.
+                |def_id| {
+                    if let Some(&PathSeg(_, index)) =
+                        path_segs.iter().find(|&PathSeg(did, _)| *did == def_id)
+                    {
+                        // If we've encountered an `impl Trait`-related error, we're just
+                        // going to infer the arguments for better error messages.
+                        if !infer_args_for_err.contains(&index) {
+                            // Check whether the user has provided generic arguments.
+                            if let Some(ref data) = segments[index].args {
+                                return (Some(data), segments[index].infer_args);
+                            }
+                        }
+                        return (None, segments[index].infer_args);
+                    }
+
+                    (None, true)
+                },
+                // Provide substitutions for parameters for which (valid) arguments have been provided.
+                |param, arg| match (&param.kind, arg) {
+                    (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
+                        AstConv::ast_region_to_region(self, lt, Some(param)).into()
+                    }
+                    (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
+                        self.to_ty(ty).into()
+                    }
+                    (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
+                        self.const_arg_to_const(&ct.value, param.def_id).into()
+                    }
+                    _ => unreachable!(),
+                },
+                // Provide substitutions for parameters for which arguments are inferred.
+                |substs, param, infer_args| {
+                    match param.kind {
+                        GenericParamDefKind::Lifetime => {
+                            self.re_infer(Some(param), span).unwrap().into()
+                        }
+                        GenericParamDefKind::Type { has_default, .. } => {
+                            if !infer_args && has_default {
+                                // If we have a default, then we it doesn't matter that we're not
+                                // inferring the type arguments: we provide the default where any
+                                // is missing.
+                                let default = tcx.type_of(param.def_id);
+                                self.normalize_ty(
+                                    span,
+                                    default.subst_spanned(tcx, substs.unwrap(), Some(span)),
+                                )
+                                .into()
+                            } else {
+                                // If no type arguments were provided, we have to infer them.
+                                // This case also occurs as a result of some malformed input, e.g.
+                                // a lifetime argument being given instead of a type parameter.
+                                // Using inference instead of `Error` gives better error messages.
+                                self.var_for_def(span, param)
+                            }
+                        }
+                        GenericParamDefKind::Const => {
+                            // FIXME(const_generics:defaults)
+                            // No const parameters were provided, we have to infer them.
+                            self.var_for_def(span, param)
+                        }
+                    }
+                },
+            )
+        });
+        assert!(!substs.has_escaping_bound_vars());
+        assert!(!ty.has_escaping_bound_vars());
+
+        // First, store the "user substs" for later.
+        self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty);
+
+        self.add_required_obligations(span, def_id, &substs);
+
+        // Substitute the values for the type parameters into the type of
+        // the referenced item.
+        let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty);
+
+        if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
+            // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method`
+            // is inherent, there is no `Self` parameter; instead, the impl needs
+            // type parameters, which we can infer by unifying the provided `Self`
+            // with the substituted impl type.
+            // This also occurs for an enum variant on a type alias.
+            let ty = tcx.type_of(impl_def_id);
+
+            let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
+            match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
+                Ok(ok) => self.register_infer_ok_obligations(ok),
+                Err(_) => {
+                    self.tcx.sess.delay_span_bug(
+                        span,
+                        &format!(
+                        "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
+                        self_ty,
+                        impl_ty,
+                    ),
+                    );
+                }
+            }
+        }
+
+        self.check_rustc_args_require_const(def_id, hir_id, span);
+
+        debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted);
+        self.write_substs(hir_id, substs);
+
+        (ty_substituted, res)
+    }
+
+    /// Add all the obligations that are required, substituting and normalized appropriately.
+    fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) {
+        let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs);
+
+        for (i, mut obligation) in traits::predicates_for_generics(
+            traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)),
+            self.param_env,
+            bounds,
+        )
+        .enumerate()
+        {
+            // This makes the error point at the bound, but we want to point at the argument
+            if let Some(span) = spans.get(i) {
+                obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span);
+            }
+            self.register_predicate(obligation);
+        }
+    }
+
+    /// Resolves `typ` by a single level if `typ` is a type variable.
+    /// If no resolution is possible, then an error is reported.
+    /// Numeric inference variables may be left unresolved.
+    pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.resolve_vars_with_obligations(ty);
+        if !ty.is_ty_var() {
+            ty
+        } else {
+            if !self.is_tainted_by_errors() {
+                self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282)
+                    .note("type must be known at this point")
+                    .emit();
+            }
+            let err = self.tcx.ty_error();
+            self.demand_suptype(sp, err, ty);
+            err
+        }
+    }
+
+    pub(in super::super) fn with_breakable_ctxt<F: FnOnce() -> R, R>(
+        &self,
+        id: hir::HirId,
+        ctxt: BreakableCtxt<'tcx>,
+        f: F,
+    ) -> (BreakableCtxt<'tcx>, R) {
+        let index;
+        {
+            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
+            index = enclosing_breakables.stack.len();
+            enclosing_breakables.by_id.insert(id, index);
+            enclosing_breakables.stack.push(ctxt);
+        }
+        let result = f();
+        let ctxt = {
+            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
+            debug_assert!(enclosing_breakables.stack.len() == index + 1);
+            enclosing_breakables.by_id.remove(&id).expect("missing breakable context");
+            enclosing_breakables.stack.pop().expect("missing breakable context")
+        };
+        (ctxt, result)
+    }
+
+    /// Instantiate a QueryResponse in a probe context, without a
+    /// good ObligationCause.
+    pub(in super::super) fn probe_instantiate_query_response(
+        &self,
+        span: Span,
+        original_values: &OriginalQueryValues<'tcx>,
+        query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+    ) -> InferResult<'tcx, Ty<'tcx>> {
+        self.instantiate_query_response_and_region_obligations(
+            &traits::ObligationCause::misc(span, self.body_id),
+            self.param_env,
+            original_values,
+            query_result,
+        )
+    }
+
+    /// Returns `true` if an expression is contained inside the LHS of an assignment expression.
+    pub(in super::super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool {
+        let mut contained_in_place = false;
+
+        while let hir::Node::Expr(parent_expr) =
+            self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id))
+        {
+            match &parent_expr.kind {
+                hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
+                    if lhs.hir_id == expr_id {
+                        contained_in_place = true;
+                        break;
+                    }
+                }
+                _ => (),
+            }
+            expr_id = parent_expr.hir_id;
+        }
+
+        contained_in_place
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
new file mode 100644
index 00000000000..fd2f5eb5018
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -0,0 +1,996 @@
+use crate::astconv::AstConv;
+use crate::check::coercion::CoerceMany;
+use crate::check::method::MethodCallee;
+use crate::check::Expectation::*;
+use crate::check::TupleArgumentsFlag::*;
+use crate::check::{
+    potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt,
+    LocalTy, Needs, TupleArgumentsFlag,
+};
+
+use rustc_ast as ast;
+use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::DefId;
+use rustc_hir::{ExprKind, Node, QPath};
+use rustc_middle::ty::adjustment::AllowTwoPhase;
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::{self, Ty};
+use rustc_session::Session;
+use rustc_span::symbol::{sym, Ident};
+use rustc_span::{self, MultiSpan, Span};
+use rustc_trait_selection::traits::{self, ObligationCauseCode};
+
+use std::mem::replace;
+use std::slice;
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub(in super::super) fn check_casts(&self) {
+        let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
+        for cast in deferred_cast_checks.drain(..) {
+            cast.check(self);
+        }
+    }
+
+    pub(in super::super) fn check_method_argument_types(
+        &self,
+        sp: Span,
+        expr: &'tcx hir::Expr<'tcx>,
+        method: Result<MethodCallee<'tcx>, ()>,
+        args_no_rcvr: &'tcx [hir::Expr<'tcx>],
+        tuple_arguments: TupleArgumentsFlag,
+        expected: Expectation<'tcx>,
+    ) -> Ty<'tcx> {
+        let has_error = match method {
+            Ok(method) => method.substs.references_error() || method.sig.references_error(),
+            Err(_) => true,
+        };
+        if has_error {
+            let err_inputs = self.err_args(args_no_rcvr.len());
+
+            let err_inputs = match tuple_arguments {
+                DontTupleArguments => err_inputs,
+                TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])],
+            };
+
+            self.check_argument_types(
+                sp,
+                expr,
+                &err_inputs[..],
+                &[],
+                args_no_rcvr,
+                false,
+                tuple_arguments,
+                None,
+            );
+            return self.tcx.ty_error();
+        }
+
+        let method = method.unwrap();
+        // HACK(eddyb) ignore self in the definition (see above).
+        let expected_arg_tys = self.expected_inputs_for_expected_output(
+            sp,
+            expected,
+            method.sig.output(),
+            &method.sig.inputs()[1..],
+        );
+        self.check_argument_types(
+            sp,
+            expr,
+            &method.sig.inputs()[1..],
+            &expected_arg_tys[..],
+            args_no_rcvr,
+            method.sig.c_variadic,
+            tuple_arguments,
+            Some(method.def_id),
+        );
+        method.sig.output()
+    }
+
+    /// Generic function that factors out common logic from function calls,
+    /// method calls and overloaded operators.
+    pub(in super::super) fn check_argument_types(
+        &self,
+        sp: Span,
+        expr: &'tcx hir::Expr<'tcx>,
+        fn_inputs: &[Ty<'tcx>],
+        expected_arg_tys: &[Ty<'tcx>],
+        args: &'tcx [hir::Expr<'tcx>],
+        c_variadic: bool,
+        tuple_arguments: TupleArgumentsFlag,
+        def_id: Option<DefId>,
+    ) {
+        let tcx = self.tcx;
+        // Grab the argument types, supplying fresh type variables
+        // if the wrong number of arguments were supplied
+        let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 };
+
+        // All the input types from the fn signature must outlive the call
+        // so as to validate implied bounds.
+        for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) {
+            self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
+        }
+
+        let expected_arg_count = fn_inputs.len();
+
+        let param_count_error = |expected_count: usize,
+                                 arg_count: usize,
+                                 error_code: &str,
+                                 c_variadic: bool,
+                                 sugg_unit: bool| {
+            let (span, start_span, args) = match &expr.kind {
+                hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]),
+                hir::ExprKind::MethodCall(path_segment, span, args, _) => (
+                    *span,
+                    // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
+                    path_segment
+                        .args
+                        .and_then(|args| args.args.iter().last())
+                        // Account for `foo.bar::<T>()`.
+                        .map(|arg| {
+                            // Skip the closing `>`.
+                            tcx.sess
+                                .source_map()
+                                .next_point(tcx.sess.source_map().next_point(arg.span()))
+                        })
+                        .unwrap_or(*span),
+                    &args[1..], // Skip the receiver.
+                ),
+                k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k),
+            };
+            let arg_spans = if args.is_empty() {
+                // foo()
+                // ^^^-- supplied 0 arguments
+                // |
+                // expected 2 arguments
+                vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())]
+            } else {
+                // foo(1, 2, 3)
+                // ^^^ -  -  - supplied 3 arguments
+                // |
+                // expected 2 arguments
+                args.iter().map(|arg| arg.span).collect::<Vec<Span>>()
+            };
+
+            let mut err = tcx.sess.struct_span_err_with_code(
+                span,
+                &format!(
+                    "this function takes {}{} but {} {} supplied",
+                    if c_variadic { "at least " } else { "" },
+                    potentially_plural_count(expected_count, "argument"),
+                    potentially_plural_count(arg_count, "argument"),
+                    if arg_count == 1 { "was" } else { "were" }
+                ),
+                DiagnosticId::Error(error_code.to_owned()),
+            );
+            let label = format!("supplied {}", potentially_plural_count(arg_count, "argument"));
+            for (i, span) in arg_spans.into_iter().enumerate() {
+                err.span_label(
+                    span,
+                    if arg_count == 0 || i + 1 == arg_count { &label } else { "" },
+                );
+            }
+
+            if let Some(def_id) = def_id {
+                if let Some(node) = tcx.hir().get_if_local(def_id) {
+                    let mut spans: MultiSpan = node
+                        .ident()
+                        .map(|ident| ident.span)
+                        .unwrap_or_else(|| tcx.hir().span(node.hir_id().unwrap()))
+                        .into();
+
+                    if let Some(id) = node.body_id() {
+                        let body = tcx.hir().body(id);
+                        for param in body.params {
+                            spans.push_span_label(param.span, String::new());
+                        }
+                    }
+
+                    let def_kind = tcx.def_kind(def_id);
+                    err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
+                }
+            }
+
+            if sugg_unit {
+                let sugg_span = tcx.sess.source_map().end_point(expr.span);
+                // remove closing `)` from the span
+                let sugg_span = sugg_span.shrink_to_lo();
+                err.span_suggestion(
+                    sugg_span,
+                    "expected the unit value `()`; create it with empty parentheses",
+                    String::from("()"),
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                err.span_label(
+                    span,
+                    format!(
+                        "expected {}{}",
+                        if c_variadic { "at least " } else { "" },
+                        potentially_plural_count(expected_count, "argument")
+                    ),
+                );
+            }
+            err.emit();
+        };
+
+        let mut expected_arg_tys = expected_arg_tys.to_vec();
+
+        let formal_tys = if tuple_arguments == TupleArguments {
+            let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
+            match tuple_type.kind() {
+                ty::Tuple(arg_types) if arg_types.len() != args.len() => {
+                    param_count_error(arg_types.len(), args.len(), "E0057", false, false);
+                    expected_arg_tys = vec![];
+                    self.err_args(args.len())
+                }
+                ty::Tuple(arg_types) => {
+                    expected_arg_tys = match expected_arg_tys.get(0) {
+                        Some(&ty) => match ty.kind() {
+                            ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
+                            _ => vec![],
+                        },
+                        None => vec![],
+                    };
+                    arg_types.iter().map(|k| k.expect_ty()).collect()
+                }
+                _ => {
+                    struct_span_err!(
+                        tcx.sess,
+                        sp,
+                        E0059,
+                        "cannot use call notation; the first type parameter \
+                         for the function trait is neither a tuple nor unit"
+                    )
+                    .emit();
+                    expected_arg_tys = vec![];
+                    self.err_args(args.len())
+                }
+            }
+        } else if expected_arg_count == supplied_arg_count {
+            fn_inputs.to_vec()
+        } else if c_variadic {
+            if supplied_arg_count >= expected_arg_count {
+                fn_inputs.to_vec()
+            } else {
+                param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
+                expected_arg_tys = vec![];
+                self.err_args(supplied_arg_count)
+            }
+        } else {
+            // is the missing argument of type `()`?
+            let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 {
+                self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit()
+            } else if fn_inputs.len() == 1 && supplied_arg_count == 0 {
+                self.resolve_vars_if_possible(&fn_inputs[0]).is_unit()
+            } else {
+                false
+            };
+            param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
+
+            expected_arg_tys = vec![];
+            self.err_args(supplied_arg_count)
+        };
+
+        debug!(
+            "check_argument_types: formal_tys={:?}",
+            formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
+        );
+
+        // If there is no expectation, expect formal_tys.
+        let expected_arg_tys =
+            if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() };
+
+        let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
+
+        // Check the arguments.
+        // We do this in a pretty awful way: first we type-check any arguments
+        // that are not closures, then we type-check the closures. This is so
+        // that we have more information about the types of arguments when we
+        // type-check the functions. This isn't really the right way to do this.
+        for &check_closures in &[false, true] {
+            debug!("check_closures={}", check_closures);
+
+            // More awful hacks: before we check argument types, try to do
+            // an "opportunistic" trait resolution of any trait bounds on
+            // the call. This helps coercions.
+            if check_closures {
+                self.select_obligations_where_possible(false, |errors| {
+                    self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
+                    self.point_at_arg_instead_of_call_if_possible(
+                        errors,
+                        &final_arg_types[..],
+                        sp,
+                        &args,
+                    );
+                })
+            }
+
+            // For C-variadic functions, we don't have a declared type for all of
+            // the arguments hence we only do our usual type checking with
+            // the arguments who's types we do know.
+            let t = if c_variadic {
+                expected_arg_count
+            } else if tuple_arguments == TupleArguments {
+                args.len()
+            } else {
+                supplied_arg_count
+            };
+            for (i, arg) in args.iter().take(t).enumerate() {
+                // Warn only for the first loop (the "no closures" one).
+                // Closure arguments themselves can't be diverging, but
+                // a previous argument can, e.g., `foo(panic!(), || {})`.
+                if !check_closures {
+                    self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
+                }
+
+                let is_closure = match arg.kind {
+                    ExprKind::Closure(..) => true,
+                    _ => false,
+                };
+
+                if is_closure != check_closures {
+                    continue;
+                }
+
+                debug!("checking the argument");
+                let formal_ty = formal_tys[i];
+
+                // The special-cased logic below has three functions:
+                // 1. Provide as good of an expected type as possible.
+                let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]);
+
+                let checked_ty = self.check_expr_with_expectation(&arg, expected);
+
+                // 2. Coerce to the most detailed type that could be coerced
+                //    to, which is `expected_ty` if `rvalue_hint` returns an
+                //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
+                let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
+                // We're processing function arguments so we definitely want to use
+                // two-phase borrows.
+                self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
+                final_arg_types.push((i, checked_ty, coerce_ty));
+
+                // 3. Relate the expected type and the formal one,
+                //    if the expected type was used for the coercion.
+                self.demand_suptype(arg.span, formal_ty, coerce_ty);
+            }
+        }
+
+        // We also need to make sure we at least write the ty of the other
+        // arguments which we skipped above.
+        if c_variadic {
+            fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) {
+                use crate::structured_errors::{StructuredDiagnostic, VariadicError};
+                VariadicError::new(s, span, t, cast_ty).diagnostic().emit();
+            }
+
+            for arg in args.iter().skip(expected_arg_count) {
+                let arg_ty = self.check_expr(&arg);
+
+                // There are a few types which get autopromoted when passed via varargs
+                // in C but we just error out instead and require explicit casts.
+                let arg_ty = self.structurally_resolved_type(arg.span, arg_ty);
+                match arg_ty.kind() {
+                    ty::Float(ast::FloatTy::F32) => {
+                        variadic_error(tcx.sess, arg.span, arg_ty, "c_double");
+                    }
+                    ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => {
+                        variadic_error(tcx.sess, arg.span, arg_ty, "c_int");
+                    }
+                    ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => {
+                        variadic_error(tcx.sess, arg.span, arg_ty, "c_uint");
+                    }
+                    ty::FnDef(..) => {
+                        let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx));
+                        let ptr_ty = self.resolve_vars_if_possible(&ptr_ty);
+                        variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string());
+                    }
+                    _ => {}
+                }
+            }
+        }
+    }
+
+    // AST fragment checking
+    pub(in super::super) fn check_lit(
+        &self,
+        lit: &hir::Lit,
+        expected: Expectation<'tcx>,
+    ) -> Ty<'tcx> {
+        let tcx = self.tcx;
+
+        match lit.node {
+            ast::LitKind::Str(..) => tcx.mk_static_str(),
+            ast::LitKind::ByteStr(ref v) => {
+                tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64))
+            }
+            ast::LitKind::Byte(_) => tcx.types.u8,
+            ast::LitKind::Char(_) => tcx.types.char,
+            ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t),
+            ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t),
+            ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
+                let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
+                    ty::Int(_) | ty::Uint(_) => Some(ty),
+                    ty::Char => Some(tcx.types.u8),
+                    ty::RawPtr(..) => Some(tcx.types.usize),
+                    ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize),
+                    _ => None,
+                });
+                opt_ty.unwrap_or_else(|| self.next_int_var())
+            }
+            ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t),
+            ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
+                let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() {
+                    ty::Float(_) => Some(ty),
+                    _ => None,
+                });
+                opt_ty.unwrap_or_else(|| self.next_float_var())
+            }
+            ast::LitKind::Bool(_) => tcx.types.bool,
+            ast::LitKind::Err(_) => tcx.ty_error(),
+        }
+    }
+
+    pub fn check_struct_path(
+        &self,
+        qpath: &QPath<'_>,
+        hir_id: hir::HirId,
+    ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> {
+        let path_span = qpath.qself_span();
+        let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id);
+        let variant = match def {
+            Res::Err => {
+                self.set_tainted_by_errors();
+                return None;
+            }
+            Res::Def(DefKind::Variant, _) => match ty.kind() {
+                ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)),
+                _ => bug!("unexpected type: {:?}", ty),
+            },
+            Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
+            | Res::SelfTy(..) => match ty.kind() {
+                ty::Adt(adt, substs) if !adt.is_enum() => {
+                    Some((adt.non_enum_variant(), adt.did, substs))
+                }
+                _ => None,
+            },
+            _ => bug!("unexpected definition: {:?}", def),
+        };
+
+        if let Some((variant, did, substs)) = variant {
+            debug!("check_struct_path: did={:?} substs={:?}", did, substs);
+            self.write_user_type_annotation_from_substs(hir_id, did, substs, None);
+
+            // Check bounds on type arguments used in the path.
+            let (bounds, _) = self.instantiate_bounds(path_span, did, substs);
+            let cause =
+                traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did));
+            self.add_obligations_for_parameters(cause, bounds);
+
+            Some((variant, ty))
+        } else {
+            struct_span_err!(
+                self.tcx.sess,
+                path_span,
+                E0071,
+                "expected struct, variant or union type, found {}",
+                ty.sort_string(self.tcx)
+            )
+            .span_label(path_span, "not a struct")
+            .emit();
+            None
+        }
+    }
+
+    pub fn check_decl_initializer(
+        &self,
+        local: &'tcx hir::Local<'tcx>,
+        init: &'tcx hir::Expr<'tcx>,
+    ) -> Ty<'tcx> {
+        // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed
+        // for #42640 (default match binding modes).
+        //
+        // See #44848.
+        let ref_bindings = local.pat.contains_explicit_ref_binding();
+
+        let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty;
+        if let Some(m) = ref_bindings {
+            // Somewhat subtle: if we have a `ref` binding in the pattern,
+            // we want to avoid introducing coercions for the RHS. This is
+            // both because it helps preserve sanity and, in the case of
+            // ref mut, for soundness (issue #23116). In particular, in
+            // the latter case, we need to be clear that the type of the
+            // referent for the reference that results is *equal to* the
+            // type of the place it is referencing, and not some
+            // supertype thereof.
+            let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m));
+            self.demand_eqtype(init.span, local_ty, init_ty);
+            init_ty
+        } else {
+            self.check_expr_coercable_to_type(init, local_ty, None)
+        }
+    }
+
+    /// Type check a `let` statement.
+    pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) {
+        // Determine and write the type which we'll check the pattern against.
+        let ty = self.local_ty(local.span, local.hir_id).decl_ty;
+        self.write_ty(local.hir_id, ty);
+
+        // Type check the initializer.
+        if let Some(ref init) = local.init {
+            let init_ty = self.check_decl_initializer(local, &init);
+            self.overwrite_local_ty_if_err(local, ty, init_ty);
+        }
+
+        // Does the expected pattern type originate from an expression and what is the span?
+        let (origin_expr, ty_span) = match (local.ty, local.init) {
+            (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type.
+            (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee.
+            _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained.
+        };
+
+        // Type check the pattern. Override if necessary to avoid knock-on errors.
+        self.check_pat_top(&local.pat, ty, ty_span, origin_expr);
+        let pat_ty = self.node_ty(local.pat.hir_id);
+        self.overwrite_local_ty_if_err(local, ty, pat_ty);
+    }
+
+    pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) {
+        // Don't do all the complex logic below for `DeclItem`.
+        match stmt.kind {
+            hir::StmtKind::Item(..) => return,
+            hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
+        }
+
+        self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement");
+
+        // Hide the outer diverging and `has_errors` flags.
+        let old_diverges = self.diverges.replace(Diverges::Maybe);
+        let old_has_errors = self.has_errors.replace(false);
+
+        match stmt.kind {
+            hir::StmtKind::Local(ref l) => {
+                self.check_decl_local(&l);
+            }
+            // Ignore for now.
+            hir::StmtKind::Item(_) => {}
+            hir::StmtKind::Expr(ref expr) => {
+                // Check with expected type of `()`.
+                self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| {
+                    self.suggest_semicolon_at_end(expr.span, err);
+                });
+            }
+            hir::StmtKind::Semi(ref expr) => {
+                self.check_expr(&expr);
+            }
+        }
+
+        // Combine the diverging and `has_error` flags.
+        self.diverges.set(self.diverges.get() | old_diverges);
+        self.has_errors.set(self.has_errors.get() | old_has_errors);
+    }
+
+    pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
+        let unit = self.tcx.mk_unit();
+        let ty = self.check_block_with_expected(blk, ExpectHasType(unit));
+
+        // if the block produces a `!` value, that can always be
+        // (effectively) coerced to unit.
+        if !ty.is_never() {
+            self.demand_suptype(blk.span, unit, ty);
+        }
+    }
+
+    pub(in super::super) fn check_block_with_expected(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected: Expectation<'tcx>,
+    ) -> Ty<'tcx> {
+        let prev = {
+            let mut fcx_ps = self.ps.borrow_mut();
+            let unsafety_state = fcx_ps.recurse(blk);
+            replace(&mut *fcx_ps, unsafety_state)
+        };
+
+        // In some cases, blocks have just one exit, but other blocks
+        // can be targeted by multiple breaks. This can happen both
+        // with labeled blocks as well as when we desugar
+        // a `try { ... }` expression.
+        //
+        // Example 1:
+        //
+        //    'a: { if true { break 'a Err(()); } Ok(()) }
+        //
+        // Here we would wind up with two coercions, one from
+        // `Err(())` and the other from the tail expression
+        // `Ok(())`. If the tail expression is omitted, that's a
+        // "forced unit" -- unless the block diverges, in which
+        // case we can ignore the tail expression (e.g., `'a: {
+        // break 'a 22; }` would not force the type of the block
+        // to be `()`).
+        let tail_expr = blk.expr.as_ref();
+        let coerce_to_ty = expected.coercion_target_type(self, blk.span);
+        let coerce = if blk.targeted_by_break {
+            CoerceMany::new(coerce_to_ty)
+        } else {
+            let tail_expr: &[&hir::Expr<'_>] = match tail_expr {
+                Some(e) => slice::from_ref(e),
+                None => &[],
+            };
+            CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr)
+        };
+
+        let prev_diverges = self.diverges.get();
+        let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false };
+
+        let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || {
+            for s in blk.stmts {
+                self.check_stmt(s);
+            }
+
+            // check the tail expression **without** holding the
+            // `enclosing_breakables` lock below.
+            let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
+
+            let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
+            let ctxt = enclosing_breakables.find_breakable(blk.hir_id);
+            let coerce = ctxt.coerce.as_mut().unwrap();
+            if let Some(tail_expr_ty) = tail_expr_ty {
+                let tail_expr = tail_expr.unwrap();
+                let span = self.get_expr_coercion_span(tail_expr);
+                let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
+                coerce.coerce(self, &cause, tail_expr, tail_expr_ty);
+            } else {
+                // Subtle: if there is no explicit tail expression,
+                // that is typically equivalent to a tail expression
+                // of `()` -- except if the block diverges. In that
+                // case, there is no value supplied from the tail
+                // expression (assuming there are no other breaks,
+                // this implies that the type of the block will be
+                // `!`).
+                //
+                // #41425 -- label the implicit `()` as being the
+                // "found type" here, rather than the "expected type".
+                if !self.diverges.get().is_always() {
+                    // #50009 -- Do not point at the entire fn block span, point at the return type
+                    // span, as it is the cause of the requirement, and
+                    // `consider_hint_about_removing_semicolon` will point at the last expression
+                    // if it were a relevant part of the error. This improves usability in editors
+                    // that highlight errors inline.
+                    let mut sp = blk.span;
+                    let mut fn_span = None;
+                    if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) {
+                        let ret_sp = decl.output.span();
+                        if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
+                            // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
+                            // output would otherwise be incorrect and even misleading. Make sure
+                            // the span we're aiming at correspond to a `fn` body.
+                            if block_sp == blk.span {
+                                sp = ret_sp;
+                                fn_span = Some(ident.span);
+                            }
+                        }
+                    }
+                    coerce.coerce_forced_unit(
+                        self,
+                        &self.misc(sp),
+                        &mut |err| {
+                            if let Some(expected_ty) = expected.only_has_type(self) {
+                                self.consider_hint_about_removing_semicolon(blk, expected_ty, err);
+                            }
+                            if let Some(fn_span) = fn_span {
+                                err.span_label(
+                                    fn_span,
+                                    "implicitly returns `()` as its body has no tail or `return` \
+                                     expression",
+                                );
+                            }
+                        },
+                        false,
+                    );
+                }
+            }
+        });
+
+        if ctxt.may_break {
+            // If we can break from the block, then the block's exit is always reachable
+            // (... as long as the entry is reachable) - regardless of the tail of the block.
+            self.diverges.set(prev_diverges);
+        }
+
+        let mut ty = ctxt.coerce.unwrap().complete(self);
+
+        if self.has_errors.get() || ty.references_error() {
+            ty = self.tcx.ty_error()
+        }
+
+        self.write_ty(blk.hir_id, ty);
+
+        *self.ps.borrow_mut() = prev;
+        ty
+    }
+
+    pub(in super::super) fn check_rustc_args_require_const(
+        &self,
+        def_id: DefId,
+        hir_id: hir::HirId,
+        span: Span,
+    ) {
+        // We're only interested in functions tagged with
+        // #[rustc_args_required_const], so ignore anything that's not.
+        if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
+            return;
+        }
+
+        // If our calling expression is indeed the function itself, we're good!
+        // If not, generate an error that this can only be called directly.
+        if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) {
+            if let ExprKind::Call(ref callee, ..) = expr.kind {
+                if callee.hir_id == hir_id {
+                    return;
+                }
+            }
+        }
+
+        self.tcx.sess.span_err(
+            span,
+            "this function can only be invoked directly, not through a function pointer",
+        );
+    }
+
+    /// A common error is to add an extra semicolon:
+    ///
+    /// ```
+    /// fn foo() -> usize {
+    ///     22;
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the final statement in a block is an
+    /// expression with an explicit semicolon whose type is compatible
+    /// with `expected_ty`. If so, it suggests removing the semicolon.
+    fn consider_hint_about_removing_semicolon(
+        &self,
+        blk: &'tcx hir::Block<'tcx>,
+        expected_ty: Ty<'tcx>,
+        err: &mut DiagnosticBuilder<'_>,
+    ) {
+        if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) {
+            err.span_suggestion(
+                span_semi,
+                "consider removing this semicolon",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
+    fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
+        let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id));
+        match node {
+            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })
+            | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
+                let body = self.tcx.hir().body(body_id);
+                if let ExprKind::Block(block, _) = &body.value.kind {
+                    return Some(block.span);
+                }
+            }
+            _ => {}
+        }
+        None
+    }
+
+    /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
+    fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
+        let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id));
+        self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
+    }
+
+    /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
+    /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors
+    /// when given code like the following:
+    /// ```text
+    /// if false { return 0i32; } else { 1u32 }
+    /// //                               ^^^^ point at this instead of the whole `if` expression
+    /// ```
+    fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span {
+        if let hir::ExprKind::Match(_, arms, _) = &expr.kind {
+            let arm_spans: Vec<Span> = arms
+                .iter()
+                .filter_map(|arm| {
+                    self.in_progress_typeck_results
+                        .and_then(|typeck_results| {
+                            typeck_results.borrow().node_type_opt(arm.body.hir_id)
+                        })
+                        .and_then(|arm_ty| {
+                            if arm_ty.is_never() {
+                                None
+                            } else {
+                                Some(match &arm.body.kind {
+                                    // Point at the tail expression when possible.
+                                    hir::ExprKind::Block(block, _) => {
+                                        block.expr.as_ref().map(|e| e.span).unwrap_or(block.span)
+                                    }
+                                    _ => arm.body.span,
+                                })
+                            }
+                        })
+                })
+                .collect();
+            if arm_spans.len() == 1 {
+                return arm_spans[0];
+            }
+        }
+        expr.span
+    }
+
+    fn overwrite_local_ty_if_err(
+        &self,
+        local: &'tcx hir::Local<'tcx>,
+        decl_ty: Ty<'tcx>,
+        ty: Ty<'tcx>,
+    ) {
+        if ty.references_error() {
+            // Override the types everywhere with `err()` to avoid knock on errors.
+            self.write_ty(local.hir_id, ty);
+            self.write_ty(local.pat.hir_id, ty);
+            let local_ty = LocalTy { decl_ty, revealed_ty: ty };
+            self.locals.borrow_mut().insert(local.hir_id, local_ty);
+            self.locals.borrow_mut().insert(local.pat.hir_id, local_ty);
+        }
+    }
+
+    // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
+    // The newly resolved definition is written into `type_dependent_defs`.
+    fn finish_resolving_struct_path(
+        &self,
+        qpath: &QPath<'_>,
+        path_span: Span,
+        hir_id: hir::HirId,
+    ) -> (Res, Ty<'tcx>) {
+        match *qpath {
+            QPath::Resolved(ref maybe_qself, ref path) => {
+                let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself));
+                let ty = AstConv::res_to_ty(self, self_ty, path, true);
+                (path.res, ty)
+            }
+            QPath::TypeRelative(ref qself, ref segment) => {
+                let ty = self.to_ty(qself);
+
+                let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind {
+                    path.res
+                } else {
+                    Res::Err
+                };
+                let result =
+                    AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true);
+                let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
+                let result = result.map(|(_, kind, def_id)| (kind, def_id));
+
+                // Write back the new resolution.
+                self.write_resolution(hir_id, result);
+
+                (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty)
+            }
+            QPath::LangItem(lang_item, span) => {
+                self.resolve_lang_item_path(lang_item, span, hir_id)
+            }
+        }
+    }
+
+    /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk
+    /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s
+    /// reference a type argument. The reason to walk also the checked type is that the coerced type
+    /// can be not easily comparable with predicate type (because of coercion). If the types match
+    /// for either checked or coerced type, and there's only *one* argument that does, we point at
+    /// the corresponding argument's expression span instead of the `fn` call path span.
+    fn point_at_arg_instead_of_call_if_possible(
+        &self,
+        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
+        final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
+        call_sp: Span,
+        args: &'tcx [hir::Expr<'tcx>],
+    ) {
+        // We *do not* do this for desugared call spans to keep good diagnostics when involving
+        // the `?` operator.
+        if call_sp.desugaring_kind().is_some() {
+            return;
+        }
+
+        for error in errors {
+            // Only if the cause is somewhere inside the expression we want try to point at arg.
+            // Otherwise, it means that the cause is somewhere else and we should not change
+            // anything because we can break the correct span.
+            if !call_sp.contains(error.obligation.cause.span) {
+                continue;
+            }
+
+            if let ty::PredicateAtom::Trait(predicate, _) =
+                error.obligation.predicate.skip_binders()
+            {
+                // Collect the argument position for all arguments that could have caused this
+                // `FulfillmentError`.
+                let mut referenced_in = final_arg_types
+                    .iter()
+                    .map(|&(i, checked_ty, _)| (i, checked_ty))
+                    .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
+                    .flat_map(|(i, ty)| {
+                        let ty = self.resolve_vars_if_possible(&ty);
+                        // We walk the argument type because the argument's type could have
+                        // been `Option<T>`, but the `FulfillmentError` references `T`.
+                        if ty.walk().any(|arg| arg == predicate.self_ty().into()) {
+                            Some(i)
+                        } else {
+                            None
+                        }
+                    })
+                    .collect::<Vec<usize>>();
+
+                // Both checked and coerced types could have matched, thus we need to remove
+                // duplicates.
+
+                // We sort primitive type usize here and can use unstable sort
+                referenced_in.sort_unstable();
+                referenced_in.dedup();
+
+                if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
+                    // We make sure that only *one* argument matches the obligation failure
+                    // and we assign the obligation's span to its expression's.
+                    error.obligation.cause.make_mut().span = args[ref_in].span;
+                    error.points_at_arg_span = true;
+                }
+            }
+        }
+    }
+
+    /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the
+    /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s
+    /// were caused by them. If they were, we point at the corresponding type argument's span
+    /// instead of the `fn` call path span.
+    fn point_at_type_arg_instead_of_call_if_possible(
+        &self,
+        errors: &mut Vec<traits::FulfillmentError<'tcx>>,
+        call_expr: &'tcx hir::Expr<'tcx>,
+    ) {
+        if let hir::ExprKind::Call(path, _) = &call_expr.kind {
+            if let hir::ExprKind::Path(qpath) = &path.kind {
+                if let hir::QPath::Resolved(_, path) = &qpath {
+                    for error in errors {
+                        if let ty::PredicateAtom::Trait(predicate, _) =
+                            error.obligation.predicate.skip_binders()
+                        {
+                            // If any of the type arguments in this path segment caused the
+                            // `FullfillmentError`, point at its span (#61860).
+                            for arg in path
+                                .segments
+                                .iter()
+                                .filter_map(|seg| seg.args.as_ref())
+                                .flat_map(|a| a.args.iter())
+                            {
+                                if let hir::GenericArg::Type(hir_ty) = &arg {
+                                    if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
+                                        &hir_ty.kind
+                                    {
+                                        // Avoid ICE with associated types. As this is best
+                                        // effort only, it's ok to ignore the case. It
+                                        // would trigger in `is_send::<T::AssocType>();`
+                                        // from `typeck-default-trait-impl-assoc-type.rs`.
+                                    } else {
+                                        let ty = AstConv::ast_ty_to_ty(self, hir_ty);
+                                        let ty = self.resolve_vars_if_possible(&ty);
+                                        if ty == predicate.self_ty() {
+                                            error.obligation.cause.make_mut().span = hir_ty.span;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
new file mode 100644
index 00000000000..72c3b233ed9
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -0,0 +1,295 @@
+mod _impl;
+mod checks;
+mod suggestions;
+
+pub use _impl::*;
+pub use checks::*;
+pub use suggestions::*;
+
+use crate::astconv::AstConv;
+use crate::check::coercion::DynamicCoerceMany;
+use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState};
+
+use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
+use rustc_infer::infer;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
+use rustc_middle::hir::map::blocks::FnLikeNode;
+use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::{self, Const, Ty, TyCtxt};
+use rustc_session::Session;
+use rustc_span::{self, Span};
+use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
+
+use std::cell::{Cell, RefCell};
+use std::ops::Deref;
+
+pub struct FnCtxt<'a, 'tcx> {
+    pub(super) body_id: hir::HirId,
+
+    /// The parameter environment used for proving trait obligations
+    /// in this function. This can change when we descend into
+    /// closures (as they bring new things into scope), hence it is
+    /// not part of `Inherited` (as of the time of this writing,
+    /// closures do not yet change the environment, but they will
+    /// eventually).
+    pub(super) param_env: ty::ParamEnv<'tcx>,
+
+    /// Number of errors that had been reported when we started
+    /// checking this function. On exit, if we find that *more* errors
+    /// have been reported, we will skip regionck and other work that
+    /// expects the types within the function to be consistent.
+    // FIXME(matthewjasper) This should not exist, and it's not correct
+    // if type checking is run in parallel.
+    err_count_on_creation: usize,
+
+    /// If `Some`, this stores coercion information for returned
+    /// expressions. If `None`, this is in a context where return is
+    /// inappropriate, such as a const expression.
+    ///
+    /// This is a `RefCell<DynamicCoerceMany>`, which means that we
+    /// can track all the return expressions and then use them to
+    /// compute a useful coercion from the set, similar to a match
+    /// expression or other branching context. You can use methods
+    /// like `expected_ty` to access the declared return type (if
+    /// any).
+    pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
+
+    pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>,
+
+    pub(super) ret_type_span: Option<Span>,
+
+    /// Used exclusively to reduce cost of advanced evaluation used for
+    /// more helpful diagnostics.
+    pub(super) in_tail_expr: bool,
+
+    /// First span of a return site that we find. Used in error messages.
+    pub(super) ret_coercion_span: RefCell<Option<Span>>,
+
+    pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>,
+
+    pub(super) ps: RefCell<UnsafetyState>,
+
+    /// Whether the last checked node generates a divergence (e.g.,
+    /// `return` will set this to `Always`). In general, when entering
+    /// an expression or other node in the tree, the initial value
+    /// indicates whether prior parts of the containing expression may
+    /// have diverged. It is then typically set to `Maybe` (and the
+    /// old value remembered) for processing the subparts of the
+    /// current expression. As each subpart is processed, they may set
+    /// the flag to `Always`, etc. Finally, at the end, we take the
+    /// result and "union" it with the original value, so that when we
+    /// return the flag indicates if any subpart of the parent
+    /// expression (up to and including this part) has diverged. So,
+    /// if you read it after evaluating a subexpression `X`, the value
+    /// you get indicates whether any subexpression that was
+    /// evaluating up to and including `X` diverged.
+    ///
+    /// We currently use this flag only for diagnostic purposes:
+    ///
+    /// - To warn about unreachable code: if, after processing a
+    ///   sub-expression but before we have applied the effects of the
+    ///   current node, we see that the flag is set to `Always`, we
+    ///   can issue a warning. This corresponds to something like
+    ///   `foo(return)`; we warn on the `foo()` expression. (We then
+    ///   update the flag to `WarnedAlways` to suppress duplicate
+    ///   reports.) Similarly, if we traverse to a fresh statement (or
+    ///   tail expression) from a `Always` setting, we will issue a
+    ///   warning. This corresponds to something like `{return;
+    ///   foo();}` or `{return; 22}`, where we would warn on the
+    ///   `foo()` or `22`.
+    ///
+    /// An expression represents dead code if, after checking it,
+    /// the diverges flag is set to something other than `Maybe`.
+    pub(super) diverges: Cell<Diverges>,
+
+    /// Whether any child nodes have any type errors.
+    pub(super) has_errors: Cell<bool>,
+
+    pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
+
+    pub(super) inh: &'a Inherited<'a, 'tcx>,
+}
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub fn new(
+        inh: &'a Inherited<'a, 'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+        body_id: hir::HirId,
+    ) -> FnCtxt<'a, 'tcx> {
+        FnCtxt {
+            body_id,
+            param_env,
+            err_count_on_creation: inh.tcx.sess.err_count(),
+            ret_coercion: None,
+            ret_coercion_impl_trait: None,
+            ret_type_span: None,
+            in_tail_expr: false,
+            ret_coercion_span: RefCell::new(None),
+            resume_yield_tys: None,
+            ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
+            diverges: Cell::new(Diverges::Maybe),
+            has_errors: Cell::new(false),
+            enclosing_breakables: RefCell::new(EnclosingBreakables {
+                stack: Vec::new(),
+                by_id: Default::default(),
+            }),
+            inh,
+        }
+    }
+
+    pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> {
+        ObligationCause::new(span, self.body_id, code)
+    }
+
+    pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
+        self.cause(span, ObligationCauseCode::MiscObligation)
+    }
+
+    pub fn sess(&self) -> &Session {
+        &self.tcx.sess
+    }
+
+    pub fn errors_reported_since_creation(&self) -> bool {
+        self.tcx.sess.err_count() > self.err_count_on_creation
+    }
+}
+
+impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> {
+    type Target = Inherited<'a, 'tcx>;
+    fn deref(&self) -> &Self::Target {
+        &self.inh
+    }
+}
+
+impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn item_def_id(&self) -> Option<DefId> {
+        None
+    }
+
+    fn default_constness_for_trait_bounds(&self) -> hir::Constness {
+        // FIXME: refactor this into a method
+        let node = self.tcx.hir().get(self.body_id);
+        if let Some(fn_like) = FnLikeNode::from_node(node) {
+            fn_like.constness()
+        } else {
+            hir::Constness::NotConst
+        }
+    }
+
+    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
+        let tcx = self.tcx;
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+        let item_id = tcx.hir().ty_param_owner(hir_id);
+        let item_def_id = tcx.hir().local_def_id(item_id);
+        let generics = tcx.generics_of(item_def_id);
+        let index = generics.param_def_id_to_index[&def_id];
+        ty::GenericPredicates {
+            parent: None,
+            predicates: tcx.arena.alloc_from_iter(
+                self.param_env.caller_bounds().iter().filter_map(|predicate| {
+                    match predicate.skip_binders() {
+                        ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => {
+                            // HACK(eddyb) should get the original `Span`.
+                            let span = tcx.def_span(def_id);
+                            Some((predicate, span))
+                        }
+                        _ => None,
+                    }
+                }),
+            ),
+        }
+    }
+
+    fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> {
+        let v = match def {
+            Some(def) => infer::EarlyBoundRegion(span, def.name),
+            None => infer::MiscVariable(span),
+        };
+        Some(self.next_region_var(v))
+    }
+
+    fn allow_ty_infer(&self) -> bool {
+        true
+    }
+
+    fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
+        if let Some(param) = param {
+            if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
+                return ty;
+            }
+            unreachable!()
+        } else {
+            self.next_ty_var(TypeVariableOrigin {
+                kind: TypeVariableOriginKind::TypeInference,
+                span,
+            })
+        }
+    }
+
+    fn ct_infer(
+        &self,
+        ty: Ty<'tcx>,
+        param: Option<&ty::GenericParamDef>,
+        span: Span,
+    ) -> &'tcx Const<'tcx> {
+        if let Some(param) = param {
+            if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
+                return ct;
+            }
+            unreachable!()
+        } else {
+            self.next_const_var(
+                ty,
+                ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
+            )
+        }
+    }
+
+    fn projected_ty_from_poly_trait_ref(
+        &self,
+        span: Span,
+        item_def_id: DefId,
+        item_segment: &hir::PathSegment<'_>,
+        poly_trait_ref: ty::PolyTraitRef<'tcx>,
+    ) -> Ty<'tcx> {
+        let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars(
+            span,
+            infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id),
+            &poly_trait_ref,
+        );
+
+        let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
+            self,
+            self.tcx,
+            span,
+            item_def_id,
+            item_segment,
+            trait_ref.substs,
+        );
+
+        self.tcx().mk_projection(item_def_id, item_substs)
+    }
+
+    fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if ty.has_escaping_bound_vars() {
+            ty // FIXME: normalization and escaping regions
+        } else {
+            self.normalize_associated_types_in(span, &ty)
+        }
+    }
+
+    fn set_tainted_by_errors(&self) {
+        self.infcx.set_tainted_by_errors()
+    }
+
+    fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) {
+        self.write_ty(hir_id, ty)
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
new file mode 100644
index 00000000000..9bad02c41b4
--- /dev/null
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -0,0 +1,528 @@
+use super::FnCtxt;
+use crate::astconv::AstConv;
+
+use rustc_ast::util::parser::ExprPrecedence;
+use rustc_span::{self, Span};
+use rustc_trait_selection::traits;
+
+use rustc_errors::{Applicability, DiagnosticBuilder};
+use rustc_hir as hir;
+use rustc_hir::def::{CtorOf, DefKind};
+use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ExprKind, ItemKind, Node};
+use rustc_infer::infer;
+use rustc_middle::ty::{self, Ty};
+use rustc_span::symbol::kw;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
+
+use std::iter;
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    pub(in super::super) fn suggest_semicolon_at_end(
+        &self,
+        span: Span,
+        err: &mut DiagnosticBuilder<'_>,
+    ) {
+        err.span_suggestion_short(
+            span.shrink_to_hi(),
+            "consider using a semicolon here",
+            ";".to_string(),
+            Applicability::MachineApplicable,
+        );
+    }
+
+    /// On implicit return expressions with mismatched types, provides the following suggestions:
+    ///
+    /// - Points out the method's return type as the reason for the expected type.
+    /// - Possible missing semicolon.
+    /// - Possible missing return type if the return type is the default, and not `fn main()`.
+    pub fn suggest_mismatched_types_on_tail(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &'tcx hir::Expr<'tcx>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+        cause_span: Span,
+        blk_id: hir::HirId,
+    ) -> bool {
+        let expr = expr.peel_drop_temps();
+        self.suggest_missing_semicolon(err, expr, expected, cause_span);
+        let mut pointing_at_return_type = false;
+        if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
+            pointing_at_return_type =
+                self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
+        }
+        pointing_at_return_type
+    }
+
+    /// When encountering an fn-like ctor that needs to unify with a value, check whether calling
+    /// the ctor would successfully solve the type mismatch and if so, suggest it:
+    /// ```
+    /// fn foo(x: usize) -> usize { x }
+    /// let x: usize = foo;  // suggest calling the `foo` function: `foo(42)`
+    /// ```
+    fn suggest_fn_call(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) -> bool {
+        let hir = self.tcx.hir();
+        let (def_id, sig) = match *found.kind() {
+            ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)),
+            ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()),
+            _ => return false,
+        };
+
+        let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0;
+        let sig = self.normalize_associated_types_in(expr.span, &sig);
+        if self.can_coerce(sig.output(), expected) {
+            let (mut sugg_call, applicability) = if sig.inputs().is_empty() {
+                (String::new(), Applicability::MachineApplicable)
+            } else {
+                ("...".to_string(), Applicability::HasPlaceholders)
+            };
+            let mut msg = "call this function";
+            match hir.get_if_local(def_id) {
+                Some(
+                    Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. })
+                    | Node::ImplItem(hir::ImplItem {
+                        kind: hir::ImplItemKind::Fn(_, body_id), ..
+                    })
+                    | Node::TraitItem(hir::TraitItem {
+                        kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)),
+                        ..
+                    }),
+                ) => {
+                    let body = hir.body(*body_id);
+                    sugg_call = body
+                        .params
+                        .iter()
+                        .map(|param| match &param.pat.kind {
+                            hir::PatKind::Binding(_, _, ident, None)
+                                if ident.name != kw::SelfLower =>
+                            {
+                                ident.to_string()
+                            }
+                            _ => "_".to_string(),
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", ");
+                }
+                Some(Node::Expr(hir::Expr {
+                    kind: ExprKind::Closure(_, _, body_id, _, _),
+                    span: full_closure_span,
+                    ..
+                })) => {
+                    if *full_closure_span == expr.span {
+                        return false;
+                    }
+                    msg = "call this closure";
+                    let body = hir.body(*body_id);
+                    sugg_call = body
+                        .params
+                        .iter()
+                        .map(|param| match &param.pat.kind {
+                            hir::PatKind::Binding(_, _, ident, None)
+                                if ident.name != kw::SelfLower =>
+                            {
+                                ident.to_string()
+                            }
+                            _ => "_".to_string(),
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", ");
+                }
+                Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => {
+                    sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", ");
+                    match def_id.as_local().map(|def_id| hir.def_kind(def_id)) {
+                        Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => {
+                            msg = "instantiate this tuple variant";
+                        }
+                        Some(DefKind::Ctor(CtorOf::Struct, _)) => {
+                            msg = "instantiate this tuple struct";
+                        }
+                        _ => {}
+                    }
+                }
+                Some(Node::ForeignItem(hir::ForeignItem {
+                    kind: hir::ForeignItemKind::Fn(_, idents, _),
+                    ..
+                })) => {
+                    sugg_call = idents
+                        .iter()
+                        .map(|ident| {
+                            if ident.name != kw::SelfLower {
+                                ident.to_string()
+                            } else {
+                                "_".to_string()
+                            }
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", ")
+                }
+                Some(Node::TraitItem(hir::TraitItem {
+                    kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)),
+                    ..
+                })) => {
+                    sugg_call = idents
+                        .iter()
+                        .map(|ident| {
+                            if ident.name != kw::SelfLower {
+                                ident.to_string()
+                            } else {
+                                "_".to_string()
+                            }
+                        })
+                        .collect::<Vec<_>>()
+                        .join(", ")
+                }
+                _ => {}
+            }
+            err.span_suggestion_verbose(
+                expr.span.shrink_to_hi(),
+                &format!("use parentheses to {}", msg),
+                format!("({})", sugg_call),
+                applicability,
+            );
+            return true;
+        }
+        false
+    }
+
+    pub fn suggest_deref_ref_or_into(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+        expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
+    ) {
+        if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) {
+            err.span_suggestion(sp, msg, suggestion, applicability);
+        } else if let (ty::FnDef(def_id, ..), true) =
+            (&found.kind(), self.suggest_fn_call(err, expr, expected, found))
+        {
+            if let Some(sp) = self.tcx.hir().span_if_local(*def_id) {
+                let sp = self.sess().source_map().guess_head_span(sp);
+                err.span_label(sp, &format!("{} defined here", found));
+            }
+        } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+            let is_struct_pat_shorthand_field =
+                self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
+            let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
+            if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
+                let mut suggestions = iter::repeat(&expr_text)
+                    .zip(methods.iter())
+                    .filter_map(|(receiver, method)| {
+                        let method_call = format!(".{}()", method.ident);
+                        if receiver.ends_with(&method_call) {
+                            None // do not suggest code that is already there (#53348)
+                        } else {
+                            let method_call_list = [".to_vec()", ".to_string()"];
+                            let sugg = if receiver.ends_with(".clone()")
+                                && method_call_list.contains(&method_call.as_str())
+                            {
+                                let max_len = receiver.rfind('.').unwrap();
+                                format!("{}{}", &receiver[..max_len], method_call)
+                            } else {
+                                if expr.precedence().order() < ExprPrecedence::MethodCall.order() {
+                                    format!("({}){}", receiver, method_call)
+                                } else {
+                                    format!("{}{}", receiver, method_call)
+                                }
+                            };
+                            Some(if is_struct_pat_shorthand_field {
+                                format!("{}: {}", receiver, sugg)
+                            } else {
+                                sugg
+                            })
+                        }
+                    })
+                    .peekable();
+                if suggestions.peek().is_some() {
+                    err.span_suggestions(
+                        expr.span,
+                        "try using a conversion method",
+                        suggestions,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+    }
+
+    /// When encountering the expected boxed value allocated in the stack, suggest allocating it
+    /// in the heap by calling `Box::new()`.
+    pub(in super::super) fn suggest_boxing_when_appropriate(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
+            // Do not suggest `Box::new` in const context.
+            return;
+        }
+        if !expected.is_box() || found.is_box() {
+            return;
+        }
+        let boxed_found = self.tcx.mk_box(found);
+        if let (true, Ok(snippet)) = (
+            self.can_coerce(boxed_found, expected),
+            self.sess().source_map().span_to_snippet(expr.span),
+        ) {
+            err.span_suggestion(
+                expr.span,
+                "store this in the heap by calling `Box::new`",
+                format!("Box::new({})", snippet),
+                Applicability::MachineApplicable,
+            );
+            err.note(
+                "for more on the distinction between the stack and the heap, read \
+                 https://doc.rust-lang.org/book/ch15-01-box.html, \
+                 https://doc.rust-lang.org/rust-by-example/std/box.html, and \
+                 https://doc.rust-lang.org/std/boxed/index.html",
+            );
+        }
+    }
+
+    /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
+    pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) -> bool {
+        // Handle #68197.
+
+        if self.tcx.hir().is_inside_const_context(expr.hir_id) {
+            // Do not suggest `Box::new` in const context.
+            return false;
+        }
+        let pin_did = self.tcx.lang_items().pin_type();
+        match expected.kind() {
+            ty::Adt(def, _) if Some(def.did) != pin_did => return false,
+            // This guards the `unwrap` and `mk_box` below.
+            _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false,
+            _ => {}
+        }
+        let boxed_found = self.tcx.mk_box(found);
+        let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap();
+        if let (true, Ok(snippet)) = (
+            self.can_coerce(new_found, expected),
+            self.sess().source_map().span_to_snippet(expr.span),
+        ) {
+            match found.kind() {
+                ty::Adt(def, _) if def.is_box() => {
+                    err.help("use `Box::pin`");
+                }
+                _ => {
+                    err.span_suggestion(
+                        expr.span,
+                        "you need to pin and box this expression",
+                        format!("Box::pin({})", snippet),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+            true
+        } else {
+            false
+        }
+    }
+
+    /// A common error is to forget to add a semicolon at the end of a block, e.g.,
+    ///
+    /// ```
+    /// fn foo() {
+    ///     bar_that_returns_u32()
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the return expression in a block would make sense on its own as a
+    /// statement and the return type has been left as default or has been specified as `()`. If so,
+    /// it suggests adding a semicolon.
+    fn suggest_missing_semicolon(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expression: &'tcx hir::Expr<'tcx>,
+        expected: Ty<'tcx>,
+        cause_span: Span,
+    ) {
+        if expected.is_unit() {
+            // `BlockTailExpression` only relevant if the tail expr would be
+            // useful on its own.
+            match expression.kind {
+                ExprKind::Call(..)
+                | ExprKind::MethodCall(..)
+                | ExprKind::Loop(..)
+                | ExprKind::Match(..)
+                | ExprKind::Block(..) => {
+                    err.span_suggestion(
+                        cause_span.shrink_to_hi(),
+                        "try adding a semicolon",
+                        ";".to_string(),
+                        Applicability::MachineApplicable,
+                    );
+                }
+                _ => (),
+            }
+        }
+    }
+
+    /// A possible error is to forget to add a return type that is needed:
+    ///
+    /// ```
+    /// fn foo() {
+    ///     bar_that_returns_u32()
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the return type is left as default, the method is not part of an
+    /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
+    /// type.
+    pub(in super::super) fn suggest_missing_return_type(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        fn_decl: &hir::FnDecl<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+        can_suggest: bool,
+    ) -> bool {
+        // Only suggest changing the return type for methods that
+        // haven't set a return type at all (and aren't `fn main()` or an impl).
+        match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
+            (&hir::FnRetTy::DefaultReturn(span), true, true, true) => {
+                err.span_suggestion(
+                    span,
+                    "try adding a return type",
+                    format!("-> {} ", self.resolve_vars_with_obligations(found)),
+                    Applicability::MachineApplicable,
+                );
+                true
+            }
+            (&hir::FnRetTy::DefaultReturn(span), false, true, true) => {
+                err.span_label(span, "possibly return type missing here?");
+                true
+            }
+            (&hir::FnRetTy::DefaultReturn(span), _, false, true) => {
+                // `fn main()` must return `()`, do not suggest changing return type
+                err.span_label(span, "expected `()` because of default return type");
+                true
+            }
+            // expectation was caused by something else, not the default return
+            (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false,
+            (&hir::FnRetTy::Return(ref ty), _, _, _) => {
+                // Only point to return type if the expected type is the return type, as if they
+                // are not, the expectation must have been caused by something else.
+                debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
+                let sp = ty.span;
+                let ty = AstConv::ast_ty_to_ty(self, ty);
+                debug!("suggest_missing_return_type: return type {:?}", ty);
+                debug!("suggest_missing_return_type: expected type {:?}", ty);
+                if ty.kind() == expected.kind() {
+                    err.span_label(sp, format!("expected `{}` because of return type", expected));
+                    return true;
+                }
+                false
+            }
+        }
+    }
+
+    /// A possible error is to forget to add `.await` when using futures:
+    ///
+    /// ```
+    /// async fn make_u32() -> u32 {
+    ///     22
+    /// }
+    ///
+    /// fn take_u32(x: u32) {}
+    ///
+    /// async fn foo() {
+    ///     let x = make_u32();
+    ///     take_u32(x);
+    /// }
+    /// ```
+    ///
+    /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the
+    /// expected type. If this is the case, and we are inside of an async body, it suggests adding
+    /// `.await` to the tail of the expression.
+    pub(in super::super) fn suggest_missing_await(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+        expected: Ty<'tcx>,
+        found: Ty<'tcx>,
+    ) {
+        debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found);
+        // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the
+        // body isn't `async`.
+        let item_id = self.tcx().hir().get_parent_node(self.body_id);
+        if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) {
+            let body = self.tcx().hir().body(body_id);
+            if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
+                let sp = expr.span;
+                // Check for `Future` implementations by constructing a predicate to
+                // prove: `<T as Future>::Output == U`
+                let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp));
+                let item_def_id = self
+                    .tcx
+                    .associated_items(future_trait)
+                    .in_definition_order()
+                    .next()
+                    .unwrap()
+                    .def_id;
+                // `<T as Future>::Output`
+                let projection_ty = ty::ProjectionTy {
+                    // `T`
+                    substs: self
+                        .tcx
+                        .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)),
+                    // `Future::Output`
+                    item_def_id,
+                };
+
+                let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate {
+                    projection_ty,
+                    ty: expected,
+                })
+                .potentially_quantified(self.tcx, ty::PredicateKind::ForAll);
+                let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate);
+
+                debug!("suggest_missing_await: trying obligation {:?}", obligation);
+
+                if self.infcx.predicate_may_hold(&obligation) {
+                    debug!("suggest_missing_await: obligation held: {:?}", obligation);
+                    if let Ok(code) = self.sess().source_map().span_to_snippet(sp) {
+                        err.span_suggestion(
+                            sp,
+                            "consider using `.await` here",
+                            format!("{}.await", code),
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        debug!("suggest_missing_await: no snippet for {:?}", sp);
+                    }
+                } else {
+                    debug!("suggest_missing_await: obligation did not hold: {:?}", obligation)
+                }
+            }
+        }
+    }
+
+    pub(in super::super) fn suggest_missing_parentheses(
+        &self,
+        err: &mut DiagnosticBuilder<'_>,
+        expr: &hir::Expr<'_>,
+    ) {
+        let sp = self.tcx.sess.source_map().start_point(expr.span);
+        if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) {
+            // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }`
+            self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None);
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index 93fdf93e9e3..3fc5f02a4a4 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -8,11 +8,13 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir::hir_id::HirIdSet;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::{Expr, ExprKind, Pat, PatKind};
+use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
 use rustc_middle::middle::region::{self, YieldData};
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
+use smallvec::SmallVec;
 
 struct InteriorVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
@@ -21,6 +23,13 @@ struct InteriorVisitor<'a, 'tcx> {
     expr_count: usize,
     kind: hir::GeneratorKind,
     prev_unresolved_span: Option<Span>,
+    /// Match arm guards have temporary borrows from the pattern bindings.
+    /// In case there is a yield point in a guard with a reference to such bindings,
+    /// such borrows can span across this yield point.
+    /// As such, we need to track these borrows and record them despite of the fact
+    /// that they may succeed the said yield point in the post-order.
+    guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>,
+    guard_bindings_set: HirIdSet,
 }
 
 impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
@@ -30,6 +39,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
         scope: Option<region::Scope>,
         expr: Option<&'tcx Expr<'tcx>>,
         source_span: Span,
+        guard_borrowing_from_pattern: bool,
     ) {
         use rustc_span::DUMMY_SP;
 
@@ -53,7 +63,12 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
                         yield_data.expr_and_pat_count, self.expr_count, source_span
                     );
 
-                    if yield_data.expr_and_pat_count >= self.expr_count {
+                    // If it is a borrowing happening in the guard,
+                    // it needs to be recorded regardless because they
+                    // do live across this yield point.
+                    if guard_borrowing_from_pattern
+                        || yield_data.expr_and_pat_count >= self.expr_count
+                    {
                         Some(yield_data)
                     } else {
                         None
@@ -134,6 +149,8 @@ pub fn resolve_interior<'a, 'tcx>(
         expr_count: 0,
         kind,
         prev_unresolved_span: None,
+        guard_bindings: <_>::default(),
+        guard_bindings_set: <_>::default(),
     };
     intravisit::walk_body(&mut visitor, body);
 
@@ -210,6 +227,38 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         NestedVisitorMap::None
     }
 
+    fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) {
+        let Arm { guard, pat, body, .. } = arm;
+        self.visit_pat(pat);
+        if let Some(ref g) = guard {
+            self.guard_bindings.push(<_>::default());
+            ArmPatCollector {
+                guard_bindings_set: &mut self.guard_bindings_set,
+                guard_bindings: self
+                    .guard_bindings
+                    .last_mut()
+                    .expect("should have pushed at least one earlier"),
+            }
+            .visit_pat(pat);
+
+            match g {
+                Guard::If(ref e) => {
+                    self.visit_expr(e);
+                }
+            }
+
+            let mut scope_var_ids =
+                self.guard_bindings.pop().expect("should have pushed at least one earlier");
+            for var_id in scope_var_ids.drain(..) {
+                assert!(
+                    self.guard_bindings_set.remove(&var_id),
+                    "variable should be placed in scope earlier"
+                );
+            }
+        }
+        self.visit_expr(body);
+    }
+
     fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
         intravisit::walk_pat(self, pat);
 
@@ -218,11 +267,12 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         if let PatKind::Binding(..) = pat.kind {
             let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
             let ty = self.fcx.typeck_results.borrow().pat_ty(pat);
-            self.record(ty, Some(scope), None, pat.span);
+            self.record(ty, Some(scope), None, pat.span, false);
         }
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        let mut guard_borrowing_from_pattern = false;
         match &expr.kind {
             ExprKind::Call(callee, args) => match &callee.kind {
                 ExprKind::Path(qpath) => {
@@ -249,6 +299,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
                 }
                 _ => intravisit::walk_expr(self, expr),
             },
+            ExprKind::Path(qpath) => {
+                intravisit::walk_expr(self, expr);
+                let res = self.fcx.typeck_results.borrow().qpath_res(qpath, expr.hir_id);
+                match res {
+                    Res::Local(id) if self.guard_bindings_set.contains(&id) => {
+                        guard_borrowing_from_pattern = true;
+                    }
+                    _ => {}
+                }
+            }
             _ => intravisit::walk_expr(self, expr),
         }
 
@@ -259,7 +319,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         // If there are adjustments, then record the final type --
         // this is the actual value that is being produced.
         if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) {
-            self.record(adjusted_ty, scope, Some(expr), expr.span);
+            self.record(adjusted_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
         }
 
         // Also record the unadjusted type (which is the only type if
@@ -267,10 +327,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         // unadjusted value is sometimes a "temporary" that would wind
         // up in a MIR temporary.
         //
-        // As an example, consider an expression like `vec![].push()`.
+        // As an example, consider an expression like `vec![].push(x)`.
         // Here, the `vec![]` would wind up MIR stored into a
         // temporary variable `t` which we can borrow to invoke
-        // `<Vec<_>>::push(&mut t)`.
+        // `<Vec<_>>::push(&mut t, x)`.
         //
         // Note that an expression can have many adjustments, and we
         // are just ignoring those intermediate types. This is because
@@ -287,9 +347,30 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
         // The type table might not have information for this expression
         // if it is in a malformed scope. (#66387)
         if let Some(ty) = self.fcx.typeck_results.borrow().expr_ty_opt(expr) {
-            self.record(ty, scope, Some(expr), expr.span);
+            self.record(ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern);
         } else {
             self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node");
         }
     }
 }
+
+struct ArmPatCollector<'a> {
+    guard_bindings_set: &'a mut HirIdSet,
+    guard_bindings: &'a mut SmallVec<[HirId; 4]>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> {
+    type Map = intravisit::ErasedMap<'tcx>;
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
+        intravisit::walk_pat(self, pat);
+        if let PatKind::Binding(_, id, ..) = pat.kind {
+            self.guard_bindings.push(id);
+            self.guard_bindings_set.insert(id);
+        }
+    }
+}
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 97172d391ba..24ffe944128 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -96,7 +96,7 @@ use check::{
 pub use check::{check_item_type, check_wf_new};
 pub use diverges::Diverges;
 pub use expectation::Expectation;
-pub use fn_ctxt::FnCtxt;
+pub use fn_ctxt::*;
 pub use inherited::{Inherited, InheritedBuilder};
 
 use crate::astconv::AstConv;
@@ -264,7 +264,7 @@ pub fn provide(providers: &mut Providers) {
 }
 
 fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> {
-    tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl)
+    tcx.calculate_dtor(def_id, dropck::check_drop_impl)
 }
 
 /// If this `DefId` is a "primary tables entry", returns
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 66975f32a1f..2f3fb49717b 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -2,6 +2,7 @@
 
 use super::method::MethodCallee;
 use super::FnCtxt;
+use rustc_ast as ast;
 use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -13,6 +14,7 @@ use rustc_middle::ty::TyKind::{Adt, Array, Char, FnDef, Never, Ref, Str, Tuple,
 use rustc_middle::ty::{
     self, suggest_constraining_type_param, Ty, TyCtxt, TypeFoldable, TypeVisitor,
 };
+use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
@@ -673,6 +675,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     match actual.kind() {
                         Uint(_) if op == hir::UnOp::UnNeg => {
                             err.note("unsigned values cannot be negated");
+
+                            if let hir::ExprKind::Unary(
+                                _,
+                                hir::Expr {
+                                    kind:
+                                        hir::ExprKind::Lit(Spanned {
+                                            node: ast::LitKind::Int(1, _),
+                                            ..
+                                        }),
+                                    ..
+                                },
+                            ) = ex.kind
+                            {
+                                err.span_suggestion(
+                                    ex.span,
+                                    &format!(
+                                        "you may have meant the maximum value of `{}`",
+                                        actual
+                                    ),
+                                    format!("{}::MAX", actual),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
                         }
                         Str | Never | Char | Tuple(_) | Array(_, _) => {}
                         Ref(_, ref lty, _) if *lty.kind() == Str => {}
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 2c3be0da5dd..1e97bd65a79 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -202,9 +202,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}",
             closure_hir_id, substs, final_upvar_tys
         );
-        for (upvar_ty, final_upvar_ty) in substs.upvar_tys().zip(final_upvar_tys) {
-            self.demand_suptype(span, upvar_ty, final_upvar_ty);
-        }
+
+        // Build a tuple (U0..Un) of the final upvar types U0..Un
+        // and unify the upvar tupe type in the closure with it:
+        let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter());
+        self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type);
 
         // If we are also inferred the closure kind here,
         // process any deferred resolutions.
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 092dae18192..630e80d502e 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -21,8 +21,8 @@ use crate::constrained_generic_params as cgp;
 use crate::errors;
 use crate::middle::resolve_lifetime as rl;
 use rustc_ast as ast;
-use rustc_ast::MetaItemKind;
-use rustc_attr::{list_contains_name, InlineAttr, OptimizeAttr};
+use rustc_ast::{MetaItemKind, NestedMetaItem};
+use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
 use rustc_errors::{struct_span_err, Applicability};
@@ -2555,7 +2555,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                 )
                 .emit();
             }
-            if !tcx.sess.target.target.llvm_target.contains("thumbv8m") {
+            if !tcx.sess.target.llvm_target.contains("thumbv8m") {
                 struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
                     .emit();
             }
@@ -2647,6 +2647,75 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                     }
                 }
             }
+        } else if tcx.sess.check_name(attr, sym::instruction_set) {
+            codegen_fn_attrs.instruction_set = match attr.meta().map(|i| i.kind) {
+                Some(MetaItemKind::List(ref items)) => match items.as_slice() {
+                    [NestedMetaItem::MetaItem(set)] => {
+                        let segments =
+                            set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
+                        match segments.as_slice() {
+                            [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
+                                if !tcx.sess.target.options.has_thumb_interworking {
+                                    struct_span_err!(
+                                        tcx.sess.diagnostic(),
+                                        attr.span,
+                                        E0779,
+                                        "target does not support `#[instruction_set]`"
+                                    )
+                                    .emit();
+                                    None
+                                } else if segments[1] == sym::a32 {
+                                    Some(InstructionSetAttr::ArmA32)
+                                } else if segments[1] == sym::t32 {
+                                    Some(InstructionSetAttr::ArmT32)
+                                } else {
+                                    unreachable!()
+                                }
+                            }
+                            _ => {
+                                struct_span_err!(
+                                    tcx.sess.diagnostic(),
+                                    attr.span,
+                                    E0779,
+                                    "invalid instruction set specified",
+                                )
+                                .emit();
+                                None
+                            }
+                        }
+                    }
+                    [] => {
+                        struct_span_err!(
+                            tcx.sess.diagnostic(),
+                            attr.span,
+                            E0778,
+                            "`#[instruction_set]` requires an argument"
+                        )
+                        .emit();
+                        None
+                    }
+                    _ => {
+                        struct_span_err!(
+                            tcx.sess.diagnostic(),
+                            attr.span,
+                            E0779,
+                            "cannot specify more than one instruction set"
+                        )
+                        .emit();
+                        None
+                    }
+                },
+                _ => {
+                    struct_span_err!(
+                        tcx.sess.diagnostic(),
+                        attr.span,
+                        E0778,
+                        "must specify an instruction set"
+                    )
+                    .emit();
+                    None
+                }
+            };
         }
     }
 
diff --git a/config.toml.example b/config.toml.example
index c5efb8ed5e5..e7e37c679e5 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -13,7 +13,7 @@
 # If it does not match the version that is currently running,
 # `x.py` will prompt you to update it and read the changelog.
 # See `src/bootstrap/CHANGELOG.md` for more information.
-changelog-seen = 1
+changelog-seen = 2
 
 # =============================================================================
 # Global Settings
@@ -370,19 +370,23 @@ changelog-seen = 1
 # binary, otherwise they are omitted.
 #
 # Defaults to rust.debug value
-#debug-assertions = debug
+#debug-assertions = rust.debug (boolean)
 
 # Whether or not debug assertions are enabled for the standard library.
 # Overrides the `debug-assertions` option, if defined.
 #
 # Defaults to rust.debug-assertions value
-#debug-assertions-std = debug-assertions
+#debug-assertions-std = rust.debug-assertions (boolean)
 
 # Whether or not to leave debug! and trace! calls in the rust binary.
 # Overrides the `debug-assertions` option, if defined.
 #
 # Defaults to rust.debug-assertions value
-#debug-logging = debug-assertions
+#
+# If you see a message from `tracing` saying
+# `max_level_info` is enabled and means logging won't be shown,
+# set this value to `true`.
+#debug-logging = rust.debug-assertions (boolean)
 
 # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`.
 # `0` - no debug info
diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs
index 4b8300f1862..bbde60952d3 100644
--- a/library/alloc/src/alloc.rs
+++ b/library/alloc/src/alloc.rs
@@ -19,8 +19,9 @@ mod tests;
 
 extern "Rust" {
     // These are the magic symbols to call the global allocator.  rustc generates
-    // them from the `#[global_allocator]` attribute if there is one, or uses the
-    // default implementations in libstd (`__rdl_alloc` etc in `src/libstd/alloc.rs`)
+    // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
+    // (the code expanding that attribute macro generates those functions), or to call
+    // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
     // otherwise.
     #[rustc_allocator]
     #[rustc_allocator_nounwind]
@@ -31,8 +32,6 @@ extern "Rust" {
     fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
     #[rustc_allocator_nounwind]
     fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
-    #[rustc_allocator_nounwind]
-    fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
 }
 
 /// The global memory allocator.
@@ -42,7 +41,7 @@ extern "Rust" {
 /// if there is one, or the `std` crate’s default.
 ///
 /// Note: while this type is unstable, the functionality it provides can be
-/// accessed through the [free functions in `alloc`](index.html#functions).
+/// accessed through the [free functions in `alloc`](self#functions).
 #[unstable(feature = "allocator_api", issue = "32838")]
 #[derive(Copy, Clone, Default, Debug)]
 #[cfg(not(test))]
@@ -334,6 +333,16 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: AllocRef>(ptr: Unique<T>, alloc: A)
     }
 }
 
+// # Allocation error handler
+
+extern "Rust" {
+    // This is the magic symbol to call the global alloc error handler.  rustc generates
+    // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
+    // default implementations below (`__rdl_oom`) otherwise.
+    #[rustc_allocator_nounwind]
+    fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
+}
+
 /// Abort on memory allocation error or failure.
 ///
 /// Callers of memory allocation APIs wishing to abort computation
@@ -378,7 +387,7 @@ pub fn handle_alloc_error(layout: Layout) -> ! {
 #[doc(hidden)]
 #[allow(unused_attributes)]
 #[unstable(feature = "alloc_internals", issue = "none")]
-pub mod __default_lib_allocator {
+pub mod __alloc_error_handler {
     use crate::alloc::Layout;
 
     // called via generated `__rust_alloc_error_handler`
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index d6d09b68a61..b4455233301 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1080,7 +1080,7 @@ impl From<Cow<'_, str>> for Box<str> {
 
 #[stable(feature = "boxed_str_conv", since = "1.19.0")]
 impl<A: AllocRef> From<Box<str, A>> for Box<[u8], A> {
-    /// Converts a `Box<str>>` into a `Box<[u8]>`
+    /// Converts a `Box<str>` into a `Box<[u8]>`
     ///
     /// This conversion does not allocate on the heap and happens in place.
     ///
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 04f317401f1..606bf94f998 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -1783,6 +1783,10 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> {
 
     /// Implementation of a typical `DrainFilter::size_hint` method.
     pub(super) fn size_hint(&self) -> (usize, Option<usize>) {
+        // In most of the btree iterators, `self.length` is the number of elements
+        // yet to be visited. Here, it includes elements that were visited and that
+        // the predicate decided not to drain. Making this upper bound more accurate
+        // requires maintaining an extra field and is not worth while.
         (0, Some(*self.length))
     }
 }
diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs
index 626521c2c3c..12f29d7efbc 100644
--- a/library/alloc/src/collections/btree/node.rs
+++ b/library/alloc/src/collections/btree/node.rs
@@ -170,6 +170,22 @@ impl<K, V> Root<K, V> {
         NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
     }
 
+    /// Borrows and returns a mutable reference to the leaf node owned by the root.
+    /// # Safety
+    /// The root node is a leaf.
+    unsafe fn leaf_node_as_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Leaf> {
+        debug_assert!(self.height == 0);
+        NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
+    }
+
+    /// Borrows and returns a mutable reference to the internal node owned by the root.
+    /// # Safety
+    /// The root node is not a leaf.
+    unsafe fn internal_node_as_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> {
+        debug_assert!(self.height > 0);
+        NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
+    }
+
     pub fn node_as_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, marker::LeafOrInternal> {
         NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }
     }
@@ -188,14 +204,11 @@ impl<K, V> Root<K, V> {
         self.node = BoxedNode::from_internal(new_node);
         self.height += 1;
 
-        let mut ret =
-            NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData };
-
         unsafe {
+            let mut ret = self.internal_node_as_mut();
             ret.reborrow_mut().first_edge().correct_parent_link();
+            ret
         }
-
-        ret
     }
 
     /// Removes the internal root node, using its first child as the new root node.
@@ -212,11 +225,8 @@ impl<K, V> Root<K, V> {
 
         let top = self.node.ptr;
 
-        self.node = unsafe {
-            BoxedNode::from_ptr(
-                self.node_as_mut().cast_unchecked::<marker::Internal>().first_edge().descend().node,
-            )
-        };
+        let internal_node = unsafe { self.internal_node_as_mut() };
+        self.node = unsafe { BoxedNode::from_ptr(internal_node.first_edge().descend().node) };
         self.height -= 1;
         self.node_as_mut().as_leaf_mut().parent = None;
 
@@ -247,8 +257,13 @@ impl<K, V> Root<K, V> {
 ///   `NodeRef` points to an internal node, and when this is `LeafOrInternal` the
 ///   `NodeRef` could be pointing to either type of node.
 pub struct NodeRef<BorrowType, K, V, Type> {
-    /// The number of levels below the node.
+    /// 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.
+    /// Unconstrained if `Type` is `LeafOrInternal`, must be zero if `Type` is `Leaf`,
+    /// and must be non-zero if `Type` is `Internal`.
     height: usize,
+    /// The pointer to the leaf or internal node. The definition of `InternalNode`
+    /// ensures that the pointer is valid either way.
     node: NonNull<LeafNode<K, V>>,
     _marker: PhantomData<(BorrowType, Type)>,
 }
@@ -305,8 +320,8 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> {
         unsafe { usize::from((*self.as_leaf_ptr()).len) }
     }
 
-    /// Returns the height of this node in the whole tree. Zero height denotes the
-    /// leaf level.
+    /// Returns the height of this node with respect to the leaf level. Zero height means the
+    /// node is a leaf itself.
     pub fn height(&self) -> usize {
         self.height
     }
@@ -443,9 +458,9 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> {
 }
 
 impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
-    /// Unsafely asserts to the compiler some static information about whether this
-    /// node is a `Leaf` or an `Internal`.
-    unsafe fn cast_unchecked<NewType>(self) -> NodeRef<marker::Mut<'a>, K, V, NewType> {
+    /// Unsafely asserts to the compiler the static information that this node is an `Internal`.
+    unsafe fn cast_to_internal_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
+        debug_assert!(self.height > 0);
         NodeRef { height: self.height, node: self.node, _marker: PhantomData }
     }
 
@@ -574,9 +589,11 @@ impl<'a, K, V, Type> NodeRef<marker::ValMut<'a>, K, V, Type> {
         // 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 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 [_] = unsafe { &raw const (*leaf).keys };
-        let vals: *mut [_] = unsafe { &raw mut (*leaf).vals };
+        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() };
@@ -807,11 +824,25 @@ impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, mar
     }
 }
 
+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 {
+            debug_assert_eq!(*height, other.height);
+            true
+        } else {
+            false
+        }
+    }
+}
+
 impl<BorrowType, K, V, NodeType, HandleType> PartialEq
     for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType>
 {
     fn eq(&self, other: &Self) -> bool {
-        self.node.node == other.node.node && self.idx == other.idx
+        let Self { node, idx, _marker: _ } = self;
+        node.eq(&other.node) && *idx == other.idx
     }
 }
 
@@ -819,7 +850,8 @@ impl<BorrowType, K, V, NodeType, HandleType> PartialOrd
     for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType>
 {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-        if self.node.node == other.node.node { Some(self.idx.cmp(&other.idx)) } else { None }
+        let Self { node, idx, _marker: _ } = self;
+        if node.eq(&other.node) { Some(idx.cmp(&other.idx)) } else { None }
     }
 }
 
@@ -943,10 +975,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark
                     Handle::new_edge(left.reborrow_mut(), insert_idx)
                 },
                 InsertionPlace::Right(insert_idx) => unsafe {
-                    Handle::new_edge(
-                        right.node_as_mut().cast_unchecked::<marker::Leaf>(),
-                        insert_idx,
-                    )
+                    Handle::new_edge(right.leaf_node_as_mut(), insert_idx)
                 },
             };
             let val_ptr = insertion_edge.insert_fit(key, val);
@@ -1006,10 +1035,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
                     Handle::new_edge(left.reborrow_mut(), insert_idx)
                 },
                 InsertionPlace::Right(insert_idx) => unsafe {
-                    Handle::new_edge(
-                        right.node_as_mut().cast_unchecked::<marker::Internal>(),
-                        insert_idx,
-                    )
+                    Handle::new_edge(right.internal_node_as_mut(), insert_idx)
                 },
             };
             insertion_edge.insert_fit(key, val, edge);
@@ -1205,7 +1231,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
 
             let mut new_root = Root { node: BoxedNode::from_internal(new_node), height };
 
-            new_root.node_as_mut().cast_unchecked().correct_childrens_parent_links(0..=new_len);
+            new_root.internal_node_as_mut().correct_childrens_parent_links(0..=new_len);
 
             (self.node, k, v, new_root)
         }
@@ -1258,8 +1284,8 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>,
             if self.node.height > 1 {
                 // SAFETY: the height of the nodes being merged is one below the height
                 // of the node of this edge, thus above zero, so they are internal.
-                let mut left_node = left_node.cast_unchecked::<marker::Internal>();
-                let right_node = right_node.cast_unchecked::<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),
diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs
index 54c3709821a..2ef9aad0ccd 100644
--- a/library/alloc/src/collections/btree/node/tests.rs
+++ b/library/alloc/src/collections/btree/node/tests.rs
@@ -1,4 +1,5 @@
 use super::*;
+use core::cmp::Ordering::*;
 
 #[test]
 fn test_splitpoint() {
@@ -25,6 +26,38 @@ fn test_splitpoint() {
 }
 
 #[test]
+fn test_partial_cmp_eq() {
+    let mut root1: Root<i32, ()> = Root::new_leaf();
+    let mut leaf1 = unsafe { root1.leaf_node_as_mut() };
+    leaf1.push(1, ());
+    root1.push_internal_level();
+    let root2: Root<i32, ()> = Root::new_leaf();
+
+    let leaf_edge_1a = root1.node_as_ref().first_leaf_edge().forget_node_type();
+    let leaf_edge_1b = root1.node_as_ref().last_leaf_edge().forget_node_type();
+    let top_edge_1 = root1.node_as_ref().first_edge();
+    let top_edge_2 = root2.node_as_ref().first_edge();
+
+    assert!(leaf_edge_1a == leaf_edge_1a);
+    assert!(leaf_edge_1a != leaf_edge_1b);
+    assert!(leaf_edge_1a != top_edge_1);
+    assert!(leaf_edge_1a != top_edge_2);
+    assert!(top_edge_1 == top_edge_1);
+    assert!(top_edge_1 != top_edge_2);
+
+    assert_eq!(leaf_edge_1a.partial_cmp(&leaf_edge_1a), Some(Equal));
+    assert_eq!(leaf_edge_1a.partial_cmp(&leaf_edge_1b), Some(Less));
+    assert_eq!(leaf_edge_1a.partial_cmp(&top_edge_1), None);
+    assert_eq!(leaf_edge_1a.partial_cmp(&top_edge_2), None);
+    assert_eq!(top_edge_1.partial_cmp(&top_edge_1), Some(Equal));
+    assert_eq!(top_edge_1.partial_cmp(&top_edge_2), None);
+
+    root1.pop_internal_level();
+    unsafe { root1.into_ref().deallocate_and_ascend() };
+    unsafe { root2.into_ref().deallocate_and_ascend() };
+}
+
+#[test]
 #[cfg(target_arch = "x86_64")]
 fn test_sizes() {
     assert_eq!(core::mem::size_of::<LeafNode<(), ()>>(), 16);
diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs
index b20ccd388d1..5e68f76693f 100644
--- a/library/alloc/src/vec.rs
+++ b/library/alloc/src/vec.rs
@@ -1476,7 +1476,8 @@ impl<T> Vec<T> {
     /// `'a`. If the type has only static references, or none at all, then this
     /// may be chosen to be `'static`.
     ///
-    /// This function is similar to the `leak` function on `Box`.
+    /// This function is similar to the [`leak`][Box::leak] function on [`Box`]
+    /// except that there is no way to recover the leaked memory.
     ///
     /// This function is mainly useful for data that lives for the remainder of
     /// the program's life. Dropping the returned reference will cause a memory
@@ -2591,6 +2592,8 @@ __impl_slice_eq1! { [] Vec<A>, &[B], #[stable(feature = "rust1", since = "1.0.0"
 __impl_slice_eq1! { [] Vec<A>, &mut [B], #[stable(feature = "rust1", since = "1.0.0")] }
 __impl_slice_eq1! { [] &[A], Vec<B>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
 __impl_slice_eq1! { [] &mut [A], Vec<B>, #[stable(feature = "partialeq_vec_for_ref_slice", since = "1.46.0")] }
+__impl_slice_eq1! { [] Vec<A>, [B], #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")]  }
+__impl_slice_eq1! { [] [A], Vec<B>, #[stable(feature = "partialeq_vec_for_slice", since = "1.48.0")]  }
 __impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B> where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
 __impl_slice_eq1! { [] Cow<'_, [A]>, &[B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
 __impl_slice_eq1! { [] Cow<'_, [A]>, &mut [B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index b7c7138db4f..771a293b8e5 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -1799,7 +1799,7 @@ fn partialeq_vec_and_prim() {
 }
 
 macro_rules! assert_partial_eq_valid {
-    ($a2:ident, $a3:ident; $b2:ident, $b3: ident) => {
+    ($a2:expr, $a3:expr; $b2:expr, $b3: expr) => {
         assert!($a2 == $b2);
         assert!($a2 != $b3);
         assert!($a3 != $b2);
@@ -1831,6 +1831,7 @@ fn partialeq_vec_full() {
     assert_partial_eq_valid!(slicemut2,slicemut3; vec2,vec3);
     assert_partial_eq_valid!(vec2,vec3; array2,array3);
     assert_partial_eq_valid!(vec2,vec3; arrayref2,arrayref3);
+    assert_partial_eq_valid!(vec2,vec3; arrayref2[..],arrayref3[..]);
 }
 
 #[test]
diff --git a/library/backtrace b/library/backtrace
-Subproject 4083a90168d605b682ba166a0c01f86b3384e47
+Subproject 893fbb23688e98376e54c26b59432a2966a8cc9
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 15ec13ca65a..7140218fa91 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -226,7 +226,7 @@ use crate::ptr;
 /// assert_eq!(my_struct.special_field.get(), new_value);
 /// ```
 ///
-/// See the [module-level documentation](index.html) for more.
+/// See the [module-level documentation](self) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[repr(transparent)]
 pub struct Cell<T: ?Sized> {
@@ -566,7 +566,7 @@ impl<T> Cell<[T]> {
 
 /// A mutable memory location with dynamically checked borrow rules
 ///
-/// See the [module-level documentation](index.html) for more.
+/// See the [module-level documentation](self) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RefCell<T: ?Sized> {
     borrow: Cell<BorrowFlag>,
@@ -1203,7 +1203,7 @@ impl Clone for BorrowRef<'_> {
 /// Wraps a borrowed reference to a value in a `RefCell` box.
 /// A wrapper type for an immutably borrowed value from a `RefCell<T>`.
 ///
-/// See the [module-level documentation](index.html) for more.
+/// See the [module-level documentation](self) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Ref<'b, T: ?Sized + 'b> {
     value: &'b T,
@@ -1493,7 +1493,7 @@ impl<'b> BorrowRefMut<'b> {
 
 /// A wrapper type for a mutably borrowed value from a `RefCell<T>`.
 ///
-/// See the [module-level documentation](index.html) for more.
+/// See the [module-level documentation](self) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RefMut<'b, T: ?Sized + 'b> {
     value: &'b mut T,
diff --git a/library/core/src/ffi.rs b/library/core/src/ffi.rs
index 4525ba78ba0..e146a97ae94 100644
--- a/library/core/src/ffi.rs
+++ b/library/core/src/ffi.rs
@@ -280,7 +280,7 @@ impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> {
 // within a private module. Once RFC 2145 has been implemented look into
 // improving this.
 mod sealed_trait {
-    /// Trait which permits the allowed types to be used with [VaList::arg].
+    /// Trait which permits the allowed types to be used with [super::VaListImpl::arg].
     #[unstable(
         feature = "c_variadic",
         reason = "the `c_variadic` feature has not been properly tested on \
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 54772ebb523..0963c6d6cd7 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -92,18 +92,14 @@ pub type Result = result::Result<(), Error>;
 #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
 pub struct Error;
 
-/// A collection of methods that are required to format a message into a stream.
+/// A trait for writing or formatting into Unicode-accepting buffers or streams.
 ///
-/// This trait is the type which this modules requires when formatting
-/// information. This is similar to the standard library's [`io::Write`] trait,
-/// but it is only intended for use in libcore.
+/// This trait only accepts UTF-8–encoded data and is not [flushable]. If you only
+/// want to accept Unicode and you don't need flushing, you should implement this trait;
+/// otherwise you should implement [`std::io::Write`].
 ///
-/// This trait should generally not be implemented by consumers of the standard
-/// library. The [`write!`] macro accepts an instance of [`io::Write`], and the
-/// [`io::Write`] trait is favored over implementing this trait.
-///
-/// [`write!`]: crate::write!
-/// [`io::Write`]: ../../std/io/trait.Write.html
+/// [`std::io::Write`]: ../../std/io/trait.Write.html
+/// [flushable]: ../../std/io/trait.Write.html#tymethod.flush
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Write {
     /// Writes a string slice into this writer, returning whether the write
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 426cdb12ec4..2a7c105e807 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1072,7 +1072,7 @@ extern "rust-intrinsic" {
     // NOTE: While this makes the intrinsic const stable, we have some custom code in const fn
     // checks that prevent its use within `const fn`.
     #[rustc_const_stable(feature = "const_transmute", since = "1.46.0")]
-    #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "transmute")]
+    #[rustc_diagnostic_item = "transmute"]
     pub fn transmute<T, U>(e: T) -> U;
 
     /// Returns `true` if the actual type given as `T` requires drop
@@ -1082,7 +1082,7 @@ extern "rust-intrinsic" {
     /// If the actual type neither requires drop glue nor implements
     /// `Copy`, then the return value of this function is unspecified.
     ///
-    /// The stabilized version of this intrinsic is [`needs_drop`].
+    /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop).
     #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")]
     pub fn needs_drop<T>() -> bool;
 
diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs
index 97562cf73b8..44da8f4715c 100644
--- a/library/core/src/iter/sources.rs
+++ b/library/core/src/iter/sources.rs
@@ -501,9 +501,9 @@ pub fn once_with<A, F: FnOnce() -> A>(gen: F) -> OnceWith<F> {
 ///
 /// # Examples
 ///
-/// Let’s re-implement the counter iterator from [module-level documentation]:
+/// Let’s re-implement the counter iterator from the [module-level documentation]:
 ///
-/// [module-level documentation]: index.html
+/// [module-level documentation]: super
 ///
 /// ```
 /// let mut count = 0;
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 41a503c4abb..1ae6d15c12d 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -94,7 +94,7 @@ pub trait FromIterator<A>: Sized {
     ///
     /// See the [module-level documentation] for more.
     ///
-    /// [module-level documentation]: index.html
+    /// [module-level documentation]: crate::iter
     ///
     /// # Examples
     ///
@@ -120,7 +120,7 @@ pub trait FromIterator<A>: Sized {
 /// collection of some kind.
 ///
 /// One benefit of implementing `IntoIterator` is that your type will [work
-/// with Rust's `for` loop syntax](index.html#for-loops-and-intoiterator).
+/// with Rust's `for` loop syntax](crate::iter#for-loops-and-intoiterator).
 ///
 /// See also: [`FromIterator`].
 ///
@@ -212,7 +212,7 @@ pub trait IntoIterator {
     ///
     /// See the [module-level documentation] for more.
     ///
-    /// [module-level documentation]: index.html
+    /// [module-level documentation]: crate::iter
     ///
     /// # Examples
     ///
diff --git a/library/core/src/iter/traits/exact_size.rs b/library/core/src/iter/traits/exact_size.rs
index 33ace60a274..eadbdf45c7c 100644
--- a/library/core/src/iter/traits/exact_size.rs
+++ b/library/core/src/iter/traits/exact_size.rs
@@ -26,10 +26,10 @@
 /// assert_eq!(5, five.len());
 /// ```
 ///
-/// In the [module level docs][moddocs], we implemented an [`Iterator`],
-/// `Counter`. Let's implement `ExactSizeIterator` for it as well:
+/// In the [module-level docs], we implemented an [`Iterator`], `Counter`.
+/// Let's implement `ExactSizeIterator` for it as well:
 ///
-/// [moddocs]: index.html
+/// [module-level docs]: crate::iter
 ///
 /// ```
 /// # struct Counter {
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 49cec162762..97f27566eb0 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -82,9 +82,9 @@
 #![feature(const_pin)]
 #![feature(const_fn)]
 #![feature(const_fn_union)]
-#![feature(const_assume)]
-#![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))]
-#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))]
+#![cfg_attr(not(bootstrap), feature(const_impl_trait))]
+#![feature(const_fn_floating_point_arithmetic)]
+#![feature(const_fn_fn_ptr_basics)]
 #![feature(const_generics)]
 #![feature(const_option)]
 #![feature(const_precise_live_drops)]
@@ -126,13 +126,14 @@
 #![feature(staged_api)]
 #![feature(std_internals)]
 #![feature(stmt_expr_attributes)]
+#![feature(str_split_as_str)]
+#![feature(str_split_inclusive_as_str)]
 #![feature(transparent_unions)]
 #![feature(unboxed_closures)]
 #![feature(unsized_locals)]
 #![feature(untagged_unions)]
 #![feature(unwind_attributes)]
 #![feature(variant_count)]
-#![cfg_attr(bootstrap, feature(doc_alias))]
 #![feature(tbm_target_feature)]
 #![feature(sse4a_target_feature)]
 #![feature(arm_target_feature)]
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 0cfb4af59b9..9cb20a0afdc 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -141,6 +141,9 @@
 //! ```
 //!
 //! [`Box<T>`]: ../../std/boxed/struct.Box.html
+//! [`Box<U>`]: ../../std/boxed/struct.Box.html
+//! [`num::NonZero*`]: crate::num
+//! [`ptr::NonNull<U>`]: crate::ptr::NonNull
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 5cec183c237..b6d9f13d881 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -233,7 +233,7 @@ use crate::{convert, fmt};
 
 /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).
 ///
-/// See the [`std::result`](index.html) module documentation for details.
+/// See the [module documentation](self) for details.
 #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
 #[must_use = "this `Result` may be an `Err` variant, which should be handled"]
 #[rustc_diagnostic_item = "result_type"]
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 793cbf99495..24f955a70b6 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -10,6 +10,7 @@ use crate::intrinsics::{assume, exact_div, unchecked_sub};
 use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess};
 use crate::marker::{PhantomData, Send, Sized, Sync};
 use crate::mem;
+use crate::num::NonZeroUsize;
 use crate::ptr::NonNull;
 
 use super::{from_raw_parts, from_raw_parts_mut};
@@ -1187,12 +1188,12 @@ forward_iterator! { RSplitNMut: T, &'a mut [T] }
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Windows<'a, T: 'a> {
     v: &'a [T],
-    size: usize,
+    size: NonZeroUsize,
 }
 
 impl<'a, T: 'a> Windows<'a, T> {
     #[inline]
-    pub(super) fn new(slice: &'a [T], size: usize) -> Self {
+    pub(super) fn new(slice: &'a [T], size: NonZeroUsize) -> Self {
         Self { v: slice, size }
     }
 }
@@ -1211,10 +1212,10 @@ impl<'a, T> Iterator for Windows<'a, T> {
 
     #[inline]
     fn next(&mut self) -> Option<&'a [T]> {
-        if self.size > self.v.len() {
+        if self.size.get() > self.v.len() {
             None
         } else {
-            let ret = Some(&self.v[..self.size]);
+            let ret = Some(&self.v[..self.size.get()]);
             self.v = &self.v[1..];
             ret
         }
@@ -1222,10 +1223,10 @@ impl<'a, T> Iterator for Windows<'a, T> {
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.size > self.v.len() {
+        if self.size.get() > self.v.len() {
             (0, Some(0))
         } else {
-            let size = self.v.len() - self.size + 1;
+            let size = self.v.len() - self.size.get() + 1;
             (size, Some(size))
         }
     }
@@ -1237,7 +1238,7 @@ impl<'a, T> Iterator for Windows<'a, T> {
 
     #[inline]
     fn nth(&mut self, n: usize) -> Option<Self::Item> {
-        let (end, overflow) = self.size.overflowing_add(n);
+        let (end, overflow) = self.size.get().overflowing_add(n);
         if end > self.v.len() || overflow {
             self.v = &[];
             None
@@ -1250,10 +1251,10 @@ impl<'a, T> Iterator for Windows<'a, T> {
 
     #[inline]
     fn last(self) -> Option<Self::Item> {
-        if self.size > self.v.len() {
+        if self.size.get() > self.v.len() {
             None
         } else {
-            let start = self.v.len() - self.size;
+            let start = self.v.len() - self.size.get();
             Some(&self.v[start..])
         }
     }
@@ -1264,7 +1265,7 @@ impl<'a, T> Iterator for Windows<'a, T> {
         // which means that `i` cannot overflow an `isize`, and the
         // slice created by `from_raw_parts` is a subslice of `self.v`
         // thus is guaranteed to be valid for the lifetime `'a` of `self.v`.
-        unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) }
+        unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size.get()) }
     }
 }
 
@@ -1272,10 +1273,10 @@ impl<'a, T> Iterator for Windows<'a, T> {
 impl<'a, T> DoubleEndedIterator for Windows<'a, T> {
     #[inline]
     fn next_back(&mut self) -> Option<&'a [T]> {
-        if self.size > self.v.len() {
+        if self.size.get() > self.v.len() {
             None
         } else {
-            let ret = Some(&self.v[self.v.len() - self.size..]);
+            let ret = Some(&self.v[self.v.len() - self.size.get()..]);
             self.v = &self.v[..self.v.len() - 1];
             ret
         }
@@ -1284,11 +1285,11 @@ impl<'a, T> DoubleEndedIterator for Windows<'a, T> {
     #[inline]
     fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
         let (end, overflow) = self.v.len().overflowing_sub(n);
-        if end < self.size || overflow {
+        if end < self.size.get() || overflow {
             self.v = &[];
             None
         } else {
-            let ret = &self.v[end - self.size..end];
+            let ret = &self.v[end - self.size.get()..end];
             self.v = &self.v[..end - 1];
             Some(ret)
         }
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 9373c6feccd..349c2cde274 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -11,6 +11,7 @@
 use crate::cmp::Ordering::{self, Equal, Greater, Less};
 use crate::marker::Copy;
 use crate::mem;
+use crate::num::NonZeroUsize;
 use crate::ops::{FnMut, Range, RangeBounds};
 use crate::option::Option;
 use crate::option::Option::{None, Some};
@@ -78,17 +79,6 @@ pub use index::check_range;
 #[lang = "slice"]
 #[cfg(not(test))]
 impl<T> [T] {
-    #[cfg(not(bootstrap))] // Unused in bootstrap
-    /// The maximum, inclusive, length such that the slice is no larger than `isize::MAX` bytes.
-    /// This constant is used in `len` below.
-    const MAX_LEN_BOUND: usize = {
-        if mem::size_of::<T>() == 0 {
-            usize::MAX
-        } else {
-            isize::MAX as usize / mem::size_of::<T>()
-        }
-    };
-
     /// Returns the number of elements in the slice.
     ///
     /// # Examples
@@ -101,23 +91,11 @@ impl<T> [T] {
     #[rustc_const_stable(feature = "const_slice_len", since = "1.32.0")]
     #[inline]
     // SAFETY: const sound because we transmute out the length field as a usize (which it must be)
-    #[allow_internal_unstable(const_fn_union, const_assume)]
+    #[allow_internal_unstable(const_fn_union)]
     pub const fn len(&self) -> usize {
         // SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
         // Only `std` can make this guarantee.
-        let raw_len = unsafe { crate::ptr::Repr { rust: self }.raw.len };
-
-        #[cfg(not(bootstrap))] // FIXME: executing assume in const eval not supported in bootstrap
-        // SAFETY: this assume asserts that `raw_len * size_of::<T>() <= isize::MAX`. All
-        // references must point to one allocation with size at most isize::MAX. Note that we the
-        // multiplication could appear to overflow until we have assumed the bound. This overflow
-        // would make additional values appear 'valid' and then `n > 1` the range of permissible
-        // length would no longer be the full or even a single range.
-        unsafe {
-            crate::intrinsics::assume(raw_len <= Self::MAX_LEN_BOUND)
-        };
-
-        raw_len
+        unsafe { crate::ptr::Repr { rust: self }.raw.len }
     }
 
     /// Returns `true` if the slice has a length of 0.
@@ -751,7 +729,7 @@ impl<T> [T] {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn windows(&self, size: usize) -> Windows<'_, T> {
-        assert_ne!(size, 0);
+        let size = NonZeroUsize::new(size).expect("size is zero");
         Windows::new(self, size)
     }
 
@@ -2057,6 +2035,50 @@ impl<T> [T] {
     }
 
     /// Reorder the slice such that the element at `index` is at its final sorted position.
+    #[unstable(feature = "slice_partition_at_index", issue = "55300")]
+    #[rustc_deprecated(since = "1.49.0", reason = "use the select_nth_unstable() instead")]
+    #[inline]
+    pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T])
+    where
+        T: Ord,
+    {
+        self.select_nth_unstable(index)
+    }
+
+    /// Reorder the slice with a comparator function such that the element at `index` is at its
+    /// final sorted position.
+    #[unstable(feature = "slice_partition_at_index", issue = "55300")]
+    #[rustc_deprecated(since = "1.49.0", reason = "use select_nth_unstable_by() instead")]
+    #[inline]
+    pub fn partition_at_index_by<F>(
+        &mut self,
+        index: usize,
+        compare: F,
+    ) -> (&mut [T], &mut T, &mut [T])
+    where
+        F: FnMut(&T, &T) -> Ordering,
+    {
+        self.select_nth_unstable_by(index, compare)
+    }
+
+    /// Reorder the slice with a key extraction function such that the element at `index` is at its
+    /// final sorted position.
+    #[unstable(feature = "slice_partition_at_index", issue = "55300")]
+    #[rustc_deprecated(since = "1.49.0", reason = "use the select_nth_unstable_by_key() instead")]
+    #[inline]
+    pub fn partition_at_index_by_key<K, F>(
+        &mut self,
+        index: usize,
+        f: F,
+    ) -> (&mut [T], &mut T, &mut [T])
+    where
+        F: FnMut(&T) -> K,
+        K: Ord,
+    {
+        self.select_nth_unstable_by_key(index, f)
+    }
+
+    /// Reorder the slice such that the element at `index` is at its final sorted position.
     ///
     /// This reordering has the additional property that any value at position `i < index` will be
     /// less than or equal to any value at a position `j > index`. Additionally, this reordering is
@@ -2080,12 +2102,10 @@ impl<T> [T] {
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_partition_at_index)]
-    ///
     /// let mut v = [-5i32, 4, 1, -3, 2];
     ///
     /// // Find the median
-    /// v.partition_at_index(2);
+    /// v.select_nth_unstable(2);
     ///
     /// // We are only guaranteed the slice will be one of the following, based on the way we sort
     /// // about the specified index.
@@ -2094,9 +2114,9 @@ impl<T> [T] {
     ///         v == [-3, -5, 1, 4, 2] ||
     ///         v == [-5, -3, 1, 4, 2]);
     /// ```
-    #[unstable(feature = "slice_partition_at_index", issue = "55300")]
+    #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")]
     #[inline]
-    pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T])
+    pub fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T])
     where
         T: Ord,
     {
@@ -2130,12 +2150,10 @@ impl<T> [T] {
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_partition_at_index)]
-    ///
     /// let mut v = [-5i32, 4, 1, -3, 2];
     ///
     /// // Find the median as if the slice were sorted in descending order.
-    /// v.partition_at_index_by(2, |a, b| b.cmp(a));
+    /// v.select_nth_unstable_by(2, |a, b| b.cmp(a));
     ///
     /// // We are only guaranteed the slice will be one of the following, based on the way we sort
     /// // about the specified index.
@@ -2144,9 +2162,9 @@ impl<T> [T] {
     ///         v == [4, 2, 1, -5, -3] ||
     ///         v == [4, 2, 1, -3, -5]);
     /// ```
-    #[unstable(feature = "slice_partition_at_index", issue = "55300")]
+    #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")]
     #[inline]
-    pub fn partition_at_index_by<F>(
+    pub fn select_nth_unstable_by<F>(
         &mut self,
         index: usize,
         mut compare: F,
@@ -2184,12 +2202,10 @@ impl<T> [T] {
     /// # Examples
     ///
     /// ```
-    /// #![feature(slice_partition_at_index)]
-    ///
     /// let mut v = [-5i32, 4, 1, -3, 2];
     ///
     /// // Return the median as if the array were sorted according to absolute value.
-    /// v.partition_at_index_by_key(2, |a| a.abs());
+    /// v.select_nth_unstable_by_key(2, |a| a.abs());
     ///
     /// // We are only guaranteed the slice will be one of the following, based on the way we sort
     /// // about the specified index.
@@ -2198,9 +2214,9 @@ impl<T> [T] {
     ///         v == [2, 1, -3, 4, -5] ||
     ///         v == [2, 1, -3, -5, 4]);
     /// ```
-    #[unstable(feature = "slice_partition_at_index", issue = "55300")]
+    #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")]
     #[inline]
-    pub fn partition_at_index_by_key<K, F>(
+    pub fn select_nth_unstable_by_key<K, F>(
         &mut self,
         index: usize,
         mut f: F,
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index 27a67e2b22f..bee86df520c 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -690,6 +690,17 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
             },
         }
     }
+
+    #[inline]
+    fn as_str(&self) -> &'a str {
+        // `Self::get_end` doesn't change `self.start`
+        if self.finished {
+            return "";
+        }
+
+        // SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
+        unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) }
+    }
 }
 
 generate_pattern_iterators! {
@@ -710,6 +721,48 @@ generate_pattern_iterators! {
     delegate double ended;
 }
 
+impl<'a, P: Pattern<'a>> Split<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_as_str)]
+    /// let mut split = "Mary had a little lamb".split(' ');
+    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// split.next();
+    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
+impl<'a, P: Pattern<'a>> RSplit<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_as_str)]
+    /// let mut split = "Mary had a little lamb".rsplit(' ');
+    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// split.next();
+    /// assert_eq!(split.as_str(), "Mary had a little");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
 generate_pattern_iterators! {
     forward:
         /// Created with the method [`split_terminator`].
@@ -728,6 +781,48 @@ generate_pattern_iterators! {
     delegate double ended;
 }
 
+impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_as_str)]
+    /// let mut split = "A..B..".split_terminator('.');
+    /// assert_eq!(split.as_str(), "A..B..");
+    /// split.next();
+    /// assert_eq!(split.as_str(), ".B..");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
+impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_as_str)]
+    /// let mut split = "A..B..".rsplit_terminator('.');
+    /// assert_eq!(split.as_str(), "A..B..");
+    /// split.next();
+    /// assert_eq!(split.as_str(), "A..B");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
 derive_pattern_clone! {
     clone SplitNInternal
     with |s| SplitNInternal { iter: s.iter.clone(), ..*s }
@@ -784,6 +879,11 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> {
             }
         }
     }
+
+    #[inline]
+    fn as_str(&self) -> &'a str {
+        self.iter.as_str()
+    }
 }
 
 generate_pattern_iterators! {
@@ -804,6 +904,48 @@ generate_pattern_iterators! {
     delegate single ended;
 }
 
+impl<'a, P: Pattern<'a>> SplitN<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_as_str)]
+    /// let mut split = "Mary had a little lamb".splitn(3, ' ');
+    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// split.next();
+    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
+impl<'a, P: Pattern<'a>> RSplitN<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_as_str)]
+    /// let mut split = "Mary had a little lamb".rsplitn(3, ' ');
+    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// split.next();
+    /// assert_eq!(split.as_str(), "Mary had a little");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
 derive_pattern_clone! {
     clone MatchIndicesInternal
     with |s| MatchIndicesInternal(s.0.clone())
@@ -1134,6 +1276,28 @@ impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator
 #[unstable(feature = "split_inclusive", issue = "72360")]
 impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
 
+impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_inclusive_as_str)]
+    /// #![feature(split_inclusive)]
+    /// let mut split = "Mary had a little lamb".split_inclusive(' ');
+    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    /// split.next();
+    /// assert_eq!(split.as_str(), "had a little lamb");
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.0.as_str()
+    }
+}
+
 /// An iterator of [`u16`] over the string encoded as UTF-16.
 ///
 /// This struct is created by the [`encode_utf16`] method on [`str`].
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index ba3fb35caaf..8cca9dc9042 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -130,8 +130,7 @@ impl RawWakerVTable {
     #[rustc_promotable]
     #[stable(feature = "futures_api", since = "1.36.0")]
     #[rustc_const_stable(feature = "futures_api", since = "1.36.0")]
-    #[cfg_attr(not(bootstrap), allow_internal_unstable(const_fn_fn_ptr_basics))]
-    #[cfg_attr(bootstrap, rustc_allow_const_fn_ptr)]
+    #[allow_internal_unstable(const_fn_fn_ptr_basics)]
     pub const fn new(
         clone: unsafe fn(*const ()) -> RawWaker,
         wake: unsafe fn(*const ()),
diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
index 27e6760e7cb..fcb0d6031be 100644
--- a/library/core/tests/num/int_macros.rs
+++ b/library/core/tests/num/int_macros.rs
@@ -204,8 +204,8 @@ macro_rules! int_module {
 
             #[test]
             fn test_from_str() {
-                fn from_str<T: ::std::str::FromStr>(t: &str) -> Option<T> {
-                    ::std::str::FromStr::from_str(t).ok()
+                fn from_str<T: std::str::FromStr>(t: &str) -> Option<T> {
+                    std::str::FromStr::from_str(t).ok()
                 }
                 assert_eq!(from_str::<$T>("0"), Some(0 as $T));
                 assert_eq!(from_str::<$T>("3"), Some(3 as $T));
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 5ef30b1a889..ac5c9353ccb 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -1571,7 +1571,7 @@ fn sort_unstable() {
 #[test]
 #[cfg(not(target_arch = "wasm32"))]
 #[cfg_attr(miri, ignore)] // Miri is too slow
-fn partition_at_index() {
+fn select_nth_unstable() {
     use core::cmp::Ordering::{Equal, Greater, Less};
     use rand::rngs::StdRng;
     use rand::seq::SliceRandom;
@@ -1597,7 +1597,7 @@ fn partition_at_index() {
                 // Sort in default order.
                 for pivot in 0..len {
                     let mut v = orig.clone();
-                    v.partition_at_index(pivot);
+                    v.select_nth_unstable(pivot);
 
                     assert_eq!(v_sorted[pivot], v[pivot]);
                     for i in 0..pivot {
@@ -1610,7 +1610,7 @@ fn partition_at_index() {
                 // Sort in ascending order.
                 for pivot in 0..len {
                     let mut v = orig.clone();
-                    let (left, pivot, right) = v.partition_at_index_by(pivot, |a, b| a.cmp(b));
+                    let (left, pivot, right) = v.select_nth_unstable_by(pivot, |a, b| a.cmp(b));
 
                     assert_eq!(left.len() + right.len(), len - 1);
 
@@ -1633,7 +1633,7 @@ fn partition_at_index() {
 
                 for pivot in 0..len {
                     let mut v = orig.clone();
-                    v.partition_at_index_by(pivot, sort_descending_comparator);
+                    v.select_nth_unstable_by(pivot, sort_descending_comparator);
 
                     assert_eq!(v_sorted_descending[pivot], v[pivot]);
                     for i in 0..pivot {
@@ -1654,7 +1654,7 @@ fn partition_at_index() {
     }
 
     for pivot in 0..v.len() {
-        v.partition_at_index_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
+        v.select_nth_unstable_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap());
         v.sort();
         for i in 0..v.len() {
             assert_eq!(v[i], i as i32);
@@ -1662,28 +1662,28 @@ fn partition_at_index() {
     }
 
     // Should not panic.
-    [(); 10].partition_at_index(0);
-    [(); 10].partition_at_index(5);
-    [(); 10].partition_at_index(9);
-    [(); 100].partition_at_index(0);
-    [(); 100].partition_at_index(50);
-    [(); 100].partition_at_index(99);
+    [(); 10].select_nth_unstable(0);
+    [(); 10].select_nth_unstable(5);
+    [(); 10].select_nth_unstable(9);
+    [(); 100].select_nth_unstable(0);
+    [(); 100].select_nth_unstable(50);
+    [(); 100].select_nth_unstable(99);
 
     let mut v = [0xDEADBEEFu64];
-    v.partition_at_index(0);
+    v.select_nth_unstable(0);
     assert!(v == [0xDEADBEEF]);
 }
 
 #[test]
 #[should_panic(expected = "index 0 greater than length of slice")]
-fn partition_at_index_zero_length() {
-    [0i32; 0].partition_at_index(0);
+fn select_nth_unstable_zero_length() {
+    [0i32; 0].select_nth_unstable(0);
 }
 
 #[test]
 #[should_panic(expected = "index 20 greater than length of slice")]
-fn partition_at_index_past_length() {
-    [0i32; 10].partition_at_index(20);
+fn select_nth_unstable_past_length() {
+    [0i32; 10].select_nth_unstable(20);
 }
 
 pub mod memchr {
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 93fa1f4e585..139b3591206 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -21,7 +21,7 @@
 #![feature(nll)]
 #![feature(staged_api)]
 #![feature(const_fn)]
-#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))]
+#![feature(const_fn_fn_ptr_basics)]
 #![feature(allow_internal_unstable)]
 #![feature(decl_macro)]
 #![feature(extern_types)]
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index cc29e1c0b05..a9d8a4e2a81 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -303,7 +303,8 @@ impl Backtrace {
     // Capture a backtrace which start just before the function addressed by
     // `ip`
     fn create(ip: usize) -> Backtrace {
-        let _lock = lock();
+        // SAFETY: We don't attempt to lock this reentrantly.
+        let _lock = unsafe { lock() };
         let mut frames = Vec::new();
         let mut actual_start = None;
         unsafe {
@@ -408,7 +409,8 @@ impl Capture {
         // Use the global backtrace lock to synchronize this as it's a
         // requirement of the `backtrace` crate, and then actually resolve
         // everything.
-        let _lock = lock();
+        // SAFETY: We don't attempt to lock this reentrantly.
+        let _lock = unsafe { lock() };
         for frame in self.frames.iter_mut() {
             let symbols = &mut frame.symbols;
             let frame = match &frame.frame {
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 2663f682a1d..7e7a28be2b0 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -69,7 +69,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
 /// [`&OsStr`]: OsStr
 /// [`&str`]: str
 /// [`CStr`]: crate::ffi::CStr
-/// [conversions]: index.html#conversions
+/// [conversions]: super#conversions
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OsString {
@@ -88,7 +88,7 @@ pub struct OsString {
 /// the traits which `OsStr` implements for [conversions] from/to native representations.
 ///
 /// [`&str`]: str
-/// [conversions]: index.html#conversions
+/// [conversions]: super#conversions
 #[stable(feature = "rust1", since = "1.0.0")]
 // FIXME:
 // `OsStr::from_inner` current implementation relies
diff --git a/library/std/src/io/buffered.rs b/library/std/src/io/buffered.rs
deleted file mode 100644
index 97c4b879793..00000000000
--- a/library/std/src/io/buffered.rs
+++ /dev/null
@@ -1,1438 +0,0 @@
-//! Buffering wrappers for I/O traits
-
-#[cfg(test)]
-mod tests;
-
-use crate::io::prelude::*;
-
-use crate::cmp;
-use crate::error;
-use crate::fmt;
-use crate::io::{
-    self, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, SeekFrom, DEFAULT_BUF_SIZE,
-};
-use crate::memchr;
-
-/// The `BufReader<R>` struct adds buffering to any reader.
-///
-/// It can be excessively inefficient to work directly with a [`Read`] instance.
-/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`]
-/// results in a system call. A `BufReader<R>` performs large, infrequent reads on
-/// the underlying [`Read`] and maintains an in-memory buffer of the results.
-///
-/// `BufReader<R>` can improve the speed of programs that make *small* and
-/// *repeated* read calls to the same file or network socket. It does not
-/// help when reading very large amounts at once, or reading just one or a few
-/// times. It also provides no advantage when reading from a source that is
-/// already in memory, like a [`Vec`]`<u8>`.
-///
-/// When the `BufReader<R>` is dropped, the contents of its buffer will be
-/// discarded. Creating multiple instances of a `BufReader<R>` on the same
-/// stream can cause data loss. Reading from the underlying reader after
-/// unwrapping the `BufReader<R>` with [`BufReader::into_inner`] can also cause
-/// data loss.
-///
-/// [`TcpStream::read`]: Read::read
-/// [`TcpStream`]: crate::net::TcpStream
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::io::prelude::*;
-/// use std::io::BufReader;
-/// use std::fs::File;
-///
-/// fn main() -> std::io::Result<()> {
-///     let f = File::open("log.txt")?;
-///     let mut reader = BufReader::new(f);
-///
-///     let mut line = String::new();
-///     let len = reader.read_line(&mut line)?;
-///     println!("First line is {} bytes long", len);
-///     Ok(())
-/// }
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct BufReader<R> {
-    inner: R,
-    buf: Box<[u8]>,
-    pos: usize,
-    cap: usize,
-}
-
-impl<R: Read> BufReader<R> {
-    /// Creates a new `BufReader<R>` with a default buffer capacity. The default is currently 8 KB,
-    /// but may change in the future.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufReader;
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f = File::open("log.txt")?;
-    ///     let reader = BufReader::new(f);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn new(inner: R) -> BufReader<R> {
-        BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
-    }
-
-    /// Creates a new `BufReader<R>` with the specified buffer capacity.
-    ///
-    /// # Examples
-    ///
-    /// Creating a buffer with ten bytes of capacity:
-    ///
-    /// ```no_run
-    /// use std::io::BufReader;
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f = File::open("log.txt")?;
-    ///     let reader = BufReader::with_capacity(10, f);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
-        unsafe {
-            let mut buffer = Vec::with_capacity(capacity);
-            buffer.set_len(capacity);
-            inner.initializer().initialize(&mut buffer);
-            BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 }
-        }
-    }
-}
-
-impl<R> BufReader<R> {
-    /// Gets a reference to the underlying reader.
-    ///
-    /// It is inadvisable to directly read from the underlying reader.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufReader;
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f1 = File::open("log.txt")?;
-    ///     let reader = BufReader::new(f1);
-    ///
-    ///     let f2 = reader.get_ref();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_ref(&self) -> &R {
-        &self.inner
-    }
-
-    /// Gets a mutable reference to the underlying reader.
-    ///
-    /// It is inadvisable to directly read from the underlying reader.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufReader;
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f1 = File::open("log.txt")?;
-    ///     let mut reader = BufReader::new(f1);
-    ///
-    ///     let f2 = reader.get_mut();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_mut(&mut self) -> &mut R {
-        &mut self.inner
-    }
-
-    /// Returns a reference to the internally buffered data.
-    ///
-    /// Unlike [`fill_buf`], this will not attempt to fill the buffer if it is empty.
-    ///
-    /// [`fill_buf`]: BufRead::fill_buf
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::{BufReader, BufRead};
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f = File::open("log.txt")?;
-    ///     let mut reader = BufReader::new(f);
-    ///     assert!(reader.buffer().is_empty());
-    ///
-    ///     if reader.fill_buf()?.len() > 0 {
-    ///         assert!(!reader.buffer().is_empty());
-    ///     }
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "bufreader_buffer", since = "1.37.0")]
-    pub fn buffer(&self) -> &[u8] {
-        &self.buf[self.pos..self.cap]
-    }
-
-    /// Returns the number of bytes the internal buffer can hold at once.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::{BufReader, BufRead};
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f = File::open("log.txt")?;
-    ///     let mut reader = BufReader::new(f);
-    ///
-    ///     let capacity = reader.capacity();
-    ///     let buffer = reader.fill_buf()?;
-    ///     assert!(buffer.len() <= capacity);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "buffered_io_capacity", since = "1.46.0")]
-    pub fn capacity(&self) -> usize {
-        self.buf.len()
-    }
-
-    /// Unwraps this `BufReader<R>`, returning the underlying reader.
-    ///
-    /// Note that any leftover data in the internal buffer is lost. Therefore,
-    /// a following read from the underlying reader may lead to data loss.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufReader;
-    /// use std::fs::File;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let f1 = File::open("log.txt")?;
-    ///     let reader = BufReader::new(f1);
-    ///
-    ///     let f2 = reader.into_inner();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_inner(self) -> R {
-        self.inner
-    }
-
-    /// Invalidates all data in the internal buffer.
-    #[inline]
-    fn discard_buffer(&mut self) {
-        self.pos = 0;
-        self.cap = 0;
-    }
-}
-
-impl<R: Seek> BufReader<R> {
-    /// Seeks relative to the current position. If the new position lies within the buffer,
-    /// the buffer will not be flushed, allowing for more efficient seeks.
-    /// This method does not return the location of the underlying reader, so the caller
-    /// must track this information themselves if it is required.
-    #[unstable(feature = "bufreader_seek_relative", issue = "31100")]
-    pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
-        let pos = self.pos as u64;
-        if offset < 0 {
-            if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
-                self.pos = new_pos as usize;
-                return Ok(());
-            }
-        } else {
-            if let Some(new_pos) = pos.checked_add(offset as u64) {
-                if new_pos <= self.cap as u64 {
-                    self.pos = new_pos as usize;
-                    return Ok(());
-                }
-            }
-        }
-        self.seek(SeekFrom::Current(offset)).map(drop)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<R: Read> Read for BufReader<R> {
-    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
-        // If we don't have any buffered data and we're doing a massive read
-        // (larger than our internal buffer), bypass our internal buffer
-        // entirely.
-        if self.pos == self.cap && buf.len() >= self.buf.len() {
-            self.discard_buffer();
-            return self.inner.read(buf);
-        }
-        let nread = {
-            let mut rem = self.fill_buf()?;
-            rem.read(buf)?
-        };
-        self.consume(nread);
-        Ok(nread)
-    }
-
-    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
-        if self.pos == self.cap && total_len >= self.buf.len() {
-            self.discard_buffer();
-            return self.inner.read_vectored(bufs);
-        }
-        let nread = {
-            let mut rem = self.fill_buf()?;
-            rem.read_vectored(bufs)?
-        };
-        self.consume(nread);
-        Ok(nread)
-    }
-
-    fn is_read_vectored(&self) -> bool {
-        self.inner.is_read_vectored()
-    }
-
-    // we can't skip unconditionally because of the large buffer case in read.
-    unsafe fn initializer(&self) -> Initializer {
-        self.inner.initializer()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<R: Read> BufRead for BufReader<R> {
-    fn fill_buf(&mut self) -> io::Result<&[u8]> {
-        // If we've reached the end of our internal buffer then we need to fetch
-        // some more data from the underlying reader.
-        // Branch using `>=` instead of the more correct `==`
-        // to tell the compiler that the pos..cap slice is always valid.
-        if self.pos >= self.cap {
-            debug_assert!(self.pos == self.cap);
-            self.cap = self.inner.read(&mut self.buf)?;
-            self.pos = 0;
-        }
-        Ok(&self.buf[self.pos..self.cap])
-    }
-
-    fn consume(&mut self, amt: usize) {
-        self.pos = cmp::min(self.pos + amt, self.cap);
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<R> fmt::Debug for BufReader<R>
-where
-    R: fmt::Debug,
-{
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt.debug_struct("BufReader")
-            .field("reader", &self.inner)
-            .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len()))
-            .finish()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<R: Seek> Seek for BufReader<R> {
-    /// Seek to an offset, in bytes, in the underlying reader.
-    ///
-    /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the
-    /// position the underlying reader would be at if the `BufReader<R>` had no
-    /// internal buffer.
-    ///
-    /// Seeking always discards the internal buffer, even if the seek position
-    /// would otherwise fall within it. This guarantees that calling
-    /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader
-    /// at the same position.
-    ///
-    /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`].
-    ///
-    /// See [`std::io::Seek`] for more details.
-    ///
-    /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)`
-    /// where `n` minus the internal buffer length overflows an `i64`, two
-    /// seeks will be performed instead of one. If the second seek returns
-    /// [`Err`], the underlying reader will be left at the same position it would
-    /// have if you called `seek` with [`SeekFrom::Current`]`(0)`.
-    ///
-    /// [`std::io::Seek`]: Seek
-    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
-        let result: u64;
-        if let SeekFrom::Current(n) = pos {
-            let remainder = (self.cap - self.pos) as i64;
-            // it should be safe to assume that remainder fits within an i64 as the alternative
-            // means we managed to allocate 8 exbibytes and that's absurd.
-            // But it's not out of the realm of possibility for some weird underlying reader to
-            // support seeking by i64::MIN so we need to handle underflow when subtracting
-            // remainder.
-            if let Some(offset) = n.checked_sub(remainder) {
-                result = self.inner.seek(SeekFrom::Current(offset))?;
-            } else {
-                // seek backwards by our remainder, and then by the offset
-                self.inner.seek(SeekFrom::Current(-remainder))?;
-                self.discard_buffer();
-                result = self.inner.seek(SeekFrom::Current(n))?;
-            }
-        } else {
-            // Seeking with Start/End doesn't care about our buffer length.
-            result = self.inner.seek(pos)?;
-        }
-        self.discard_buffer();
-        Ok(result)
-    }
-
-    /// Returns the current seek position from the start of the stream.
-    ///
-    /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))`
-    /// but does not flush the internal buffer. Due to this optimization the
-    /// function does not guarantee that calling `.into_inner()` immediately
-    /// afterwards will yield the underlying reader at the same position. Use
-    /// [`BufReader::seek`] instead if you require that guarantee.
-    ///
-    /// # Panics
-    ///
-    /// This function will panic if the position of the inner reader is smaller
-    /// than the amount of buffered data. That can happen if the inner reader
-    /// has an incorrect implementation of [`Seek::stream_position`], or if the
-    /// position has gone out of sync due to calling [`Seek::seek`] directly on
-    /// the underlying reader.
-    ///
-    /// # Example
-    ///
-    /// ```no_run
-    /// #![feature(seek_convenience)]
-    /// use std::{
-    ///     io::{self, BufRead, BufReader, Seek},
-    ///     fs::File,
-    /// };
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let mut f = BufReader::new(File::open("foo.txt")?);
-    ///
-    ///     let before = f.stream_position()?;
-    ///     f.read_line(&mut String::new())?;
-    ///     let after = f.stream_position()?;
-    ///
-    ///     println!("The first line was {} bytes long", after - before);
-    ///     Ok(())
-    /// }
-    /// ```
-    fn stream_position(&mut self) -> io::Result<u64> {
-        let remainder = (self.cap - self.pos) as u64;
-        self.inner.stream_position().map(|pos| {
-            pos.checked_sub(remainder).expect(
-                "overflow when subtracting remaining buffer size from inner stream position",
-            )
-        })
-    }
-}
-
-/// Wraps a writer and buffers its output.
-///
-/// It can be excessively inefficient to work directly with something that
-/// implements [`Write`]. For example, every call to
-/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A
-/// `BufWriter<W>` keeps an in-memory buffer of data and writes it to an underlying
-/// writer in large, infrequent batches.
-///
-/// `BufWriter<W>` can improve the speed of programs that make *small* and
-/// *repeated* write calls to the same file or network socket. It does not
-/// help when writing very large amounts at once, or writing just one or a few
-/// times. It also provides no advantage when writing to a destination that is
-/// in memory, like a [`Vec`]<u8>`.
-///
-/// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though
-/// dropping will attempt to flush the contents of the buffer, any errors
-/// that happen in the process of dropping will be ignored. Calling [`flush`]
-/// ensures that the buffer is empty and thus dropping will not even attempt
-/// file operations.
-///
-/// # Examples
-///
-/// Let's write the numbers one through ten to a [`TcpStream`]:
-///
-/// ```no_run
-/// use std::io::prelude::*;
-/// use std::net::TcpStream;
-///
-/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
-///
-/// for i in 0..10 {
-///     stream.write(&[i+1]).unwrap();
-/// }
-/// ```
-///
-/// Because we're not buffering, we write each one in turn, incurring the
-/// overhead of a system call per byte written. We can fix this with a
-/// `BufWriter<W>`:
-///
-/// ```no_run
-/// use std::io::prelude::*;
-/// use std::io::BufWriter;
-/// use std::net::TcpStream;
-///
-/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-///
-/// for i in 0..10 {
-///     stream.write(&[i+1]).unwrap();
-/// }
-/// stream.flush().unwrap();
-/// ```
-///
-/// By wrapping the stream with a `BufWriter<W>`, these ten writes are all grouped
-/// together by the buffer and will all be written out in one system call when
-/// the `stream` is flushed.
-///
-/// [`TcpStream::write`]: Write::write
-/// [`TcpStream`]: crate::net::TcpStream
-/// [`flush`]: Write::flush
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct BufWriter<W: Write> {
-    inner: Option<W>,
-    buf: Vec<u8>,
-    // #30888: If the inner writer panics in a call to write, we don't want to
-    // write the buffered data a second time in BufWriter's destructor. This
-    // flag tells the Drop impl if it should skip the flush.
-    panicked: bool,
-}
-
-/// An error returned by [`BufWriter::into_inner`] which combines an error that
-/// happened while writing out the buffer, and the buffered writer object
-/// which may be used to recover from the condition.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::io::BufWriter;
-/// use std::net::TcpStream;
-///
-/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-///
-/// // do stuff with the stream
-///
-/// // we want to get our `TcpStream` back, so let's try:
-///
-/// let stream = match stream.into_inner() {
-///     Ok(s) => s,
-///     Err(e) => {
-///         // Here, e is an IntoInnerError
-///         panic!("An error occurred");
-///     }
-/// };
-/// ```
-#[derive(Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct IntoInnerError<W>(W, Error);
-
-impl<W: Write> BufWriter<W> {
-    /// Creates a new `BufWriter<W>` with a default buffer capacity. The default is currently 8 KB,
-    /// but may change in the future.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn new(inner: W) -> BufWriter<W> {
-        BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
-    }
-
-    /// Creates a new `BufWriter<W>` with the specified buffer capacity.
-    ///
-    /// # Examples
-    ///
-    /// Creating a buffer with a buffer of a hundred bytes.
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap();
-    /// let mut buffer = BufWriter::with_capacity(100, stream);
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn with_capacity(capacity: usize, inner: W) -> BufWriter<W> {
-        BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false }
-    }
-
-    /// Send data in our local buffer into the inner writer, looping as
-    /// necessary until either it's all been sent or an error occurs.
-    ///
-    /// Because all the data in the buffer has been reported to our owner as
-    /// "successfully written" (by returning nonzero success values from
-    /// `write`), any 0-length writes from `inner` must be reported as i/o
-    /// errors from this method.
-    fn flush_buf(&mut self) -> io::Result<()> {
-        /// Helper struct to ensure the buffer is updated after all the writes
-        /// are complete. It tracks the number of written bytes and drains them
-        /// all from the front of the buffer when dropped.
-        struct BufGuard<'a> {
-            buffer: &'a mut Vec<u8>,
-            written: usize,
-        }
-
-        impl<'a> BufGuard<'a> {
-            fn new(buffer: &'a mut Vec<u8>) -> Self {
-                Self { buffer, written: 0 }
-            }
-
-            /// The unwritten part of the buffer
-            fn remaining(&self) -> &[u8] {
-                &self.buffer[self.written..]
-            }
-
-            /// Flag some bytes as removed from the front of the buffer
-            fn consume(&mut self, amt: usize) {
-                self.written += amt;
-            }
-
-            /// true if all of the bytes have been written
-            fn done(&self) -> bool {
-                self.written >= self.buffer.len()
-            }
-        }
-
-        impl Drop for BufGuard<'_> {
-            fn drop(&mut self) {
-                if self.written > 0 {
-                    self.buffer.drain(..self.written);
-                }
-            }
-        }
-
-        let mut guard = BufGuard::new(&mut self.buf);
-        let inner = self.inner.as_mut().unwrap();
-        while !guard.done() {
-            self.panicked = true;
-            let r = inner.write(guard.remaining());
-            self.panicked = false;
-
-            match r {
-                Ok(0) => {
-                    return Err(Error::new(
-                        ErrorKind::WriteZero,
-                        "failed to write the buffered data",
-                    ));
-                }
-                Ok(n) => guard.consume(n),
-                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
-                Err(e) => return Err(e),
-            }
-        }
-        Ok(())
-    }
-
-    /// Buffer some data without flushing it, regardless of the size of the
-    /// data. Writes as much as possible without exceeding capacity. Returns
-    /// the number of bytes written.
-    fn write_to_buf(&mut self, buf: &[u8]) -> usize {
-        let available = self.buf.capacity() - self.buf.len();
-        let amt_to_buffer = available.min(buf.len());
-        self.buf.extend_from_slice(&buf[..amt_to_buffer]);
-        amt_to_buffer
-    }
-
-    /// Gets a reference to the underlying writer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // we can use reference just like buffer
-    /// let reference = buffer.get_ref();
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_ref(&self) -> &W {
-        self.inner.as_ref().unwrap()
-    }
-
-    /// Gets a mutable reference to the underlying writer.
-    ///
-    /// It is inadvisable to directly write to the underlying writer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // we can use reference just like buffer
-    /// let reference = buffer.get_mut();
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_mut(&mut self) -> &mut W {
-        self.inner.as_mut().unwrap()
-    }
-
-    /// Returns a reference to the internally buffered data.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // See how many bytes are currently buffered
-    /// let bytes_buffered = buf_writer.buffer().len();
-    /// ```
-    #[stable(feature = "bufreader_buffer", since = "1.37.0")]
-    pub fn buffer(&self) -> &[u8] {
-        &self.buf
-    }
-
-    /// Returns the number of bytes the internal buffer can hold without flushing.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // Check the capacity of the inner buffer
-    /// let capacity = buf_writer.capacity();
-    /// // Calculate how many bytes can be written without flushing
-    /// let without_flush = capacity - buf_writer.buffer().len();
-    /// ```
-    #[stable(feature = "buffered_io_capacity", since = "1.46.0")]
-    pub fn capacity(&self) -> usize {
-        self.buf.capacity()
-    }
-
-    /// Unwraps this `BufWriter<W>`, returning the underlying writer.
-    ///
-    /// The buffer is written out before returning the writer.
-    ///
-    /// # Errors
-    ///
-    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // unwrap the TcpStream and flush the buffer
-    /// let stream = buffer.into_inner().unwrap();
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
-        match self.flush_buf() {
-            Err(e) => Err(IntoInnerError(self, e)),
-            Ok(()) => Ok(self.inner.take().unwrap()),
-        }
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> Write for BufWriter<W> {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        if self.buf.len() + buf.len() > self.buf.capacity() {
-            self.flush_buf()?;
-        }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
-        if buf.len() >= self.buf.capacity() {
-            self.panicked = true;
-            let r = self.get_mut().write(buf);
-            self.panicked = false;
-            r
-        } else {
-            self.buf.extend_from_slice(buf);
-            Ok(buf.len())
-        }
-    }
-
-    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        // Normally, `write_all` just calls `write` in a loop. We can do better
-        // by calling `self.get_mut().write_all()` directly, which avoids
-        // round trips through the buffer in the event of a series of partial
-        // writes in some circumstances.
-        if self.buf.len() + buf.len() > self.buf.capacity() {
-            self.flush_buf()?;
-        }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
-        if buf.len() >= self.buf.capacity() {
-            self.panicked = true;
-            let r = self.get_mut().write_all(buf);
-            self.panicked = false;
-            r
-        } else {
-            self.buf.extend_from_slice(buf);
-            Ok(())
-        }
-    }
-
-    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
-        if self.buf.len() + total_len > self.buf.capacity() {
-            self.flush_buf()?;
-        }
-        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
-        if total_len >= self.buf.capacity() {
-            self.panicked = true;
-            let r = self.get_mut().write_vectored(bufs);
-            self.panicked = false;
-            r
-        } else {
-            bufs.iter().for_each(|b| self.buf.extend_from_slice(b));
-            Ok(total_len)
-        }
-    }
-
-    fn is_write_vectored(&self) -> bool {
-        self.get_ref().is_write_vectored()
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        self.flush_buf().and_then(|()| self.get_mut().flush())
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> fmt::Debug for BufWriter<W>
-where
-    W: fmt::Debug,
-{
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt.debug_struct("BufWriter")
-            .field("writer", &self.inner.as_ref().unwrap())
-            .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity()))
-            .finish()
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write + Seek> Seek for BufWriter<W> {
-    /// Seek to the offset, in bytes, in the underlying writer.
-    ///
-    /// Seeking always writes out the internal buffer before seeking.
-    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
-        self.flush_buf()?;
-        self.get_mut().seek(pos)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> Drop for BufWriter<W> {
-    fn drop(&mut self) {
-        if self.inner.is_some() && !self.panicked {
-            // dtors should not panic, so we ignore a failed flush
-            let _r = self.flush_buf();
-        }
-    }
-}
-
-impl<W> IntoInnerError<W> {
-    /// Returns the error which caused the call to [`BufWriter::into_inner()`]
-    /// to fail.
-    ///
-    /// This error was returned when attempting to write the internal buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // do stuff with the stream
-    ///
-    /// // we want to get our `TcpStream` back, so let's try:
-    ///
-    /// let stream = match stream.into_inner() {
-    ///     Ok(s) => s,
-    ///     Err(e) => {
-    ///         // Here, e is an IntoInnerError, let's log the inner error.
-    ///         //
-    ///         // We'll just 'log' to stdout for this example.
-    ///         println!("{}", e.error());
-    ///
-    ///         panic!("An unexpected error occurred.");
-    ///     }
-    /// };
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn error(&self) -> &Error {
-        &self.1
-    }
-
-    /// Returns the buffered writer instance which generated the error.
-    ///
-    /// The returned object can be used for error recovery, such as
-    /// re-inspecting the buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::io::BufWriter;
-    /// use std::net::TcpStream;
-    ///
-    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
-    ///
-    /// // do stuff with the stream
-    ///
-    /// // we want to get our `TcpStream` back, so let's try:
-    ///
-    /// let stream = match stream.into_inner() {
-    ///     Ok(s) => s,
-    ///     Err(e) => {
-    ///         // Here, e is an IntoInnerError, let's re-examine the buffer:
-    ///         let buffer = e.into_inner();
-    ///
-    ///         // do stuff to try to recover
-    ///
-    ///         // afterwards, let's just return the stream
-    ///         buffer.into_inner().unwrap()
-    ///     }
-    /// };
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_inner(self) -> W {
-        self.0
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W> From<IntoInnerError<W>> for Error {
-    fn from(iie: IntoInnerError<W>) -> Error {
-        iie.1
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
-    #[allow(deprecated, deprecated_in_future)]
-    fn description(&self) -> &str {
-        error::Error::description(self.error())
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W> fmt::Display for IntoInnerError<W> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.error().fmt(f)
-    }
-}
-
-/// Private helper struct for implementing the line-buffered writing logic.
-/// This shim temporarily wraps a BufWriter, and uses its internals to
-/// implement a line-buffered writer (specifically by using the internal
-/// methods like write_to_buf and flush_buf). In this way, a more
-/// efficient abstraction can be created than one that only had access to
-/// `write` and `flush`, without needlessly duplicating a lot of the
-/// implementation details of BufWriter. This also allows existing
-/// `BufWriters` to be temporarily given line-buffering logic; this is what
-/// enables Stdout to be alternately in line-buffered or block-buffered mode.
-#[derive(Debug)]
-pub(super) struct LineWriterShim<'a, W: Write> {
-    buffer: &'a mut BufWriter<W>,
-}
-
-impl<'a, W: Write> LineWriterShim<'a, W> {
-    pub fn new(buffer: &'a mut BufWriter<W>) -> Self {
-        Self { buffer }
-    }
-
-    /// Get a mutable reference to the inner writer (that is, the writer
-    /// wrapped by the BufWriter). Be careful with this writer, as writes to
-    /// it will bypass the buffer.
-    fn inner_mut(&mut self) -> &mut W {
-        self.buffer.get_mut()
-    }
-
-    /// Get the content currently buffered in self.buffer
-    fn buffered(&self) -> &[u8] {
-        self.buffer.buffer()
-    }
-
-    /// Flush the buffer iff the last byte is a newline (indicating that an
-    /// earlier write only succeeded partially, and we want to retry flushing
-    /// the buffered line before continuing with a subsequent write)
-    fn flush_if_completed_line(&mut self) -> io::Result<()> {
-        match self.buffered().last().copied() {
-            Some(b'\n') => self.buffer.flush_buf(),
-            _ => Ok(()),
-        }
-    }
-}
-
-impl<'a, W: Write> Write for LineWriterShim<'a, W> {
-    /// Write some data into this BufReader with line buffering. This means
-    /// that, if any newlines are present in the data, the data up to the last
-    /// newline is sent directly to the underlying writer, and data after it
-    /// is buffered. Returns the number of bytes written.
-    ///
-    /// This function operates on a "best effort basis"; in keeping with the
-    /// convention of `Write::write`, it makes at most one attempt to write
-    /// new data to the underlying writer. If that write only reports a partial
-    /// success, the remaining data will be buffered.
-    ///
-    /// Because this function attempts to send completed lines to the underlying
-    /// writer, it will also flush the existing buffer if it ends with a
-    /// newline, even if the incoming data does not contain any newlines.
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        let newline_idx = match memchr::memrchr(b'\n', buf) {
-            // If there are no new newlines (that is, if this write is less than
-            // one line), just do a regular buffered write (which may flush if
-            // we exceed the inner buffer's size)
-            None => {
-                self.flush_if_completed_line()?;
-                return self.buffer.write(buf);
-            }
-            // Otherwise, arrange for the lines to be written directly to the
-            // inner writer.
-            Some(newline_idx) => newline_idx + 1,
-        };
-
-        // Flush existing content to prepare for our write. We have to do this
-        // before attempting to write `buf` in order to maintain consistency;
-        // if we add `buf` to the buffer then try to flush it all at once,
-        // we're obligated to return Ok(), which would mean suppressing any
-        // errors that occur during flush.
-        self.buffer.flush_buf()?;
-
-        // This is what we're going to try to write directly to the inner
-        // writer. The rest will be buffered, if nothing goes wrong.
-        let lines = &buf[..newline_idx];
-
-        // Write `lines` directly to the inner writer. In keeping with the
-        // `write` convention, make at most one attempt to add new (unbuffered)
-        // data. Because this write doesn't touch the BufWriter state directly,
-        // and the buffer is known to be empty, we don't need to worry about
-        // self.buffer.panicked here.
-        let flushed = self.inner_mut().write(lines)?;
-
-        // If buffer returns Ok(0), propagate that to the caller without
-        // doing additional buffering; otherwise we're just guaranteeing
-        // an "ErrorKind::WriteZero" later.
-        if flushed == 0 {
-            return Ok(0);
-        }
-
-        // Now that the write has succeeded, buffer the rest (or as much of
-        // the rest as possible). If there were any unwritten newlines, we
-        // only buffer out to the last unwritten newline that fits in the
-        // buffer; this helps prevent flushing partial lines on subsequent
-        // calls to LineWriterShim::write.
-
-        // Handle the cases in order of most-common to least-common, under
-        // the presumption that most writes succeed in totality, and that most
-        // writes are smaller than the buffer.
-        // - Is this a partial line (ie, no newlines left in the unwritten tail)
-        // - If not, does the data out to the last unwritten newline fit in
-        //   the buffer?
-        // - If not, scan for the last newline that *does* fit in the buffer
-        let tail = if flushed >= newline_idx {
-            &buf[flushed..]
-        } else if newline_idx - flushed <= self.buffer.capacity() {
-            &buf[flushed..newline_idx]
-        } else {
-            let scan_area = &buf[flushed..];
-            let scan_area = &scan_area[..self.buffer.capacity()];
-            match memchr::memrchr(b'\n', scan_area) {
-                Some(newline_idx) => &scan_area[..newline_idx + 1],
-                None => scan_area,
-            }
-        };
-
-        let buffered = self.buffer.write_to_buf(tail);
-        Ok(flushed + buffered)
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        self.buffer.flush()
-    }
-
-    /// Write some vectored data into this BufReader with line buffering. This
-    /// means that, if any newlines are present in the data, the data up to
-    /// and including the buffer containing the last newline is sent directly
-    /// to the inner writer, and the data after it is buffered. Returns the
-    /// number of bytes written.
-    ///
-    /// This function operates on a "best effort basis"; in keeping with the
-    /// convention of `Write::write`, it makes at most one attempt to write
-    /// new data to the underlying writer.
-    ///
-    /// Because this function attempts to send completed lines to the underlying
-    /// writer, it will also flush the existing buffer if it contains any
-    /// newlines.
-    ///
-    /// Because sorting through an array of `IoSlice` can be a bit convoluted,
-    /// This method differs from write in the following ways:
-    ///
-    /// - It attempts to write the full content of all the buffers up to and
-    ///   including the one containing the last newline. This means that it
-    ///   may attempt to write a partial line, that buffer has data past the
-    ///   newline.
-    /// - If the write only reports partial success, it does not attempt to
-    ///   find the precise location of the written bytes and buffer the rest.
-    ///
-    /// If the underlying vector doesn't support vectored writing, we instead
-    /// simply write the first non-empty buffer with `write`. This way, we
-    /// get the benefits of more granular partial-line handling without losing
-    /// anything in efficiency
-    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        // If there's no specialized behavior for write_vectored, just use
-        // write. This has the benefit of more granular partial-line handling.
-        if !self.is_write_vectored() {
-            return match bufs.iter().find(|buf| !buf.is_empty()) {
-                Some(buf) => self.write(buf),
-                None => Ok(0),
-            };
-        }
-
-        // Find the buffer containing the last newline
-        let last_newline_buf_idx = bufs
-            .iter()
-            .enumerate()
-            .rev()
-            .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i));
-
-        // If there are no new newlines (that is, if this write is less than
-        // one line), just do a regular buffered write
-        let last_newline_buf_idx = match last_newline_buf_idx {
-            // No newlines; just do a normal buffered write
-            None => {
-                self.flush_if_completed_line()?;
-                return self.buffer.write_vectored(bufs);
-            }
-            Some(i) => i,
-        };
-
-        // Flush existing content to prepare for our write
-        self.buffer.flush_buf()?;
-
-        // This is what we're going to try to write directly to the inner
-        // writer. The rest will be buffered, if nothing goes wrong.
-        let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1);
-
-        // Write `lines` directly to the inner writer. In keeping with the
-        // `write` convention, make at most one attempt to add new (unbuffered)
-        // data. Because this write doesn't touch the BufWriter state directly,
-        // and the buffer is known to be empty, we don't need to worry about
-        // self.panicked here.
-        let flushed = self.inner_mut().write_vectored(lines)?;
-
-        // If inner returns Ok(0), propagate that to the caller without
-        // doing additional buffering; otherwise we're just guaranteeing
-        // an "ErrorKind::WriteZero" later.
-        if flushed == 0 {
-            return Ok(0);
-        }
-
-        // Don't try to reconstruct the exact amount written; just bail
-        // in the event of a partial write
-        let lines_len = lines.iter().map(|buf| buf.len()).sum();
-        if flushed < lines_len {
-            return Ok(flushed);
-        }
-
-        // Now that the write has succeeded, buffer the rest (or as much of the
-        // rest as possible)
-        let buffered: usize = tail
-            .iter()
-            .filter(|buf| !buf.is_empty())
-            .map(|buf| self.buffer.write_to_buf(buf))
-            .take_while(|&n| n > 0)
-            .sum();
-
-        Ok(flushed + buffered)
-    }
-
-    fn is_write_vectored(&self) -> bool {
-        self.buffer.is_write_vectored()
-    }
-
-    /// Write some data into this BufReader with line buffering. This means
-    /// that, if any newlines are present in the data, the data up to the last
-    /// newline is sent directly to the underlying writer, and data after it
-    /// is buffered.
-    ///
-    /// Because this function attempts to send completed lines to the underlying
-    /// writer, it will also flush the existing buffer if it contains any
-    /// newlines, even if the incoming data does not contain any newlines.
-    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        match memchr::memrchr(b'\n', buf) {
-            // If there are no new newlines (that is, if this write is less than
-            // one line), just do a regular buffered write (which may flush if
-            // we exceed the inner buffer's size)
-            None => {
-                self.flush_if_completed_line()?;
-                self.buffer.write_all(buf)
-            }
-            Some(newline_idx) => {
-                let (lines, tail) = buf.split_at(newline_idx + 1);
-
-                if self.buffered().is_empty() {
-                    self.inner_mut().write_all(lines)?;
-                } else {
-                    // If there is any buffered data, we add the incoming lines
-                    // to that buffer before flushing, which saves us at least
-                    // one write call. We can't really do this with `write`,
-                    // since we can't do this *and* not suppress errors *and*
-                    // report a consistent state to the caller in a return
-                    // value, but here in write_all it's fine.
-                    self.buffer.write_all(lines)?;
-                    self.buffer.flush_buf()?;
-                }
-
-                self.buffer.write_all(tail)
-            }
-        }
-    }
-}
-
-/// Wraps a writer and buffers output to it, flushing whenever a newline
-/// (`0x0a`, `'\n'`) is detected.
-///
-/// The [`BufWriter`] struct wraps a writer and buffers its output.
-/// But it only does this batched write when it goes out of scope, or when the
-/// internal buffer is full. Sometimes, you'd prefer to write each line as it's
-/// completed, rather than the entire buffer at once. Enter `LineWriter`. It
-/// does exactly that.
-///
-/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the
-/// `LineWriter` goes out of scope or when its internal buffer is full.
-///
-/// If there's still a partial line in the buffer when the `LineWriter` is
-/// dropped, it will flush those contents.
-///
-/// # Examples
-///
-/// We can use `LineWriter` to write one line at a time, significantly
-/// reducing the number of actual writes to the file.
-///
-/// ```no_run
-/// use std::fs::{self, File};
-/// use std::io::prelude::*;
-/// use std::io::LineWriter;
-///
-/// fn main() -> std::io::Result<()> {
-///     let road_not_taken = b"I shall be telling this with a sigh
-/// Somewhere ages and ages hence:
-/// Two roads diverged in a wood, and I -
-/// I took the one less traveled by,
-/// And that has made all the difference.";
-///
-///     let file = File::create("poem.txt")?;
-///     let mut file = LineWriter::new(file);
-///
-///     file.write_all(b"I shall be telling this with a sigh")?;
-///
-///     // No bytes are written until a newline is encountered (or
-///     // the internal buffer is filled).
-///     assert_eq!(fs::read_to_string("poem.txt")?, "");
-///     file.write_all(b"\n")?;
-///     assert_eq!(
-///         fs::read_to_string("poem.txt")?,
-///         "I shall be telling this with a sigh\n",
-///     );
-///
-///     // Write the rest of the poem.
-///     file.write_all(b"Somewhere ages and ages hence:
-/// Two roads diverged in a wood, and I -
-/// I took the one less traveled by,
-/// And that has made all the difference.")?;
-///
-///     // The last line of the poem doesn't end in a newline, so
-///     // we have to flush or drop the `LineWriter` to finish
-///     // writing.
-///     file.flush()?;
-///
-///     // Confirm the whole poem was written.
-///     assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]);
-///     Ok(())
-/// }
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct LineWriter<W: Write> {
-    inner: BufWriter<W>,
-}
-
-impl<W: Write> LineWriter<W> {
-    /// Creates a new `LineWriter`.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io::LineWriter;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let file = File::create("poem.txt")?;
-    ///     let file = LineWriter::new(file);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn new(inner: W) -> LineWriter<W> {
-        // Lines typically aren't that long, don't use a giant buffer
-        LineWriter::with_capacity(1024, inner)
-    }
-
-    /// Creates a new `LineWriter` with a specified capacity for the internal
-    /// buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io::LineWriter;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let file = File::create("poem.txt")?;
-    ///     let file = LineWriter::with_capacity(100, file);
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn with_capacity(capacity: usize, inner: W) -> LineWriter<W> {
-        LineWriter { inner: BufWriter::with_capacity(capacity, inner) }
-    }
-
-    /// Gets a reference to the underlying writer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io::LineWriter;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let file = File::create("poem.txt")?;
-    ///     let file = LineWriter::new(file);
-    ///
-    ///     let reference = file.get_ref();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_ref(&self) -> &W {
-        self.inner.get_ref()
-    }
-
-    /// Gets a mutable reference to the underlying writer.
-    ///
-    /// Caution must be taken when calling methods on the mutable reference
-    /// returned as extra writes could corrupt the output stream.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io::LineWriter;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let file = File::create("poem.txt")?;
-    ///     let mut file = LineWriter::new(file);
-    ///
-    ///     // we can use reference just like file
-    ///     let reference = file.get_mut();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn get_mut(&mut self) -> &mut W {
-        self.inner.get_mut()
-    }
-
-    /// Unwraps this `LineWriter`, returning the underlying writer.
-    ///
-    /// The internal buffer is written out before returning the writer.
-    ///
-    /// # Errors
-    ///
-    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs::File;
-    /// use std::io::LineWriter;
-    ///
-    /// fn main() -> std::io::Result<()> {
-    ///     let file = File::create("poem.txt")?;
-    ///
-    ///     let writer: LineWriter<File> = LineWriter::new(file);
-    ///
-    ///     let file: File = writer.into_inner()?;
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
-        self.inner
-            .into_inner()
-            .map_err(|IntoInnerError(buf, e)| IntoInnerError(LineWriter { inner: buf }, e))
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> Write for LineWriter<W> {
-    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
-        LineWriterShim::new(&mut self.inner).write(buf)
-    }
-
-    fn flush(&mut self) -> io::Result<()> {
-        self.inner.flush()
-    }
-
-    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        LineWriterShim::new(&mut self.inner).write_vectored(bufs)
-    }
-
-    fn is_write_vectored(&self) -> bool {
-        self.inner.is_write_vectored()
-    }
-
-    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
-        LineWriterShim::new(&mut self.inner).write_all(buf)
-    }
-
-    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
-        LineWriterShim::new(&mut self.inner).write_all_vectored(bufs)
-    }
-
-    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
-        LineWriterShim::new(&mut self.inner).write_fmt(fmt)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Write> fmt::Debug for LineWriter<W>
-where
-    W: fmt::Debug,
-{
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt.debug_struct("LineWriter")
-            .field("writer", &self.inner.inner)
-            .field(
-                "buffer",
-                &format_args!("{}/{}", self.inner.buf.len(), self.inner.buf.capacity()),
-            )
-            .finish()
-    }
-}
diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs
new file mode 100644
index 00000000000..8fe29f08a7b
--- /dev/null
+++ b/library/std/src/io/buffered/bufreader.rs
@@ -0,0 +1,423 @@
+use crate::cmp;
+use crate::fmt;
+use crate::io::{self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE};
+
+/// The `BufReader<R>` struct adds buffering to any reader.
+///
+/// It can be excessively inefficient to work directly with a [`Read`] instance.
+/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`]
+/// results in a system call. A `BufReader<R>` performs large, infrequent reads on
+/// the underlying [`Read`] and maintains an in-memory buffer of the results.
+///
+/// `BufReader<R>` can improve the speed of programs that make *small* and
+/// *repeated* read calls to the same file or network socket. It does not
+/// help when reading very large amounts at once, or reading just one or a few
+/// times. It also provides no advantage when reading from a source that is
+/// already in memory, like a [`Vec`]`<u8>`.
+///
+/// When the `BufReader<R>` is dropped, the contents of its buffer will be
+/// discarded. Creating multiple instances of a `BufReader<R>` on the same
+/// stream can cause data loss. Reading from the underlying reader after
+/// unwrapping the `BufReader<R>` with [`BufReader::into_inner`] can also cause
+/// data loss.
+///
+/// [`TcpStream::read`]: Read::read
+/// [`TcpStream`]: crate::net::TcpStream
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::BufReader;
+/// use std::fs::File;
+///
+/// fn main() -> std::io::Result<()> {
+///     let f = File::open("log.txt")?;
+///     let mut reader = BufReader::new(f);
+///
+///     let mut line = String::new();
+///     let len = reader.read_line(&mut line)?;
+///     println!("First line is {} bytes long", len);
+///     Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct BufReader<R> {
+    inner: R,
+    buf: Box<[u8]>,
+    pos: usize,
+    cap: usize,
+}
+
+impl<R: Read> BufReader<R> {
+    /// Creates a new `BufReader<R>` with a default buffer capacity. The default is currently 8 KB,
+    /// but may change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("log.txt")?;
+    ///     let reader = BufReader::new(f);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn new(inner: R) -> BufReader<R> {
+        BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
+    }
+
+    /// Creates a new `BufReader<R>` with the specified buffer capacity.
+    ///
+    /// # Examples
+    ///
+    /// Creating a buffer with ten bytes of capacity:
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("log.txt")?;
+    ///     let reader = BufReader::with_capacity(10, f);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> {
+        unsafe {
+            let mut buffer = Vec::with_capacity(capacity);
+            buffer.set_len(capacity);
+            inner.initializer().initialize(&mut buffer);
+            BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 }
+        }
+    }
+}
+
+impl<R> BufReader<R> {
+    /// Gets a reference to the underlying reader.
+    ///
+    /// It is inadvisable to directly read from the underlying reader.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f1 = File::open("log.txt")?;
+    ///     let reader = BufReader::new(f1);
+    ///
+    ///     let f2 = reader.get_ref();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_ref(&self) -> &R {
+        &self.inner
+    }
+
+    /// Gets a mutable reference to the underlying reader.
+    ///
+    /// It is inadvisable to directly read from the underlying reader.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f1 = File::open("log.txt")?;
+    ///     let mut reader = BufReader::new(f1);
+    ///
+    ///     let f2 = reader.get_mut();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_mut(&mut self) -> &mut R {
+        &mut self.inner
+    }
+
+    /// Returns a reference to the internally buffered data.
+    ///
+    /// Unlike [`fill_buf`], this will not attempt to fill the buffer if it is empty.
+    ///
+    /// [`fill_buf`]: BufRead::fill_buf
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::{BufReader, BufRead};
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("log.txt")?;
+    ///     let mut reader = BufReader::new(f);
+    ///     assert!(reader.buffer().is_empty());
+    ///
+    ///     if reader.fill_buf()?.len() > 0 {
+    ///         assert!(!reader.buffer().is_empty());
+    ///     }
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "bufreader_buffer", since = "1.37.0")]
+    pub fn buffer(&self) -> &[u8] {
+        &self.buf[self.pos..self.cap]
+    }
+
+    /// Returns the number of bytes the internal buffer can hold at once.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::{BufReader, BufRead};
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f = File::open("log.txt")?;
+    ///     let mut reader = BufReader::new(f);
+    ///
+    ///     let capacity = reader.capacity();
+    ///     let buffer = reader.fill_buf()?;
+    ///     assert!(buffer.len() <= capacity);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "buffered_io_capacity", since = "1.46.0")]
+    pub fn capacity(&self) -> usize {
+        self.buf.len()
+    }
+
+    /// Unwraps this `BufReader<R>`, returning the underlying reader.
+    ///
+    /// Note that any leftover data in the internal buffer is lost. Therefore,
+    /// a following read from the underlying reader may lead to data loss.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufReader;
+    /// use std::fs::File;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let f1 = File::open("log.txt")?;
+    ///     let reader = BufReader::new(f1);
+    ///
+    ///     let f2 = reader.into_inner();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn into_inner(self) -> R {
+        self.inner
+    }
+
+    /// Invalidates all data in the internal buffer.
+    #[inline]
+    fn discard_buffer(&mut self) {
+        self.pos = 0;
+        self.cap = 0;
+    }
+}
+
+impl<R: Seek> BufReader<R> {
+    /// Seeks relative to the current position. If the new position lies within the buffer,
+    /// the buffer will not be flushed, allowing for more efficient seeks.
+    /// This method does not return the location of the underlying reader, so the caller
+    /// must track this information themselves if it is required.
+    #[unstable(feature = "bufreader_seek_relative", issue = "31100")]
+    pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
+        let pos = self.pos as u64;
+        if offset < 0 {
+            if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
+                self.pos = new_pos as usize;
+                return Ok(());
+            }
+        } else {
+            if let Some(new_pos) = pos.checked_add(offset as u64) {
+                if new_pos <= self.cap as u64 {
+                    self.pos = new_pos as usize;
+                    return Ok(());
+                }
+            }
+        }
+        self.seek(SeekFrom::Current(offset)).map(drop)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Read> Read for BufReader<R> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        // If we don't have any buffered data and we're doing a massive read
+        // (larger than our internal buffer), bypass our internal buffer
+        // entirely.
+        if self.pos == self.cap && buf.len() >= self.buf.len() {
+            self.discard_buffer();
+            return self.inner.read(buf);
+        }
+        let nread = {
+            let mut rem = self.fill_buf()?;
+            rem.read(buf)?
+        };
+        self.consume(nread);
+        Ok(nread)
+    }
+
+    fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
+        if self.pos == self.cap && total_len >= self.buf.len() {
+            self.discard_buffer();
+            return self.inner.read_vectored(bufs);
+        }
+        let nread = {
+            let mut rem = self.fill_buf()?;
+            rem.read_vectored(bufs)?
+        };
+        self.consume(nread);
+        Ok(nread)
+    }
+
+    fn is_read_vectored(&self) -> bool {
+        self.inner.is_read_vectored()
+    }
+
+    // we can't skip unconditionally because of the large buffer case in read.
+    unsafe fn initializer(&self) -> Initializer {
+        self.inner.initializer()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Read> BufRead for BufReader<R> {
+    fn fill_buf(&mut self) -> io::Result<&[u8]> {
+        // If we've reached the end of our internal buffer then we need to fetch
+        // some more data from the underlying reader.
+        // Branch using `>=` instead of the more correct `==`
+        // to tell the compiler that the pos..cap slice is always valid.
+        if self.pos >= self.cap {
+            debug_assert!(self.pos == self.cap);
+            self.cap = self.inner.read(&mut self.buf)?;
+            self.pos = 0;
+        }
+        Ok(&self.buf[self.pos..self.cap])
+    }
+
+    fn consume(&mut self, amt: usize) {
+        self.pos = cmp::min(self.pos + amt, self.cap);
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R> fmt::Debug for BufReader<R>
+where
+    R: fmt::Debug,
+{
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct("BufReader")
+            .field("reader", &self.inner)
+            .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len()))
+            .finish()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R: Seek> Seek for BufReader<R> {
+    /// Seek to an offset, in bytes, in the underlying reader.
+    ///
+    /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the
+    /// position the underlying reader would be at if the `BufReader<R>` had no
+    /// internal buffer.
+    ///
+    /// Seeking always discards the internal buffer, even if the seek position
+    /// would otherwise fall within it. This guarantees that calling
+    /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader
+    /// at the same position.
+    ///
+    /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`].
+    ///
+    /// See [`std::io::Seek`] for more details.
+    ///
+    /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)`
+    /// where `n` minus the internal buffer length overflows an `i64`, two
+    /// seeks will be performed instead of one. If the second seek returns
+    /// [`Err`], the underlying reader will be left at the same position it would
+    /// have if you called `seek` with [`SeekFrom::Current`]`(0)`.
+    ///
+    /// [`std::io::Seek`]: Seek
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+        let result: u64;
+        if let SeekFrom::Current(n) = pos {
+            let remainder = (self.cap - self.pos) as i64;
+            // it should be safe to assume that remainder fits within an i64 as the alternative
+            // means we managed to allocate 8 exbibytes and that's absurd.
+            // But it's not out of the realm of possibility for some weird underlying reader to
+            // support seeking by i64::MIN so we need to handle underflow when subtracting
+            // remainder.
+            if let Some(offset) = n.checked_sub(remainder) {
+                result = self.inner.seek(SeekFrom::Current(offset))?;
+            } else {
+                // seek backwards by our remainder, and then by the offset
+                self.inner.seek(SeekFrom::Current(-remainder))?;
+                self.discard_buffer();
+                result = self.inner.seek(SeekFrom::Current(n))?;
+            }
+        } else {
+            // Seeking with Start/End doesn't care about our buffer length.
+            result = self.inner.seek(pos)?;
+        }
+        self.discard_buffer();
+        Ok(result)
+    }
+
+    /// Returns the current seek position from the start of the stream.
+    ///
+    /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))`
+    /// but does not flush the internal buffer. Due to this optimization the
+    /// function does not guarantee that calling `.into_inner()` immediately
+    /// afterwards will yield the underlying reader at the same position. Use
+    /// [`BufReader::seek`] instead if you require that guarantee.
+    ///
+    /// # Panics
+    ///
+    /// This function will panic if the position of the inner reader is smaller
+    /// than the amount of buffered data. That can happen if the inner reader
+    /// has an incorrect implementation of [`Seek::stream_position`], or if the
+    /// position has gone out of sync due to calling [`Seek::seek`] directly on
+    /// the underlying reader.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// #![feature(seek_convenience)]
+    /// use std::{
+    ///     io::{self, BufRead, BufReader, Seek},
+    ///     fs::File,
+    /// };
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let mut f = BufReader::new(File::open("foo.txt")?);
+    ///
+    ///     let before = f.stream_position()?;
+    ///     f.read_line(&mut String::new())?;
+    ///     let after = f.stream_position()?;
+    ///
+    ///     println!("The first line was {} bytes long", after - before);
+    ///     Ok(())
+    /// }
+    /// ```
+    fn stream_position(&mut self) -> io::Result<u64> {
+        let remainder = (self.cap - self.pos) as u64;
+        self.inner.stream_position().map(|pos| {
+            pos.checked_sub(remainder).expect(
+                "overflow when subtracting remaining buffer size from inner stream position",
+            )
+        })
+    }
+}
diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs
new file mode 100644
index 00000000000..8ce795a05ed
--- /dev/null
+++ b/library/std/src/io/buffered/bufwriter.rs
@@ -0,0 +1,387 @@
+use crate::fmt;
+use crate::io::{
+    self, Error, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
+};
+
+/// Wraps a writer and buffers its output.
+///
+/// It can be excessively inefficient to work directly with something that
+/// implements [`Write`]. For example, every call to
+/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A
+/// `BufWriter<W>` keeps an in-memory buffer of data and writes it to an underlying
+/// writer in large, infrequent batches.
+///
+/// `BufWriter<W>` can improve the speed of programs that make *small* and
+/// *repeated* write calls to the same file or network socket. It does not
+/// help when writing very large amounts at once, or writing just one or a few
+/// times. It also provides no advantage when writing to a destination that is
+/// in memory, like a [`Vec`]<u8>`.
+///
+/// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though
+/// dropping will attempt to flush the contents of the buffer, any errors
+/// that happen in the process of dropping will be ignored. Calling [`flush`]
+/// ensures that the buffer is empty and thus dropping will not even attempt
+/// file operations.
+///
+/// # Examples
+///
+/// Let's write the numbers one through ten to a [`TcpStream`]:
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::net::TcpStream;
+///
+/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+///
+/// for i in 0..10 {
+///     stream.write(&[i+1]).unwrap();
+/// }
+/// ```
+///
+/// Because we're not buffering, we write each one in turn, incurring the
+/// overhead of a system call per byte written. We can fix this with a
+/// `BufWriter<W>`:
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::io::BufWriter;
+/// use std::net::TcpStream;
+///
+/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+///
+/// for i in 0..10 {
+///     stream.write(&[i+1]).unwrap();
+/// }
+/// stream.flush().unwrap();
+/// ```
+///
+/// By wrapping the stream with a `BufWriter<W>`, these ten writes are all grouped
+/// together by the buffer and will all be written out in one system call when
+/// the `stream` is flushed.
+///
+/// [`TcpStream::write`]: Write::write
+/// [`TcpStream`]: crate::net::TcpStream
+/// [`flush`]: Write::flush
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct BufWriter<W: Write> {
+    inner: Option<W>,
+    buf: Vec<u8>,
+    // #30888: If the inner writer panics in a call to write, we don't want to
+    // write the buffered data a second time in BufWriter's destructor. This
+    // flag tells the Drop impl if it should skip the flush.
+    panicked: bool,
+}
+
+impl<W: Write> BufWriter<W> {
+    /// Creates a new `BufWriter<W>` with a default buffer capacity. The default is currently 8 KB,
+    /// but may change in the future.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn new(inner: W) -> BufWriter<W> {
+        BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
+    }
+
+    /// Creates a new `BufWriter<W>` with the specified buffer capacity.
+    ///
+    /// # Examples
+    ///
+    /// Creating a buffer with a buffer of a hundred bytes.
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+    /// let mut buffer = BufWriter::with_capacity(100, stream);
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn with_capacity(capacity: usize, inner: W) -> BufWriter<W> {
+        BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false }
+    }
+
+    /// Send data in our local buffer into the inner writer, looping as
+    /// necessary until either it's all been sent or an error occurs.
+    ///
+    /// Because all the data in the buffer has been reported to our owner as
+    /// "successfully written" (by returning nonzero success values from
+    /// `write`), any 0-length writes from `inner` must be reported as i/o
+    /// errors from this method.
+    pub(super) fn flush_buf(&mut self) -> io::Result<()> {
+        /// Helper struct to ensure the buffer is updated after all the writes
+        /// are complete. It tracks the number of written bytes and drains them
+        /// all from the front of the buffer when dropped.
+        struct BufGuard<'a> {
+            buffer: &'a mut Vec<u8>,
+            written: usize,
+        }
+
+        impl<'a> BufGuard<'a> {
+            fn new(buffer: &'a mut Vec<u8>) -> Self {
+                Self { buffer, written: 0 }
+            }
+
+            /// The unwritten part of the buffer
+            fn remaining(&self) -> &[u8] {
+                &self.buffer[self.written..]
+            }
+
+            /// Flag some bytes as removed from the front of the buffer
+            fn consume(&mut self, amt: usize) {
+                self.written += amt;
+            }
+
+            /// true if all of the bytes have been written
+            fn done(&self) -> bool {
+                self.written >= self.buffer.len()
+            }
+        }
+
+        impl Drop for BufGuard<'_> {
+            fn drop(&mut self) {
+                if self.written > 0 {
+                    self.buffer.drain(..self.written);
+                }
+            }
+        }
+
+        let mut guard = BufGuard::new(&mut self.buf);
+        let inner = self.inner.as_mut().unwrap();
+        while !guard.done() {
+            self.panicked = true;
+            let r = inner.write(guard.remaining());
+            self.panicked = false;
+
+            match r {
+                Ok(0) => {
+                    return Err(Error::new(
+                        ErrorKind::WriteZero,
+                        "failed to write the buffered data",
+                    ));
+                }
+                Ok(n) => guard.consume(n),
+                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        Ok(())
+    }
+
+    /// Buffer some data without flushing it, regardless of the size of the
+    /// data. Writes as much as possible without exceeding capacity. Returns
+    /// the number of bytes written.
+    pub(super) fn write_to_buf(&mut self, buf: &[u8]) -> usize {
+        let available = self.buf.capacity() - self.buf.len();
+        let amt_to_buffer = available.min(buf.len());
+        self.buf.extend_from_slice(&buf[..amt_to_buffer]);
+        amt_to_buffer
+    }
+
+    /// Gets a reference to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // we can use reference just like buffer
+    /// let reference = buffer.get_ref();
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_ref(&self) -> &W {
+        self.inner.as_ref().unwrap()
+    }
+
+    /// Gets a mutable reference to the underlying writer.
+    ///
+    /// It is inadvisable to directly write to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // we can use reference just like buffer
+    /// let reference = buffer.get_mut();
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_mut(&mut self) -> &mut W {
+        self.inner.as_mut().unwrap()
+    }
+
+    /// Returns a reference to the internally buffered data.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // See how many bytes are currently buffered
+    /// let bytes_buffered = buf_writer.buffer().len();
+    /// ```
+    #[stable(feature = "bufreader_buffer", since = "1.37.0")]
+    pub fn buffer(&self) -> &[u8] {
+        &self.buf
+    }
+
+    /// Returns the number of bytes the internal buffer can hold without flushing.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // Check the capacity of the inner buffer
+    /// let capacity = buf_writer.capacity();
+    /// // Calculate how many bytes can be written without flushing
+    /// let without_flush = capacity - buf_writer.buffer().len();
+    /// ```
+    #[stable(feature = "buffered_io_capacity", since = "1.46.0")]
+    pub fn capacity(&self) -> usize {
+        self.buf.capacity()
+    }
+
+    /// Unwraps this `BufWriter<W>`, returning the underlying writer.
+    ///
+    /// The buffer is written out before returning the writer.
+    ///
+    /// # Errors
+    ///
+    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // unwrap the TcpStream and flush the buffer
+    /// let stream = buffer.into_inner().unwrap();
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
+        match self.flush_buf() {
+            Err(e) => Err(IntoInnerError::new(self, e)),
+            Ok(()) => Ok(self.inner.take().unwrap()),
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> Write for BufWriter<W> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        if self.buf.len() + buf.len() > self.buf.capacity() {
+            self.flush_buf()?;
+        }
+        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
+        if buf.len() >= self.buf.capacity() {
+            self.panicked = true;
+            let r = self.get_mut().write(buf);
+            self.panicked = false;
+            r
+        } else {
+            self.buf.extend_from_slice(buf);
+            Ok(buf.len())
+        }
+    }
+
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        // Normally, `write_all` just calls `write` in a loop. We can do better
+        // by calling `self.get_mut().write_all()` directly, which avoids
+        // round trips through the buffer in the event of a series of partial
+        // writes in some circumstances.
+        if self.buf.len() + buf.len() > self.buf.capacity() {
+            self.flush_buf()?;
+        }
+        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
+        if buf.len() >= self.buf.capacity() {
+            self.panicked = true;
+            let r = self.get_mut().write_all(buf);
+            self.panicked = false;
+            r
+        } else {
+            self.buf.extend_from_slice(buf);
+            Ok(())
+        }
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
+        if self.buf.len() + total_len > self.buf.capacity() {
+            self.flush_buf()?;
+        }
+        // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919
+        if total_len >= self.buf.capacity() {
+            self.panicked = true;
+            let r = self.get_mut().write_vectored(bufs);
+            self.panicked = false;
+            r
+        } else {
+            bufs.iter().for_each(|b| self.buf.extend_from_slice(b));
+            Ok(total_len)
+        }
+    }
+
+    fn is_write_vectored(&self) -> bool {
+        self.get_ref().is_write_vectored()
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.flush_buf().and_then(|()| self.get_mut().flush())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> fmt::Debug for BufWriter<W>
+where
+    W: fmt::Debug,
+{
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct("BufWriter")
+            .field("writer", &self.inner.as_ref().unwrap())
+            .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity()))
+            .finish()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write + Seek> Seek for BufWriter<W> {
+    /// Seek to the offset, in bytes, in the underlying writer.
+    ///
+    /// Seeking always writes out the internal buffer before seeking.
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
+        self.flush_buf()?;
+        self.get_mut().seek(pos)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> Drop for BufWriter<W> {
+    fn drop(&mut self) {
+        if self.inner.is_some() && !self.panicked {
+            // dtors should not panic, so we ignore a failed flush
+            let _r = self.flush_buf();
+        }
+    }
+}
diff --git a/library/std/src/io/buffered/linewriter.rs b/library/std/src/io/buffered/linewriter.rs
new file mode 100644
index 00000000000..502c6e3c6c0
--- /dev/null
+++ b/library/std/src/io/buffered/linewriter.rs
@@ -0,0 +1,232 @@
+use crate::fmt;
+use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSlice, Write};
+
+/// Wraps a writer and buffers output to it, flushing whenever a newline
+/// (`0x0a`, `'\n'`) is detected.
+///
+/// The [`BufWriter`] struct wraps a writer and buffers its output.
+/// But it only does this batched write when it goes out of scope, or when the
+/// internal buffer is full. Sometimes, you'd prefer to write each line as it's
+/// completed, rather than the entire buffer at once. Enter `LineWriter`. It
+/// does exactly that.
+///
+/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the
+/// `LineWriter` goes out of scope or when its internal buffer is full.
+///
+/// If there's still a partial line in the buffer when the `LineWriter` is
+/// dropped, it will flush those contents.
+///
+/// # Examples
+///
+/// We can use `LineWriter` to write one line at a time, significantly
+/// reducing the number of actual writes to the file.
+///
+/// ```no_run
+/// use std::fs::{self, File};
+/// use std::io::prelude::*;
+/// use std::io::LineWriter;
+///
+/// fn main() -> std::io::Result<()> {
+///     let road_not_taken = b"I shall be telling this with a sigh
+/// Somewhere ages and ages hence:
+/// Two roads diverged in a wood, and I -
+/// I took the one less traveled by,
+/// And that has made all the difference.";
+///
+///     let file = File::create("poem.txt")?;
+///     let mut file = LineWriter::new(file);
+///
+///     file.write_all(b"I shall be telling this with a sigh")?;
+///
+///     // No bytes are written until a newline is encountered (or
+///     // the internal buffer is filled).
+///     assert_eq!(fs::read_to_string("poem.txt")?, "");
+///     file.write_all(b"\n")?;
+///     assert_eq!(
+///         fs::read_to_string("poem.txt")?,
+///         "I shall be telling this with a sigh\n",
+///     );
+///
+///     // Write the rest of the poem.
+///     file.write_all(b"Somewhere ages and ages hence:
+/// Two roads diverged in a wood, and I -
+/// I took the one less traveled by,
+/// And that has made all the difference.")?;
+///
+///     // The last line of the poem doesn't end in a newline, so
+///     // we have to flush or drop the `LineWriter` to finish
+///     // writing.
+///     file.flush()?;
+///
+///     // Confirm the whole poem was written.
+///     assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]);
+///     Ok(())
+/// }
+/// ```
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct LineWriter<W: Write> {
+    inner: BufWriter<W>,
+}
+
+impl<W: Write> LineWriter<W> {
+    /// Creates a new `LineWriter`.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let file = LineWriter::new(file);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn new(inner: W) -> LineWriter<W> {
+        // Lines typically aren't that long, don't use a giant buffer
+        LineWriter::with_capacity(1024, inner)
+    }
+
+    /// Creates a new `LineWriter` with a specified capacity for the internal
+    /// buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let file = LineWriter::with_capacity(100, file);
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn with_capacity(capacity: usize, inner: W) -> LineWriter<W> {
+        LineWriter { inner: BufWriter::with_capacity(capacity, inner) }
+    }
+
+    /// Gets a reference to the underlying writer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let file = LineWriter::new(file);
+    ///
+    ///     let reference = file.get_ref();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_ref(&self) -> &W {
+        self.inner.get_ref()
+    }
+
+    /// Gets a mutable reference to the underlying writer.
+    ///
+    /// Caution must be taken when calling methods on the mutable reference
+    /// returned as extra writes could corrupt the output stream.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///     let mut file = LineWriter::new(file);
+    ///
+    ///     // we can use reference just like file
+    ///     let reference = file.get_mut();
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn get_mut(&mut self) -> &mut W {
+        self.inner.get_mut()
+    }
+
+    /// Unwraps this `LineWriter`, returning the underlying writer.
+    ///
+    /// The internal buffer is written out before returning the writer.
+    ///
+    /// # Errors
+    ///
+    /// An [`Err`] will be returned if an error occurs while flushing the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// use std::io::LineWriter;
+    ///
+    /// fn main() -> std::io::Result<()> {
+    ///     let file = File::create("poem.txt")?;
+    ///
+    ///     let writer: LineWriter<File> = LineWriter::new(file);
+    ///
+    ///     let file: File = writer.into_inner()?;
+    ///     Ok(())
+    /// }
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
+        self.inner.into_inner().map_err(|err| err.new_wrapped(|inner| LineWriter { inner }))
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> Write for LineWriter<W> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        LineWriterShim::new(&mut self.inner).write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.inner.flush()
+    }
+
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        LineWriterShim::new(&mut self.inner).write_vectored(bufs)
+    }
+
+    fn is_write_vectored(&self) -> bool {
+        self.inner.is_write_vectored()
+    }
+
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        LineWriterShim::new(&mut self.inner).write_all(buf)
+    }
+
+    fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
+        LineWriterShim::new(&mut self.inner).write_all_vectored(bufs)
+    }
+
+    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
+        LineWriterShim::new(&mut self.inner).write_fmt(fmt)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Write> fmt::Debug for LineWriter<W>
+where
+    W: fmt::Debug,
+{
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct("LineWriter")
+            .field("writer", &self.get_ref())
+            .field(
+                "buffer",
+                &format_args!("{}/{}", self.inner.buffer().len(), self.inner.capacity()),
+            )
+            .finish()
+    }
+}
diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs
new file mode 100644
index 00000000000..a80d08db869
--- /dev/null
+++ b/library/std/src/io/buffered/linewritershim.rs
@@ -0,0 +1,270 @@
+use crate::io::{self, BufWriter, IoSlice, Write};
+use crate::memchr;
+
+/// Private helper struct for implementing the line-buffered writing logic.
+/// This shim temporarily wraps a BufWriter, and uses its internals to
+/// implement a line-buffered writer (specifically by using the internal
+/// methods like write_to_buf and flush_buf). In this way, a more
+/// efficient abstraction can be created than one that only had access to
+/// `write` and `flush`, without needlessly duplicating a lot of the
+/// implementation details of BufWriter. This also allows existing
+/// `BufWriters` to be temporarily given line-buffering logic; this is what
+/// enables Stdout to be alternately in line-buffered or block-buffered mode.
+#[derive(Debug)]
+pub struct LineWriterShim<'a, W: Write> {
+    buffer: &'a mut BufWriter<W>,
+}
+
+impl<'a, W: Write> LineWriterShim<'a, W> {
+    pub fn new(buffer: &'a mut BufWriter<W>) -> Self {
+        Self { buffer }
+    }
+
+    /// Get a mutable reference to the inner writer (that is, the writer
+    /// wrapped by the BufWriter). Be careful with this writer, as writes to
+    /// it will bypass the buffer.
+    fn inner_mut(&mut self) -> &mut W {
+        self.buffer.get_mut()
+    }
+
+    /// Get the content currently buffered in self.buffer
+    fn buffered(&self) -> &[u8] {
+        self.buffer.buffer()
+    }
+
+    /// Flush the buffer iff the last byte is a newline (indicating that an
+    /// earlier write only succeeded partially, and we want to retry flushing
+    /// the buffered line before continuing with a subsequent write)
+    fn flush_if_completed_line(&mut self) -> io::Result<()> {
+        match self.buffered().last().copied() {
+            Some(b'\n') => self.buffer.flush_buf(),
+            _ => Ok(()),
+        }
+    }
+}
+
+impl<'a, W: Write> Write for LineWriterShim<'a, W> {
+    /// Write some data into this BufReader with line buffering. This means
+    /// that, if any newlines are present in the data, the data up to the last
+    /// newline is sent directly to the underlying writer, and data after it
+    /// is buffered. Returns the number of bytes written.
+    ///
+    /// This function operates on a "best effort basis"; in keeping with the
+    /// convention of `Write::write`, it makes at most one attempt to write
+    /// new data to the underlying writer. If that write only reports a partial
+    /// success, the remaining data will be buffered.
+    ///
+    /// Because this function attempts to send completed lines to the underlying
+    /// writer, it will also flush the existing buffer if it ends with a
+    /// newline, even if the incoming data does not contain any newlines.
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let newline_idx = match memchr::memrchr(b'\n', buf) {
+            // If there are no new newlines (that is, if this write is less than
+            // one line), just do a regular buffered write (which may flush if
+            // we exceed the inner buffer's size)
+            None => {
+                self.flush_if_completed_line()?;
+                return self.buffer.write(buf);
+            }
+            // Otherwise, arrange for the lines to be written directly to the
+            // inner writer.
+            Some(newline_idx) => newline_idx + 1,
+        };
+
+        // Flush existing content to prepare for our write. We have to do this
+        // before attempting to write `buf` in order to maintain consistency;
+        // if we add `buf` to the buffer then try to flush it all at once,
+        // we're obligated to return Ok(), which would mean suppressing any
+        // errors that occur during flush.
+        self.buffer.flush_buf()?;
+
+        // This is what we're going to try to write directly to the inner
+        // writer. The rest will be buffered, if nothing goes wrong.
+        let lines = &buf[..newline_idx];
+
+        // Write `lines` directly to the inner writer. In keeping with the
+        // `write` convention, make at most one attempt to add new (unbuffered)
+        // data. Because this write doesn't touch the BufWriter state directly,
+        // and the buffer is known to be empty, we don't need to worry about
+        // self.buffer.panicked here.
+        let flushed = self.inner_mut().write(lines)?;
+
+        // If buffer returns Ok(0), propagate that to the caller without
+        // doing additional buffering; otherwise we're just guaranteeing
+        // an "ErrorKind::WriteZero" later.
+        if flushed == 0 {
+            return Ok(0);
+        }
+
+        // Now that the write has succeeded, buffer the rest (or as much of
+        // the rest as possible). If there were any unwritten newlines, we
+        // only buffer out to the last unwritten newline that fits in the
+        // buffer; this helps prevent flushing partial lines on subsequent
+        // calls to LineWriterShim::write.
+
+        // Handle the cases in order of most-common to least-common, under
+        // the presumption that most writes succeed in totality, and that most
+        // writes are smaller than the buffer.
+        // - Is this a partial line (ie, no newlines left in the unwritten tail)
+        // - If not, does the data out to the last unwritten newline fit in
+        //   the buffer?
+        // - If not, scan for the last newline that *does* fit in the buffer
+        let tail = if flushed >= newline_idx {
+            &buf[flushed..]
+        } else if newline_idx - flushed <= self.buffer.capacity() {
+            &buf[flushed..newline_idx]
+        } else {
+            let scan_area = &buf[flushed..];
+            let scan_area = &scan_area[..self.buffer.capacity()];
+            match memchr::memrchr(b'\n', scan_area) {
+                Some(newline_idx) => &scan_area[..newline_idx + 1],
+                None => scan_area,
+            }
+        };
+
+        let buffered = self.buffer.write_to_buf(tail);
+        Ok(flushed + buffered)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.buffer.flush()
+    }
+
+    /// Write some vectored data into this BufReader with line buffering. This
+    /// means that, if any newlines are present in the data, the data up to
+    /// and including the buffer containing the last newline is sent directly
+    /// to the inner writer, and the data after it is buffered. Returns the
+    /// number of bytes written.
+    ///
+    /// This function operates on a "best effort basis"; in keeping with the
+    /// convention of `Write::write`, it makes at most one attempt to write
+    /// new data to the underlying writer.
+    ///
+    /// Because this function attempts to send completed lines to the underlying
+    /// writer, it will also flush the existing buffer if it contains any
+    /// newlines.
+    ///
+    /// Because sorting through an array of `IoSlice` can be a bit convoluted,
+    /// This method differs from write in the following ways:
+    ///
+    /// - It attempts to write the full content of all the buffers up to and
+    ///   including the one containing the last newline. This means that it
+    ///   may attempt to write a partial line, that buffer has data past the
+    ///   newline.
+    /// - If the write only reports partial success, it does not attempt to
+    ///   find the precise location of the written bytes and buffer the rest.
+    ///
+    /// If the underlying vector doesn't support vectored writing, we instead
+    /// simply write the first non-empty buffer with `write`. This way, we
+    /// get the benefits of more granular partial-line handling without losing
+    /// anything in efficiency
+    fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        // If there's no specialized behavior for write_vectored, just use
+        // write. This has the benefit of more granular partial-line handling.
+        if !self.is_write_vectored() {
+            return match bufs.iter().find(|buf| !buf.is_empty()) {
+                Some(buf) => self.write(buf),
+                None => Ok(0),
+            };
+        }
+
+        // Find the buffer containing the last newline
+        let last_newline_buf_idx = bufs
+            .iter()
+            .enumerate()
+            .rev()
+            .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i));
+
+        // If there are no new newlines (that is, if this write is less than
+        // one line), just do a regular buffered write
+        let last_newline_buf_idx = match last_newline_buf_idx {
+            // No newlines; just do a normal buffered write
+            None => {
+                self.flush_if_completed_line()?;
+                return self.buffer.write_vectored(bufs);
+            }
+            Some(i) => i,
+        };
+
+        // Flush existing content to prepare for our write
+        self.buffer.flush_buf()?;
+
+        // This is what we're going to try to write directly to the inner
+        // writer. The rest will be buffered, if nothing goes wrong.
+        let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1);
+
+        // Write `lines` directly to the inner writer. In keeping with the
+        // `write` convention, make at most one attempt to add new (unbuffered)
+        // data. Because this write doesn't touch the BufWriter state directly,
+        // and the buffer is known to be empty, we don't need to worry about
+        // self.panicked here.
+        let flushed = self.inner_mut().write_vectored(lines)?;
+
+        // If inner returns Ok(0), propagate that to the caller without
+        // doing additional buffering; otherwise we're just guaranteeing
+        // an "ErrorKind::WriteZero" later.
+        if flushed == 0 {
+            return Ok(0);
+        }
+
+        // Don't try to reconstruct the exact amount written; just bail
+        // in the event of a partial write
+        let lines_len = lines.iter().map(|buf| buf.len()).sum();
+        if flushed < lines_len {
+            return Ok(flushed);
+        }
+
+        // Now that the write has succeeded, buffer the rest (or as much of the
+        // rest as possible)
+        let buffered: usize = tail
+            .iter()
+            .filter(|buf| !buf.is_empty())
+            .map(|buf| self.buffer.write_to_buf(buf))
+            .take_while(|&n| n > 0)
+            .sum();
+
+        Ok(flushed + buffered)
+    }
+
+    fn is_write_vectored(&self) -> bool {
+        self.buffer.is_write_vectored()
+    }
+
+    /// Write some data into this BufReader with line buffering. This means
+    /// that, if any newlines are present in the data, the data up to the last
+    /// newline is sent directly to the underlying writer, and data after it
+    /// is buffered.
+    ///
+    /// Because this function attempts to send completed lines to the underlying
+    /// writer, it will also flush the existing buffer if it contains any
+    /// newlines, even if the incoming data does not contain any newlines.
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        match memchr::memrchr(b'\n', buf) {
+            // If there are no new newlines (that is, if this write is less than
+            // one line), just do a regular buffered write (which may flush if
+            // we exceed the inner buffer's size)
+            None => {
+                self.flush_if_completed_line()?;
+                self.buffer.write_all(buf)
+            }
+            Some(newline_idx) => {
+                let (lines, tail) = buf.split_at(newline_idx + 1);
+
+                if self.buffered().is_empty() {
+                    self.inner_mut().write_all(lines)?;
+                } else {
+                    // If there is any buffered data, we add the incoming lines
+                    // to that buffer before flushing, which saves us at least
+                    // one write call. We can't really do this with `write`,
+                    // since we can't do this *and* not suppress errors *and*
+                    // report a consistent state to the caller in a return
+                    // value, but here in write_all it's fine.
+                    self.buffer.write_all(lines)?;
+                    self.buffer.flush_buf()?;
+                }
+
+                self.buffer.write_all(tail)
+            }
+        }
+    }
+}
diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs
new file mode 100644
index 00000000000..f9caeaf98e2
--- /dev/null
+++ b/library/std/src/io/buffered/mod.rs
@@ -0,0 +1,151 @@
+//! Buffering wrappers for I/O traits
+
+mod bufreader;
+mod bufwriter;
+mod linewriter;
+mod linewritershim;
+
+#[cfg(test)]
+mod tests;
+
+use crate::error;
+use crate::fmt;
+use crate::io::Error;
+
+pub use bufreader::BufReader;
+pub use bufwriter::BufWriter;
+pub use linewriter::LineWriter;
+use linewritershim::LineWriterShim;
+
+/// An error returned by [`BufWriter::into_inner`] which combines an error that
+/// happened while writing out the buffer, and the buffered writer object
+/// which may be used to recover from the condition.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::io::BufWriter;
+/// use std::net::TcpStream;
+///
+/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+///
+/// // do stuff with the stream
+///
+/// // we want to get our `TcpStream` back, so let's try:
+///
+/// let stream = match stream.into_inner() {
+///     Ok(s) => s,
+///     Err(e) => {
+///         // Here, e is an IntoInnerError
+///         panic!("An error occurred");
+///     }
+/// };
+/// ```
+#[derive(Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct IntoInnerError<W>(W, Error);
+
+impl<W> IntoInnerError<W> {
+    /// Construct a new IntoInnerError
+    fn new(writer: W, error: Error) -> Self {
+        Self(writer, error)
+    }
+
+    /// Helper to construct a new IntoInnerError; intended to help with
+    /// adapters that wrap other adapters
+    fn new_wrapped<W2>(self, f: impl FnOnce(W) -> W2) -> IntoInnerError<W2> {
+        let Self(writer, error) = self;
+        IntoInnerError::new(f(writer), error)
+    }
+
+    /// Returns the error which caused the call to [`BufWriter::into_inner()`]
+    /// to fail.
+    ///
+    /// This error was returned when attempting to write the internal buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // do stuff with the stream
+    ///
+    /// // we want to get our `TcpStream` back, so let's try:
+    ///
+    /// let stream = match stream.into_inner() {
+    ///     Ok(s) => s,
+    ///     Err(e) => {
+    ///         // Here, e is an IntoInnerError, let's log the inner error.
+    ///         //
+    ///         // We'll just 'log' to stdout for this example.
+    ///         println!("{}", e.error());
+    ///
+    ///         panic!("An unexpected error occurred.");
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn error(&self) -> &Error {
+        &self.1
+    }
+
+    /// Returns the buffered writer instance which generated the error.
+    ///
+    /// The returned object can be used for error recovery, such as
+    /// re-inspecting the buffer.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// use std::io::BufWriter;
+    /// use std::net::TcpStream;
+    ///
+    /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
+    ///
+    /// // do stuff with the stream
+    ///
+    /// // we want to get our `TcpStream` back, so let's try:
+    ///
+    /// let stream = match stream.into_inner() {
+    ///     Ok(s) => s,
+    ///     Err(e) => {
+    ///         // Here, e is an IntoInnerError, let's re-examine the buffer:
+    ///         let buffer = e.into_inner();
+    ///
+    ///         // do stuff to try to recover
+    ///
+    ///         // afterwards, let's just return the stream
+    ///         buffer.into_inner().unwrap()
+    ///     }
+    /// };
+    /// ```
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn into_inner(self) -> W {
+        self.0
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W> From<IntoInnerError<W>> for Error {
+    fn from(iie: IntoInnerError<W>) -> Error {
+        iie.1
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
+    #[allow(deprecated, deprecated_in_future)]
+    fn description(&self) -> &str {
+        error::Error::description(self.error())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W> fmt::Display for IntoInnerError<W> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.error().fmt(f)
+    }
+}
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index b2bd5f4da50..5224672adb2 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -85,7 +85,7 @@
 //! # Contributing changes to the documentation
 //!
 //! Check out the rust contribution guidelines [here](
-//! https://rustc-dev-guide.rust-lang.org/getting-started.html).
+//! https://rustc-dev-guide.rust-lang.org/contributing.html#writing-documentation).
 //! The source for this documentation can be found on
 //! [GitHub](https://github.com/rust-lang/rust).
 //! To contribute changes, make sure you read the guidelines first, then submit
@@ -237,10 +237,10 @@
 #![feature(clamp)]
 #![feature(concat_idents)]
 #![feature(const_cstr_unchecked)]
-#![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))]
+#![feature(const_fn_floating_point_arithmetic)]
 #![feature(const_fn_transmute)]
 #![feature(const_fn)]
-#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))]
+#![feature(const_fn_fn_ptr_basics)]
 #![feature(const_ip)]
 #![feature(const_ipv6)]
 #![feature(const_raw_ptr_deref)]
@@ -249,7 +249,6 @@
 #![feature(core_intrinsics)]
 #![feature(custom_test_frameworks)]
 #![feature(decl_macro)]
-#![cfg_attr(bootstrap, feature(doc_alias))]
 #![feature(doc_cfg)]
 #![feature(doc_keyword)]
 #![feature(doc_masked)]
diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs
index 3a5fd8f6f5d..e8b89626fbd 100644
--- a/library/std/src/net/parser.rs
+++ b/library/std/src/net/parser.rs
@@ -32,7 +32,7 @@ macro_rules! impl_helper {
     })*)
 }
 
-impl_helper! { u8 u16 }
+impl_helper! { u8 u16 u32 }
 
 struct Parser<'a> {
     // parsing as ASCII, so can use byte array
@@ -75,9 +75,12 @@ impl<'a> Parser<'a> {
         })
     }
 
-    /// Read the next character from the input if it matches the target
-    fn read_given_char(&mut self, target: char) -> Option<char> {
-        self.read_atomically(|p| p.read_char().filter(|&c| c == target))
+    #[must_use]
+    /// Read the next character from the input if it matches the target.
+    fn read_given_char(&mut self, target: char) -> Option<()> {
+        self.read_atomically(|p| {
+            p.read_char().and_then(|c| if c == target { Some(()) } else { None })
+        })
     }
 
     /// Helper for reading separators in an indexed loop. Reads the separator
@@ -90,7 +93,7 @@ impl<'a> Parser<'a> {
     {
         self.read_atomically(move |p| {
             if index > 0 {
-                let _ = p.read_given_char(sep)?;
+                p.read_given_char(sep)?;
             }
             inner(p)
         })
@@ -187,8 +190,8 @@ impl<'a> Parser<'a> {
 
             // read `::` if previous code parsed less than 8 groups
             // `::` indicates one or more groups of 16 bits of zeros
-            let _ = p.read_given_char(':')?;
-            let _ = p.read_given_char(':')?;
+            p.read_given_char(':')?;
+            p.read_given_char(':')?;
 
             // Read the back part of the address. The :: must contain at least one
             // set of zeroes, so our max length is 7.
@@ -211,7 +214,15 @@ impl<'a> Parser<'a> {
     /// Read a : followed by a port in base 10.
     fn read_port(&mut self) -> Option<u16> {
         self.read_atomically(|p| {
-            let _ = p.read_given_char(':')?;
+            p.read_given_char(':')?;
+            p.read_number(10, None)
+        })
+    }
+
+    /// Read a % followed by a scope id in base 10.
+    fn read_scope_id(&mut self) -> Option<u32> {
+        self.read_atomically(|p| {
+            p.read_given_char('%')?;
             p.read_number(10, None)
         })
     }
@@ -228,12 +239,13 @@ impl<'a> Parser<'a> {
     /// Read an IPV6 address with a port
     fn read_socket_addr_v6(&mut self) -> Option<SocketAddrV6> {
         self.read_atomically(|p| {
-            let _ = p.read_given_char('[')?;
+            p.read_given_char('[')?;
             let ip = p.read_ipv6_addr()?;
-            let _ = p.read_given_char(']')?;
+            let scope_id = p.read_scope_id().unwrap_or(0);
+            p.read_given_char(']')?;
 
             let port = p.read_port()?;
-            Some(SocketAddrV6::new(ip, port, 0, 0))
+            Some(SocketAddrV6::new(ip, port, 0, scope_id))
         })
     }
 
diff --git a/library/std/src/net/parser/tests.rs b/library/std/src/net/parser/tests.rs
index ecf5a782c0c..8d8889cd19d 100644
--- a/library/std/src/net/parser/tests.rs
+++ b/library/std/src/net/parser/tests.rs
@@ -3,6 +3,7 @@ use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAdd
 use crate::str::FromStr;
 
 const PORT: u16 = 8080;
+const SCOPE_ID: u32 = 1337;
 
 const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1);
 const IPV4_STR: &str = "192.168.0.1";
@@ -13,6 +14,7 @@ const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1";
 const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1";
 const IPV6_STR_V4: &str = "2001:db8::192.168.0.1";
 const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080";
+const IPV6_STR_PORT_SCOPE_ID: &str = "[2001:db8::c0a8:1%1337]:8080";
 
 #[test]
 fn parse_ipv4() {
@@ -74,8 +76,8 @@ fn parse_socket_v4() {
 
 #[test]
 fn parse_socket_v6() {
-    let result: SocketAddrV6 = IPV6_STR_PORT.parse().unwrap();
-    assert_eq!(result, SocketAddrV6::new(IPV6, PORT, 0, 0));
+    assert_eq!(IPV6_STR_PORT.parse(), Ok(SocketAddrV6::new(IPV6, PORT, 0, 0)));
+    assert_eq!(IPV6_STR_PORT_SCOPE_ID.parse(), Ok(SocketAddrV6::new(IPV6, PORT, 0, SCOPE_ID)));
 
     assert!(SocketAddrV6::from_str(IPV4_STR).is_err());
     assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err());
diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs
index ff23c3d67e3..9b7af97616c 100644
--- a/library/std/src/os/linux/fs.rs
+++ b/library/std/src/os/linux/fs.rs
@@ -20,7 +20,7 @@ pub trait MetadataExt {
     /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
     /// cross-Unix abstractions contained within the raw stat.
     ///
-    /// [`stat`]: crate::os::linux::raw::stat
+    /// [`stat`]: struct@crate::os::linux::raw::stat
     ///
     /// # Examples
     ///
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 6fa73042a30..50bd2a03b62 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1009,7 +1009,7 @@ impl FusedIterator for Ancestors<'_> {}
 /// [`set_extension`]: PathBuf::set_extension
 ///
 /// More details about the overall approach can be found in
-/// the [module documentation](index.html).
+/// the [module documentation](self).
 ///
 /// # Examples
 ///
@@ -1655,7 +1655,7 @@ impl AsRef<OsStr> for PathBuf {
 /// see [`PathBuf`].
 ///
 /// More details about the overall approach can be found in
-/// the [module documentation](index.html).
+/// the [module documentation](self).
 ///
 /// # Examples
 ///
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 81bbf376378..ae678479234 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -1118,6 +1118,8 @@ mod prim_ref {}
 /// For more information and a list of supported ABIs, see [the nomicon's
 /// section on foreign calling conventions][nomicon-abi].
 ///
+/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions
+///
 /// ### Variadic functions
 ///
 /// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index e8f5a6f4294..a01ebb316e8 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -276,7 +276,7 @@ impl<T: ?Sized> Mutex<T> {
     /// # Errors
     ///
     /// If another user of this mutex panicked while holding the mutex, then
-    /// this call will return failure if the mutex would otherwise be
+    /// this call will return an error if the mutex would otherwise be
     /// acquired.
     ///
     /// # Examples
diff --git a/library/std/src/sys/cloudabi/condvar.rs b/library/std/src/sys/cloudabi/condvar.rs
index 82d89b260fa..f09bc01701b 100644
--- a/library/std/src/sys/cloudabi/condvar.rs
+++ b/library/std/src/sys/cloudabi/condvar.rs
@@ -1,4 +1,3 @@
-use crate::cell::UnsafeCell;
 use crate::mem;
 use crate::sync::atomic::{AtomicU32, Ordering};
 use crate::sys::cloudabi::abi;
@@ -12,7 +11,7 @@ extern "C" {
 }
 
 pub struct Condvar {
-    condvar: UnsafeCell<AtomicU32>,
+    condvar: AtomicU32,
 }
 
 pub type MovableCondvar = Condvar;
@@ -20,29 +19,28 @@ pub type MovableCondvar = Condvar;
 unsafe impl Send for Condvar {}
 unsafe impl Sync for Condvar {}
 
-const NEW: Condvar =
-    Condvar { condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)) };
-
 impl Condvar {
     pub const fn new() -> Condvar {
-        NEW
+        Condvar { condvar: AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0) }
     }
 
     pub unsafe fn init(&mut self) {}
 
     pub unsafe fn notify_one(&self) {
-        let condvar = self.condvar.get();
-        if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
-            let ret = abi::condvar_signal(condvar as *mut abi::condvar, abi::scope::PRIVATE, 1);
+        if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
+            let ret = abi::condvar_signal(
+                &self.condvar as *const AtomicU32 as *mut abi::condvar,
+                abi::scope::PRIVATE,
+                1,
+            );
             assert_eq!(ret, abi::errno::SUCCESS, "Failed to signal on condition variable");
         }
     }
 
     pub unsafe fn notify_all(&self) {
-        let condvar = self.condvar.get();
-        if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
+        if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
             let ret = abi::condvar_signal(
-                condvar as *mut abi::condvar,
+                &self.condvar as *const AtomicU32 as *mut abi::condvar,
                 abi::scope::PRIVATE,
                 abi::nthreads::MAX,
             );
@@ -53,20 +51,19 @@ impl Condvar {
     pub unsafe fn wait(&self, mutex: &Mutex) {
         let mutex = mutex::raw(mutex);
         assert_eq!(
-            (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+            mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
             "This lock is not write-locked by this thread"
         );
 
         // Call into the kernel to wait on the condition variable.
-        let condvar = self.condvar.get();
         let subscription = abi::subscription {
             type_: abi::eventtype::CONDVAR,
             union: abi::subscription_union {
                 condvar: abi::subscription_condvar {
-                    condvar: condvar as *mut abi::condvar,
+                    condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar,
                     condvar_scope: abi::scope::PRIVATE,
-                    lock: mutex as *mut abi::lock,
+                    lock: mutex as *const AtomicU32 as *mut abi::lock,
                     lock_scope: abi::scope::PRIVATE,
                 },
             },
@@ -86,13 +83,12 @@ impl Condvar {
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         let mutex = mutex::raw(mutex);
         assert_eq!(
-            (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+            mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
             "This lock is not write-locked by this thread"
         );
 
         // Call into the kernel to wait on the condition variable.
-        let condvar = self.condvar.get();
         let timeout =
             checked_dur2intervals(&dur).expect("overflow converting duration to nanoseconds");
         let subscriptions = [
@@ -100,9 +96,9 @@ impl Condvar {
                 type_: abi::eventtype::CONDVAR,
                 union: abi::subscription_union {
                     condvar: abi::subscription_condvar {
-                        condvar: condvar as *mut abi::condvar,
+                        condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar,
                         condvar_scope: abi::scope::PRIVATE,
-                        lock: mutex as *mut abi::lock,
+                        lock: mutex as *const AtomicU32 as *mut abi::lock,
                         lock_scope: abi::scope::PRIVATE,
                     },
                 },
@@ -124,7 +120,7 @@ impl Condvar {
         let mut nevents: mem::MaybeUninit<usize> = mem::MaybeUninit::uninit();
         let ret = abi::poll(
             subscriptions.as_ptr(),
-            mem::MaybeUninit::first_ptr_mut(&mut events),
+            mem::MaybeUninit::slice_as_mut_ptr(&mut events),
             2,
             nevents.as_mut_ptr(),
         );
@@ -144,9 +140,8 @@ impl Condvar {
     }
 
     pub unsafe fn destroy(&self) {
-        let condvar = self.condvar.get();
         assert_eq!(
-            (*condvar).load(Ordering::Relaxed),
+            self.condvar.load(Ordering::Relaxed),
             abi::CONDVAR_HAS_NO_WAITERS.0,
             "Attempted to destroy a condition variable with blocked threads"
         );
diff --git a/library/std/src/sys/cloudabi/mutex.rs b/library/std/src/sys/cloudabi/mutex.rs
index 66839e05bf0..1203d8de0c5 100644
--- a/library/std/src/sys/cloudabi/mutex.rs
+++ b/library/std/src/sys/cloudabi/mutex.rs
@@ -1,4 +1,4 @@
-use crate::cell::UnsafeCell;
+use crate::cell::Cell;
 use crate::mem;
 use crate::mem::MaybeUninit;
 use crate::sync::atomic::{AtomicU32, Ordering};
@@ -17,7 +17,7 @@ pub struct Mutex(RWLock);
 
 pub type MovableMutex = Mutex;
 
-pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 {
+pub unsafe fn raw(m: &Mutex) -> &AtomicU32 {
     rwlock::raw(&m.0)
 }
 
@@ -50,28 +50,23 @@ impl Mutex {
 }
 
 pub struct ReentrantMutex {
-    lock: UnsafeCell<MaybeUninit<AtomicU32>>,
-    recursion: UnsafeCell<MaybeUninit<u32>>,
+    lock: AtomicU32,
+    recursion: Cell<u32>,
 }
 
+unsafe impl Send for ReentrantMutex {}
+unsafe impl Sync for ReentrantMutex {}
+
 impl ReentrantMutex {
     pub const unsafe fn uninitialized() -> ReentrantMutex {
-        ReentrantMutex {
-            lock: UnsafeCell::new(MaybeUninit::uninit()),
-            recursion: UnsafeCell::new(MaybeUninit::uninit()),
-        }
+        ReentrantMutex { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0), recursion: Cell::new(0) }
     }
 
-    pub unsafe fn init(&self) {
-        *self.lock.get() = MaybeUninit::new(AtomicU32::new(abi::LOCK_UNLOCKED.0));
-        *self.recursion.get() = MaybeUninit::new(0);
-    }
+    pub unsafe fn init(&self) {}
 
     pub unsafe fn try_lock(&self) -> bool {
         // Attempt to acquire the lock.
-        let lock = (*self.lock.get()).as_mut_ptr();
-        let recursion = (*self.recursion.get()).as_mut_ptr();
-        if let Err(old) = (*lock).compare_exchange(
+        if let Err(old) = self.lock.compare_exchange(
             abi::LOCK_UNLOCKED.0,
             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
             Ordering::Acquire,
@@ -80,14 +75,14 @@ impl ReentrantMutex {
             // If we fail to acquire the lock, it may be the case
             // that we've already acquired it and may need to recurse.
             if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 {
-                *recursion += 1;
+                self.recursion.set(self.recursion.get() + 1);
                 true
             } else {
                 false
             }
         } else {
             // Success.
-            assert_eq!(*recursion, 0, "Mutex has invalid recursion count");
+            assert_eq!(self.recursion.get(), 0, "Mutex has invalid recursion count");
             true
         }
     }
@@ -95,7 +90,7 @@ impl ReentrantMutex {
     pub unsafe fn lock(&self) {
         if !self.try_lock() {
             // Call into the kernel to acquire a write lock.
-            let lock = self.lock.get();
+            let lock = &self.lock as *const AtomicU32;
             let subscription = abi::subscription {
                 type_: abi::eventtype::LOCK_WRLOCK,
                 union: abi::subscription_union {
@@ -116,17 +111,17 @@ impl ReentrantMutex {
     }
 
     pub unsafe fn unlock(&self) {
-        let lock = (*self.lock.get()).as_mut_ptr();
-        let recursion = (*self.recursion.get()).as_mut_ptr();
         assert_eq!(
-            (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+            self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
             "This mutex is locked by a different thread"
         );
 
-        if *recursion > 0 {
-            *recursion -= 1;
-        } else if !(*lock)
+        let r = self.recursion.get();
+        if r > 0 {
+            self.recursion.set(r - 1);
+        } else if !self
+            .lock
             .compare_exchange(
                 __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
                 abi::LOCK_UNLOCKED.0,
@@ -137,19 +132,20 @@ impl ReentrantMutex {
         {
             // Lock is managed by kernelspace. Call into the kernel
             // to unblock waiting threads.
-            let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
+            let ret = abi::lock_unlock(
+                &self.lock as *const AtomicU32 as *mut abi::lock,
+                abi::scope::PRIVATE,
+            );
             assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex");
         }
     }
 
     pub unsafe fn destroy(&self) {
-        let lock = (*self.lock.get()).as_mut_ptr();
-        let recursion = (*self.recursion.get()).as_mut_ptr();
         assert_eq!(
-            (*lock).load(Ordering::Relaxed),
+            self.lock.load(Ordering::Relaxed),
             abi::LOCK_UNLOCKED.0,
             "Attempted to destroy locked mutex"
         );
-        assert_eq!(*recursion, 0, "Recursion counter invalid");
+        assert_eq!(self.recursion.get(), 0, "Recursion counter invalid");
     }
 }
diff --git a/library/std/src/sys/cloudabi/rwlock.rs b/library/std/src/sys/cloudabi/rwlock.rs
index b8af5af1d70..508de8ba47c 100644
--- a/library/std/src/sys/cloudabi/rwlock.rs
+++ b/library/std/src/sys/cloudabi/rwlock.rs
@@ -1,4 +1,3 @@
-use crate::cell::UnsafeCell;
 use crate::mem;
 use crate::mem::MaybeUninit;
 use crate::sync::atomic::{AtomicU32, Ordering};
@@ -13,28 +12,25 @@ extern "C" {
 static mut RDLOCKS_ACQUIRED: u32 = 0;
 
 pub struct RWLock {
-    lock: UnsafeCell<AtomicU32>,
+    lock: AtomicU32,
 }
 
-pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 {
-    r.lock.get()
+pub unsafe fn raw(r: &RWLock) -> &AtomicU32 {
+    &r.lock
 }
 
 unsafe impl Send for RWLock {}
 unsafe impl Sync for RWLock {}
 
-const NEW: RWLock = RWLock { lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)) };
-
 impl RWLock {
     pub const fn new() -> RWLock {
-        NEW
+        RWLock { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0) }
     }
 
     pub unsafe fn try_read(&self) -> bool {
-        let lock = self.lock.get();
         let mut old = abi::LOCK_UNLOCKED.0;
         while let Err(cur) =
-            (*lock).compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed)
+            self.lock.compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed)
         {
             if (cur & abi::LOCK_WRLOCKED.0) != 0 {
                 // Another thread already has a write lock.
@@ -61,12 +57,11 @@ impl RWLock {
     pub unsafe fn read(&self) {
         if !self.try_read() {
             // Call into the kernel to acquire a read lock.
-            let lock = self.lock.get();
             let subscription = abi::subscription {
                 type_: abi::eventtype::LOCK_RDLOCK,
                 union: abi::subscription_union {
                     lock: abi::subscription_lock {
-                        lock: lock as *mut abi::lock,
+                        lock: &self.lock as *const AtomicU32 as *mut abi::lock,
                         lock_scope: abi::scope::PRIVATE,
                     },
                 },
@@ -96,11 +91,10 @@ impl RWLock {
         assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count");
         let mut old = 1;
         loop {
-            let lock = self.lock.get();
             if old == 1 | abi::LOCK_KERNEL_MANAGED.0 {
                 // Last read lock while threads are waiting. Attempt to upgrade
                 // to a write lock before calling into the kernel to unlock.
-                if let Err(cur) = (*lock).compare_exchange_weak(
+                if let Err(cur) = self.lock.compare_exchange_weak(
                     old,
                     __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0,
                     Ordering::Acquire,
@@ -109,7 +103,10 @@ impl RWLock {
                     old = cur;
                 } else {
                     // Call into the kernel to unlock.
-                    let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
+                    let ret = abi::lock_unlock(
+                        &self.lock as *const AtomicU32 as *mut abi::lock,
+                        abi::scope::PRIVATE,
+                    );
                     assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
                     break;
                 }
@@ -122,7 +119,7 @@ impl RWLock {
                     0,
                     "Attempted to read-unlock a write-locked rwlock"
                 );
-                if let Err(cur) = (*lock).compare_exchange_weak(
+                if let Err(cur) = self.lock.compare_exchange_weak(
                     old,
                     old - 1,
                     Ordering::Acquire,
@@ -140,8 +137,7 @@ impl RWLock {
 
     pub unsafe fn try_write(&self) -> bool {
         // Attempt to acquire the lock.
-        let lock = self.lock.get();
-        if let Err(old) = (*lock).compare_exchange(
+        if let Err(old) = self.lock.compare_exchange(
             abi::LOCK_UNLOCKED.0,
             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
             Ordering::Acquire,
@@ -163,12 +159,11 @@ impl RWLock {
     pub unsafe fn write(&self) {
         if !self.try_write() {
             // Call into the kernel to acquire a write lock.
-            let lock = self.lock.get();
             let subscription = abi::subscription {
                 type_: abi::eventtype::LOCK_WRLOCK,
                 union: abi::subscription_union {
                     lock: abi::subscription_lock {
-                        lock: lock as *mut abi::lock,
+                        lock: &self.lock as *const AtomicU32 as *mut abi::lock,
                         lock_scope: abi::scope::PRIVATE,
                     },
                 },
@@ -184,14 +179,14 @@ impl RWLock {
     }
 
     pub unsafe fn write_unlock(&self) {
-        let lock = self.lock.get();
         assert_eq!(
-            (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
+            self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
             __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
             "This rwlock is not write-locked by this thread"
         );
 
-        if !(*lock)
+        if !self
+            .lock
             .compare_exchange(
                 __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
                 abi::LOCK_UNLOCKED.0,
@@ -202,15 +197,17 @@ impl RWLock {
         {
             // Lock is managed by kernelspace. Call into the kernel
             // to unblock waiting threads.
-            let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
+            let ret = abi::lock_unlock(
+                &self.lock as *const AtomicU32 as *mut abi::lock,
+                abi::scope::PRIVATE,
+            );
             assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
         }
     }
 
     pub unsafe fn destroy(&self) {
-        let lock = self.lock.get();
         assert_eq!(
-            (*lock).load(Ordering::Relaxed),
+            self.lock.load(Ordering::Relaxed),
             abi::LOCK_UNLOCKED.0,
             "Attempted to destroy locked rwlock"
         );
diff --git a/library/std/src/sys/sgx/abi/mod.rs b/library/std/src/sys/sgx/abi/mod.rs
index b0693b63a48..a0eb12c3d15 100644
--- a/library/std/src/sys/sgx/abi/mod.rs
+++ b/library/std/src/sys/sgx/abi/mod.rs
@@ -45,7 +45,7 @@ unsafe extern "C" fn tcs_init(secondary: bool) {
         // We need to wait until the initialization is done.
         BUSY => {
             while RELOC_STATE.load(Ordering::Acquire) == BUSY {
-                core::arch::x86_64::_mm_pause()
+                core::hint::spin_loop();
             }
         }
         // Initialization is done.
diff --git a/library/std/src/sys/sgx/abi/tls.rs b/library/std/src/sys/sgx/abi/tls.rs
index 0d8952b2f27..13d96e9a633 100644
--- a/library/std/src/sys/sgx/abi/tls.rs
+++ b/library/std/src/sys/sgx/abi/tls.rs
@@ -87,18 +87,21 @@ impl Tls {
     }
 
     pub unsafe fn activate(&self) -> ActiveTls<'_> {
-        set_tls_ptr(self as *const Tls as _);
+        // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition.
+        unsafe { set_tls_ptr(self as *const Tls as _) };
         ActiveTls { tls: self }
     }
 
     #[allow(unused)]
     pub unsafe fn activate_persistent(self: Box<Self>) {
-        set_tls_ptr((&*self) as *const Tls as _);
+        // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition.
+        unsafe { set_tls_ptr((&*self) as *const Tls as _) };
         mem::forget(self);
     }
 
     unsafe fn current<'a>() -> &'a Tls {
-        &*(get_tls_ptr() as *const Tls)
+        // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition.
+        unsafe { &*(get_tls_ptr() as *const Tls) }
     }
 
     pub fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs
index 76a9b427b39..9fdb1b45844 100644
--- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs
@@ -89,9 +89,12 @@ pub unsafe trait UserSafe {
     /// * the pointed-to range is not in user memory.
     unsafe fn from_raw_sized(ptr: *mut u8, size: usize) -> NonNull<Self> {
         assert!(ptr.wrapping_add(size) >= ptr);
-        let ret = Self::from_raw_sized_unchecked(ptr, size);
-        Self::check_ptr(ret);
-        NonNull::new_unchecked(ret as _)
+        // SAFETY: The caller has guaranteed the pointer is valid
+        let ret = unsafe { Self::from_raw_sized_unchecked(ptr, size) };
+        unsafe {
+            Self::check_ptr(ret);
+            NonNull::new_unchecked(ret as _)
+        }
     }
 
     /// Checks if a pointer may point to `Self` in user memory.
@@ -112,7 +115,7 @@ pub unsafe trait UserSafe {
         let is_aligned = |p| -> bool { 0 == (p as usize) & (Self::align_of() - 1) };
 
         assert!(is_aligned(ptr as *const u8));
-        assert!(is_user_range(ptr as _, mem::size_of_val(&*ptr)));
+        assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr })));
         assert!(!ptr.is_null());
     }
 }
@@ -135,11 +138,23 @@ unsafe impl<T: UserSafeSized> UserSafe for [T] {
         mem::align_of::<T>()
     }
 
+    /// # Safety
+    /// Behavior is undefined if any of these conditions are violated:
+    /// * `ptr` must be [valid] for writes of `size` many bytes, and it must be
+    ///   properly aligned.
+    ///
+    /// [valid]: core::ptr#safety
+    /// # Panics
+    ///
+    /// This function panics if:
+    ///
+    /// * the element size is not a factor of the size
     unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self {
         let elem_size = mem::size_of::<T>();
         assert_eq!(size % elem_size, 0);
         let len = size / elem_size;
-        slice::from_raw_parts_mut(ptr as _, len)
+        // SAFETY: The caller must uphold the safety contract for `from_raw_sized_unchecked`
+        unsafe { slice::from_raw_parts_mut(ptr as _, len) }
     }
 }
 
@@ -170,13 +185,15 @@ trait NewUserRef<T: ?Sized> {
 
 impl<T: ?Sized> NewUserRef<*mut T> for NonNull<UserRef<T>> {
     unsafe fn new_userref(v: *mut T) -> Self {
-        NonNull::new_unchecked(v as _)
+        // SAFETY: The caller has guaranteed the pointer is valid
+        unsafe { NonNull::new_unchecked(v as _) }
     }
 }
 
 impl<T: ?Sized> NewUserRef<NonNull<T>> for NonNull<UserRef<T>> {
     unsafe fn new_userref(v: NonNull<T>) -> Self {
-        NonNull::new_userref(v.as_ptr())
+        // SAFETY: The caller has guaranteed the pointer is valid
+        unsafe { NonNull::new_userref(v.as_ptr()) }
     }
 }
 
@@ -231,8 +248,9 @@ where
     /// * The pointer is null
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw(ptr: *mut T) -> Self {
-        T::check_ptr(ptr);
-        User(NonNull::new_userref(ptr))
+        // SAFETY: the caller must uphold the safety contract for `from_raw`.
+        unsafe { T::check_ptr(ptr) };
+        User(unsafe { NonNull::new_userref(ptr) })
     }
 
     /// Converts this value into a raw pointer. The value will no longer be
@@ -280,7 +298,9 @@ where
     /// * The pointed-to range does not fit in the address space
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
-        User(NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>())))
+        User(unsafe {
+            NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()))
+        })
     }
 }
 
@@ -301,8 +321,9 @@ where
     /// * The pointer is null
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_ptr<'a>(ptr: *const T) -> &'a Self {
-        T::check_ptr(ptr);
-        &*(ptr as *const Self)
+        // SAFETY: The caller must uphold the safety contract for `from_ptr`.
+        unsafe { T::check_ptr(ptr) };
+        unsafe { &*(ptr as *const Self) }
     }
 
     /// Creates a `&mut UserRef<[T]>` from a raw pointer. See the struct
@@ -318,8 +339,9 @@ where
     /// * The pointer is null
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_mut_ptr<'a>(ptr: *mut T) -> &'a mut Self {
-        T::check_ptr(ptr);
-        &mut *(ptr as *mut Self)
+        // SAFETY: The caller must uphold the safety contract for `from_mut_ptr`.
+        unsafe { T::check_ptr(ptr) };
+        unsafe { &mut *(ptr as *mut Self) }
     }
 
     /// Copies `val` into user memory.
@@ -394,7 +416,10 @@ where
     /// * The pointed-to range does not fit in the address space
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self {
-        &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *const Self)
+        // SAFETY: The caller must uphold the safety contract for `from_raw_parts`.
+        unsafe {
+            &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *const Self)
+        }
     }
 
     /// Creates a `&mut UserRef<[T]>` from a raw thin pointer and a slice length.
@@ -412,7 +437,10 @@ where
     /// * The pointed-to range does not fit in the address space
     /// * The pointed-to range is not in user memory
     pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self {
-        &mut *(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *mut Self)
+        // SAFETY: The caller must uphold the safety contract for `from_raw_parts_mut`.
+        unsafe {
+            &mut *(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::<T>()).as_ptr() as *mut Self)
+        }
     }
 
     /// Obtain a raw pointer to the first element of this user slice.
@@ -437,13 +465,12 @@ where
     /// This function panics if the destination doesn't have the same size as
     /// the source. This can happen for dynamically-sized types such as slices.
     pub fn copy_to_enclave_vec(&self, dest: &mut Vec<T>) {
-        unsafe {
-            if let Some(missing) = self.len().checked_sub(dest.capacity()) {
-                dest.reserve(missing)
-            }
-            dest.set_len(self.len());
-            self.copy_to_enclave(&mut dest[..]);
+        if let Some(missing) = self.len().checked_sub(dest.capacity()) {
+            dest.reserve(missing)
         }
+        // SAFETY: We reserve enough space above.
+        unsafe { dest.set_len(self.len()) };
+        self.copy_to_enclave(&mut dest[..]);
     }
 
     /// Copies the value from user memory into a vector in enclave memory.
diff --git a/library/std/src/sys/sgx/abi/usercalls/mod.rs b/library/std/src/sys/sgx/abi/usercalls/mod.rs
index 73f1b951e74..a6a659df291 100644
--- a/library/std/src/sys/sgx/abi/usercalls/mod.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/mod.rs
@@ -140,7 +140,8 @@ pub fn connect_stream(addr: &str) -> IoResult<(Fd, String, String)> {
 /// Usercall `launch_thread`. See the ABI documentation for more information.
 #[unstable(feature = "sgx_platform", issue = "56975")]
 pub unsafe fn launch_thread() -> IoResult<()> {
-    raw::launch_thread().from_sgx_result()
+    // SAFETY: The caller must uphold the safety contract for `launch_thread`.
+    unsafe { raw::launch_thread().from_sgx_result() }
 }
 
 /// Usercall `exit`. See the ABI documentation for more information.
diff --git a/library/std/src/sys/sgx/abi/usercalls/raw.rs b/library/std/src/sys/sgx/abi/usercalls/raw.rs
index e0ebf860618..b0e6a6aaed7 100644
--- a/library/std/src/sys/sgx/abi/usercalls/raw.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/raw.rs
@@ -33,7 +33,7 @@ pub unsafe fn do_usercall(
     p4: u64,
     abort: bool,
 ) -> (u64, u64) {
-    let UsercallReturn(a, b) = usercall(nr, p1, p2, abort as _, p3, p4);
+    let UsercallReturn(a, b) = unsafe { usercall(nr, p1, p2, abort as _, p3, p4) };
     (a, b)
 }
 
@@ -175,14 +175,14 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
-            ReturnValue::from_registers(stringify!($f), do_usercall(
-                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
-                RegisterArgument::into_register($n1),
-                RegisterArgument::into_register($n2),
-                RegisterArgument::into_register($n3),
-                RegisterArgument::into_register($n4),
-                return_type_is_abort!($r)
-            ))
+            ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
+                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    RegisterArgument::into_register($n1),
+                    RegisterArgument::into_register($n2),
+                    RegisterArgument::into_register($n3),
+                    RegisterArgument::into_register($n4),
+                    return_type_is_abort!($r)
+            ) })
         }
     );
     (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:tt) => (
@@ -191,14 +191,14 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
-            ReturnValue::from_registers(stringify!($f), do_usercall(
-                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
-                RegisterArgument::into_register($n1),
-                RegisterArgument::into_register($n2),
-                RegisterArgument::into_register($n3),
-                0,
-                return_type_is_abort!($r)
-            ))
+            ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
+                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    RegisterArgument::into_register($n1),
+                    RegisterArgument::into_register($n2),
+                    RegisterArgument::into_register($n3),
+                    0,
+                    return_type_is_abort!($r)
+            ) })
         }
     );
     (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:tt) => (
@@ -207,13 +207,13 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
-            ReturnValue::from_registers(stringify!($f), do_usercall(
-                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
-                RegisterArgument::into_register($n1),
-                RegisterArgument::into_register($n2),
-                0,0,
-                return_type_is_abort!($r)
-            ))
+            ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
+                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    RegisterArgument::into_register($n1),
+                    RegisterArgument::into_register($n2),
+                    0,0,
+                    return_type_is_abort!($r)
+            ) })
         }
     );
     (def fn $f:ident($n1:ident: $t1:ty) -> $r:tt) => (
@@ -222,12 +222,12 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f($n1: $t1) -> $r {
-            ReturnValue::from_registers(stringify!($f), do_usercall(
-                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
-                RegisterArgument::into_register($n1),
-                0,0,0,
-                return_type_is_abort!($r)
-            ))
+            ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
+                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    RegisterArgument::into_register($n1),
+                    0,0,0,
+                    return_type_is_abort!($r)
+            ) })
         }
     );
     (def fn $f:ident() -> $r:tt) => (
@@ -236,11 +236,11 @@ macro_rules! enclave_usercalls_internal_define_usercalls {
         #[unstable(feature = "sgx_platform", issue = "56975")]
         #[inline(always)]
         pub unsafe fn $f() -> $r {
-            ReturnValue::from_registers(stringify!($f), do_usercall(
-                rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
-                0,0,0,0,
-                return_type_is_abort!($r)
-            ))
+            ReturnValue::from_registers(stringify!($f), unsafe { do_usercall(
+                    rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)),
+                    0,0,0,0,
+                    return_type_is_abort!($r)
+            ) })
         }
     );
     (def fn $f:ident($($n:ident: $t:ty),*)) => (
diff --git a/library/std/src/sys/sgx/alloc.rs b/library/std/src/sys/sgx/alloc.rs
index 40daec758a9..4559ea7cd25 100644
--- a/library/std/src/sys/sgx/alloc.rs
+++ b/library/std/src/sys/sgx/alloc.rs
@@ -4,6 +4,10 @@ use super::waitqueue::SpinMutex;
 
 // Using a SpinMutex because we never want to exit the enclave waiting for the
 // allocator.
+//
+// The current allocator here is the `dlmalloc` crate which we've got included
+// in the rust-lang/rust repository as a submodule. The crate is a port of
+// dlmalloc.c from C to Rust.
 #[cfg_attr(test, linkage = "available_externally")]
 #[export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE"]
 static DLMALLOC: SpinMutex<dlmalloc::Dlmalloc> = SpinMutex::new(dlmalloc::DLMALLOC_INIT);
@@ -12,22 +16,26 @@ static DLMALLOC: SpinMutex<dlmalloc::Dlmalloc> = SpinMutex::new(dlmalloc::DLMALL
 unsafe impl GlobalAlloc for System {
     #[inline]
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        DLMALLOC.lock().malloc(layout.size(), layout.align())
+        // SAFETY: the caller must uphold the safety contract for `malloc`
+        unsafe { DLMALLOC.lock().malloc(layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-        DLMALLOC.lock().calloc(layout.size(), layout.align())
+        // SAFETY: the caller must uphold the safety contract for `malloc`
+        unsafe { DLMALLOC.lock().calloc(layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
-        DLMALLOC.lock().free(ptr, layout.size(), layout.align())
+        // SAFETY: the caller must uphold the safety contract for `malloc`
+        unsafe { DLMALLOC.lock().free(ptr, layout.size(), layout.align()) }
     }
 
     #[inline]
     unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-        DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size)
+        // SAFETY: the caller must uphold the safety contract for `malloc`
+        unsafe { DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size) }
     }
 }
 
@@ -36,11 +44,11 @@ unsafe impl GlobalAlloc for System {
 #[cfg(not(test))]
 #[no_mangle]
 pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 {
-    crate::alloc::alloc(Layout::from_size_align_unchecked(size, align))
+    unsafe { crate::alloc::alloc(Layout::from_size_align_unchecked(size, align)) }
 }
 
 #[cfg(not(test))]
 #[no_mangle]
 pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) {
-    crate::alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align))
+    unsafe { crate::alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) }
 }
diff --git a/library/std/src/sys/sgx/args.rs b/library/std/src/sys/sgx/args.rs
index 5a53695a846..2d2e692ec7d 100644
--- a/library/std/src/sys/sgx/args.rs
+++ b/library/std/src/sys/sgx/args.rs
@@ -13,7 +13,7 @@ type ArgsStore = Vec<OsString>;
 #[cfg_attr(test, allow(dead_code))]
 pub unsafe fn init(argc: isize, argv: *const *const u8) {
     if argc != 0 {
-        let args = alloc::User::<[ByteBuffer]>::from_raw_parts(argv as _, argc as _);
+        let args = unsafe { alloc::User::<[ByteBuffer]>::from_raw_parts(argv as _, argc as _) };
         let args = args
             .iter()
             .map(|a| OsString::from_inner(Buf { inner: a.copy_user_buffer() }))
diff --git a/library/std/src/sys/sgx/condvar.rs b/library/std/src/sys/sgx/condvar.rs
index dfe22e6a1b3..55ac052d975 100644
--- a/library/std/src/sys/sgx/condvar.rs
+++ b/library/std/src/sys/sgx/condvar.rs
@@ -29,13 +29,13 @@ impl Condvar {
 
     pub unsafe fn wait(&self, mutex: &Mutex) {
         let guard = self.inner.lock();
-        WaitQueue::wait(guard, || mutex.unlock());
-        mutex.lock()
+        WaitQueue::wait(guard, || unsafe { mutex.unlock() });
+        unsafe { mutex.lock() }
     }
 
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
-        let success = WaitQueue::wait_timeout(&self.inner, dur, || mutex.unlock());
-        mutex.lock();
+        let success = WaitQueue::wait_timeout(&self.inner, dur, || unsafe { mutex.unlock() });
+        unsafe { mutex.lock() };
         success
     }
 
diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs
index 1abd91e75e8..b10bed621db 100644
--- a/library/std/src/sys/sgx/mod.rs
+++ b/library/std/src/sys/sgx/mod.rs
@@ -2,6 +2,7 @@
 //!
 //! This module contains the facade (aka platform-specific) implementations of
 //! OS level functionality for Fortanix SGX.
+#![deny(unsafe_op_in_unsafe_fn)]
 
 use crate::io::ErrorKind;
 use crate::os::raw::c_char;
@@ -121,9 +122,9 @@ pub enum Void {}
 
 pub unsafe fn strlen(mut s: *const c_char) -> usize {
     let mut n = 0;
-    while *s != 0 {
+    while unsafe { *s } != 0 {
         n += 1;
-        s = s.offset(1);
+        s = unsafe { s.offset(1) };
     }
     return n;
 }
diff --git a/library/std/src/sys/sgx/rwlock.rs b/library/std/src/sys/sgx/rwlock.rs
index 3bf2a7d8fb4..0c96e3fcddc 100644
--- a/library/std/src/sys/sgx/rwlock.rs
+++ b/library/std/src/sys/sgx/rwlock.rs
@@ -14,9 +14,12 @@ pub struct RWLock {
 }
 
 // Check at compile time that RWLock size matches C definition (see test_c_rwlock_initializer below)
+//
+// # Safety
+// Never called, as it is a compile time check.
 #[allow(dead_code)]
 unsafe fn rw_lock_size_assert(r: RWLock) {
-    mem::transmute::<RWLock, [u8; 144]>(r);
+    unsafe { mem::transmute::<RWLock, [u8; 144]>(r) };
 }
 
 impl RWLock {
@@ -112,7 +115,7 @@ impl RWLock {
     pub unsafe fn read_unlock(&self) {
         let rguard = self.readers.lock();
         let wguard = self.writer.lock();
-        self.__read_unlock(rguard, wguard);
+        unsafe { self.__read_unlock(rguard, wguard) };
     }
 
     #[inline]
@@ -148,7 +151,7 @@ impl RWLock {
     pub unsafe fn write_unlock(&self) {
         let rguard = self.readers.lock();
         let wguard = self.writer.lock();
-        self.__write_unlock(rguard, wguard);
+        unsafe { self.__write_unlock(rguard, wguard) };
     }
 
     // only used by __rust_rwlock_unlock below
@@ -158,9 +161,9 @@ impl RWLock {
         let rguard = self.readers.lock();
         let wguard = self.writer.lock();
         if *wguard.lock_var() == true {
-            self.__write_unlock(rguard, wguard);
+            unsafe { self.__write_unlock(rguard, wguard) };
         } else {
-            self.__read_unlock(rguard, wguard);
+            unsafe { self.__read_unlock(rguard, wguard) };
         }
     }
 
@@ -179,7 +182,7 @@ pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 {
     if p.is_null() {
         return EINVAL;
     }
-    (*p).read();
+    unsafe { (*p).read() };
     return 0;
 }
 
@@ -189,7 +192,7 @@ pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RWLock) -> i32 {
     if p.is_null() {
         return EINVAL;
     }
-    (*p).write();
+    unsafe { (*p).write() };
     return 0;
 }
 #[cfg(not(test))]
@@ -198,6 +201,6 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 {
     if p.is_null() {
         return EINVAL;
     }
-    (*p).unlock();
+    unsafe { (*p).unlock() };
     return 0;
 }
diff --git a/library/std/src/sys/sgx/stdio.rs b/library/std/src/sys/sgx/stdio.rs
index 49f44f9f498..548e28a43d6 100644
--- a/library/std/src/sys/sgx/stdio.rs
+++ b/library/std/src/sys/sgx/stdio.rs
@@ -81,7 +81,7 @@ pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
     if s < 0 {
         return;
     }
-    let buf = slice::from_raw_parts(m as *const u8, s as _);
+    let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) };
     if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
         eprint!("{}", s);
     }
diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs
index 5895f70436e..55ef460cc90 100644
--- a/library/std/src/sys/sgx/thread.rs
+++ b/library/std/src/sys/sgx/thread.rs
@@ -51,7 +51,7 @@ impl Thread {
     // unsafe: see thread::Builder::spawn_unchecked for safety requirements
     pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
         let mut queue_lock = task_queue::lock();
-        usercalls::launch_thread()?;
+        unsafe { usercalls::launch_thread()? };
         let (task, handle) = task_queue::Task::new(p);
         queue_lock.push(task);
         Ok(Thread(handle))
diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs
index 7a246542739..0834d2593fc 100644
--- a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs
+++ b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs
@@ -30,31 +30,34 @@ impl<T> UnsafeList<T> {
         unsafe { UnsafeList { head_tail: NonNull::new_unchecked(1 as _), head_tail_entry: None } }
     }
 
+    /// # Safety
     unsafe fn init(&mut self) {
         if self.head_tail_entry.is_none() {
             self.head_tail_entry = Some(UnsafeListEntry::dummy());
-            self.head_tail = NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap());
-            self.head_tail.as_mut().next = self.head_tail;
-            self.head_tail.as_mut().prev = self.head_tail;
+            // SAFETY: `head_tail_entry` must be non-null, which it is because we assign it above.
+            self.head_tail =
+                unsafe { NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap()) };
+            // SAFETY: `self.head_tail` must meet all requirements for a mutable reference.
+            unsafe { self.head_tail.as_mut() }.next = self.head_tail;
+            unsafe { self.head_tail.as_mut() }.prev = self.head_tail;
         }
     }
 
     pub fn is_empty(&self) -> bool {
-        unsafe {
-            if self.head_tail_entry.is_some() {
-                let first = self.head_tail.as_ref().next;
-                if first == self.head_tail {
-                    // ,-------> /---------\ next ---,
-                    // |         |head_tail|         |
-                    // `--- prev \---------/ <-------`
-                    rtassert!(self.head_tail.as_ref().prev == first);
-                    true
-                } else {
-                    false
-                }
-            } else {
+        if self.head_tail_entry.is_some() {
+            let first = unsafe { self.head_tail.as_ref() }.next;
+            if first == self.head_tail {
+                // ,-------> /---------\ next ---,
+                // |         |head_tail|         |
+                // `--- prev \---------/ <-------`
+                // SAFETY: `self.head_tail` must meet all requirements for a reference.
+                unsafe { rtassert!(self.head_tail.as_ref().prev == first) };
                 true
+            } else {
+                false
             }
+        } else {
+            true
         }
     }
 
@@ -67,7 +70,7 @@ impl<T> UnsafeList<T> {
     /// care must be taken in the caller of `push` to ensure unwinding does
     /// not destroy the stack frame containing the entry.
     pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T {
-        self.init();
+        unsafe { self.init() };
 
         // BEFORE:
         //     /---------\ next ---> /---------\
@@ -78,13 +81,15 @@ impl<T> UnsafeList<T> {
         //     /---------\ next ---> /-----\ next ---> /---------\
         // ... |prev_tail|           |entry|           |head_tail| ...
         //     \---------/ <--- prev \-----/ <--- prev \---------/
-        let mut entry = NonNull::new_unchecked(entry);
-        let mut prev_tail = mem::replace(&mut self.head_tail.as_mut().prev, entry);
-        entry.as_mut().prev = prev_tail;
-        entry.as_mut().next = self.head_tail;
-        prev_tail.as_mut().next = entry;
+        let mut entry = unsafe { NonNull::new_unchecked(entry) };
+        let mut prev_tail = mem::replace(&mut unsafe { self.head_tail.as_mut() }.prev, entry);
+        // SAFETY: `entry` must meet all requirements for a mutable reference.
+        unsafe { entry.as_mut() }.prev = prev_tail;
+        unsafe { entry.as_mut() }.next = self.head_tail;
+        // SAFETY: `prev_tail` must meet all requirements for a mutable reference.
+        unsafe { prev_tail.as_mut() }.next = entry;
         // unwrap ok: always `Some` on non-dummy entries
-        (*entry.as_ptr()).value.as_ref().unwrap()
+        unsafe { (*entry.as_ptr()).value.as_ref() }.unwrap()
     }
 
     /// Pops an entry from the front of the list.
@@ -94,7 +99,7 @@ impl<T> UnsafeList<T> {
     /// The caller must make sure to synchronize ending the borrow of the
     /// return value and deallocation of the containing entry.
     pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> {
-        self.init();
+        unsafe { self.init() };
 
         if self.is_empty() {
             None
@@ -108,14 +113,14 @@ impl<T> UnsafeList<T> {
             //     /---------\ next ---> /------\
             // ... |head_tail|           |second| ...
             //     \---------/ <--- prev \------/
-            let mut first = self.head_tail.as_mut().next;
-            let mut second = first.as_mut().next;
-            self.head_tail.as_mut().next = second;
-            second.as_mut().prev = self.head_tail;
-            first.as_mut().next = NonNull::dangling();
-            first.as_mut().prev = NonNull::dangling();
+            let mut first = unsafe { self.head_tail.as_mut() }.next;
+            let mut second = unsafe { first.as_mut() }.next;
+            unsafe { self.head_tail.as_mut() }.next = second;
+            unsafe { second.as_mut() }.prev = self.head_tail;
+            unsafe { first.as_mut() }.next = NonNull::dangling();
+            unsafe { first.as_mut() }.prev = NonNull::dangling();
             // unwrap ok: always `Some` on non-dummy entries
-            Some((*first.as_ptr()).value.as_ref().unwrap())
+            Some(unsafe { (*first.as_ptr()).value.as_ref() }.unwrap())
         }
     }
 
@@ -138,8 +143,9 @@ impl<T> UnsafeList<T> {
         //     \----/ <--- prev \----/
         let mut prev = entry.prev;
         let mut next = entry.next;
-        prev.as_mut().next = next;
-        next.as_mut().prev = prev;
+        // SAFETY: `prev` and `next` must meet all requirements for a mutable reference.entry
+        unsafe { prev.as_mut() }.next = next;
+        unsafe { next.as_mut() }.prev = prev;
         entry.next = NonNull::dangling();
         entry.prev = NonNull::dangling();
     }
diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs
index 1f031ed1959..c653dee17bc 100644
--- a/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs
+++ b/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs
@@ -1,8 +1,10 @@
 use super::*;
 use crate::cell::Cell;
 
+/// # Safety
+/// List must be valid.
 unsafe fn assert_empty<T>(list: &mut UnsafeList<T>) {
-    assert!(list.pop().is_none(), "assertion failed: list is not empty");
+    assert!(unsafe { list.pop() }.is_none(), "assertion failed: list is not empty");
 }
 
 #[test]
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 566ac0920dc..8184c25afcf 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -183,9 +183,14 @@ struct InnerReadDir {
     root: PathBuf,
 }
 
-#[derive(Clone)]
 pub struct ReadDir {
     inner: Arc<InnerReadDir>,
+    #[cfg(not(any(
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "fuchsia",
+        target_os = "redox",
+    )))]
     end_of_stream: bool,
 }
 
@@ -196,7 +201,7 @@ unsafe impl Sync for Dir {}
 
 pub struct DirEntry {
     entry: dirent64,
-    dir: ReadDir,
+    dir: Arc<InnerReadDir>,
     // We need to store an owned copy of the entry name
     // on Solaris and Fuchsia because a) it uses a zero-length
     // array to store the name, b) its lifetime between readdir
@@ -443,7 +448,7 @@ impl Iterator for ReadDir {
                     name: slice::from_raw_parts(name as *const u8, namelen as usize)
                         .to_owned()
                         .into_boxed_slice(),
-                    dir: self.clone(),
+                    dir: Arc::clone(&self.inner),
                 };
                 if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
                     return Some(Ok(ret));
@@ -464,7 +469,7 @@ impl Iterator for ReadDir {
         }
 
         unsafe {
-            let mut ret = DirEntry { entry: mem::zeroed(), dir: self.clone() };
+            let mut ret = DirEntry { entry: mem::zeroed(), dir: Arc::clone(&self.inner) };
             let mut entry_ptr = ptr::null_mut();
             loop {
                 if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
@@ -497,7 +502,7 @@ impl Drop for Dir {
 
 impl DirEntry {
     pub fn path(&self) -> PathBuf {
-        self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes()))
+        self.dir.root.join(OsStr::from_bytes(self.name_bytes()))
     }
 
     pub fn file_name(&self) -> OsString {
@@ -506,7 +511,7 @@ impl DirEntry {
 
     #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
     pub fn metadata(&self) -> io::Result<FileAttr> {
-        let fd = cvt(unsafe { dirfd(self.dir.inner.dirp.0) })?;
+        let fd = cvt(unsafe { dirfd(self.dir.dirp.0) })?;
         let name = self.entry.d_name.as_ptr();
 
         cfg_has_statx! {
@@ -944,7 +949,16 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
             Err(Error::last_os_error())
         } else {
             let inner = InnerReadDir { dirp: Dir(ptr), root };
-            Ok(ReadDir { inner: Arc::new(inner), end_of_stream: false })
+            Ok(ReadDir {
+                inner: Arc::new(inner),
+                #[cfg(not(any(
+                    target_os = "solaris",
+                    target_os = "illumos",
+                    target_os = "fuchsia",
+                    target_os = "redox",
+                )))]
+                end_of_stream: false,
+            })
         }
     }
 }
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index c9f9ed01e12..2392238d0a1 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -470,7 +470,7 @@ pub unsafe fn environ() -> *mut *const *const c_char {
     &mut environ
 }
 
-pub unsafe fn env_lock() -> StaticMutexGuard<'static> {
+pub unsafe fn env_lock() -> StaticMutexGuard {
     // It is UB to attempt to acquire this mutex reentrantly!
     static ENV_LOCK: StaticMutex = StaticMutex::new();
     ENV_LOCK.lock()
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index eb600d2465c..5e55f97705d 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -319,9 +319,9 @@ impl Command {
 
         let mut p = Process { pid: 0, status: None };
 
-        struct PosixSpawnFileActions(MaybeUninit<libc::posix_spawn_file_actions_t>);
+        struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit<libc::posix_spawn_file_actions_t>);
 
-        impl Drop for PosixSpawnFileActions {
+        impl Drop for PosixSpawnFileActions<'_> {
             fn drop(&mut self) {
                 unsafe {
                     libc::posix_spawn_file_actions_destroy(self.0.as_mut_ptr());
@@ -329,9 +329,9 @@ impl Command {
             }
         }
 
-        struct PosixSpawnattr(MaybeUninit<libc::posix_spawnattr_t>);
+        struct PosixSpawnattr<'a>(&'a mut MaybeUninit<libc::posix_spawnattr_t>);
 
-        impl Drop for PosixSpawnattr {
+        impl Drop for PosixSpawnattr<'_> {
             fn drop(&mut self) {
                 unsafe {
                     libc::posix_spawnattr_destroy(self.0.as_mut_ptr());
@@ -339,59 +339,65 @@ impl Command {
             }
         }
 
+        fn cvt_nz(error: libc::c_int) -> io::Result<()> {
+            if error == 0 { Ok(()) } else { Err(io::Error::from_raw_os_error(error)) }
+        }
+
         unsafe {
-            let mut file_actions = PosixSpawnFileActions(MaybeUninit::uninit());
-            let mut attrs = PosixSpawnattr(MaybeUninit::uninit());
+            let mut attrs = MaybeUninit::uninit();
+            cvt_nz(libc::posix_spawnattr_init(attrs.as_mut_ptr()))?;
+            let attrs = PosixSpawnattr(&mut attrs);
 
-            libc::posix_spawnattr_init(attrs.0.as_mut_ptr());
-            libc::posix_spawn_file_actions_init(file_actions.0.as_mut_ptr());
+            let mut file_actions = MaybeUninit::uninit();
+            cvt_nz(libc::posix_spawn_file_actions_init(file_actions.as_mut_ptr()))?;
+            let file_actions = PosixSpawnFileActions(&mut file_actions);
 
             if let Some(fd) = stdio.stdin.fd() {
-                cvt(libc::posix_spawn_file_actions_adddup2(
+                cvt_nz(libc::posix_spawn_file_actions_adddup2(
                     file_actions.0.as_mut_ptr(),
                     fd,
                     libc::STDIN_FILENO,
                 ))?;
             }
             if let Some(fd) = stdio.stdout.fd() {
-                cvt(libc::posix_spawn_file_actions_adddup2(
+                cvt_nz(libc::posix_spawn_file_actions_adddup2(
                     file_actions.0.as_mut_ptr(),
                     fd,
                     libc::STDOUT_FILENO,
                 ))?;
             }
             if let Some(fd) = stdio.stderr.fd() {
-                cvt(libc::posix_spawn_file_actions_adddup2(
+                cvt_nz(libc::posix_spawn_file_actions_adddup2(
                     file_actions.0.as_mut_ptr(),
                     fd,
                     libc::STDERR_FILENO,
                 ))?;
             }
             if let Some((f, cwd)) = addchdir {
-                cvt(f(file_actions.0.as_mut_ptr(), cwd.as_ptr()))?;
+                cvt_nz(f(file_actions.0.as_mut_ptr(), cwd.as_ptr()))?;
             }
 
             let mut set = MaybeUninit::<libc::sigset_t>::uninit();
             cvt(sigemptyset(set.as_mut_ptr()))?;
-            cvt(libc::posix_spawnattr_setsigmask(attrs.0.as_mut_ptr(), set.as_ptr()))?;
+            cvt_nz(libc::posix_spawnattr_setsigmask(attrs.0.as_mut_ptr(), set.as_ptr()))?;
             cvt(sigaddset(set.as_mut_ptr(), libc::SIGPIPE))?;
-            cvt(libc::posix_spawnattr_setsigdefault(attrs.0.as_mut_ptr(), set.as_ptr()))?;
+            cvt_nz(libc::posix_spawnattr_setsigdefault(attrs.0.as_mut_ptr(), set.as_ptr()))?;
 
             let flags = libc::POSIX_SPAWN_SETSIGDEF | libc::POSIX_SPAWN_SETSIGMASK;
-            cvt(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;
+            cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?;
 
             // Make sure we synchronize access to the global `environ` resource
             let _env_lock = sys::os::env_lock();
             let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
-            let ret = libc::posix_spawnp(
+            cvt_nz(libc::posix_spawnp(
                 &mut p.pid,
                 self.get_program_cstr().as_ptr(),
                 file_actions.0.as_ptr(),
                 attrs.0.as_ptr(),
                 self.get_argv().as_ptr() as *const _,
                 envp as *const _,
-            );
-            if ret == 0 { Ok(Some(p)) } else { Err(io::Error::from_raw_os_error(ret)) }
+            ))?;
+            Ok(Some(p))
         }
     }
 }
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index f2a9cb5a0e8..fac4b05ad0b 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -117,8 +117,7 @@ impl Hash for Timespec {
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 mod inner {
     use crate::fmt;
-    use crate::mem;
-    use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+    use crate::sync::atomic::{AtomicU64, Ordering};
     use crate::sys::cvt;
     use crate::sys_common::mul_div_u64;
     use crate::time::Duration;
@@ -233,31 +232,42 @@ mod inner {
     }
 
     fn info() -> mach_timebase_info {
-        static mut INFO: mach_timebase_info = mach_timebase_info { numer: 0, denom: 0 };
-        static STATE: AtomicUsize = AtomicUsize::new(0);
-
-        unsafe {
-            // If a previous thread has filled in this global state, use that.
-            if STATE.load(SeqCst) == 2 {
-                return INFO;
-            }
+        // INFO_BITS conceptually is an `Option<mach_timebase_info>`. We can do
+        // this in 64 bits because we know 0 is never a valid value for the
+        // `denom` field.
+        //
+        // Encoding this as a single `AtomicU64` allows us to use `Relaxed`
+        // operations, as we are only interested in in the effects on a single
+        // memory location.
+        static INFO_BITS: AtomicU64 = AtomicU64::new(0);
+
+        // If a previous thread has initialized `INFO_BITS`, use it.
+        let info_bits = INFO_BITS.load(Ordering::Relaxed);
+        if info_bits != 0 {
+            return info_from_bits(info_bits);
+        }
 
-            // ... otherwise learn for ourselves ...
-            let mut info = mem::zeroed();
-            extern "C" {
-                fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
-            }
+        // ... otherwise learn for ourselves ...
+        extern "C" {
+            fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t;
+        }
 
+        let mut info = info_from_bits(0);
+        unsafe {
             mach_timebase_info(&mut info);
-
-            // ... and attempt to be the one thread that stores it globally for
-            // all other threads
-            if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() {
-                INFO = info;
-                STATE.store(2, SeqCst);
-            }
-            return info;
         }
+        INFO_BITS.store(info_to_bits(info), Ordering::Relaxed);
+        info
+    }
+
+    #[inline]
+    fn info_to_bits(info: mach_timebase_info) -> u64 {
+        ((info.denom as u64) << 32) | (info.numer as u64)
+    }
+
+    #[inline]
+    fn info_from_bits(bits: u64) -> mach_timebase_info {
+        mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 }
     }
 }
 
diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs
index 80311d26819..2cdd9c4d19e 100644
--- a/library/std/src/sys/unsupported/common.rs
+++ b/library/std/src/sys/unsupported/common.rs
@@ -39,10 +39,13 @@ pub fn hashmap_random_keys() -> (u64, u64) {
 pub enum Void {}
 
 pub unsafe fn strlen(mut s: *const c_char) -> usize {
-    let mut n = 0;
-    while *s != 0 {
-        n += 1;
-        s = s.offset(1);
+    // SAFETY: The caller must guarantee `s` points to a valid 0-terminated string.
+    unsafe {
+        let mut n = 0;
+        while *s != 0 {
+            n += 1;
+            s = s.offset(1);
+        }
+        n
     }
-    return n;
 }
diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs
index 8ba870c5dbc..d9efdec33d9 100644
--- a/library/std/src/sys/unsupported/mod.rs
+++ b/library/std/src/sys/unsupported/mod.rs
@@ -1,3 +1,5 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+
 pub mod alloc;
 pub mod args;
 pub mod cmath;
diff --git a/library/std/src/sys/unsupported/mutex.rs b/library/std/src/sys/unsupported/mutex.rs
index 06ea9a1e2c1..b3203c16c50 100644
--- a/library/std/src/sys/unsupported/mutex.rs
+++ b/library/std/src/sys/unsupported/mutex.rs
@@ -1,7 +1,8 @@
-use crate::cell::UnsafeCell;
+use crate::cell::Cell;
 
 pub struct Mutex {
-    locked: UnsafeCell<bool>,
+    // This platform has no threads, so we can use a Cell here.
+    locked: Cell<bool>,
 }
 
 pub type MovableMutex = Mutex;
@@ -10,9 +11,8 @@ unsafe impl Send for Mutex {}
 unsafe impl Sync for Mutex {} // no threads on this platform
 
 impl Mutex {
-    #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
     pub const fn new() -> Mutex {
-        Mutex { locked: UnsafeCell::new(false) }
+        Mutex { locked: Cell::new(false) }
     }
 
     #[inline]
@@ -20,25 +20,17 @@ impl Mutex {
 
     #[inline]
     pub unsafe fn lock(&self) {
-        let locked = self.locked.get();
-        assert!(!*locked, "cannot recursively acquire mutex");
-        *locked = true;
+        assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex");
     }
 
     #[inline]
     pub unsafe fn unlock(&self) {
-        *self.locked.get() = false;
+        self.locked.set(false);
     }
 
     #[inline]
     pub unsafe fn try_lock(&self) -> bool {
-        let locked = self.locked.get();
-        if *locked {
-            false
-        } else {
-            *locked = true;
-            true
-        }
+        self.locked.replace(true) == false
     }
 
     #[inline]
diff --git a/library/std/src/sys/unsupported/rwlock.rs b/library/std/src/sys/unsupported/rwlock.rs
index d37f34ac935..6982b2b155f 100644
--- a/library/std/src/sys/unsupported/rwlock.rs
+++ b/library/std/src/sys/unsupported/rwlock.rs
@@ -1,7 +1,8 @@
-use crate::cell::UnsafeCell;
+use crate::cell::Cell;
 
 pub struct RWLock {
-    mode: UnsafeCell<isize>,
+    // This platform has no threads, so we can use a Cell here.
+    mode: Cell<isize>,
 }
 
 unsafe impl Send for RWLock {}
@@ -9,14 +10,14 @@ unsafe impl Sync for RWLock {} // no threads on this platform
 
 impl RWLock {
     pub const fn new() -> RWLock {
-        RWLock { mode: UnsafeCell::new(0) }
+        RWLock { mode: Cell::new(0) }
     }
 
     #[inline]
     pub unsafe fn read(&self) {
-        let mode = self.mode.get();
-        if *mode >= 0 {
-            *mode += 1;
+        let m = self.mode.get();
+        if m >= 0 {
+            self.mode.set(m + 1);
         } else {
             rtabort!("rwlock locked for writing");
         }
@@ -24,9 +25,9 @@ impl RWLock {
 
     #[inline]
     pub unsafe fn try_read(&self) -> bool {
-        let mode = self.mode.get();
-        if *mode >= 0 {
-            *mode += 1;
+        let m = self.mode.get();
+        if m >= 0 {
+            self.mode.set(m + 1);
             true
         } else {
             false
@@ -35,19 +36,15 @@ impl RWLock {
 
     #[inline]
     pub unsafe fn write(&self) {
-        let mode = self.mode.get();
-        if *mode == 0 {
-            *mode = -1;
-        } else {
+        if self.mode.replace(-1) != 0 {
             rtabort!("rwlock locked for reading")
         }
     }
 
     #[inline]
     pub unsafe fn try_write(&self) -> bool {
-        let mode = self.mode.get();
-        if *mode == 0 {
-            *mode = -1;
+        if self.mode.get() == 0 {
+            self.mode.set(-1);
             true
         } else {
             false
@@ -56,12 +53,12 @@ impl RWLock {
 
     #[inline]
     pub unsafe fn read_unlock(&self) {
-        *self.mode.get() -= 1;
+        self.mode.set(self.mode.get() - 1);
     }
 
     #[inline]
     pub unsafe fn write_unlock(&self) {
-        *self.mode.get() += 1;
+        assert_eq!(self.mode.replace(0), -1);
     }
 
     #[inline]
diff --git a/library/std/src/sys/vxworks/fs.rs b/library/std/src/sys/vxworks/fs.rs
index 557e65ca01b..cb761af1a25 100644
--- a/library/std/src/sys/vxworks/fs.rs
+++ b/library/std/src/sys/vxworks/fs.rs
@@ -27,7 +27,6 @@ struct InnerReadDir {
     root: PathBuf,
 }
 
-#[derive(Clone)]
 pub struct ReadDir {
     inner: Arc<InnerReadDir>,
     end_of_stream: bool,
@@ -40,7 +39,7 @@ unsafe impl Sync for Dir {}
 
 pub struct DirEntry {
     entry: dirent,
-    dir: ReadDir,
+    dir: Arc<InnerReadDir>,
 }
 
 #[derive(Clone, Debug)]
@@ -170,7 +169,7 @@ impl Iterator for ReadDir {
         }
 
         unsafe {
-            let mut ret = DirEntry { entry: mem::zeroed(), dir: self.clone() };
+            let mut ret = DirEntry { entry: mem::zeroed(), dir: Arc::clone(&self.inner) };
             let mut entry_ptr = ptr::null_mut();
             loop {
                 if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
@@ -204,7 +203,7 @@ impl Drop for Dir {
 impl DirEntry {
     pub fn path(&self) -> PathBuf {
         use crate::sys::vxworks::ext::ffi::OsStrExt;
-        self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes()))
+        self.dir.root.join(OsStr::from_bytes(self.name_bytes()))
     }
 
     pub fn file_name(&self) -> OsString {
diff --git a/library/std/src/sys/vxworks/os.rs b/library/std/src/sys/vxworks/os.rs
index 08394a8d29d..6eaec6f1e50 100644
--- a/library/std/src/sys/vxworks/os.rs
+++ b/library/std/src/sys/vxworks/os.rs
@@ -212,7 +212,7 @@ pub unsafe fn environ() -> *mut *const *const c_char {
     &mut environ
 }
 
-pub unsafe fn env_lock() -> StaticMutexGuard<'static> {
+pub unsafe fn env_lock() -> StaticMutexGuard {
     // It is UB to attempt to acquire this mutex reentrantly!
     static ENV_LOCK: StaticMutex = StaticMutex::new();
     ENV_LOCK.lock()
diff --git a/library/std/src/sys/wasi/ext/io.rs b/library/std/src/sys/wasi/ext/io.rs
index 661214e8f4c..81413f39dc1 100644
--- a/library/std/src/sys/wasi/ext/io.rs
+++ b/library/std/src/sys/wasi/ext/io.rs
@@ -160,3 +160,21 @@ impl AsRawFd for io::Stderr {
         sys::stdio::Stderr.as_raw_fd()
     }
 }
+
+impl<'a> AsRawFd for io::StdinLock<'a> {
+    fn as_raw_fd(&self) -> RawFd {
+        sys::stdio::Stdin.as_raw_fd()
+    }
+}
+
+impl<'a> AsRawFd for io::StdoutLock<'a> {
+    fn as_raw_fd(&self) -> RawFd {
+        sys::stdio::Stdout.as_raw_fd()
+    }
+}
+
+impl<'a> AsRawFd for io::StderrLock<'a> {
+    fn as_raw_fd(&self) -> RawFd {
+        sys::stdio::Stderr.as_raw_fd()
+    }
+}
diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs
index a7a4407ac38..a0a37ef8316 100644
--- a/library/std/src/sys/wasi/mod.rs
+++ b/library/std/src/sys/wasi/mod.rs
@@ -53,6 +53,7 @@ pub mod thread_local_key;
 pub mod time;
 
 #[path = "../unsupported/common.rs"]
+#[deny(unsafe_op_in_unsafe_fn)]
 #[allow(unused)]
 mod common;
 pub use common::*;
diff --git a/library/std/src/sys/wasm/futex_atomics.rs b/library/std/src/sys/wasm/futex_atomics.rs
new file mode 100644
index 00000000000..3d8bf42f725
--- /dev/null
+++ b/library/std/src/sys/wasm/futex_atomics.rs
@@ -0,0 +1,17 @@
+use crate::arch::wasm32;
+use crate::convert::TryInto;
+use crate::sync::atomic::AtomicI32;
+use crate::time::Duration;
+
+pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) {
+    let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1);
+    unsafe {
+        wasm32::memory_atomic_wait32(futex as *const AtomicI32 as *mut i32, expected, timeout);
+    }
+}
+
+pub fn futex_wake(futex: &AtomicI32) {
+    unsafe {
+        wasm32::memory_atomic_notify(futex as *const AtomicI32 as *mut i32, 1);
+    }
+}
diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs
index 2934ea59ab5..11c6896f050 100644
--- a/library/std/src/sys/wasm/mod.rs
+++ b/library/std/src/sys/wasm/mod.rs
@@ -55,6 +55,8 @@ cfg_if::cfg_if! {
         pub mod mutex;
         #[path = "rwlock_atomics.rs"]
         pub mod rwlock;
+        #[path = "futex_atomics.rs"]
+        pub mod futex;
     } else {
         #[path = "../unsupported/condvar.rs"]
         pub mod condvar;
@@ -66,5 +68,6 @@ cfg_if::cfg_if! {
 }
 
 #[path = "../unsupported/common.rs"]
+#[deny(unsafe_op_in_unsafe_fn)]
 mod common;
 pub use common::*;
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 559c4dc9c7c..657421e3fa4 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -47,7 +47,6 @@ pub type LPWCH = *mut WCHAR;
 pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
 pub type LPWSADATA = *mut WSADATA;
 pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
-pub type LPSTR = *mut CHAR;
 pub type LPWSTR = *mut WCHAR;
 pub type LPFILETIME = *mut FILETIME;
 pub type LPWSABUF = *mut WSABUF;
@@ -876,16 +875,6 @@ extern "system" {
     pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
     pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD;
     pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
-    pub fn WideCharToMultiByte(
-        CodePage: UINT,
-        dwFlags: DWORD,
-        lpWideCharStr: LPCWSTR,
-        cchWideChar: c_int,
-        lpMultiByteStr: LPSTR,
-        cbMultiByte: c_int,
-        lpDefaultChar: LPCSTR,
-        lpUsedDefaultChar: LPBOOL,
-    ) -> c_int;
 
     pub fn closesocket(socket: SOCKET) -> c_int;
     pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int;
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index 8178e6806b9..8c19cc78b09 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -4,7 +4,6 @@ use crate::ffi::{OsStr, OsString};
 use crate::io::ErrorKind;
 use crate::os::windows::ffi::{OsStrExt, OsStringExt};
 use crate::path::PathBuf;
-use crate::ptr;
 use crate::time::Duration;
 
 pub use self::rand::hashmap_random_keys;
@@ -206,58 +205,6 @@ fn os2path(s: &[u16]) -> PathBuf {
     PathBuf::from(OsString::from_wide(s))
 }
 
-#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename()
-fn wide_char_to_multi_byte(
-    code_page: u32,
-    flags: u32,
-    s: &[u16],
-    no_default_char: bool,
-) -> crate::io::Result<Vec<i8>> {
-    unsafe {
-        let mut size = c::WideCharToMultiByte(
-            code_page,
-            flags,
-            s.as_ptr(),
-            s.len() as i32,
-            ptr::null_mut(),
-            0,
-            ptr::null(),
-            ptr::null_mut(),
-        );
-        if size == 0 {
-            return Err(crate::io::Error::last_os_error());
-        }
-
-        let mut buf = Vec::with_capacity(size as usize);
-        buf.set_len(size as usize);
-
-        let mut used_default_char = c::FALSE;
-        size = c::WideCharToMultiByte(
-            code_page,
-            flags,
-            s.as_ptr(),
-            s.len() as i32,
-            buf.as_mut_ptr(),
-            buf.len() as i32,
-            ptr::null(),
-            if no_default_char { &mut used_default_char } else { ptr::null_mut() },
-        );
-        if size == 0 {
-            return Err(crate::io::Error::last_os_error());
-        }
-        if no_default_char && used_default_char == c::TRUE {
-            return Err(crate::io::Error::new(
-                crate::io::ErrorKind::InvalidData,
-                "string cannot be converted to requested code page",
-            ));
-        }
-
-        buf.set_len(size as usize);
-
-        Ok(buf)
-    }
-}
-
 pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
     match unrolled_find_u16s(0, v) {
         // don't include the 0
diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs
index 900260169c7..91e4f765484 100644
--- a/library/std/src/sys/windows/time.rs
+++ b/library/std/src/sys/windows/time.rs
@@ -165,7 +165,7 @@ fn intervals2dur(intervals: u64) -> Duration {
 
 mod perf_counter {
     use super::NANOS_PER_SEC;
-    use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
+    use crate::sync::atomic::{AtomicU64, Ordering};
     use crate::sys::c;
     use crate::sys::cvt;
     use crate::sys_common::mul_div_u64;
@@ -197,27 +197,25 @@ mod perf_counter {
     }
 
     fn frequency() -> c::LARGE_INTEGER {
-        static mut FREQUENCY: c::LARGE_INTEGER = 0;
-        static STATE: AtomicUsize = AtomicUsize::new(0);
-
+        // Either the cached result of `QueryPerformanceFrequency` or `0` for
+        // uninitialized. Storing this as a single `AtomicU64` allows us to use
+        // `Relaxed` operations, as we are only interested in the effects on a
+        // single memory location.
+        static FREQUENCY: AtomicU64 = AtomicU64::new(0);
+
+        let cached = FREQUENCY.load(Ordering::Relaxed);
+        // If a previous thread has filled in this global state, use that.
+        if cached != 0 {
+            return cached as c::LARGE_INTEGER;
+        }
+        // ... otherwise learn for ourselves ...
+        let mut frequency = 0;
         unsafe {
-            // If a previous thread has filled in this global state, use that.
-            if STATE.load(SeqCst) == 2 {
-                return FREQUENCY;
-            }
-
-            // ... otherwise learn for ourselves ...
-            let mut frequency = 0;
             cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap();
-
-            // ... and attempt to be the one thread that stores it globally for
-            // all other threads
-            if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() {
-                FREQUENCY = frequency;
-                STATE.store(2, SeqCst);
-            }
-            frequency
         }
+
+        FREQUENCY.store(frequency as u64, Ordering::Relaxed);
+        frequency
     }
 
     fn query() -> c::LARGE_INTEGER {
diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs
index 1c5fbf7d701..a549770d8b3 100644
--- a/library/std/src/sys_common/backtrace.rs
+++ b/library/std/src/sys_common/backtrace.rs
@@ -8,27 +8,15 @@ use crate::io;
 use crate::io::prelude::*;
 use crate::path::{self, Path, PathBuf};
 use crate::sync::atomic::{self, Ordering};
-use crate::sys::mutex::Mutex;
+use crate::sys_common::mutex::StaticMutex;
 
 /// Max number of frames to print.
 const MAX_NB_FRAMES: usize = 100;
 
-pub fn lock() -> impl Drop {
-    struct Guard;
-    static LOCK: Mutex = Mutex::new();
-
-    impl Drop for Guard {
-        fn drop(&mut self) {
-            unsafe {
-                LOCK.unlock();
-            }
-        }
-    }
-
-    unsafe {
-        LOCK.lock();
-        Guard
-    }
+// SAFETY: Don't attempt to lock this reentrantly.
+pub unsafe fn lock() -> impl Drop {
+    static LOCK: StaticMutex = StaticMutex::new();
+    LOCK.lock()
 }
 
 /// Prints the current backtrace.
diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs
index a1e11d24465..f3e7efb955a 100644
--- a/library/std/src/sys_common/mutex.rs
+++ b/library/std/src/sys_common/mutex.rs
@@ -3,8 +3,7 @@ use crate::sys::mutex as imp;
 /// An OS-based mutual exclusion lock, meant for use in static variables.
 ///
 /// This mutex has a const constructor ([`StaticMutex::new`]), does not
-/// implement `Drop` to cleanup resources, and causes UB when moved or used
-/// reentrantly.
+/// implement `Drop` to cleanup resources, and causes UB when used reentrantly.
 ///
 /// This mutex does not implement poisoning.
 ///
@@ -16,12 +15,6 @@ unsafe impl Sync for StaticMutex {}
 
 impl StaticMutex {
     /// Creates a new mutex for use.
-    ///
-    /// Behavior is undefined if the mutex is moved after it is
-    /// first used with any of the functions below.
-    /// Also, the behavior is undefined if this mutex is ever used reentrantly,
-    /// i.e., `lock` is called by the thread currently holding the lock.
-    #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
     pub const fn new() -> Self {
         Self(imp::Mutex::new())
     }
@@ -29,19 +22,19 @@ impl StaticMutex {
     /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
     /// will be unlocked.
     ///
-    /// It is undefined behaviour to call this function while locked, or if the
-    /// mutex has been moved since the last time this was called.
+    /// It is undefined behaviour to call this function while locked by the
+    /// same thread.
     #[inline]
-    pub unsafe fn lock(&self) -> StaticMutexGuard<'_> {
+    pub unsafe fn lock(&'static self) -> StaticMutexGuard {
         self.0.lock();
         StaticMutexGuard(&self.0)
     }
 }
 
 #[must_use]
-pub struct StaticMutexGuard<'a>(&'a imp::Mutex);
+pub struct StaticMutexGuard(&'static imp::Mutex);
 
-impl Drop for StaticMutexGuard<'_> {
+impl Drop for StaticMutexGuard {
     #[inline]
     fn drop(&mut self) {
         unsafe {
diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs
index 23c17c8e2cf..5e75ac65de4 100644
--- a/library/std/src/sys_common/thread_parker/mod.rs
+++ b/library/std/src/sys_common/thread_parker/mod.rs
@@ -1,5 +1,9 @@
 cfg_if::cfg_if! {
-    if #[cfg(any(target_os = "linux", target_os = "android"))] {
+    if #[cfg(any(
+        target_os = "linux",
+        target_os = "android",
+        all(target_arch = "wasm32", target_feature = "atomics"),
+    ))] {
         mod futex;
         pub use futex::Parker;
     } else {
diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs
index 9ebc991d638..41e7e6adcf1 100644
--- a/library/test/src/formatters/json.rs
+++ b/library/test/src/formatters/json.rs
@@ -182,8 +182,8 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> {
 /// Base code taken form `libserialize::json::escape_str`
 struct EscapedString<S: AsRef<str>>(S);
 
-impl<S: AsRef<str>> ::std::fmt::Display for EscapedString<S> {
-    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+impl<S: AsRef<str>> std::fmt::Display for EscapedString<S> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> ::std::fmt::Result {
         let mut start = 0;
 
         for (i, byte) in self.0.as_ref().bytes().enumerate() {
diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs
index 806df572cf9..ff1d82fc990 100644
--- a/library/unwind/src/libunwind.rs
+++ b/library/unwind/src/libunwind.rs
@@ -89,7 +89,7 @@ extern "C" {
 }
 
 cfg_if::cfg_if! {
-if #[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm"))))] {
+if #[cfg(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")))] {
     // Not ARM EHABI
     #[repr(C)]
     #[derive(Copy, Clone, PartialEq)]
diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md
index 7c12642da35..7bb4e504275 100644
--- a/src/bootstrap/CHANGELOG.md
+++ b/src/bootstrap/CHANGELOG.md
@@ -19,13 +19,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 
 - Add `x.py setup` [#76631](https://github.com/rust-lang/rust/pull/76631)
 - Add a changelog for x.py [#76626](https://github.com/rust-lang/rust/pull/76626)
-- Optionally, download LLVM from CI on Linux and NixOS
+- Optionally, download LLVM from CI on Linux and NixOS. This can be enabled with `download-ci-llvm = true` under `[llvm]`.
   + [#76439](https://github.com/rust-lang/rust/pull/76349)
   + [#76667](https://github.com/rust-lang/rust/pull/76667)
   + [#76708](https://github.com/rust-lang/rust/pull/76708)
 - Distribute rustc sources as part of `rustc-dev` [#76856](https://github.com/rust-lang/rust/pull/76856)
-- Make the default stage for x.py configurable [#76625](https://github.com/rust-lang/rust/pull/76625)
-- Add a dedicated debug-logging option [#76588](https://github.com/rust-lang/rust/pull/76588)
+- Make the default stage for x.py configurable [#76625](https://github.com/rust-lang/rust/pull/76625). This can be enabled with `build-stage = N`, `doc-stage = N`, etc.
+- Add a dedicated debug-logging option [#76588](https://github.com/rust-lang/rust/pull/76588). Previously, `debug-logging` could only be set with `debug-assertions`, slowing down the compiler more than necessary.
 - Add sample defaults for x.py [#76628](https://github.com/rust-lang/rust/pull/76628)
 - Add `--keep-stage-std`, which behaves like `keep-stage` but allows the stage
   0 compiler artifacts (i.e., stage1/bin/rustc) to be rebuilt if changed
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index bc8bae14b21..84ed9446ae7 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -93,12 +93,12 @@ handled naturally. `./configure` should almost never be used for local
 installations, and is primarily useful for CI. Prefer to customize behavior
 using `config.toml`.
 
-Finally, rustbuild makes use of the [gcc-rs crate] which has [its own
+Finally, rustbuild makes use of the [cc-rs crate] which has [its own
 method][env-vars] of configuring C compilers and C flags via environment
 variables.
 
-[gcc-rs crate]: https://github.com/alexcrichton/gcc-rs
-[env-vars]: https://github.com/alexcrichton/gcc-rs#external-configuration-via-environment-variables
+[cc-rs crate]: https://github.com/alexcrichton/cc-rs
+[env-vars]: https://github.com/alexcrichton/cc-rs#external-configuration-via-environment-variables
 
 ## Build stages
 
diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs
index d31f95ee5e9..07e582d4d29 100644
--- a/src/bootstrap/bin/main.rs
+++ b/src/bootstrap/bin/main.rs
@@ -7,13 +7,15 @@
 
 use std::env;
 
-use bootstrap::{Build, Config, Subcommand};
+use bootstrap::{Build, Config, Subcommand, VERSION};
 
 fn main() {
     let args = env::args().skip(1).collect::<Vec<_>>();
     let config = Config::parse(&args);
 
-    let changelog_suggestion = check_version(&config);
+    // check_version warnings are not printed during setup
+    let changelog_suggestion =
+        if matches!(config.cmd, Subcommand::Setup {..}) { None } else { check_version(&config) };
 
     // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the
     // changelog warning, not the `x.py setup` message.
@@ -40,8 +42,6 @@ fn main() {
 }
 
 fn check_version(config: &Config) -> Option<String> {
-    const VERSION: usize = 2;
-
     let mut msg = String::new();
 
     let suggestion = if let Some(seen) = config.changelog_seen {
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 5c9184f4506..ce37adeb28c 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -447,7 +447,8 @@ class RustBuild(object):
 
     def downloading_llvm(self):
         opt = self.get_toml('download-ci-llvm', 'llvm')
-        return opt == "true"
+        return opt == "true" \
+            or (opt == "if-available" and self.build == "x86_64-unknown-linux-gnu")
 
     def _download_stage0_helper(self, filename, pattern, tarball_suffix, date=None):
         if date is None:
@@ -892,7 +893,7 @@ class RustBuild(object):
         submodules_names = []
         for module in submodules:
             if module.endswith("llvm-project"):
-                if self.get_toml('llvm-config') or self.get_toml('download-ci-llvm') == 'true':
+                if self.get_toml('llvm-config') or self.downloading_llvm():
                     if self.get_toml('lld') != 'true':
                         continue
             check = self.check_submodule(module, slow_submodules)
@@ -1003,6 +1004,16 @@ def bootstrap(help_triggered):
         with open(toml_path) as config:
             build.config_toml = config.read()
 
+    profile = build.get_toml('profile')
+    if profile is not None:
+        include_file = 'config.{}.toml'.format(profile)
+        include_dir = os.path.join(build.rust_root, 'src', 'bootstrap', 'defaults')
+        include_path = os.path.join(include_dir, include_file)
+        # HACK: This works because `build.get_toml()` returns the first match it finds for a
+        # specific key, so appending our defaults at the end allows the user to override them
+        with open(include_path) as included_toml:
+            build.config_toml += os.linesep + included_toml.read()
+
     config_verbose = build.get_toml('verbose', 'build')
     if config_verbose is not None:
         build.verbose = max(build.verbose, int(config_verbose))
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 4bc162abee6..707c1ff3efa 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -193,37 +193,37 @@ impl StepDescription {
             );
         }
 
-        if paths.is_empty() {
-            for (desc, should_run) in v.iter().zip(should_runs) {
+        if paths.is_empty() || builder.config.include_default_paths {
+            for (desc, should_run) in v.iter().zip(&should_runs) {
                 if desc.default && should_run.is_really_default {
                     for pathset in &should_run.paths {
                         desc.maybe_run(builder, pathset);
                     }
                 }
             }
-        } else {
-            for path in paths {
-                // strip CurDir prefix if present
-                let path = match path.strip_prefix(".") {
-                    Ok(p) => p,
-                    Err(_) => path,
-                };
+        }
 
-                let mut attempted_run = false;
-                for (desc, should_run) in v.iter().zip(&should_runs) {
-                    if let Some(suite) = should_run.is_suite_path(path) {
-                        attempted_run = true;
-                        desc.maybe_run(builder, suite);
-                    } else if let Some(pathset) = should_run.pathset_for_path(path) {
-                        attempted_run = true;
-                        desc.maybe_run(builder, pathset);
-                    }
-                }
+        for path in paths {
+            // strip CurDir prefix if present
+            let path = match path.strip_prefix(".") {
+                Ok(p) => p,
+                Err(_) => path,
+            };
 
-                if !attempted_run {
-                    panic!("error: no rules matched {}", path.display());
+            let mut attempted_run = false;
+            for (desc, should_run) in v.iter().zip(&should_runs) {
+                if let Some(suite) = should_run.is_suite_path(path) {
+                    attempted_run = true;
+                    desc.maybe_run(builder, suite);
+                } else if let Some(pathset) = should_run.pathset_for_path(path) {
+                    attempted_run = true;
+                    desc.maybe_run(builder, pathset);
                 }
             }
+
+            if !attempted_run {
+                panic!("error: no rules matched {}", path.display());
+            }
         }
     }
 }
@@ -462,6 +462,7 @@ impl<'a> Builder<'a> {
                 dist::LlvmTools,
                 dist::RustDev,
                 dist::Extended,
+                dist::BuildManifest,
                 dist::HashSign
             ),
             Kind::Install => describe!(
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 40bf6c48296..5215ab3dd4f 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -234,14 +234,14 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
         // Note that `libprofiler_builtins/build.rs` also computes this so if
         // you're changing something here please also change that.
         cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root);
-        " compiler-builtins-c".to_string()
+        " compiler-builtins-c"
     } else {
-        String::new()
+        ""
     };
 
     if builder.no_std(target) == Some(true) {
         let mut features = "compiler-builtins-mem".to_string();
-        features.push_str(&compiler_builtins_c_feature);
+        features.push_str(compiler_builtins_c_feature);
 
         // for no-std targets we only compile a few no_std crates
         cargo
@@ -249,10 +249,10 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car
             .arg("--manifest-path")
             .arg(builder.src.join("library/alloc/Cargo.toml"))
             .arg("--features")
-            .arg("compiler-builtins-mem compiler-builtins-c");
+            .arg(features);
     } else {
         let mut features = builder.std_features();
-        features.push_str(&compiler_builtins_c_feature);
+        features.push_str(compiler_builtins_c_feature);
 
         cargo
             .arg("--features")
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 6265bbaf5c2..3c1249f8de4 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -61,6 +61,7 @@ pub struct Config {
     pub profiler: bool,
     pub ignore_git: bool,
     pub exclude: Vec<PathBuf>,
+    pub include_default_paths: bool,
     pub rustc_error_format: Option<String>,
     pub json_output: bool,
     pub test_compare_mode: bool,
@@ -390,7 +391,7 @@ struct Llvm {
     use_libcxx: Option<bool>,
     use_linker: Option<String>,
     allow_old_toolchain: Option<bool>,
-    download_ci_llvm: Option<bool>,
+    download_ci_llvm: Option<StringOrBool>,
 }
 
 #[derive(Deserialize, Default, Clone, Merge)]
@@ -532,6 +533,7 @@ impl Config {
 
         let mut config = Config::default_opts();
         config.exclude = flags.exclude;
+        config.include_default_paths = flags.include_default_paths;
         config.rustc_error_format = flags.rustc_error_format;
         config.json_output = flags.json_output;
         config.on_fail = flags.on_fail;
@@ -733,7 +735,14 @@ 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_from_ci = llvm.download_ci_llvm.unwrap_or(false);
+            config.llvm_from_ci = match llvm.download_ci_llvm {
+                Some(StringOrBool::String(s)) => {
+                    assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
+                    config.build.triple == "x86_64-unknown-linux-gnu"
+                }
+                Some(StringOrBool::Bool(b)) => b,
+                None => false,
+            };
 
             if config.llvm_from_ci {
                 // None of the LLVM options, except assertions, are supported
diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml
index 4772de8a2cb..0ca928843d5 100644
--- a/src/bootstrap/defaults/config.compiler.toml
+++ b/src/bootstrap/defaults/config.compiler.toml
@@ -6,3 +6,8 @@
 debug-logging = true
 # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
 incremental = true
+
+[llvm]
+# Will download LLVM from CI if available on your platform (Linux only for now)
+# https://github.com/rust-lang/rust/issues/77084 tracks support for more platforms
+download-ci-llvm = "if-available"
diff --git a/src/bootstrap/defaults/config.library.toml b/src/bootstrap/defaults/config.library.toml
index e4316f4d864..9874fdb767f 100644
--- a/src/bootstrap/defaults/config.library.toml
+++ b/src/bootstrap/defaults/config.library.toml
@@ -8,3 +8,8 @@ bench-stage = 0
 [rust]
 # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
 incremental = true
+
+[llvm]
+# Will download LLVM from CI if available on your platform (Linux only for now)
+# https://github.com/rust-lang/rust/issues/77084 tracks support for more platforms
+download-ci-llvm = "if-available"
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 857e06d846d..1887b805da1 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -26,24 +26,7 @@ use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
 use time::{self, Timespec};
 
 pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
-    if component == "cargo" {
-        format!("{}-{}", component, builder.cargo_package_vers())
-    } else if component == "rls" {
-        format!("{}-{}", component, builder.rls_package_vers())
-    } else if component == "rust-analyzer" {
-        format!("{}-{}", component, builder.rust_analyzer_package_vers())
-    } else if component == "clippy" {
-        format!("{}-{}", component, builder.clippy_package_vers())
-    } else if component == "miri" {
-        format!("{}-{}", component, builder.miri_package_vers())
-    } else if component == "rustfmt" {
-        format!("{}-{}", component, builder.rustfmt_package_vers())
-    } else if component == "llvm-tools" {
-        format!("{}-{}", component, builder.llvm_tools_package_vers())
-    } else {
-        assert!(component.starts_with("rust"));
-        format!("{}-{}", component, builder.rust_package_vers())
-    }
+    format!("{}-{}", component, builder.rust_package_vers())
 }
 
 pub(crate) fn distdir(builder: &Builder<'_>) -> PathBuf {
@@ -2370,7 +2353,6 @@ impl Step for HashSign {
         cmd.arg(today.trim());
         cmd.arg(addr);
         cmd.arg(&builder.config.channel);
-        cmd.arg(&builder.src);
         cmd.env("BUILD_MANIFEST_LEGACY", "1");
 
         builder.create_dir(&distdir(builder));
@@ -2601,3 +2583,70 @@ impl Step for RustDev {
         Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
     }
 }
+
+/// Tarball containing a prebuilt version of the build-manifest tool, intented to be used by the
+/// release process to avoid cloning the monorepo and building stuff.
+///
+/// Should not be considered stable by end users.
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+pub struct BuildManifest {
+    pub target: TargetSelection,
+}
+
+impl Step for BuildManifest {
+    type Output = PathBuf;
+    const DEFAULT: bool = false;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/build-manifest")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(BuildManifest { target: run.target });
+    }
+
+    fn run(self, builder: &Builder<'_>) -> PathBuf {
+        let build_manifest = builder.tool_exe(Tool::BuildManifest);
+
+        let name = pkgname(builder, "build-manifest");
+        let tmp = tmpdir(builder);
+
+        // Prepare the image.
+        let image = tmp.join("build-manifest-image");
+        let image_bin = image.join("bin");
+        let _ = fs::remove_dir_all(&image);
+        t!(fs::create_dir_all(&image_bin));
+        builder.install(&build_manifest, &image_bin, 0o755);
+
+        // Prepare the overlay.
+        let overlay = tmp.join("build-manifest-overlay");
+        let _ = fs::remove_dir_all(&overlay);
+        builder.create_dir(&overlay);
+        builder.create(&overlay.join("version"), &builder.rust_version());
+        for file in &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"] {
+            builder.install(&builder.src.join(file), &overlay, 0o644);
+        }
+
+        // Create the final tarball.
+        let mut cmd = rust_installer(builder);
+        cmd.arg("generate")
+            .arg("--product-name=Rust")
+            .arg("--rel-manifest-dir=rustlib")
+            .arg("--success-message=build-manifest installed.")
+            .arg("--image-dir")
+            .arg(&image)
+            .arg("--work-dir")
+            .arg(&tmpdir(builder))
+            .arg("--output-dir")
+            .arg(&distdir(builder))
+            .arg("--non-installed-overlay")
+            .arg(&overlay)
+            .arg(format!("--package-name={}-{}", name, self.target.triple))
+            .arg("--legacy-manifest-dirs=rustlib,cargo")
+            .arg("--component-name=build-manifest");
+
+        builder.run(&mut cmd);
+        distdir(builder).join(format!("{}-{}.tar.gz", name, self.target.triple))
+    }
+}
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 319a0b4e611..22cfd0c5643 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -30,6 +30,7 @@ pub struct Flags {
     pub cmd: Subcommand,
     pub incremental: bool,
     pub exclude: Vec<PathBuf>,
+    pub include_default_paths: bool,
     pub rustc_error_format: Option<String>,
     pub json_output: bool,
     pub dry_run: bool,
@@ -124,6 +125,7 @@ Subcommands:
     dist        Build distribution artifacts
     install     Install distribution artifacts
     run, r      Run tools contained in this repository
+    setup       Create a config.toml (making it easier to use `x.py` itself)
 
 To learn more about a subcommand, run `./x.py <subcommand> -h`",
         );
@@ -137,6 +139,11 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
         opts.optmulti("", "host", "host targets to build", "HOST");
         opts.optmulti("", "target", "target targets to build", "TARGET");
         opts.optmulti("", "exclude", "build paths to exclude", "PATH");
+        opts.optflag(
+            "",
+            "include-default-paths",
+            "include default paths in addition to the provided ones",
+        );
         opts.optopt("", "on-fail", "command to run on failure", "CMD");
         opts.optflag("", "dry-run", "dry run; don't build anything");
         opts.optopt(
@@ -466,15 +473,21 @@ Arguments:
                 );
             }
             "setup" => {
-                subcommand_help.push_str(
+                subcommand_help.push_str(&format!(
                     "\n
+x.py setup creates a `config.toml` which changes the defaults for x.py itself.
+
 Arguments:
     This subcommand accepts a 'profile' to use for builds. For example:
 
         ./x.py setup library
 
-    The profile is optional and you will be prompted interactively if it is not given.",
-                );
+    The profile is optional and you will be prompted interactively if it is not given.
+    The following profiles are available:
+
+{}",
+                    Profile::all_for_help("        ").trim_end()
+                ));
             }
             _ => {}
         };
@@ -545,9 +558,7 @@ Arguments:
                     profile_string.parse().unwrap_or_else(|err| {
                         eprintln!("error: {}", err);
                         eprintln!("help: the available profiles are:");
-                        for choice in Profile::all() {
-                            eprintln!("- {}", choice);
-                        }
+                        eprint!("{}", Profile::all_for_help("- "));
                         std::process::exit(1);
                     })
                 } else {
@@ -618,6 +629,7 @@ Arguments:
                 .into_iter()
                 .map(|p| p.into())
                 .collect::<Vec<_>>(),
+            include_default_paths: matches.opt_present("include-default-paths"),
             deny_warnings: parse_deny_warnings(&matches),
             llvm_skip_rebuild: matches.opt_str("llvm-skip-rebuild").map(|s| s.to_lowercase()).map(
                 |s| s.parse::<bool>().expect("`llvm-skip-rebuild` should be either true or false"),
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 147bcf30709..22a8e828862 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -177,8 +177,13 @@ const LLVM_TOOLS: &[&str] = &[
     "llvm-size", // used to prints the size of the linker sections of a program
     "llvm-strip", // used to discard symbols from binary files to reduce their size
     "llvm-ar", // used for creating and modifying archive files
+    "llvm-dis", // used to disassemble LLVM bitcode
+    "llc",     // used to compile LLVM bytecode
+    "opt",     // used to optimize LLVM bytecode
 ];
 
+pub const VERSION: usize = 2;
+
 /// A structure representing a Rust compiler.
 ///
 /// Each compiler has a `stage` that it is associated with and a `host` that
@@ -1051,40 +1056,6 @@ impl Build {
         self.package_vers(&self.version)
     }
 
-    /// Returns the value of `package_vers` above for Cargo
-    fn cargo_package_vers(&self) -> String {
-        self.package_vers(&self.release_num("cargo"))
-    }
-
-    /// Returns the value of `package_vers` above for rls
-    fn rls_package_vers(&self) -> String {
-        self.package_vers(&self.release_num("rls"))
-    }
-
-    /// Returns the value of `package_vers` above for rust-analyzer
-    fn rust_analyzer_package_vers(&self) -> String {
-        self.package_vers(&self.release_num("rust-analyzer/crates/rust-analyzer"))
-    }
-
-    /// Returns the value of `package_vers` above for clippy
-    fn clippy_package_vers(&self) -> String {
-        self.package_vers(&self.release_num("clippy"))
-    }
-
-    /// Returns the value of `package_vers` above for miri
-    fn miri_package_vers(&self) -> String {
-        self.package_vers(&self.release_num("miri"))
-    }
-
-    /// Returns the value of `package_vers` above for rustfmt
-    fn rustfmt_package_vers(&self) -> String {
-        self.package_vers(&self.release_num("rustfmt"))
-    }
-
-    fn llvm_tools_package_vers(&self) -> String {
-        self.package_vers(&self.version)
-    }
-
     fn llvm_tools_vers(&self) -> String {
         self.rust_version()
     }
diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs
index 80c093e713e..7c64e5a0aad 100644
--- a/src/bootstrap/run.rs
+++ b/src/bootstrap/run.rs
@@ -77,7 +77,6 @@ impl Step for BuildManifest {
         cmd.arg(today.trim());
         cmd.arg(addr);
         cmd.arg(&builder.config.channel);
-        cmd.arg(&builder.src);
 
         builder.create_dir(&distdir(builder));
         builder.run(&mut cmd);
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index dcfb9fd6734..a281061ace1 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -1,4 +1,5 @@
-use crate::t;
+use crate::{t, VERSION};
+use std::fmt::Write as _;
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 use std::{
@@ -20,7 +21,28 @@ impl Profile {
     }
 
     pub fn all() -> impl Iterator<Item = Self> {
-        [Profile::Compiler, Profile::Codegen, Profile::Library, Profile::User].iter().copied()
+        use Profile::*;
+        // N.B. these are ordered by how they are displayed, not alphabetically
+        [Library, Compiler, Codegen, User].iter().copied()
+    }
+
+    pub fn purpose(&self) -> String {
+        use Profile::*;
+        match self {
+            Library => "Contribute to the standard library",
+            Compiler => "Contribute to the compiler or rustdoc",
+            Codegen => "Contribute to the compiler, and also modify LLVM or codegen",
+            User => "Install Rust from source",
+        }
+        .to_string()
+    }
+
+    pub fn all_for_help(indent: &str) -> String {
+        let mut out = String::new();
+        for choice in Profile::all() {
+            writeln!(&mut out, "{}{}: {}", indent, choice, choice.purpose()).unwrap();
+        }
+        out
     }
 }
 
@@ -29,10 +51,10 @@ impl FromStr for Profile {
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
         match s {
-            "a" | "lib" | "library" => Ok(Profile::Library),
-            "b" | "compiler" => Ok(Profile::Compiler),
-            "c" | "llvm" | "codegen" => Ok(Profile::Codegen),
-            "d" | "maintainer" | "user" => Ok(Profile::User),
+            "lib" | "library" => Ok(Profile::Library),
+            "compiler" | "rustdoc" => Ok(Profile::Compiler),
+            "llvm" | "codegen" => Ok(Profile::Codegen),
+            "maintainer" | "user" => Ok(Profile::User),
             _ => Err(format!("unknown profile: '{}'", s)),
         }
     }
@@ -69,8 +91,9 @@ pub fn setup(src_path: &Path, profile: Profile) {
     let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml"));
     let settings = format!(
         "# Includes one of the default files in src/bootstrap/defaults\n\
-    profile = \"{}\"\n",
-        profile
+    profile = \"{}\"\n\
+    changelog-seen = {}\n",
+        profile, VERSION
     );
     t!(fs::write(path, settings));
 
@@ -103,19 +126,37 @@ pub fn setup(src_path: &Path, profile: Profile) {
 
 // Used to get the path for `Subcommand::Setup`
 pub fn interactive_path() -> io::Result<Profile> {
-    let mut input = String::new();
-    println!(
-        "Welcome to the Rust project! What do you want to do with x.py?
-a) Contribute to the standard library
-b) Contribute to the compiler
-c) Contribute to the compiler, and also modify LLVM or codegen
-d) Install Rust from source"
-    );
+    fn abbrev_all() -> impl Iterator<Item = (String, Profile)> {
+        ('a'..).map(|c| c.to_string()).zip(Profile::all())
+    }
+
+    fn parse_with_abbrev(input: &str) -> Result<Profile, String> {
+        let input = input.trim().to_lowercase();
+        for (letter, profile) in abbrev_all() {
+            if input == letter {
+                return Ok(profile);
+            }
+        }
+        input.parse()
+    }
+
+    println!("Welcome to the Rust project! What do you want to do with x.py?");
+    for (letter, profile) in abbrev_all() {
+        println!("{}) {}: {}", letter, profile, profile.purpose());
+    }
     let template = loop {
-        print!("Please choose one (a/b/c/d): ");
+        print!(
+            "Please choose one ({}): ",
+            abbrev_all().map(|(l, _)| l).collect::<Vec<_>>().join("/")
+        );
         io::stdout().flush()?;
+        let mut input = String::new();
         io::stdin().read_line(&mut input)?;
-        break match input.trim().to_lowercase().parse() {
+        if input == "" {
+            eprintln!("EOF on stdin, when expecting answer to question.  Giving up.");
+            std::process::exit(1);
+        }
+        break match parse_with_abbrev(&input) {
             Ok(profile) => profile,
             Err(err) => {
                 println!("error: {}", err);
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 00522ee6b67..bda9e0f5784 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -966,6 +966,15 @@ impl Step for Compiletest {
     /// compiletest `mode` and `suite` arguments. For example `mode` can be
     /// "run-pass" or `suite` can be something like `debuginfo`.
     fn run(self, builder: &Builder<'_>) {
+        if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() {
+            eprintln!("\
+error: `--stage 0` runs compiletest on the beta compiler, not your local changes, and will almost always cause tests to fail
+help: use `--stage 1` instead
+note: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`."
+            );
+            std::process::exit(1);
+        }
+
         let compiler = self.compiler;
         let target = self.target;
         let mode = self.mode;
diff --git a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile
index 3c39a638496..f3f52ed61d1 100644
--- a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile
@@ -84,9 +84,9 @@ RUN riscv64-linux-gnu-gcc addentropy.c -o rootfs/addentropy -static
 # download and build the riscv bootloader
 RUN git clone https://github.com/riscv/riscv-pk
 WORKDIR /tmp/riscv-pk
-# nothing special about this revision: it is just master at the time of writing
-# v1.0.0 doesn't build
-RUN git checkout 5d9ed238e1cabfbca3c47f50d32894ce94bfc304
+# This revision fixes a fault in recent QEMU from 64-bit accesses to the PLIC
+# commits later than this one should work too
+RUN git checkout 7d8b7c0dab72108e3ea7bb7744d3f6cc907c7ef4
 RUN mkdir build && cd build && \
     ../configure --with-payload=/tmp/vmlinux --host=riscv64-linux-gnu && \
     make -j$(nproc) && \
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index 58e2567a58f..14700aeea05 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -98,7 +98,9 @@ ENV RUST_CONFIGURE_ARGS \
       --set llvm.thin-lto=true \
       --set llvm.ninja=false \
       --set rust.jemalloc
-ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS \
+        --include-default-paths \
+        src/tools/build-manifest
 ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang
 
 # This is the only builder which will create source tarballs
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 101716d1601..01f15a82f0f 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -149,6 +149,10 @@ x--expand-yaml-anchors--remove:
         run: src/ci/scripts/install-sccache.sh
         <<: *step
 
+      - name: select Xcode
+        run: src/ci/scripts/select-xcode.sh
+        <<: *step
+
       - name: install clang
         run: src/ci/scripts/install-clang.sh
         <<: *step
@@ -457,6 +461,37 @@ jobs:
               NO_DEBUG_ASSERTIONS: 1
             <<: *job-macos-xl
 
+          # This target only needs to support 11.0 and up as nothing else supports the hardware
+          - name: dist-aarch64-apple
+            env:
+              SCRIPT: ./x.py dist --stage 2
+              RUST_CONFIGURE_ARGS: >-
+                --build=x86_64-apple-darwin
+                --host=aarch64-apple-darwin
+                --target=aarch64-apple-darwin
+                --enable-full-tools
+                --enable-sanitizers
+                --enable-profiler
+                --set rust.jemalloc
+                --set llvm.ninja=false
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              SELECT_XCODE: /Applications/Xcode_12.2.app
+              USE_XCODE_CLANG: 1
+              MACOSX_DEPLOYMENT_TARGET: 11.0
+              MACOSX_STD_DEPLOYMENT_TARGET: 11.0
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+              DIST_REQUIRE_ALL_TOOLS: 1
+              # Corresponds to 16K page size
+              #
+              # Shouldn't be needed if jemalloc-sys is updated to
+              # handle this platform like iOS or if we build on
+              # aarch64-apple-darwin itself.
+              #
+              # https://github.com/gnzlbg/jemallocator/blob/c27a859e98e3cb790dc269773d9da71a1e918458/jemalloc-sys/build.rs#L237
+              JEMALLOC_SYS_WITH_LG_PAGE: 14
+            <<: *job-macos-xl
+
           ######################
           #  Windows Builders  #
           ######################
@@ -565,7 +600,7 @@ jobs:
               RUST_CONFIGURE_ARGS: >-
                 --build=x86_64-pc-windows-msvc
                 --host=x86_64-pc-windows-msvc
-                --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
+                --target=x86_64-pc-windows-msvc
                 --enable-full-tools
                 --enable-profiler
               SCRIPT: python x.py dist
@@ -584,6 +619,18 @@ jobs:
               DIST_REQUIRE_ALL_TOOLS: 1
             <<: *job-windows-xl
 
+          - name: dist-aarch64-msvc
+            env:
+              RUST_CONFIGURE_ARGS: >-
+                --build=x86_64-pc-windows-msvc
+                --host=aarch64-pc-windows-msvc
+                --enable-full-tools
+                --enable-profiler
+              SCRIPT: python x.py dist
+              # RLS does not build for aarch64-pc-windows-msvc. See rust-lang/rls#1693
+              DIST_REQUIRE_ALL_TOOLS: 0
+            <<: *job-windows-xl
+
           - name: dist-i686-mingw
             env:
               RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler
diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh
index a1481f22f50..8070e90f155 100755
--- a/src/ci/scripts/install-clang.sh
+++ b/src/ci/scripts/install-clang.sh
@@ -12,10 +12,18 @@ source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 LLVM_VERSION="10.0.0"
 
 if isMacOS; then
-    curl -f "${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz" | tar xJf -
+    # If the job selects a specific Xcode version, use that instead of
+    # downloading our own version.
+    if [[ ${USE_XCODE_CLANG-0} -eq 1 ]]; then
+        bindir="$(xcode-select --print-path)/Toolchains/XcodeDefault.xctoolchain/usr/bin"
+    else
+        file="${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
+        curl -f "${file}" | tar xJf -
+        bindir="$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin"
+    fi
 
-    ciCommandSetEnv CC "$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin/clang"
-    ciCommandSetEnv CXX "$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin/clang++"
+    ciCommandSetEnv CC "${bindir}/clang"
+    ciCommandSetEnv CXX "${bindir}/clang++"
 
     # macOS 10.15 onwards doesn't have libraries in /usr/include anymore: those
     # are now located deep into the filesystem, under Xcode's own files. The
diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh
index ae85d5cab01..1685fbbbbba 100755
--- a/src/ci/scripts/install-mingw.sh
+++ b/src/ci/scripts/install-mingw.sh
@@ -42,6 +42,13 @@ if isWindows; then
             arch=x86_64
             mingw_archive="${MINGW_ARCHIVE_64}"
             ;;
+        *aarch64*)
+            # aarch64 is a cross-compiled target. Use the x86_64
+            # mingw, since that's the host architecture.
+            bits=64
+            arch=x86_64
+            mingw_archive="${MINGW_ARCHIVE_64}"
+            ;;
         *)
             echo "src/ci/scripts/install-mingw.sh can't detect the builder's architecture"
             echo "please tweak it to recognize the builder named '${CI_JOB_NAME}'"
diff --git a/src/ci/scripts/select-xcode.sh b/src/ci/scripts/select-xcode.sh
new file mode 100755
index 00000000000..3b9c77d42ba
--- /dev/null
+++ b/src/ci/scripts/select-xcode.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+# This script selects the Xcode instance to use.
+
+set -euo pipefail
+IFS=$'\n\t'
+
+source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
+
+if isMacOS; then
+    if [[ -s "${SELECT_XCODE-}" ]]; then
+        sudo xcode-select -s "${SELECT_XCODE}"
+    fi
+fi
diff --git a/src/doc/book b/src/doc/book
-Subproject cb28dee95e5e50b793e6ba9291c5d1568d3ad72
+Subproject 451a1e30f2dd137aa04e142414eafb8d05f87f8
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject dd310616308e01f6cf227f46347b744aa56b77d
+Subproject 79ab7776929c66db83203397958fa7037d5d9a3
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 56a13c082ee90736c08d6abdcd90462517b703d
+Subproject 1b78182e71709169dc0f1c3acdc4541b6860e1c
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 7d3ff1c12db08a847a57a054be4a7951ce532d2
+Subproject 152475937a8d8a1f508d8eeb57db79139bc803d
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index bed10ca16d3..f6493e49c3c 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -497,8 +497,10 @@ point instructions in software. It takes one of the following values:
 This instructs `rustc` to generate code specifically for a particular processor.
 
 You can run `rustc --print target-cpus` to see the valid options to pass
-here. Additionally, `native` can be passed to use the processor of the host
-machine. Each target has a default base CPU.
+here. Each target has a default base CPU. Special values include:
+
+* `native` can be passed to use the processor of the host machine. 
+* `generic` refers to an LLVM target with minimal features but modern tuning.
 
 ## target-feature
 
@@ -530,6 +532,20 @@ This also supports the feature `+crt-static` and `-crt-static` to control
 Each target and [`target-cpu`](#target-cpu) has a default set of enabled
 features.
 
+## tune-cpu
+
+This instructs `rustc` to schedule code specifically for a particular
+processor. This does not affect the compatibility (instruction sets or ABI),
+but should make your code slightly more efficient on the selected CPU.
+
+The valid options are the same as those for [`target-cpu`](#target-cpu).
+The default is `None`, which LLVM translates as the `target-cpu`.
+
+This is an unstable option. Use `-Z tune-cpu=machine` to specify a value.
+
+Due to limitations in LLVM (12.0.0-git9218f92), this option is currently
+effective only for x86 targets.
+
 [option-emit]: ../command-line-arguments.md#option-emit
 [option-o-optimize]: ../command-line-arguments.md#option-o-optimize
 [profile-guided optimization]: ../profile-guided-optimization.md
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 6c605f045e5..ae55297b78c 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -37,7 +37,7 @@ target | std | host | notes
 `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+)
-`x86_64-apple-darwin` | ✓ | ✓ | 64-bit OSX (10.7+, Lion+)
+`x86_64-apple-darwin` | ✓ | ✓ | 64-bit macOS (10.7+, Lion+)
 `x86_64-pc-windows-gnu` | ✓ | ✓ | 64-bit MinGW (Windows 7+)
 `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+)
@@ -57,10 +57,11 @@ Specifically, these platforms are required to have each of the following:
 
 target | std | host | notes
 -------|-----|------|-------
+`aarch64-apple-darwin` | ✓ | ✓ | ARM64 macOS (11.0+, Big Sur+)
 `aarch64-apple-ios` | ✓ |  | ARM64 iOS
 `aarch64-fuchsia` | ✓ |  | ARM64 Fuchsia
 `aarch64-linux-android` | ✓ |  | ARM64 Android
-`aarch64-pc-windows-msvc` | ✓ |  | ARM64 Windows MSVC
+`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
@@ -145,7 +146,6 @@ not available.
 
 target | std | host | notes
 -------|-----|------|-------
-`aarch64-apple-darwin` | ? |  | ARM64 macOS
 `aarch64-apple-tvos` | * |  | ARM64 tvOS
 `aarch64-unknown-cloudabi` | ✓ |  | ARM64 CloudABI
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
@@ -168,7 +168,7 @@ target | std | host | notes
 `avr-unknown-gnu-atmega328` | ✗ |  | AVR. Requires `-Z build-std=core`
 `hexagon-unknown-linux-musl` | ? |  |
 `i386-apple-ios` | ✓ |  | 32-bit x86 iOS
-`i686-apple-darwin` | ✓ | ✓ | 32-bit OSX (10.7+, Lion+)
+`i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+)
 `i686-pc-windows-msvc` | ✓ |  | 32-bit Windows XP support
 `i686-unknown-cloudabi` | ✓ |  | 32-bit CloudABI
 `i686-unknown-uefi` | ? |  | 32-bit UEFI
diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md
index 93454b4f909..a3fa525be1d 100644
--- a/src/doc/rustdoc/src/SUMMARY.md
+++ b/src/doc/rustdoc/src/SUMMARY.md
@@ -8,5 +8,5 @@
 - [Linking to items by name](linking-to-items-by-name.md)
 - [Lints](lints.md)
 - [Passes](passes.md)
-- [Advanced Features](advanced-features.md)
+- [Advanced features](advanced-features.md)
 - [Unstable features](unstable-features.md)
diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md
index 8be9489c617..5128ff13b7a 100644
--- a/src/doc/rustdoc/src/advanced-features.md
+++ b/src/doc/rustdoc/src/advanced-features.md
@@ -1,4 +1,4 @@
-# Advanced Features
+# Advanced features
 
 The features listed on this page fall outside the rest of the main categories.
 
diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md
index 5e46ef583f6..76e04398530 100644
--- a/src/doc/rustdoc/src/linking-to-items-by-name.md
+++ b/src/doc/rustdoc/src/linking-to-items-by-name.md
@@ -1,6 +1,7 @@
 # Linking to items by name
 
-Rustdoc is capable of directly linking to other rustdoc pages in Markdown documentation using the path of item as a link.
+Rustdoc is capable of directly linking to other rustdoc pages using the path of
+the item as a link.
 
 For example, in the following code all of the links will link to the rustdoc page for `Bar`:
 
@@ -19,15 +20,26 @@ pub struct Foo3;
 /// This struct is also not [`Bar`]
 pub struct Foo4;
 
+/// This struct *is* [`Bar`]!
 pub struct Bar;
 ```
 
-You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and `crate`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. Backticks around the link will be stripped.
+Backticks around the link will be stripped, so ``[`Option`]`` will correctly
+link to `Option`.
+
+You can refer to anything in scope, and use paths, including `Self`, `self`,
+`super`, and `crate`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros, respectively.
+
+You can also refer to items with generic parameters like `Vec<T>`. The link will
+resolve as if you had written ``[`Vec<T>`](Vec)``. Fully-qualified syntax (for example,
+`<Vec as IntoIterator>::into_iter()`) is [not yet supported][fqs-issue], however.
+
+[fqs-issue]: https://github.com/rust-lang/rust/issues/74563
 
 ```rust,edition2018
 use std::sync::mpsc::Receiver;
 
-/// This is an version of [`Receiver`], with support for [`std::future`].
+/// This is a version of [`Receiver<T>`] with support for [`std::future`].
 ///
 /// You can obtain a [`std::future::Future`] by calling [`Self::recv()`].
 pub struct AsyncReceiver<T> {
@@ -44,13 +56,15 @@ impl<T> AsyncReceiver<T> {
 You can also link to sections using URL fragment specifiers:
 
 ```rust
-/// This is a special implementation of [positional parameters]
+/// This is a special implementation of [positional parameters].
 ///
 /// [positional parameters]: std::fmt#formatting-parameters
 struct MySpecialFormatter;
 ```
 
-Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like  `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`:
+Paths in Rust have three namespaces: type, value, and macro. Item names must be
+unique within their namespace, but can overlap with items outside of their
+namespace. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `fn@`, `function@`, `mod@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`:
 
 ```rust
 /// See also: [`Foo`](struct@Foo)
@@ -62,4 +76,19 @@ struct Foo {}
 fn Foo() {}
 ```
 
-Note: Because of how `macro_rules` macros are scoped in Rust, the intra-doc links of a `macro_rules` macro will be resolved relative to the crate root, as opposed to the module it is defined in.
+You can also disambiguate for functions by adding `()` after the function name,
+or for macros by adding `!` after the macro name:
+
+```rust
+/// See also: [`Foo`](struct@Foo)
+struct Bar;
+
+/// This is different from [`Foo()`]
+struct Foo {}
+
+fn Foo() {}
+```
+
+Note: Because of how `macro_rules!` macros are scoped in Rust, the intra-doc links of a `macro_rules!` macro will be resolved [relative to the crate root][#72243], as opposed to the module it is defined in.
+
+[#72243]: https://github.com/rust-lang/rust/issues/72243
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index 3e632a0644a..cb9099cd50b 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -4,18 +4,18 @@
 can use them like any other lints by doing this:
 
 ```rust,ignore
-#![allow(missing_docs)] // allowing the lint, no message
-#![warn(missing_docs)] // warn if there is missing docs
-#![deny(missing_docs)] // rustdoc will fail if there is missing docs
+#![allow(missing_docs)] // allows the lint, no diagnostics will be reported
+#![warn(missing_docs)] // warn if there are missing docs
+#![deny(missing_docs)] // error if there are missing docs
 ```
 
 Here is the list of the lints provided by `rustdoc`:
 
 ## broken_intra_doc_links
 
-This lint **warns by default**. This lint detects when an [intra-doc link] fails to get resolved. For example:
+This lint **warns by default**. This lint detects when an [intra-doc link] fails to be resolved. For example:
 
- [intra-doc link]: linking-to-items-by-name.html
+[intra-doc link]: linking-to-items-by-name.md
 
 ```rust
 /// I want to link to [`Nonexistent`] but it doesn't exist!
@@ -250,3 +250,38 @@ warning: unknown attribute `should-panic`. Did you mean `should_panic`?
 
 In the example above, the correct form is `should_panic`. This helps detect
 typo mistakes for some common attributes.
+
+## invalid_html_tags
+
+This lint is **allowed by default** and is **nightly-only**. It detects unclosed
+or invalid HTML tags. For example:
+
+```rust
+#![warn(invalid_html_tags)]
+
+/// <h1>
+/// </script>
+pub fn foo() {}
+```
+
+Which will give:
+
+```text
+warning: unopened HTML tag `script`
+ --> foo.rs:1:1
+  |
+1 | / /// <h1>
+2 | | /// </script>
+  | |_____________^
+  |
+  = note: `#[warn(invalid_html_tags)]` on by default
+
+warning: unclosed HTML tag `h1`
+ --> foo.rs:1:1
+  |
+1 | / /// <h1>
+2 | | /// </script>
+  | |_____________^
+
+warning: 2 warnings emitted
+```
diff --git a/src/doc/unstable-book/src/compiler-flags/codegen-backend.md b/src/doc/unstable-book/src/compiler-flags/codegen-backend.md
new file mode 100644
index 00000000000..878c894a6ca
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/codegen-backend.md
@@ -0,0 +1,31 @@
+# `codegen-backend`
+
+The tracking issue for this feature is: [#77933](https://github.com/rust-lang/rust/issues/77933).
+
+------------------------
+
+This feature allows you to specify a path to a dynamic library to use as rustc's
+code generation backend at runtime.
+
+Set the `-Zcodegen-backend=<path>` compiler flag to specify the location of the
+backend. The library must be of crate type `dylib` and must contain a function
+named `__rustc_codegen_backend` with a signature of `fn() -> Box<dyn rustc_codegen_ssa::traits::CodegenBackend>`.
+
+## Example
+See also the [`hotplug_codegen_backend`](https://github.com/rust-lang/rust/tree/master/src/test/run-make-fulldeps/hotplug_codegen_backend) test
+for a full example.
+
+```rust,ignore
+use rustc_codegen_ssa::traits::CodegenBackend;
+
+struct MyBackend;
+
+impl CodegenBackend for MyBackend {
+   // Implement codegen methods
+}
+
+#[no_mangle]
+pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
+    Box::new(MyBackend)
+}
+```
diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md
index af39424ec6c..6e4e1f78b96 100644
--- a/src/doc/unstable-book/src/library-features/asm.md
+++ b/src/doc/unstable-book/src/library-features/asm.md
@@ -27,7 +27,7 @@ Inline assembly is currently supported on the following architectures:
 - RISC-V
 - NVPTX
 - Hexagon
-- MIPS32
+- MIPS32r2 and MIPS64r2
 
 ## Basic usage
 
@@ -513,8 +513,8 @@ Here is the list of currently supported register classes:
 | ARM | `qreg` | `q[0-15]` | `w` |
 | ARM | `qreg_low8` | `q[0-7]` | `t` |
 | ARM | `qreg_low4` | `q[0-3]` | `x` |
-| MIPS32 | `reg` | `$[2-25]` | `r` |
-| MIPS32 | `freg` | `$f[0-31]` | `f` |
+| MIPS | `reg` | `$[2-25]` | `r` |
+| MIPS | `freg` | `$f[0-31]` | `f` |
 | NVPTX | `reg16` | None\* | `h` |
 | NVPTX | `reg32` | None\* | `r` |
 | NVPTX | `reg64` | None\* | `l` |
@@ -551,7 +551,9 @@ Each register class has constraints on which value types they can be used with.
 | ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` |
 | ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` |
 | MIPS32 | `reg` | None | `i8`, `i16`, `i32`, `f32` |
-| MIPS32 | `freg` | None | `f32` |
+| MIPS32 | `freg` | None | `f32`, `f64` |
+| MIPS64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` |
+| MIPS64 | `freg` | None | `f32`, `f64` |
 | NVPTX | `reg16` | None | `i8`, `i16` |
 | NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` |
 | NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
@@ -600,7 +602,6 @@ Some registers have multiple names. These are all treated by the compiler as ide
 | ARM | `r13` | `sp` |
 | ARM | `r14` | `lr` |
 | ARM | `r15` | `pc` |
-| MIPS32 | `$[2-25]` | Please [see the Wikipedia page][mips-regs] |
 | RISC-V | `x0` | `zero` |
 | RISC-V | `x1` | `ra` |
 | RISC-V | `x2` | `sp` |
@@ -621,8 +622,6 @@ Some registers have multiple names. These are all treated by the compiler as ide
 | Hexagon | `r30` | `fr` |
 | Hexagon | `r31` | `lr` |
 
-[mips-regs]: https://en.wikibooks.org/wiki/MIPS_Assembly/Register_File#Registers
-
 Some registers cannot be used for input or output operands:
 
 | Architecture | Unsupported register | Reason |
@@ -637,11 +636,11 @@ Some registers cannot be used for input or output operands:
 | x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). |
 | AArch64 | `xzr` | This is a constant zero register which can't be modified. |
 | ARM | `pc` | This is the program counter, not a real register. |
-| MIPS32 | `$0` or `$zero` | This is a constant zero register which can't be modified. |
-| MIPS32 | `$1` or `$at` | Reserved for assembler. |
-| MIPS32 | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
-| MIPS32 | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. |
-| MIPS32 | `$ra` | Return address cannot be used as inputs or outputs. |
+| MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. |
+| MIPS | `$1` or `$at` | Reserved for assembler. |
+| MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. |
+| MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. |
+| MIPS | `$ra` | Return address cannot be used as inputs or outputs. |
 | RISC-V | `x0` | This is a constant zero register which can't be modified. |
 | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. |
 | Hexagon | `lr` | This is the link register which cannot be used as an input or output. |
@@ -689,8 +688,8 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen
 | ARM | `dreg` | None | `d0` | `P` |
 | ARM | `qreg` | None | `q0` | `q` |
 | ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` |
-| MIPS32 | `reg` | None | `$2` | None |
-| MIPS32 | `freg` | None | `$f0` | None |
+| MIPS | `reg` | None | `$2` | None |
+| MIPS | `freg` | None | `$f0` | None |
 | NVPTX | `reg16` | None | `rs0` | None |
 | NVPTX | `reg32` | None | `r0` | None |
 | NVPTX | `reg64` | None | `rd0` | None |
diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py
index bae51e6f9ee..b2d343fd7af 100644
--- a/src/etc/gdb_providers.py
+++ b/src/etc/gdb_providers.py
@@ -207,30 +207,46 @@ class StdRefCellProvider:
         yield "borrow", self.borrow
 
 
-# Yield each key (and optionally value) from a BoxedNode.
-def children_of_node(boxed_node, height, want_values):
+# Yields children (in a provider's sense of the word) for a tree headed by a BoxedNode.
+# In particular, yields each key/value pair in the node and in any child nodes.
+def children_of_node(boxed_node, height):
     def cast_to_internal(node):
-        internal_type_name = str(node.type.target()).replace("LeafNode", "InternalNode", 1)
+        internal_type_name = node.type.target().name.replace("LeafNode", "InternalNode", 1)
         internal_type = lookup_type(internal_type_name)
         return node.cast(internal_type.pointer())
 
     node_ptr = unwrap_unique_or_non_null(boxed_node["ptr"])
-    node_ptr = cast_to_internal(node_ptr) if height > 0 else node_ptr
-    leaf = node_ptr["data"] if height > 0 else node_ptr.dereference()
+    leaf = node_ptr.dereference()
     keys = leaf["keys"]
-    values = leaf["vals"]
+    vals = leaf["vals"]
+    edges = cast_to_internal(node_ptr)["edges"] if height > 0 else None
     length = int(leaf["len"])
 
     for i in xrange(0, length + 1):
         if height > 0:
-            child_ptr = node_ptr["edges"][i]["value"]["value"]
-            for child in children_of_node(child_ptr, height - 1, want_values):
+            boxed_child_node = edges[i]["value"]["value"]
+            for child in children_of_node(boxed_child_node, height - 1):
                 yield child
         if i < length:
-            if want_values:
-                yield keys[i]["value"]["value"], values[i]["value"]["value"]
-            else:
-                yield keys[i]["value"]["value"]
+            # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays.
+            key = keys[i]["value"]["value"] if keys.type.sizeof > 0 else None
+            val = vals[i]["value"]["value"] if vals.type.sizeof > 0 else None
+            yield key, val
+
+
+# Yields children for a BTreeMap.
+def children_of_map(map):
+    if map["length"] > 0:
+        root = map["root"]
+        if root.type.name.startswith("core::option::Option<"):
+            root = root.cast(gdb.lookup_type(root.type.name[21:-1]))
+        boxed_root_node = root["node"]
+        height = root["height"]
+        for i, (key, val) in enumerate(children_of_node(boxed_root_node, height)):
+            if key is not None:
+                yield "key{}".format(i), key
+            if val is not None:
+                yield "val{}".format(i), val
 
 
 class StdBTreeSetProvider:
@@ -242,15 +258,8 @@ class StdBTreeSetProvider:
 
     def children(self):
         inner_map = self.valobj["map"]
-        if inner_map["length"] > 0:
-            root = inner_map["root"]
-            if "core::option::Option<" in root.type.name:
-                type_name = str(root.type.name).replace("core::option::Option<", "", 1)[:-1]
-                root = root.cast(gdb.lookup_type(type_name))
-
-            node_ptr = root["node"]
-            for i, child in enumerate(children_of_node(node_ptr, root["height"], False)):
-                yield "[{}]".format(i), child
+        for child in children_of_map(inner_map):
+            yield child
 
     @staticmethod
     def display_hint():
@@ -265,16 +274,8 @@ class StdBTreeMapProvider:
         return "BTreeMap(size={})".format(self.valobj["length"])
 
     def children(self):
-        if self.valobj["length"] > 0:
-            root = self.valobj["root"]
-            if "core::option::Option<" in root.type.name:
-                type_name = str(root.type.name).replace("core::option::Option<", "", 1)[:-1]
-                root = root.cast(gdb.lookup_type(type_name))
-
-            node_ptr = root["node"]
-            for i, child in enumerate(children_of_node(node_ptr, root["height"], True)):
-                yield "key{}".format(i), child[0]
-                yield "val{}".format(i), child[1]
+        for child in children_of_map(self.valobj):
+            yield child
 
     @staticmethod
     def display_hint():
diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands
index 979f2fa7ae8..b8e6c6c0c89 100644
--- a/src/etc/lldb_commands
+++ b/src/etc/lldb_commands
@@ -1,18 +1,18 @@
-type synthetic add -l lldb_lookup.synthetic_lookup -x \".*\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)String$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^&str$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^&\\[.+\\]$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(std::ffi::([a-z_]+::)+)OsString$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)Vec<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)VecDeque<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)BTreeSet<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)BTreeMap<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(std::collections::([a-z_]+::)+)HashMap<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(std::collections::([a-z_]+::)+)HashSet<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)Rc<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(alloc::([a-z_]+::)+)Arc<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(core::([a-z_]+::)+)Cell<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(core::([a-z_]+::)+)Ref<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(core::([a-z_]+::)+)RefMut<.+>$\" --category Rust
-type summary add -F lldb_lookup.summary_lookup  -e -x -h \"^(core::([a-z_]+::)+)RefCell<.+>$\" --category Rust
+type synthetic add -l lldb_lookup.synthetic_lookup -x ".*" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&str$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^&\\[.+\\]$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust
+type summary add -F lldb_lookup.summary_lookup  -e -x -h "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust
 type category enable Rust
diff --git a/src/etc/pre-commit.sh b/src/etc/pre-commit.sh
index 5c5922a7e63..70b4e9d9908 100755
--- a/src/etc/pre-commit.sh
+++ b/src/etc/pre-commit.sh
@@ -7,15 +7,17 @@
 
 set -Eeuo pipefail
 
-ROOT_DIR="$(git rev-parse --show-toplevel)";
-COMMAND="$ROOT_DIR/x.py test tidy --bless";
+# https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570
+unset GIT_DIR
+ROOT_DIR="$(git rev-parse --show-toplevel)"
+COMMAND="$ROOT_DIR/x.py test tidy --bless"
 
 if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
   COMMAND="python $COMMAND"
 fi
 
-echo "Running pre-commit script '$COMMAND'";
+echo "Running pre-commit script '$COMMAND'"
 
 cd "$ROOT_DIR"
 
-$COMMAND;
+$COMMAND
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index c039b181178..b659f3eab43 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -201,6 +201,37 @@ impl Cfg {
             _ => false,
         }
     }
+
+    /// Attempt to simplify this cfg by assuming that `assume` is already known to be true, will
+    /// return `None` if simplification managed to completely eliminate any requirements from this
+    /// `Cfg`.
+    ///
+    /// See `tests::test_simplify_with` for examples.
+    pub(crate) fn simplify_with(&self, assume: &Cfg) -> Option<Cfg> {
+        if self == assume {
+            return None;
+        }
+
+        if let Cfg::All(a) = self {
+            let mut sub_cfgs: Vec<Cfg> = if let Cfg::All(b) = assume {
+                a.iter().filter(|a| !b.contains(a)).cloned().collect()
+            } else {
+                a.iter().filter(|&a| a != assume).cloned().collect()
+            };
+            let len = sub_cfgs.len();
+            return match len {
+                0 => None,
+                1 => sub_cfgs.pop(),
+                _ => Some(Cfg::All(sub_cfgs)),
+            };
+        } else if let Cfg::All(b) = assume {
+            if b.contains(self) {
+                return None;
+            }
+        }
+
+        Some(self.clone())
+    }
 }
 
 impl ops::Not for Cfg {
diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs
index 794a7bcaf1c..3a78269f19a 100644
--- a/src/librustdoc/clean/cfg/tests.rs
+++ b/src/librustdoc/clean/cfg/tests.rs
@@ -433,3 +433,39 @@ fn test_render_long_html() {
         );
     })
 }
+
+#[test]
+fn test_simplify_with() {
+    // This is a tiny subset of things that could be simplified, but it likely covers 90% of
+    // real world usecases well.
+    with_default_session_globals(|| {
+        let foo = word_cfg("foo");
+        let bar = word_cfg("bar");
+        let baz = word_cfg("baz");
+        let quux = word_cfg("quux");
+
+        let foobar = Cfg::All(vec![foo.clone(), bar.clone()]);
+        let barbaz = Cfg::All(vec![bar.clone(), baz.clone()]);
+        let foobarbaz = Cfg::All(vec![foo.clone(), bar.clone(), baz.clone()]);
+        let bazquux = Cfg::All(vec![baz.clone(), quux.clone()]);
+
+        // Unrelated cfgs don't affect each other
+        assert_eq!(foo.simplify_with(&bar).as_ref(), Some(&foo));
+        assert_eq!(foobar.simplify_with(&bazquux).as_ref(), Some(&foobar));
+
+        // Identical cfgs are eliminated
+        assert_eq!(foo.simplify_with(&foo), None);
+        assert_eq!(foobar.simplify_with(&foobar), None);
+
+        // Multiple cfgs eliminate a single assumed cfg
+        assert_eq!(foobar.simplify_with(&foo).as_ref(), Some(&bar));
+        assert_eq!(foobar.simplify_with(&bar).as_ref(), Some(&foo));
+
+        // A single cfg is eliminated by multiple assumed cfg containing it
+        assert_eq!(foo.simplify_with(&foobar), None);
+
+        // Multiple cfgs eliminate the matching subset of multiple assumed cfg
+        assert_eq!(foobar.simplify_with(&barbaz).as_ref(), Some(&foo));
+        assert_eq!(foobar.simplify_with(&foobarbaz), None);
+    });
+}
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 7f64d20d8e7..6267b02e5d2 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -15,7 +15,7 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 
-use crate::clean::{self, GetDefId, ToSource, TypeKind};
+use crate::clean::{self, Attributes, GetDefId, ToSource, TypeKind};
 use crate::core::DocContext;
 use crate::doctree;
 
@@ -35,8 +35,11 @@ type Attrs<'hir> = rustc_middle::ty::Attributes<'hir>;
 ///
 /// The returned value is `None` if the definition could not be inlined,
 /// and `Some` of a vector of items if it was successfully expanded.
+///
+/// `parent_module` refers to the parent of the *re-export*, not the original item.
 pub fn try_inline(
     cx: &DocContext<'_>,
+    parent_module: DefId,
     res: Res,
     name: Symbol,
     attrs: Option<Attrs<'_>>,
@@ -48,12 +51,13 @@ pub fn try_inline(
     }
     let mut ret = Vec::new();
 
+    debug!("attrs={:?}", attrs);
     let attrs_clone = attrs;
 
     let inner = match res {
         Res::Def(DefKind::Trait, did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Trait);
-            ret.extend(build_impls(cx, did, attrs));
+            ret.extend(build_impls(cx, Some(parent_module), did, attrs));
             clean::TraitItem(build_external_trait(cx, did))
         }
         Res::Def(DefKind::Fn, did) => {
@@ -62,27 +66,27 @@ pub fn try_inline(
         }
         Res::Def(DefKind::Struct, did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Struct);
-            ret.extend(build_impls(cx, did, attrs));
+            ret.extend(build_impls(cx, Some(parent_module), did, attrs));
             clean::StructItem(build_struct(cx, did))
         }
         Res::Def(DefKind::Union, did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Union);
-            ret.extend(build_impls(cx, did, attrs));
+            ret.extend(build_impls(cx, Some(parent_module), did, attrs));
             clean::UnionItem(build_union(cx, did))
         }
         Res::Def(DefKind::TyAlias, did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Typedef);
-            ret.extend(build_impls(cx, did, attrs));
+            ret.extend(build_impls(cx, Some(parent_module), did, attrs));
             clean::TypedefItem(build_type_alias(cx, did), false)
         }
         Res::Def(DefKind::Enum, did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Enum);
-            ret.extend(build_impls(cx, did, attrs));
+            ret.extend(build_impls(cx, Some(parent_module), did, attrs));
             clean::EnumItem(build_enum(cx, did))
         }
         Res::Def(DefKind::ForeignTy, did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Foreign);
-            ret.extend(build_impls(cx, did, attrs));
+            ret.extend(build_impls(cx, Some(parent_module), did, attrs));
             clean::ForeignTypeItem
         }
         // Never inline enum variants but leave them shown as re-exports.
@@ -117,7 +121,7 @@ pub fn try_inline(
     };
 
     let target_attrs = load_attrs(cx, did);
-    let attrs = merge_attrs(cx, target_attrs, attrs_clone);
+    let attrs = merge_attrs(cx, Some(parent_module), target_attrs, attrs_clone);
 
     cx.renderinfo.borrow_mut().inlined.insert(did);
     ret.push(clean::Item {
@@ -126,7 +130,7 @@ pub fn try_inline(
         attrs,
         inner,
         visibility: clean::Public,
-        stability: cx.tcx.lookup_stability(did).clean(cx),
+        stability: cx.tcx.lookup_stability(did).cloned(),
         deprecation: cx.tcx.lookup_deprecation(did).clean(cx),
         def_id: did,
     });
@@ -291,40 +295,52 @@ pub fn build_ty(cx: &DocContext<'_>, did: DefId) -> Option<clean::Type> {
 }
 
 /// Builds all inherent implementations of an ADT (struct/union/enum) or Trait item/path/reexport.
-pub fn build_impls(cx: &DocContext<'_>, did: DefId, attrs: Option<Attrs<'_>>) -> Vec<clean::Item> {
+pub fn build_impls(
+    cx: &DocContext<'_>,
+    parent_module: Option<DefId>,
+    did: DefId,
+    attrs: Option<Attrs<'_>>,
+) -> Vec<clean::Item> {
     let tcx = cx.tcx;
     let mut impls = Vec::new();
 
     // for each implementation of an item represented by `did`, build the clean::Item for that impl
     for &did in tcx.inherent_impls(did).iter() {
-        build_impl(cx, did, attrs, &mut impls);
+        build_impl(cx, parent_module, did, attrs, &mut impls);
     }
 
     impls
 }
 
+/// `parent_module` refers to the parent of the re-export, not the original item
 fn merge_attrs(
     cx: &DocContext<'_>,
-    attrs: Attrs<'_>,
-    other_attrs: Option<Attrs<'_>>,
+    parent_module: Option<DefId>,
+    old_attrs: Attrs<'_>,
+    new_attrs: Option<Attrs<'_>>,
 ) -> clean::Attributes {
     // NOTE: If we have additional attributes (from a re-export),
     // always insert them first. This ensure that re-export
     // doc comments show up before the original doc comments
     // when we render them.
-    let merged_attrs = if let Some(inner) = other_attrs {
-        let mut both = inner.to_vec();
-        both.extend_from_slice(attrs);
-        both
+    if let Some(inner) = new_attrs {
+        if let Some(new_id) = parent_module {
+            let diag = cx.sess().diagnostic();
+            Attributes::from_ast(diag, old_attrs, Some((inner, new_id)))
+        } else {
+            let mut both = inner.to_vec();
+            both.extend_from_slice(old_attrs);
+            both.clean(cx)
+        }
     } else {
-        attrs.to_vec()
-    };
-    merged_attrs.clean(cx)
+        old_attrs.clean(cx)
+    }
 }
 
 /// Builds a specific implementation of a type. The `did` could be a type method or trait method.
 pub fn build_impl(
     cx: &DocContext<'_>,
+    parent_module: impl Into<Option<DefId>>,
     did: DefId,
     attrs: Option<Attrs<'_>>,
     ret: &mut Vec<clean::Item>,
@@ -333,7 +349,8 @@ pub fn build_impl(
         return;
     }
 
-    let attrs = merge_attrs(cx, load_attrs(cx, did), attrs);
+    let attrs = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
+    debug!("merged_attrs={:?}", attrs);
 
     let tcx = cx.tcx;
     let associated_trait = tcx.impl_trait_ref(did);
@@ -444,7 +461,7 @@ pub fn build_impl(
         name: None,
         attrs,
         visibility: clean::Inherited,
-        stability: tcx.lookup_stability(did).clean(cx),
+        stability: tcx.lookup_stability(did).cloned(),
         deprecation: tcx.lookup_deprecation(did).clean(cx),
         def_id: did,
     });
@@ -481,7 +498,7 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet<DefId>)
                         visibility: clean::Public,
                         stability: None,
                         deprecation: None,
-                        inner: clean::ImportItem(clean::Import::Simple(
+                        inner: clean::ImportItem(clean::Import::new_simple(
                             item.ident.to_string(),
                             clean::ImportSource {
                                 path: clean::Path {
@@ -497,9 +514,12 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet<DefId>)
                                 },
                                 did: None,
                             },
+                            true,
                         )),
                     });
-                } else if let Some(i) = try_inline(cx, item.res, item.ident.name, None, visited) {
+                } else if let Some(i) =
+                    try_inline(cx, did, item.res, item.ident.name, None, visited)
+                {
                     items.extend(i)
                 }
             }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ac1e2b46704..776b131a076 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -19,7 +19,6 @@ use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
 use rustc_middle::bug;
 use rustc_middle::middle::resolve_lifetime as rl;
-use rustc_middle::middle::stability;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
 use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt};
@@ -274,7 +273,7 @@ impl Clean<Item> for doctree::Module<'_> {
             attrs,
             source: span.clean(cx),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             inner: ModuleItem(Module { is_crate: self.is_crate, items }),
@@ -284,7 +283,7 @@ impl Clean<Item> for doctree::Module<'_> {
 
 impl Clean<Attributes> for [ast::Attribute] {
     fn clean(&self, cx: &DocContext<'_>) -> Attributes {
-        Attributes::from_ast(cx.sess().diagnostic(), self)
+        Attributes::from_ast(cx.sess().diagnostic(), self, None)
     }
 }
 
@@ -914,7 +913,7 @@ impl Clean<Item> for doctree::Function<'_> {
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             def_id: did.to_def_id(),
             inner: FunctionItem(Function {
@@ -1023,7 +1022,7 @@ impl Clean<Item> for doctree::Trait<'_> {
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: TraitItem(Trait {
                 auto: self.is_auto.clean(cx),
@@ -1047,7 +1046,7 @@ impl Clean<Item> for doctree::TraitAlias<'_> {
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: TraitAliasItem(TraitAlias {
                 generics: self.generics.clean(cx),
@@ -1832,7 +1831,7 @@ impl Clean<Item> for doctree::Struct<'_> {
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: StructItem(Struct {
                 struct_type: self.struct_type,
@@ -1852,7 +1851,7 @@ impl Clean<Item> for doctree::Union<'_> {
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: UnionItem(Union {
                 struct_type: self.struct_type,
@@ -1882,7 +1881,7 @@ impl Clean<Item> for doctree::Enum<'_> {
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: EnumItem(Enum {
                 variants: self.variants.iter().map(|v| v.clean(cx)).collect(),
@@ -1900,7 +1899,7 @@ impl Clean<Item> for doctree::Variant<'_> {
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
             visibility: Inherited,
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             inner: VariantItem(Variant { kind: self.def.clean(cx) }),
@@ -2049,7 +2048,7 @@ impl Clean<Item> for doctree::Typedef<'_> {
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: TypedefItem(Typedef { type_, generics: self.gen.clean(cx), item_type }, false),
         }
@@ -2064,7 +2063,7 @@ impl Clean<Item> for doctree::OpaqueTy<'_> {
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: OpaqueTyItem(OpaqueTy {
                 bounds: self.opaque_ty.bounds.clean(cx),
@@ -2092,7 +2091,7 @@ impl Clean<Item> for doctree::Static<'_> {
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: StaticItem(Static {
                 type_: self.type_.clean(cx),
@@ -2113,7 +2112,7 @@ impl Clean<Item> for doctree::Constant<'_> {
             source: self.span.clean(cx),
             def_id: def_id.to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: ConstantItem(Constant {
                 type_: self.type_.clean(cx),
@@ -2167,7 +2166,7 @@ impl Clean<Vec<Item>> for doctree::Impl<'_> {
             source: self.span.clean(cx),
             def_id: def_id.to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner: ImplItem(Impl {
                 unsafety: self.unsafety,
@@ -2205,9 +2204,14 @@ impl Clean<Vec<Item>> for doctree::ExternCrate<'_> {
 
             let res = Res::Def(DefKind::Mod, DefId { krate: self.cnum, index: CRATE_DEF_INDEX });
 
-            if let Some(items) =
-                inline::try_inline(cx, res, self.name, Some(self.attrs), &mut visited)
-            {
+            if let Some(items) = inline::try_inline(
+                cx,
+                cx.tcx.parent_module(self.hir_id).to_def_id(),
+                res,
+                self.name,
+                Some(self.attrs),
+                &mut visited,
+            ) {
                 return items;
             }
         }
@@ -2253,8 +2257,7 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
                     return items;
                 }
             }
-
-            Import::Glob(resolve_use_source(cx, path))
+            Import::new_glob(resolve_use_source(cx, path), true)
         } else {
             let name = self.name;
             if !please_inline {
@@ -2268,13 +2271,33 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
             }
             if !denied {
                 let mut visited = FxHashSet::default();
-                if let Some(items) =
-                    inline::try_inline(cx, path.res, name, Some(self.attrs), &mut visited)
-                {
+
+                if let Some(mut items) = inline::try_inline(
+                    cx,
+                    cx.tcx.parent_module(self.id).to_def_id(),
+                    path.res,
+                    name,
+                    Some(self.attrs),
+                    &mut visited,
+                ) {
+                    items.push(Item {
+                        name: None,
+                        attrs: self.attrs.clean(cx),
+                        source: self.span.clean(cx),
+                        def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
+                        visibility: self.vis.clean(cx),
+                        stability: None,
+                        deprecation: None,
+                        inner: ImportItem(Import::new_simple(
+                            self.name.clean(cx),
+                            resolve_use_source(cx, path),
+                            false,
+                        )),
+                    });
                     return items;
                 }
             }
-            Import::Simple(name.clean(cx), resolve_use_source(cx, path))
+            Import::new_simple(name.clean(cx), resolve_use_source(cx, path), true)
         };
 
         vec![Item {
@@ -2325,7 +2348,7 @@ impl Clean<Item> for doctree::ForeignItem<'_> {
             source: self.span.clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             visibility: self.vis.clean(cx),
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             inner,
         }
@@ -2340,7 +2363,7 @@ impl Clean<Item> for doctree::Macro<'_> {
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
             visibility: Public,
-            stability: cx.stability(self.hid).clean(cx),
+            stability: cx.stability(self.hid),
             deprecation: cx.deprecation(self.hid).clean(cx),
             def_id: self.def_id,
             inner: MacroItem(Macro {
@@ -2365,7 +2388,7 @@ impl Clean<Item> for doctree::ProcMacro<'_> {
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
             visibility: Public,
-            stability: cx.stability(self.id).clean(cx),
+            stability: cx.stability(self.id),
             deprecation: cx.deprecation(self.id).clean(cx),
             def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
             inner: ProcMacroItem(ProcMacro { kind: self.kind, helpers: self.helpers.clean(cx) }),
@@ -2373,27 +2396,6 @@ impl Clean<Item> for doctree::ProcMacro<'_> {
     }
 }
 
-impl Clean<Stability> for attr::Stability {
-    fn clean(&self, _: &DocContext<'_>) -> Stability {
-        Stability {
-            level: stability::StabilityLevel::from_attr_level(&self.level),
-            feature: self.feature.to_string(),
-            since: match self.level {
-                attr::Stable { ref since } => since.to_string(),
-                _ => String::new(),
-            },
-            unstable_reason: match self.level {
-                attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()),
-                _ => None,
-            },
-            issue: match self.level {
-                attr::Unstable { issue, .. } => issue,
-                _ => None,
-            },
-        }
-    }
-}
-
 impl Clean<Deprecation> for attr::Deprecation {
     fn clean(&self, _: &DocContext<'_>) -> Deprecation {
         Deprecation {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index bb6f449e355..3b72cf5c4f9 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -4,7 +4,6 @@ use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::iter::FromIterator;
 use std::lazy::SyncOnceCell as OnceCell;
-use std::num::NonZeroU32;
 use std::rc::Rc;
 use std::sync::Arc;
 use std::{slice, vec};
@@ -12,6 +11,8 @@ use std::{slice, vec};
 use rustc_ast::attr;
 use rustc_ast::util::comments::beautify_doc_string;
 use rustc_ast::{self as ast, AttrStyle};
+use rustc_ast::{FloatTy, IntTy, UintTy};
+use rustc_attr::{Stability, StabilityLevel};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -19,11 +20,10 @@ use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::Mutability;
 use rustc_index::vec::IndexVec;
-use rustc_middle::middle::stability;
 use rustc_middle::ty::{AssocKind, TyCtxt};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::DUMMY_SP;
-use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol, SymbolStr};
 use rustc_span::{self, FileName};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
@@ -177,6 +177,7 @@ impl Item {
     pub fn is_stripped(&self) -> bool {
         match self.inner {
             StrippedItem(..) => true,
+            ImportItem(ref i) => !i.should_be_displayed,
             _ => false,
         }
     }
@@ -195,7 +196,7 @@ impl Item {
         self.stability.as_ref().and_then(|ref s| {
             let mut classes = Vec::with_capacity(2);
 
-            if s.level == stability::Unstable {
+            if s.level.is_unstable() {
                 classes.push("unstable");
             }
 
@@ -208,8 +209,11 @@ impl Item {
         })
     }
 
-    pub fn stable_since(&self) -> Option<&str> {
-        self.stability.as_ref().map(|s| &s.since[..])
+    pub fn stable_since(&self) -> Option<SymbolStr> {
+        match self.stability?.level {
+            StabilityLevel::Stable { since, .. } => Some(since.as_str()),
+            StabilityLevel::Unstable { .. } => None,
+        }
     }
 
     pub fn is_non_exhaustive(&self) -> bool {
@@ -373,6 +377,11 @@ impl<I: IntoIterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I {
 pub struct DocFragment {
     pub line: usize,
     pub span: rustc_span::Span,
+    /// The module this doc-comment came from.
+    ///
+    /// This allows distinguishing between the original documentation and a pub re-export.
+    /// If it is `None`, the item was not re-exported.
+    pub parent_module: Option<DefId>,
     pub doc: String,
     pub kind: DocFragmentKind,
 }
@@ -521,57 +530,74 @@ impl Attributes {
         false
     }
 
-    pub fn from_ast(diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute]) -> Attributes {
+    pub fn from_ast(
+        diagnostic: &::rustc_errors::Handler,
+        attrs: &[ast::Attribute],
+        additional_attrs: Option<(&[ast::Attribute], DefId)>,
+    ) -> Attributes {
         let mut doc_strings = vec![];
         let mut sp = None;
         let mut cfg = Cfg::True;
         let mut doc_line = 0;
 
-        let other_attrs = attrs
-            .iter()
-            .filter_map(|attr| {
-                if let Some(value) = attr.doc_str() {
-                    let value = beautify_doc_string(value);
-                    let kind = if attr.is_doc_comment() {
-                        DocFragmentKind::SugaredDoc
-                    } else {
-                        DocFragmentKind::RawDoc
-                    };
-
-                    let line = doc_line;
-                    doc_line += value.lines().count();
-                    doc_strings.push(DocFragment { line, span: attr.span, doc: value, kind });
-
-                    if sp.is_none() {
-                        sp = Some(attr.span);
-                    }
-                    None
+        let clean_attr = |(attr, parent_module): (&ast::Attribute, _)| {
+            if let Some(value) = attr.doc_str() {
+                trace!("got doc_str={:?}", value);
+                let value = beautify_doc_string(value);
+                let kind = if attr.is_doc_comment() {
+                    DocFragmentKind::SugaredDoc
                 } else {
-                    if attr.has_name(sym::doc) {
-                        if let Some(mi) = attr.meta() {
-                            if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
-                                // Extracted #[doc(cfg(...))]
-                                match Cfg::parse(cfg_mi) {
-                                    Ok(new_cfg) => cfg &= new_cfg,
-                                    Err(e) => diagnostic.span_err(e.span, e.msg),
-                                }
-                            } else if let Some((filename, contents)) =
-                                Attributes::extract_include(&mi)
-                            {
-                                let line = doc_line;
-                                doc_line += contents.lines().count();
-                                doc_strings.push(DocFragment {
-                                    line,
-                                    span: attr.span,
-                                    doc: contents,
-                                    kind: DocFragmentKind::Include { filename },
-                                });
+                    DocFragmentKind::RawDoc
+                };
+
+                let line = doc_line;
+                doc_line += value.lines().count();
+                doc_strings.push(DocFragment {
+                    line,
+                    span: attr.span,
+                    doc: value,
+                    kind,
+                    parent_module,
+                });
+
+                if sp.is_none() {
+                    sp = Some(attr.span);
+                }
+                None
+            } else {
+                if attr.has_name(sym::doc) {
+                    if let Some(mi) = attr.meta() {
+                        if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
+                            // Extracted #[doc(cfg(...))]
+                            match Cfg::parse(cfg_mi) {
+                                Ok(new_cfg) => cfg &= new_cfg,
+                                Err(e) => diagnostic.span_err(e.span, e.msg),
                             }
+                        } else if let Some((filename, contents)) = Attributes::extract_include(&mi)
+                        {
+                            let line = doc_line;
+                            doc_line += contents.lines().count();
+                            doc_strings.push(DocFragment {
+                                line,
+                                span: attr.span,
+                                doc: contents,
+                                kind: DocFragmentKind::Include { filename },
+                                parent_module: parent_module,
+                            });
                         }
                     }
-                    Some(attr.clone())
                 }
-            })
+                Some(attr.clone())
+            }
+        };
+
+        // Additional documentation should be shown before the original documentation
+        let other_attrs = additional_attrs
+            .into_iter()
+            .map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
+            .flatten()
+            .chain(attrs.iter().map(|attr| (attr, None)))
+            .filter_map(clean_attr)
             .collect();
 
         // treat #[target_feature(enable = "feat")] attributes as if they were
@@ -1235,6 +1261,28 @@ impl GetDefId for Type {
 }
 
 impl PrimitiveType {
+    pub fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
+        match prim {
+            hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize,
+            hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8,
+            hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16,
+            hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32,
+            hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64,
+            hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128,
+            hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize,
+            hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8,
+            hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16,
+            hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
+            hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
+            hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
+            hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
+            hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
+            hir::PrimTy::Str => PrimitiveType::Str,
+            hir::PrimTy::Bool => PrimitiveType::Bool,
+            hir::PrimTy::Char => PrimitiveType::Char,
+        }
+    }
+
     pub fn from_symbol(s: Symbol) -> Option<PrimitiveType> {
         match s {
             sym::isize => Some(PrimitiveType::Isize),
@@ -1610,11 +1658,28 @@ pub struct Impl {
 }
 
 #[derive(Clone, Debug)]
-pub enum Import {
+pub struct Import {
+    pub kind: ImportKind,
+    pub source: ImportSource,
+    pub should_be_displayed: bool,
+}
+
+impl Import {
+    pub fn new_simple(name: String, source: ImportSource, should_be_displayed: bool) -> Self {
+        Self { kind: ImportKind::Simple(name), source, should_be_displayed }
+    }
+
+    pub fn new_glob(source: ImportSource, should_be_displayed: bool) -> Self {
+        Self { kind: ImportKind::Glob, source, should_be_displayed }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub enum ImportKind {
     // use source as str;
-    Simple(String, ImportSource),
+    Simple(String),
     // use source::*;
-    Glob(ImportSource),
+    Glob,
 }
 
 #[derive(Clone, Debug)]
@@ -1636,15 +1701,6 @@ pub struct ProcMacro {
 }
 
 #[derive(Clone, Debug)]
-pub struct Stability {
-    pub level: stability::StabilityLevel,
-    pub feature: String,
-    pub since: String,
-    pub unstable_reason: Option<String>,
-    pub issue: Option<NonZeroU32>,
-}
-
-#[derive(Clone, Debug)]
 pub struct Deprecation {
     pub since: Option<String>,
     pub note: Option<String>,
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 58b76d24a5b..9a7f1964a11 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -3,12 +3,13 @@ use crate::clean::blanket_impl::BlanketImplFinder;
 use crate::clean::{
     inline, Clean, Crate, Deprecation, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg,
     GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemEnum, Lifetime,
-    MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Stability, Type,
-    TypeBinding, TypeKind, Visibility, WherePredicate,
+    MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Type, TypeBinding,
+    TypeKind, Visibility, WherePredicate,
 };
 use crate::core::DocContext;
 
 use itertools::Itertools;
+use rustc_attr::Stability;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
@@ -102,14 +103,14 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate {
 
 // extract the stability index for a node from tcx, if possible
 pub fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option<Stability> {
-    cx.tcx.lookup_stability(def_id).clean(cx)
+    cx.tcx.lookup_stability(def_id).cloned()
 }
 
 pub fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option<Deprecation> {
     cx.tcx.lookup_deprecation(def_id).clean(cx)
 }
 
-pub fn external_generic_args(
+fn external_generic_args(
     cx: &DocContext<'_>,
     trait_did: Option<DefId>,
     has_self: bool,
@@ -159,7 +160,7 @@ pub fn external_generic_args(
 
 // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
 // from Fn<(A, B,), C> to Fn(A, B) -> C
-pub fn external_path(
+pub(super) fn external_path(
     cx: &DocContext<'_>,
     name: Symbol,
     trait_did: Option<DefId>,
@@ -361,7 +362,7 @@ pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut V
         let primitive = match *target {
             ResolvedPath { did, .. } if did.is_local() => continue,
             ResolvedPath { did, .. } => {
-                ret.extend(inline::build_impls(cx, did, None));
+                ret.extend(inline::build_impls(cx, None, did, None));
                 continue;
             }
             _ => match target.primitive_type() {
@@ -371,7 +372,7 @@ pub fn build_deref_target_impls(cx: &DocContext<'_>, items: &[Item], ret: &mut V
         };
         for &did in primitive.impls(tcx) {
             if !did.is_local() {
-                inline::build_impl(cx, did, None, ret);
+                inline::build_impl(cx, None, did, None, ret);
             }
         }
     }
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 391859050e8..45a84c4fb30 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -328,6 +328,7 @@ pub fn run_core(
     let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name;
     let no_crate_level_docs = rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name;
     let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name;
+    let invalid_html_tags = rustc_lint::builtin::INVALID_HTML_TAGS.name;
     let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name;
     let unknown_lints = rustc_lint::builtin::UNKNOWN_LINTS.name;
 
@@ -340,6 +341,7 @@ pub fn run_core(
         private_doc_tests.to_owned(),
         no_crate_level_docs.to_owned(),
         invalid_codeblock_attributes_name.to_owned(),
+        invalid_html_tags.to_owned(),
         renamed_and_removed_lints.to_owned(),
         unknown_lints.to_owned(),
     ];
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 7a6c9eabb5f..eb33890fb5f 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -927,7 +927,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
         sp: Span,
         nested: F,
     ) {
-        let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs);
+        let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs, None);
         if let Some(ref cfg) = attrs.cfg {
             if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) {
                 return;
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index cfa51dcf4f1..ee217d99d2c 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -8,6 +8,7 @@ use rustc_span::{self, Span, Symbol};
 
 use rustc_hir as hir;
 use rustc_hir::def_id::CrateNum;
+use rustc_hir::HirId;
 
 pub struct Module<'hir> {
     pub name: Option<Symbol>,
@@ -236,6 +237,7 @@ pub struct Macro<'hir> {
 
 pub struct ExternCrate<'hir> {
     pub name: Symbol,
+    pub hir_id: HirId,
     pub cnum: CrateNum,
     pub path: Option<String>,
     pub vis: &'hir hir::Visibility<'hir>,
@@ -243,6 +245,7 @@ pub struct ExternCrate<'hir> {
     pub span: Span,
 }
 
+#[derive(Debug)]
 pub struct Import<'hir> {
     pub name: Symbol,
     pub id: hir::HirId,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 2da9c68b196..d18282d6e67 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1149,19 +1149,19 @@ impl PrintWithSpace for hir::Mutability {
 
 impl clean::Import {
     crate fn print(&self) -> impl fmt::Display + '_ {
-        display_fn(move |f| match *self {
-            clean::Import::Simple(ref name, ref src) => {
-                if *name == src.path.last_name() {
-                    write!(f, "use {};", src.print())
+        display_fn(move |f| match self.kind {
+            clean::ImportKind::Simple(ref name) => {
+                if *name == self.source.path.last_name() {
+                    write!(f, "use {};", self.source.print())
                 } else {
-                    write!(f, "use {} as {};", src.print(), *name)
+                    write!(f, "use {} as {};", self.source.print(), *name)
                 }
             }
-            clean::Import::Glob(ref src) => {
-                if src.path.segments.is_empty() {
+            clean::ImportKind::Glob => {
+                if self.source.path.segments.is_empty() {
                     write!(f, "use *;")
                 } else {
-                    write!(f, "use {}::*;", src.print())
+                    write!(f, "use {}::*;", self.source.print())
                 }
             }
         })
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 6c0f1c02ac6..2fd06d7e573 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -43,7 +43,7 @@ use pulldown_cmark::{html, BrokenLink, CodeBlockKind, CowStr, Event, Options, Pa
 #[cfg(test)]
 mod tests;
 
-fn opts() -> Options {
+pub(crate) fn opts() -> Options {
     Options::ENABLE_TABLES | Options::ENABLE_FOOTNOTES | Options::ENABLE_STRIKETHROUGH
 }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index afd1dc59642..22ae7af617f 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -49,6 +49,7 @@ use std::sync::Arc;
 
 use itertools::Itertools;
 use rustc_ast_pretty::pprust;
+use rustc_attr::StabilityLevel;
 use rustc_data_structures::flock;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_feature::UnstableFeatures;
@@ -1762,11 +1763,11 @@ crate fn shorten(s: String) -> String {
     }
 }
 
-fn document(w: &mut Buffer, cx: &Context, item: &clean::Item) {
+fn document(w: &mut Buffer, cx: &Context, item: &clean::Item, parent: Option<&clean::Item>) {
     if let Some(ref name) = item.name {
         info!("Documenting {}", name);
     }
-    document_stability(w, cx, item, false);
+    document_stability(w, cx, item, false, parent);
     document_full(w, item, cx, "", false);
 }
 
@@ -1850,8 +1851,14 @@ fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context, prefix: &str,
     }
 }
 
-fn document_stability(w: &mut Buffer, cx: &Context, item: &clean::Item, is_hidden: bool) {
-    let stabilities = short_stability(item, cx);
+fn document_stability(
+    w: &mut Buffer,
+    cx: &Context,
+    item: &clean::Item,
+    is_hidden: bool,
+    parent: Option<&clean::Item>,
+) {
+    let stabilities = short_stability(item, cx, parent);
     if !stabilities.is_empty() {
         write!(w, "<div class='stability{}'>", if is_hidden { " hidden" } else { "" });
         for stability in stabilities {
@@ -1951,7 +1958,7 @@ pub fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering {
 }
 
 fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean::Item]) {
-    document(w, cx, item);
+    document(w, cx, item, None);
 
     let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::<Vec<usize>>();
 
@@ -1983,10 +1990,12 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
         }
         let s1 = i1.stability.as_ref().map(|s| s.level);
         let s2 = i2.stability.as_ref().map(|s| s.level);
-        match (s1, s2) {
-            (Some(stability::Unstable), Some(stability::Stable)) => return Ordering::Greater,
-            (Some(stability::Stable), Some(stability::Unstable)) => return Ordering::Less,
-            _ => {}
+        if let (Some(a), Some(b)) = (s1, s2) {
+            match (a.is_stable(), b.is_stable()) {
+                (true, true) | (false, false) => {}
+                (false, true) => return Ordering::Less,
+                (true, false) => return Ordering::Greater,
+            }
         }
         let lhs = i1.name.as_ref().map_or("", |s| &**s);
         let rhs = i2.name.as_ref().map_or("", |s| &**s);
@@ -2108,7 +2117,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
                          <td class='docblock-short'>{stab_tags}{docs}</td>\
                      </tr>",
                     name = *myitem.name.as_ref().unwrap(),
-                    stab_tags = stability_tags(myitem),
+                    stab_tags = stability_tags(myitem, item),
                     docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(),
                     class = myitem.type_(),
                     add = add,
@@ -2132,7 +2141,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
 
 /// Render the stability and deprecation tags that are displayed in the item's summary at the
 /// module level.
-fn stability_tags(item: &clean::Item) -> String {
+fn stability_tags(item: &clean::Item, parent: &clean::Item) -> String {
     let mut tags = String::new();
 
     fn tag_html(class: &str, title: &str, contents: &str) -> String {
@@ -2150,16 +2159,19 @@ fn stability_tags(item: &clean::Item) -> String {
 
     // The "rustc_private" crates are permanently unstable so it makes no sense
     // to render "unstable" everywhere.
-    if item
-        .stability
-        .as_ref()
-        .map(|s| s.level == stability::Unstable && s.feature != "rustc_private")
+    if item.stability.as_ref().map(|s| s.level.is_unstable() && s.feature != sym::rustc_private)
         == Some(true)
     {
         tags += &tag_html("unstable", "", "Experimental");
     }
 
-    if let Some(ref cfg) = item.attrs.cfg {
+    let cfg = match (&item.attrs.cfg, parent.attrs.cfg.as_ref()) {
+        (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
+        (cfg, _) => cfg.as_deref().cloned(),
+    };
+
+    debug!("Portability {:?} - {:?} = {:?}", item.attrs.cfg, parent.attrs.cfg, cfg);
+    if let Some(ref cfg) = cfg {
         tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html());
     }
 
@@ -2168,7 +2180,7 @@ fn stability_tags(item: &clean::Item) -> String {
 
 /// Render the stability and/or deprecation warning that is displayed at the top of the item's
 /// documentation.
-fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
+fn short_stability(item: &clean::Item, cx: &Context, parent: Option<&clean::Item>) -> Vec<String> {
     let mut stability = vec![];
     let error_codes = cx.shared.codes;
 
@@ -2204,16 +2216,17 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
 
     // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
     // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
-    if let Some(stab) = item
+    if let Some((StabilityLevel::Unstable { reason, issue, .. }, feature)) = item
         .stability
         .as_ref()
-        .filter(|stab| stab.level == stability::Unstable && stab.feature != "rustc_private")
+        .filter(|stab| stab.feature != sym::rustc_private)
+        .map(|stab| (stab.level, stab.feature))
     {
         let mut message =
             "<span class='emoji'>🔬</span> This is a nightly-only experimental API.".to_owned();
 
-        let mut feature = format!("<code>{}</code>", Escape(&stab.feature));
-        if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, stab.issue) {
+        let mut feature = format!("<code>{}</code>", Escape(&feature.as_str()));
+        if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) {
             feature.push_str(&format!(
                 "&nbsp;<a href=\"{url}{issue}\">#{issue}</a>",
                 url = url,
@@ -2223,13 +2236,13 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
 
         message.push_str(&format!(" ({})", feature));
 
-        if let Some(unstable_reason) = &stab.unstable_reason {
+        if let Some(unstable_reason) = reason {
             let mut ids = cx.id_map.borrow_mut();
             message = format!(
                 "<details><summary>{}</summary>{}</details>",
                 message,
                 MarkdownHtml(
-                    &unstable_reason,
+                    &unstable_reason.as_str(),
                     &mut ids,
                     error_codes,
                     cx.shared.edition,
@@ -2242,7 +2255,18 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
         stability.push(format!("<div class='stab unstable'>{}</div>", message));
     }
 
-    if let Some(ref cfg) = item.attrs.cfg {
+    let cfg = match (&item.attrs.cfg, parent.and_then(|p| p.attrs.cfg.as_ref())) {
+        (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
+        (cfg, _) => cfg.as_deref().cloned(),
+    };
+
+    debug!(
+        "Portability {:?} - {:?} = {:?}",
+        item.attrs.cfg,
+        parent.and_then(|p| p.attrs.cfg.as_ref()),
+        cfg
+    );
+    if let Some(cfg) = cfg {
         stability.push(format!("<div class='stab portability'>{}</div>", cfg.render_long_html()));
     }
 
@@ -2281,7 +2305,7 @@ fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Cons
     }
 
     write!(w, "</pre>");
-    document(w, cx, it)
+    document(w, cx, it, None)
 }
 
 fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static) {
@@ -2295,7 +2319,7 @@ fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static
         name = it.name.as_ref().unwrap(),
         typ = s.type_.print()
     );
-    document(w, cx, it)
+    document(w, cx, it, None)
 }
 
 fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Function) {
@@ -2328,7 +2352,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func
             .print(),
         spotlight = spotlight_decl(&f.decl),
     );
-    document(w, cx, it)
+    document(w, cx, it, None)
 }
 
 fn render_implementor(
@@ -2353,9 +2377,10 @@ fn render_implementor(
         w,
         cx,
         implementor,
+        None,
         AssocItemLink::Anchor(None),
         RenderMode::Normal,
-        implementor.impl_item.stable_since(),
+        implementor.impl_item.stable_since().as_deref(),
         false,
         Some(use_absolute),
         false,
@@ -2382,9 +2407,10 @@ fn render_impls(
                 &mut buffer,
                 cx,
                 i,
+                Some(containing_item),
                 assoc_link,
                 RenderMode::Normal,
-                containing_item.stable_since(),
+                containing_item.stable_since().as_deref(),
                 true,
                 None,
                 false,
@@ -2501,7 +2527,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait,
     });
 
     // Trait documentation
-    document(w, cx, it);
+    document(w, cx, it, None);
 
     fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) {
         write!(
@@ -2519,6 +2545,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait,
 
     fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item) {
         let name = m.name.as_ref().unwrap();
+        info!("Documenting {} on {}", name, t.name.as_deref().unwrap_or_default());
         let item_type = m.type_();
         let id = cx.derive_id(format!("{}.{}", item_type, name));
         write!(w, "<h3 id='{id}' class='method'><code>", id = id,);
@@ -2526,7 +2553,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait,
         write!(w, "</code>");
         render_stability_since(w, m, t);
         write!(w, "</h3>");
-        document(w, cx, m);
+        document(w, cx, m, Some(t));
     }
 
     if !types.is_empty() {
@@ -2627,9 +2654,10 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait,
                     w,
                     cx,
                     &implementor,
+                    None,
                     assoc_link,
                     RenderMode::Normal,
-                    implementor.impl_item.stable_since(),
+                    implementor.impl_item.stable_since().as_deref(),
                     false,
                     None,
                     true,
@@ -2780,7 +2808,11 @@ fn render_stability_since_raw(w: &mut Buffer, ver: Option<&str>, containing_ver:
 }
 
 fn render_stability_since(w: &mut Buffer, item: &clean::Item, containing_item: &clean::Item) {
-    render_stability_since_raw(w, item.stable_since(), containing_item.stable_since())
+    render_stability_since_raw(
+        w,
+        item.stable_since().as_deref(),
+        containing_item.stable_since().as_deref(),
+    )
 }
 
 fn render_assoc_item(
@@ -2885,7 +2917,7 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct
         write!(w, "</pre>")
     });
 
-    document(w, cx, it);
+    document(w, cx, it, None);
     let mut fields = s
         .fields
         .iter()
@@ -2920,7 +2952,7 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct
                     name = field.name.as_ref().unwrap(),
                     ty = ty.print()
                 );
-                document(w, cx, field);
+                document(w, cx, field, Some(it));
             }
         }
     }
@@ -2935,7 +2967,7 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union,
         write!(w, "</pre>")
     });
 
-    document(w, cx, it);
+    document(w, cx, it, None);
     let mut fields = s
         .fields
         .iter()
@@ -2967,7 +2999,7 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union,
             if let Some(stability_class) = field.stability_class() {
                 write!(w, "<span class='stab {stab}'></span>", stab = stability_class);
             }
-            document(w, cx, field);
+            document(w, cx, field, Some(it));
         }
     }
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
@@ -3022,7 +3054,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca
         write!(w, "</pre>")
     });
 
-    document(w, cx, it);
+    document(w, cx, it, None);
     if !e.variants.is_empty() {
         write!(
             w,
@@ -3055,7 +3087,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca
                 }
             }
             write!(w, "</code></div>");
-            document(w, cx, variant);
+            document(w, cx, variant, Some(it));
             document_non_exhaustive(w, variant);
 
             use crate::clean::{Variant, VariantKind};
@@ -3090,7 +3122,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca
                             f = field.name.as_ref().unwrap(),
                             t = ty.print()
                         );
-                        document(w, cx, field);
+                        document(w, cx, field, Some(variant));
                     }
                 }
                 write!(w, "</div></div>");
@@ -3288,6 +3320,10 @@ fn render_assoc_items(
     what: AssocItemRender<'_>,
     cache: &Cache,
 ) {
+    info!(
+        "Documenting associated items of {}",
+        containing_item.name.as_deref().unwrap_or_default()
+    );
     let v = match cache.impls.get(&it) {
         Some(v) => v,
         None => return,
@@ -3322,9 +3358,10 @@ fn render_assoc_items(
                 w,
                 cx,
                 i,
+                Some(containing_item),
                 AssocItemLink::Anchor(None),
                 render_mode,
-                containing_item.stable_since(),
+                containing_item.stable_since().as_deref(),
                 true,
                 None,
                 false,
@@ -3513,6 +3550,7 @@ fn render_impl(
     w: &mut Buffer,
     cx: &Context,
     i: &Impl,
+    parent: Option<&clean::Item>,
     link: AssocItemLink<'_>,
     render_mode: RenderMode,
     outer_version: Option<&str>,
@@ -3564,8 +3602,11 @@ fn render_impl(
             );
         }
         write!(w, "<a href='#{}' class='anchor'></a>", id);
-        let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]);
-        render_stability_since_raw(w, since, outer_version);
+        let since = i.impl_item.stability.as_ref().and_then(|s| match s.level {
+            StabilityLevel::Stable { since } => Some(since.as_str()),
+            StabilityLevel::Unstable { .. } => None,
+        });
+        render_stability_since_raw(w, since.as_deref(), outer_version);
         if let Some(l) = cx.src_href(&i.impl_item, cache) {
             write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>", l, "goto source code");
         }
@@ -3592,6 +3633,7 @@ fn render_impl(
         w: &mut Buffer,
         cx: &Context,
         item: &clean::Item,
+        parent: Option<&clean::Item>,
         link: AssocItemLink<'_>,
         render_mode: RenderMode,
         is_default_item: bool,
@@ -3626,7 +3668,7 @@ fn render_impl(
                     write!(w, "<code>");
                     render_assoc_item(w, item, link.anchor(&id), ItemType::Impl);
                     write!(w, "</code>");
-                    render_stability_since_raw(w, item.stable_since(), outer_version);
+                    render_stability_since_raw(w, item.stable_since().as_deref(), outer_version);
                     if let Some(l) = cx.src_href(item, cache) {
                         write!(
                             w,
@@ -3648,7 +3690,7 @@ fn render_impl(
                 write!(w, "<h4 id='{}' class=\"{}{}\"><code>", id, item_type, extra_class);
                 assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "");
                 write!(w, "</code>");
-                render_stability_since_raw(w, item.stable_since(), outer_version);
+                render_stability_since_raw(w, item.stable_since().as_deref(), outer_version);
                 if let Some(l) = cx.src_href(item, cache) {
                     write!(
                         w,
@@ -3676,7 +3718,7 @@ fn render_impl(
                     if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
                         // We need the stability of the item from the trait
                         // because impls can't have a stability.
-                        document_stability(w, cx, it, is_hidden);
+                        document_stability(w, cx, it, is_hidden, parent);
                         if item.doc_value().is_some() {
                             document_full(w, item, cx, "", is_hidden);
                         } else if show_def_docs {
@@ -3686,13 +3728,13 @@ fn render_impl(
                         }
                     }
                 } else {
-                    document_stability(w, cx, item, is_hidden);
+                    document_stability(w, cx, item, is_hidden, parent);
                     if show_def_docs {
                         document_full(w, item, cx, "", is_hidden);
                     }
                 }
             } else {
-                document_stability(w, cx, item, is_hidden);
+                document_stability(w, cx, item, is_hidden, parent);
                 if show_def_docs {
                     document_short(w, item, link, "", is_hidden);
                 }
@@ -3709,6 +3751,7 @@ fn render_impl(
             w,
             cx,
             trait_item,
+            parent,
             link,
             render_mode,
             false,
@@ -3724,6 +3767,7 @@ fn render_impl(
         cx: &Context,
         t: &clean::Trait,
         i: &clean::Impl,
+        parent: Option<&clean::Item>,
         render_mode: RenderMode,
         outer_version: Option<&str>,
         show_def_docs: bool,
@@ -3741,6 +3785,7 @@ fn render_impl(
                 w,
                 cx,
                 trait_item,
+                parent,
                 assoc_link,
                 render_mode,
                 true,
@@ -3763,6 +3808,7 @@ fn render_impl(
                 cx,
                 t,
                 &i.inner_impl(),
+                parent,
                 render_mode,
                 outer_version,
                 show_def_docs,
@@ -3791,7 +3837,7 @@ fn item_opaque_ty(
         bounds = bounds(&t.bounds, false)
     );
 
-    document(w, cx, it);
+    document(w, cx, it, None);
 
     // Render any items associated directly to this alias, as otherwise they
     // won't be visible anywhere in the docs. It would be nice to also show
@@ -3818,7 +3864,7 @@ fn item_trait_alias(
         bounds(&t.bounds, true)
     );
 
-    document(w, cx, it);
+    document(w, cx, it, None);
 
     // Render any items associated directly to this alias, as otherwise they
     // won't be visible anywhere in the docs. It would be nice to also show
@@ -3839,7 +3885,7 @@ fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typed
         type_ = t.type_.print()
     );
 
-    document(w, cx, it);
+    document(w, cx, it, None);
 
     // Render any items associated directly to this alias, as otherwise they
     // won't be visible anywhere in the docs. It would be nice to also show
@@ -3858,7 +3904,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cac
         it.name.as_ref().unwrap(),
     );
 
-    document(w, cx, it);
+    document(w, cx, it, None);
 
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
 }
@@ -4438,8 +4484,9 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
 fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
     let mut sidebar = String::new();
 
-    if items.iter().any(|it| it.type_() == ItemType::ExternCrate || it.type_() == ItemType::Import)
-    {
+    if items.iter().any(|it| {
+        it.type_() == ItemType::ExternCrate || (it.type_() == ItemType::Import && !it.is_stripped())
+    }) {
         sidebar.push_str(&format!(
             "<li><a href=\"#{id}\">{name}</a></li>",
             id = "reexports",
@@ -4502,7 +4549,7 @@ fn item_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Macro)
             None,
         ))
     });
-    document(w, cx, it)
+    document(w, cx, it, None)
 }
 
 fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) {
@@ -4532,16 +4579,16 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::Pr
             write!(w, "</pre>");
         }
     }
-    document(w, cx, it)
+    document(w, cx, it, None)
 }
 
 fn item_primitive(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cache) {
-    document(w, cx, it);
+    document(w, cx, it, None);
     render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache)
 }
 
 fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item) {
-    document(w, cx, it)
+    document(w, cx, it, None)
 }
 
 crate const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang";
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 3f4bd2886b1..a163899839d 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -390,17 +390,13 @@ nav.sub {
 	cursor: pointer;
 }
 
+.docblock-short {
+	overflow-wrap: anywhere;
+}
 .docblock-short p {
 	display: inline;
 }
 
-.docblock-short.nowrap {
-	display: block;
-	overflow: hidden;
-	white-space: nowrap;
-	text-overflow: ellipsis;
-}
-
 .docblock-short p {
 	overflow: hidden;
 	text-overflow: ellipsis;
@@ -1098,6 +1094,10 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
 	border-style: solid;
 }
 
+.tooltip:hover .tooltiptext {
+	display: inline;
+}
+
 .tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore {
 	font-weight: bold;
 	font-size: 20px;
@@ -1540,6 +1540,14 @@ h4 > .notable-traits {
 		left: 0;
 		top: 100%;
 	}
+
+	/* We don't display the help button on mobile devices. */
+	.help-button {
+		display: none;
+	}
+	.search-container > div {
+		width: calc(100% - 32px);
+	}
 }
 
 @media print {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 7762e8f8d4f..12726d2bd9a 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -3,11 +3,13 @@
     html_playground_url = "https://play.rust-lang.org/"
 )]
 #![feature(rustc_private)]
+#![feature(array_methods)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
 #![feature(or_patterns)]
+#![feature(peekable_next_if)]
 #![feature(test)]
 #![feature(crate_visibility_modifier)]
 #![feature(never_type)]
diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs
index 4bca3996eb4..ced26fcf5b0 100644
--- a/src/librustdoc/passes/calculate_doc_coverage.rs
+++ b/src/librustdoc/passes/calculate_doc_coverage.rs
@@ -1,10 +1,12 @@
 use crate::clean;
-use crate::config::OutputFormat;
 use crate::core::DocContext;
 use crate::fold::{self, DocFolder};
 use crate::html::markdown::{find_testable_code, ErrorCodes};
 use crate::passes::doc_test_lints::{should_have_doc_example, Tests};
 use crate::passes::Pass;
+use rustc_lint::builtin::MISSING_DOCS;
+use rustc_middle::lint::LintSource;
+use rustc_session::lint;
 use rustc_span::symbol::sym;
 use rustc_span::FileName;
 use serde::Serialize;
@@ -19,10 +21,10 @@ pub const CALCULATE_DOC_COVERAGE: Pass = Pass {
 };
 
 fn calculate_doc_coverage(krate: clean::Crate, ctx: &DocContext<'_>) -> clean::Crate {
-    let mut calc = CoverageCalculator::new();
+    let mut calc = CoverageCalculator::new(ctx);
     let krate = calc.fold_crate(krate);
 
-    calc.print_results(ctx.renderinfo.borrow().output_format);
+    calc.print_results();
 
     krate
 }
@@ -41,8 +43,11 @@ impl ItemCount {
         has_docs: bool,
         has_doc_example: bool,
         should_have_doc_examples: bool,
+        should_have_docs: bool,
     ) {
-        self.total += 1;
+        if has_docs || should_have_docs {
+            self.total += 1;
+        }
 
         if has_docs {
             self.with_docs += 1;
@@ -94,8 +99,9 @@ impl ops::AddAssign for ItemCount {
     }
 }
 
-struct CoverageCalculator {
+struct CoverageCalculator<'a, 'b> {
     items: BTreeMap<FileName, ItemCount>,
+    ctx: &'a DocContext<'b>,
 }
 
 fn limit_filename_len(filename: String) -> String {
@@ -108,9 +114,9 @@ fn limit_filename_len(filename: String) -> String {
     }
 }
 
-impl CoverageCalculator {
-    fn new() -> CoverageCalculator {
-        CoverageCalculator { items: Default::default() }
+impl<'a, 'b> CoverageCalculator<'a, 'b> {
+    fn new(ctx: &'a DocContext<'b>) -> CoverageCalculator<'a, 'b> {
+        CoverageCalculator { items: Default::default(), ctx }
     }
 
     fn to_json(&self) -> String {
@@ -124,7 +130,8 @@ impl CoverageCalculator {
         .expect("failed to convert JSON data to string")
     }
 
-    fn print_results(&self, output_format: Option<OutputFormat>) {
+    fn print_results(&self) {
+        let output_format = self.ctx.renderinfo.borrow().output_format;
         if output_format.map(|o| o.is_json()).unwrap_or_else(|| false) {
             println!("{}", self.to_json());
             return;
@@ -178,7 +185,7 @@ impl CoverageCalculator {
     }
 }
 
-impl fold::DocFolder for CoverageCalculator {
+impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
     fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
         match i.inner {
             _ if !i.def_id.is_local() => {
@@ -245,11 +252,18 @@ impl fold::DocFolder for CoverageCalculator {
                 );
 
                 let has_doc_example = tests.found_tests != 0;
+                let hir_id = self.ctx.tcx.hir().local_def_id_to_hir_id(i.def_id.expect_local());
+                let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id);
+                // `missing_docs` is allow-by-default, so don't treat this as ignoring the item
+                // unless the user had an explicit `allow`
+                let should_have_docs =
+                    level != lint::Level::Allow || matches!(source, LintSource::Default);
                 debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename);
                 self.items.entry(i.source.filename.clone()).or_default().count_item(
                     has_docs,
                     has_doc_example,
-                    should_have_doc_example(&i.inner),
+                    should_have_doc_example(self.ctx, &i),
+                    should_have_docs,
                 );
             }
         }
diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs
index be7250f833f..c2f7f97a673 100644
--- a/src/librustdoc/passes/collapse_docs.rs
+++ b/src/librustdoc/passes/collapse_docs.rs
@@ -36,7 +36,10 @@ fn collapse(doc_strings: &mut Vec<DocFragment>) {
             let curr_kind = &curr_frag.kind;
             let new_kind = &frag.kind;
 
-            if matches!(*curr_kind, DocFragmentKind::Include { .. }) || curr_kind != new_kind {
+            if matches!(*curr_kind, DocFragmentKind::Include { .. })
+                || curr_kind != new_kind
+                || curr_frag.parent_module != frag.parent_module
+            {
                 if *curr_kind == DocFragmentKind::SugaredDoc
                     || *curr_kind == DocFragmentKind::RawDoc
                 {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index f234dc5c03b..8be9482acff 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -8,7 +8,7 @@ use rustc_hir::def::{
     Namespace::{self, *},
     PerNS, Res,
 };
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{CrateNum, DefId};
 use rustc_middle::ty;
 use rustc_resolve::ParentScope;
 use rustc_session::lint::{
@@ -16,6 +16,7 @@ use rustc_session::lint::{
     Lint,
 };
 use rustc_span::hygiene::MacroKind;
+use rustc_span::symbol::sym;
 use rustc_span::symbol::Ident;
 use rustc_span::symbol::Symbol;
 use rustc_span::DUMMY_SP;
@@ -23,6 +24,7 @@ use smallvec::{smallvec, SmallVec};
 
 use std::borrow::Cow;
 use std::cell::Cell;
+use std::mem;
 use std::ops::Range;
 
 use crate::clean::*;
@@ -65,10 +67,53 @@ enum ResolutionFailure<'a> {
     NotResolved { module_id: DefId, partial_res: Option<Res>, unresolved: Cow<'a, str> },
     /// should not ever happen
     NoParentItem,
+    /// This link has malformed generic parameters; e.g., the angle brackets are unbalanced.
+    MalformedGenerics(MalformedGenerics),
     /// used to communicate that this should be ignored, but shouldn't be reported to the user
     Dummy,
 }
 
+#[derive(Debug)]
+enum MalformedGenerics {
+    /// This link has unbalanced angle brackets.
+    ///
+    /// For example, `Vec<T` should trigger this, as should `Vec<T>>`.
+    UnbalancedAngleBrackets,
+    /// The generics are not attached to a type.
+    ///
+    /// For example, `<T>` should trigger this.
+    ///
+    /// This is detected by checking if the path is empty after the generics are stripped.
+    MissingType,
+    /// The link uses fully-qualified syntax, which is currently unsupported.
+    ///
+    /// For example, `<Vec as IntoIterator>::into_iter` should trigger this.
+    ///
+    /// This is detected by checking if ` as ` (the keyword `as` with spaces around it) is inside
+    /// angle brackets.
+    HasFullyQualifiedSyntax,
+    /// The link has an invalid path separator.
+    ///
+    /// For example, `Vec:<T>:new()` should trigger this. Note that `Vec:new()` will **not**
+    /// trigger this because it has no generics and thus [`strip_generics_from_path`] will not be
+    /// called.
+    ///
+    /// Note that this will also **not** be triggered if the invalid path separator is inside angle
+    /// brackets because rustdoc mostly ignores what's inside angle brackets (except for
+    /// [`HasFullyQualifiedSyntax`](MalformedGenerics::HasFullyQualifiedSyntax)).
+    ///
+    /// This is detected by checking if there is a colon followed by a non-colon in the link.
+    InvalidPathSeparator,
+    /// The link has too many angle brackets.
+    ///
+    /// For example, `Vec<<T>>` should trigger this.
+    TooManyAngleBrackets,
+    /// The link has empty angle brackets.
+    ///
+    /// For example, `Vec<>` should trigger this.
+    EmptyAngleBrackets,
+}
+
 impl ResolutionFailure<'a> {
     // This resolved fully (not just partially) but is erroneous for some other reason
     fn full_res(&self) -> Option<Res> {
@@ -190,6 +235,56 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         }
     }
 
+    fn resolve_primitive_associated_item(
+        &self,
+        prim_ty: hir::PrimTy,
+        ns: Namespace,
+        module_id: DefId,
+        item_name: Symbol,
+        item_str: &'path str,
+    ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
+        let cx = self.cx;
+
+        PrimitiveType::from_hir(prim_ty)
+            .impls(cx.tcx)
+            .into_iter()
+            .find_map(|&impl_| {
+                cx.tcx
+                    .associated_items(impl_)
+                    .find_by_name_and_namespace(
+                        cx.tcx,
+                        Ident::with_dummy_span(item_name),
+                        ns,
+                        impl_,
+                    )
+                    .map(|item| match item.kind {
+                        ty::AssocKind::Fn => "method",
+                        ty::AssocKind::Const => "associatedconstant",
+                        ty::AssocKind::Type => "associatedtype",
+                    })
+                    .map(|out| {
+                        (
+                            Res::PrimTy(prim_ty),
+                            Some(format!("{}#{}.{}", prim_ty.name(), out, item_str)),
+                        )
+                    })
+            })
+            .ok_or_else(|| {
+                debug!(
+                    "returning primitive error for {}::{} in {} namespace",
+                    prim_ty.name(),
+                    item_name,
+                    ns.descr()
+                );
+                ResolutionFailure::NotResolved {
+                    module_id,
+                    partial_res: Some(Res::PrimTy(prim_ty)),
+                    unresolved: item_str.into(),
+                }
+                .into()
+            })
+    }
+
     /// Resolves a string as a macro.
     fn macro_resolve(
         &self,
@@ -231,6 +326,19 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         })
     }
 
+    fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option<Res> {
+        let result = self.cx.enter_resolver(|resolver| {
+            resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
+        });
+        debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
+        match result.map(|(_, res)| res) {
+            // resolver doesn't know about true and false so we'll have to resolve them
+            // manually as bool
+            Ok(Res::Err) | Err(()) => is_bool_value(path_str, ns).map(|(_, res)| res),
+            Ok(res) => Some(res.map_id(|_| panic!("unexpected node_id"))),
+        }
+    }
+
     /// Resolves a string as a path within a particular namespace. Also returns an optional
     /// URL fragment in the case of variants and methods.
     fn resolve<'path>(
@@ -243,22 +351,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     ) -> Result<(Res, Option<String>), ErrorKind<'path>> {
         let cx = self.cx;
 
-        let result = cx.enter_resolver(|resolver| {
-            resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
-        });
-        debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
-        let result = match result {
-            Ok((_, Res::Err)) => Err(()),
-            x => x,
-        };
-
-        if let Ok((_, res)) = result {
-            let res = res.map_id(|_| panic!("unexpected node_id"));
-            // In case this is a trait item, skip the
-            // early return and try looking for the trait.
-            let value = match res {
-                Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true,
-                Res::Def(DefKind::AssocTy, _) => false,
+        if let Some(res) = self.resolve_path(path_str, ns, module_id) {
+            match res {
+                Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => {
+                    assert_eq!(ns, ValueNS);
+                    // Fall through: In case this is a trait item, skip the
+                    // early return and try looking for the trait.
+                }
+                Res::Def(DefKind::AssocTy, _) => {
+                    assert_eq!(ns, TypeNS);
+                    // Fall through: In case this is a trait item, skip the
+                    // early return and try looking for the trait.
+                }
                 Res::Def(DefKind::Variant, _) => {
                     return handle_variant(cx, res, extra_fragment);
                 }
@@ -277,17 +381,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 _ => {
                     return Ok((res, extra_fragment.clone()));
                 }
-            };
-
-            if value != (ns == ValueNS) {
-                return Err(ResolutionFailure::WrongNamespace(res, ns).into());
-            }
-        // FIXME: why is this necessary?
-        } else if let Some((path, prim)) = is_primitive(path_str, ns) {
-            if extra_fragment.is_some() {
-                return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(prim)));
             }
-            return Ok((prim, Some(path.to_owned())));
         }
 
         // Try looking for methods and associated items.
@@ -315,70 +409,30 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                 }
             })?;
 
-        if let Some((path, prim)) = is_primitive(&path_root, TypeNS) {
-            let impls =
-                primitive_impl(cx, &path).ok_or_else(|| ResolutionFailure::NotResolved {
+        // FIXME: are these both necessary?
+        let ty_res = if let Some(ty_res) = is_primitive(&path_root, TypeNS)
+            .map(|(_, res)| res)
+            .or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
+        {
+            ty_res
+        } else {
+            // FIXME: this is duplicated on the end of this function.
+            return if ns == Namespace::ValueNS {
+                self.variant_field(path_str, current_item, module_id)
+            } else {
+                Err(ResolutionFailure::NotResolved {
                     module_id,
-                    partial_res: Some(prim),
-                    unresolved: item_str.into(),
-                })?;
-            for &impl_ in impls {
-                let link = cx
-                    .tcx
-                    .associated_items(impl_)
-                    .find_by_name_and_namespace(
-                        cx.tcx,
-                        Ident::with_dummy_span(item_name),
-                        ns,
-                        impl_,
-                    )
-                    .map(|item| match item.kind {
-                        ty::AssocKind::Fn => "method",
-                        ty::AssocKind::Const => "associatedconstant",
-                        ty::AssocKind::Type => "associatedtype",
-                    })
-                    .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_str))));
-                if let Some(link) = link {
-                    return Ok(link);
+                    partial_res: None,
+                    unresolved: path_root.into(),
                 }
-            }
-            debug!(
-                "returning primitive error for {}::{} in {} namespace",
-                path,
-                item_name,
-                ns.descr()
-            );
-            return Err(ResolutionFailure::NotResolved {
-                module_id,
-                partial_res: Some(prim),
-                unresolved: item_str.into(),
-            }
-            .into());
-        }
-
-        let ty_res = cx
-            .enter_resolver(|resolver| {
-                // only types can have associated items
-                resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id)
-            })
-            .map(|(_, res)| res);
-        let ty_res = match ty_res {
-            Err(()) | Ok(Res::Err) => {
-                return if ns == Namespace::ValueNS {
-                    self.variant_field(path_str, current_item, module_id)
-                } else {
-                    Err(ResolutionFailure::NotResolved {
-                        module_id,
-                        partial_res: None,
-                        unresolved: path_root.into(),
-                    }
-                    .into())
-                };
-            }
-            Ok(res) => res,
+                .into())
+            };
         };
-        let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
+
         let res = match ty_res {
+            Res::PrimTy(prim) => Some(
+                self.resolve_primitive_associated_item(prim, ns, module_id, item_name, item_str),
+            ),
             Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did) => {
                 debug!("looking for associated item named {} for item {:?}", item_name, did);
                 // Checks if item_name belongs to `impl SomeItem`
@@ -418,7 +472,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     Some(if extra_fragment.is_some() {
                         Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
                     } else {
-                        // HACK(jynelson): `clean` expects the type, not the associated item.
+                        // HACK(jynelson): `clean` expects the type, not the associated item
                         // but the disambiguator logic expects the associated item.
                         // Store the kind in a side channel so that only the disambiguator logic looks at it.
                         self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
@@ -464,13 +518,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                         _ => None,
                     }
                 } else {
-                    // We already know this isn't in ValueNS, so no need to check variant_field
-                    return Err(ResolutionFailure::NotResolved {
-                        module_id,
-                        partial_res: Some(ty_res),
-                        unresolved: item_str.into(),
-                    }
-                    .into());
+                    None
                 }
             }
             Res::Def(DefKind::Trait, did) => cx
@@ -527,30 +575,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
         current_item: &Option<String>,
         extra_fragment: &Option<String>,
     ) -> Option<Res> {
-        let check_full_res_inner = |this: &Self, result: Result<Res, ErrorKind<'_>>| {
-            let res = match result {
-                Ok(res) => Some(res),
-                Err(ErrorKind::Resolve(box kind)) => kind.full_res(),
-                Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => {
-                    Some(res)
-                }
-                Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None,
-            };
-            this.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res)
-        };
-        // cannot be used for macro namespace
-        let check_full_res = |this: &Self, ns| {
-            let result = this.resolve(path_str, ns, current_item, module_id, extra_fragment);
-            check_full_res_inner(this, result.map(|(res, _)| res))
+        // resolve() can't be used for macro namespace
+        let result = match ns {
+            Namespace::MacroNS => self.macro_resolve(path_str, module_id).map_err(ErrorKind::from),
+            Namespace::TypeNS | Namespace::ValueNS => self
+                .resolve(path_str, ns, current_item, module_id, extra_fragment)
+                .map(|(res, _)| res),
         };
-        let check_full_res_macro = |this: &Self| {
-            let result = this.macro_resolve(path_str, module_id);
-            check_full_res_inner(this, result.map_err(ErrorKind::from))
+
+        let res = match result {
+            Ok(res) => Some(res),
+            Err(ErrorKind::Resolve(box kind)) => kind.full_res(),
+            Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => Some(res),
+            Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None,
         };
-        match ns {
-            Namespace::MacroNS => check_full_res_macro(self),
-            Namespace::TypeNS | Namespace::ValueNS => check_full_res(self, ns),
-        }
+        self.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res)
     }
 }
 
@@ -650,14 +689,9 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx
     let ty = cx.tcx.type_of(type_);
     let iter = in_scope_traits.iter().flat_map(|&trait_| {
         trace!("considering explicit impl for trait {:?}", trait_);
-        let mut saw_impl = false;
-        // Look at each trait implementation to see if it's an impl for `did`
-        cx.tcx.for_each_relevant_impl(trait_, ty, |impl_| {
-            // FIXME: this is inefficient, find a way to short-circuit for_each_* so this doesn't take as long
-            if saw_impl {
-                return;
-            }
 
+        // Look at each trait implementation to see if it's an impl for `did`
+        cx.tcx.find_map_relevant_impl(trait_, ty, |impl_| {
             let trait_ref = cx.tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
             // Check if these are the same type.
             let impl_type = trait_ref.self_ty();
@@ -668,7 +702,7 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx
                 type_
             );
             // Fast path: if this is a primitive simple `==` will work
-            saw_impl = impl_type == ty
+            let saw_impl = impl_type == ty
                 || match impl_type.kind() {
                     // Check if these are the same def_id
                     ty::Adt(def, _) => {
@@ -678,8 +712,9 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx
                     ty::Foreign(def_id) => *def_id == type_,
                     _ => false,
                 };
-        });
-        if saw_impl { Some(trait_) } else { None }
+
+            if saw_impl { Some(trait_) } else { None }
+        })
     });
     iter.collect()
 }
@@ -758,7 +793,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
                 debug!("ignoring extern crate item {:?}", item.def_id);
                 return self.fold_item_recur(item);
             }
-            ImportItem(Import::Simple(ref name, ..)) => Some(name.clone()),
+            ImportItem(Import { kind: ImportKind::Simple(ref name, ..), .. }) => Some(name.clone()),
             MacroItem(..) => None,
             _ => item.name.clone(),
         };
@@ -767,9 +802,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
             self.mod_ids.push(item.def_id);
         }
 
-        let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
-        trace!("got documentation '{}'", dox);
-
         // find item's parent to resolve `Self` in item's docs below
         let parent_name = self.cx.as_local_hir_id(item.def_id).and_then(|item_hir| {
             let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir);
@@ -807,16 +839,53 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
             }
         });
 
-        for (ori_link, link_range) in markdown_links(&dox) {
-            self.resolve_link(
-                &mut item,
-                &dox,
-                &current_item,
-                parent_node,
-                &parent_name,
-                ori_link,
-                link_range,
-            );
+        // We want to resolve in the lexical scope of the documentation.
+        // In the presence of re-exports, this is not the same as the module of the item.
+        // Rather than merging all documentation into one, resolve it one attribute at a time
+        // so we know which module it came from.
+        let mut attrs = item.attrs.doc_strings.iter().peekable();
+        while let Some(attr) = attrs.next() {
+            // `collapse_docs` does not have the behavior we want:
+            // we want `///` and `#[doc]` to count as the same attribute,
+            // but currently it will treat them as separate.
+            // As a workaround, combine all attributes with the same parent module into the same attribute.
+            let mut combined_docs = attr.doc.clone();
+            loop {
+                match attrs.peek() {
+                    Some(next) if next.parent_module == attr.parent_module => {
+                        combined_docs.push('\n');
+                        combined_docs.push_str(&attrs.next().unwrap().doc);
+                    }
+                    _ => break,
+                }
+            }
+            debug!("combined_docs={}", combined_docs);
+
+            let (krate, parent_node) = if let Some(id) = attr.parent_module {
+                trace!("docs {:?} came from {:?}", attr.doc, id);
+                (id.krate, Some(id))
+            } else {
+                trace!("no parent found for {:?}", attr.doc);
+                (item.def_id.krate, parent_node)
+            };
+            // NOTE: if there are links that start in one crate and end in another, this will not resolve them.
+            // This is a degenerate case and it's not supported by rustdoc.
+            // FIXME: this will break links that start in `#[doc = ...]` and end as a sugared doc. Should this be supported?
+            for (ori_link, link_range) in markdown_links(&combined_docs) {
+                let link = self.resolve_link(
+                    &item,
+                    &combined_docs,
+                    &current_item,
+                    parent_node,
+                    &parent_name,
+                    krate,
+                    ori_link,
+                    link_range,
+                );
+                if let Some(link) = link {
+                    item.attrs.links.push(link);
+                }
+            }
         }
 
         if item.is_mod() && !item.attrs.inner_docs {
@@ -838,24 +907,25 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
 impl LinkCollector<'_, '_> {
     fn resolve_link(
         &self,
-        item: &mut Item,
+        item: &Item,
         dox: &str,
         current_item: &Option<String>,
         parent_node: Option<DefId>,
         parent_name: &Option<String>,
+        krate: CrateNum,
         ori_link: String,
         link_range: Option<Range<usize>>,
-    ) {
+    ) -> Option<ItemLink> {
         trace!("considering link '{}'", ori_link);
 
         // Bail early for real links.
         if ori_link.contains('/') {
-            return;
+            return None;
         }
 
         // [] is mostly likely not supposed to be a link
         if ori_link.is_empty() {
-            return;
+            return None;
         }
 
         let cx = self.cx;
@@ -863,11 +933,11 @@ impl LinkCollector<'_, '_> {
         let parts = link.split('#').collect::<Vec<_>>();
         let (link, extra_fragment) = if parts.len() > 2 {
             anchor_failure(cx, &item, &link, dox, link_range, AnchorFailure::MultipleAnchors);
-            return;
+            return None;
         } else if parts.len() == 2 {
             if parts[0].trim().is_empty() {
                 // This is an anchor to an element of the current page, nothing to do in here!
-                return;
+                return None;
             }
             (parts[0], Some(parts[1].to_owned()))
         } else {
@@ -877,6 +947,7 @@ impl LinkCollector<'_, '_> {
         let link_text;
         let mut path_str;
         let disambiguator;
+        let stripped_path_string;
         let (mut res, mut fragment) = {
             path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) {
                 disambiguator = Some(d);
@@ -887,8 +958,8 @@ impl LinkCollector<'_, '_> {
             }
             .trim();
 
-            if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) {
-                return;
+            if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, ".contains(ch))) {
+                return None;
             }
 
             // We stripped `()` and `!` when parsing the disambiguator.
@@ -928,7 +999,7 @@ impl LinkCollector<'_, '_> {
                     link_range,
                     smallvec![err_kind],
                 );
-                return;
+                return None;
             };
 
             // replace `Self` with suitable item's parent name
@@ -947,7 +1018,37 @@ impl LinkCollector<'_, '_> {
                 // (consider `crate::char`). Instead, change it to `self::`. This works because 'self' is now the crate root.
                 resolved_self = format!("self::{}", &path_str["crate::".len()..]);
                 path_str = &resolved_self;
-                module_id = DefId { krate: item.def_id.krate, index: CRATE_DEF_INDEX };
+                module_id = DefId { krate, index: CRATE_DEF_INDEX };
+            }
+
+            // Strip generics from the path.
+            if path_str.contains(['<', '>'].as_slice()) {
+                stripped_path_string = match strip_generics_from_path(path_str) {
+                    Ok(path) => path,
+                    Err(err_kind) => {
+                        debug!("link has malformed generics: {}", path_str);
+                        resolution_failure(
+                            self,
+                            &item,
+                            path_str,
+                            disambiguator,
+                            dox,
+                            link_range,
+                            smallvec![err_kind],
+                        );
+                        return None;
+                    }
+                };
+                path_str = &stripped_path_string;
+            }
+
+            // Sanity check to make sure we don't have any angle brackets after stripping generics.
+            assert!(!path_str.contains(['<', '>'].as_slice()));
+
+            // The link is not an intra-doc link if it still contains commas or spaces after
+            // stripping generics.
+            if path_str.contains([',', ' '].as_slice()) {
+                return None;
             }
 
             match self.resolve_with_disambiguator(
@@ -962,7 +1063,7 @@ impl LinkCollector<'_, '_> {
                 link_range.clone(),
             ) {
                 Some(x) => x,
-                None => return,
+                None => return None,
             }
         };
 
@@ -986,15 +1087,15 @@ impl LinkCollector<'_, '_> {
                             link_range,
                             AnchorFailure::RustdocAnchorConflict(prim),
                         );
-                        return;
+                        return None;
                     }
                     res = prim;
-                    fragment = Some(path.to_owned());
+                    fragment = Some(path.as_str().to_string());
                 } else {
                     // `[char]` when a `char` module is in scope
                     let candidates = vec![res, prim];
                     ambiguity_error(cx, &item, path_str, dox, link_range, candidates);
-                    return;
+                    return None;
                 }
             }
         }
@@ -1018,16 +1119,11 @@ impl LinkCollector<'_, '_> {
         if let Res::PrimTy(..) = res {
             match disambiguator {
                 Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {
-                    item.attrs.links.push(ItemLink {
-                        link: ori_link,
-                        link_text,
-                        did: None,
-                        fragment,
-                    });
+                    Some(ItemLink { link: ori_link, link_text, did: None, fragment })
                 }
                 Some(other) => {
                     report_mismatch(other, Disambiguator::Primitive);
-                    return;
+                    None
                 }
             }
         } else {
@@ -1050,7 +1146,7 @@ impl LinkCollector<'_, '_> {
                     (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
                     (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
                         report_mismatch(specified, Disambiguator::Kind(kind));
-                        return;
+                        return None;
                     }
                 }
             }
@@ -1073,14 +1169,14 @@ impl LinkCollector<'_, '_> {
                 }
             }
             let id = register_res(cx, res);
-            item.attrs.links.push(ItemLink { link: ori_link, link_text, did: Some(id), fragment });
+            Some(ItemLink { link: ori_link, link_text, did: Some(id), fragment })
         }
     }
 
     fn resolve_with_disambiguator(
         &self,
         disambiguator: Option<Disambiguator>,
-        item: &mut Item,
+        item: &Item,
         dox: &str,
         path_str: &str,
         current_item: &Option<String>,
@@ -1688,6 +1784,27 @@ fn resolution_failure(
                         diag.level = rustc_errors::Level::Bug;
                         "all intra doc links should have a parent item".to_owned()
                     }
+                    ResolutionFailure::MalformedGenerics(variant) => match variant {
+                        MalformedGenerics::UnbalancedAngleBrackets => {
+                            String::from("unbalanced angle brackets")
+                        }
+                        MalformedGenerics::MissingType => {
+                            String::from("missing type for generic parameters")
+                        }
+                        MalformedGenerics::HasFullyQualifiedSyntax => {
+                            diag.note("see https://github.com/rust-lang/rust/issues/74563 for more information");
+                            String::from("fully-qualified syntax is unsupported")
+                        }
+                        MalformedGenerics::InvalidPathSeparator => {
+                            String::from("has invalid path separator")
+                        }
+                        MalformedGenerics::TooManyAngleBrackets => {
+                            String::from("too many angle brackets")
+                        }
+                        MalformedGenerics::EmptyAngleBrackets => {
+                            String::from("empty angle brackets")
+                        }
+                    },
                 };
                 if let Some(span) = sp {
                     diag.span_label(span, &note);
@@ -1830,51 +1947,158 @@ fn handle_variant(
     if extra_fragment.is_some() {
         return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res)));
     }
-    let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) {
-        parent
-    } else {
-        return Err(ResolutionFailure::NoParentItem.into());
-    };
-    let parent_def = Res::Def(DefKind::Enum, parent);
-    let variant = cx.tcx.expect_variant_res(res);
-    Ok((parent_def, Some(format!("variant.{}", variant.ident.name))))
+    cx.tcx
+        .parent(res.def_id())
+        .map(|parent| {
+            let parent_def = Res::Def(DefKind::Enum, parent);
+            let variant = cx.tcx.expect_variant_res(res);
+            (parent_def, Some(format!("variant.{}", variant.ident.name)))
+        })
+        .ok_or_else(|| ResolutionFailure::NoParentItem.into())
 }
 
-const PRIMITIVES: &[(&str, Res)] = &[
-    ("u8", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U8))),
-    ("u16", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U16))),
-    ("u32", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U32))),
-    ("u64", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U64))),
-    ("u128", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U128))),
-    ("usize", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::Usize))),
-    ("i8", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I8))),
-    ("i16", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I16))),
-    ("i32", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I32))),
-    ("i64", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I64))),
-    ("i128", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I128))),
-    ("isize", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::Isize))),
-    ("f32", Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F32))),
-    ("f64", Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F64))),
-    ("str", Res::PrimTy(hir::PrimTy::Str)),
-    ("bool", Res::PrimTy(hir::PrimTy::Bool)),
-    ("true", Res::PrimTy(hir::PrimTy::Bool)),
-    ("false", Res::PrimTy(hir::PrimTy::Bool)),
-    ("char", Res::PrimTy(hir::PrimTy::Char)),
+// FIXME: At this point, this is basically a copy of the PrimitiveTypeTable
+const PRIMITIVES: &[(Symbol, Res)] = &[
+    (sym::u8, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U8))),
+    (sym::u16, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U16))),
+    (sym::u32, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U32))),
+    (sym::u64, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U64))),
+    (sym::u128, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U128))),
+    (sym::usize, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::Usize))),
+    (sym::i8, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I8))),
+    (sym::i16, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I16))),
+    (sym::i32, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I32))),
+    (sym::i64, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I64))),
+    (sym::i128, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I128))),
+    (sym::isize, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::Isize))),
+    (sym::f32, Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F32))),
+    (sym::f64, Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F64))),
+    (sym::str, Res::PrimTy(hir::PrimTy::Str)),
+    (sym::bool, Res::PrimTy(hir::PrimTy::Bool)),
+    (sym::char, Res::PrimTy(hir::PrimTy::Char)),
 ];
 
-fn is_primitive(path_str: &str, ns: Namespace) -> Option<(&'static str, Res)> {
-    if ns == TypeNS {
-        PRIMITIVES
-            .iter()
-            .filter(|x| x.0 == path_str)
-            .copied()
-            .map(|x| if x.0 == "true" || x.0 == "false" { ("bool", x.1) } else { x })
-            .next()
+fn is_primitive(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> {
+    is_bool_value(path_str, ns).or_else(|| {
+        if ns == TypeNS {
+            // FIXME: this should be replaced by a lookup in PrimitiveTypeTable
+            let maybe_primitive = Symbol::intern(path_str);
+            PRIMITIVES.iter().find(|x| x.0 == maybe_primitive).copied()
+        } else {
+            None
+        }
+    })
+}
+
+fn is_bool_value(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> {
+    if ns == TypeNS && (path_str == "true" || path_str == "false") {
+        Some((sym::bool, Res::PrimTy(hir::PrimTy::Bool)))
     } else {
         None
     }
 }
 
-fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option<&'static SmallVec<[DefId; 4]>> {
-    Some(PrimitiveType::from_symbol(Symbol::intern(path_str))?.impls(cx.tcx))
+fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure<'static>> {
+    let mut stripped_segments = vec![];
+    let mut path = path_str.chars().peekable();
+    let mut segment = Vec::new();
+
+    while let Some(chr) = path.next() {
+        match chr {
+            ':' => {
+                if path.next_if_eq(&':').is_some() {
+                    let stripped_segment =
+                        strip_generics_from_path_segment(mem::take(&mut segment))?;
+                    if !stripped_segment.is_empty() {
+                        stripped_segments.push(stripped_segment);
+                    }
+                } else {
+                    return Err(ResolutionFailure::MalformedGenerics(
+                        MalformedGenerics::InvalidPathSeparator,
+                    ));
+                }
+            }
+            '<' => {
+                segment.push(chr);
+
+                match path.next() {
+                    Some('<') => {
+                        return Err(ResolutionFailure::MalformedGenerics(
+                            MalformedGenerics::TooManyAngleBrackets,
+                        ));
+                    }
+                    Some('>') => {
+                        return Err(ResolutionFailure::MalformedGenerics(
+                            MalformedGenerics::EmptyAngleBrackets,
+                        ));
+                    }
+                    Some(chr) => {
+                        segment.push(chr);
+
+                        while let Some(chr) = path.next_if(|c| *c != '>') {
+                            segment.push(chr);
+                        }
+                    }
+                    None => break,
+                }
+            }
+            _ => segment.push(chr),
+        }
+        debug!("raw segment: {:?}", segment);
+    }
+
+    if !segment.is_empty() {
+        let stripped_segment = strip_generics_from_path_segment(segment)?;
+        if !stripped_segment.is_empty() {
+            stripped_segments.push(stripped_segment);
+        }
+    }
+
+    debug!("path_str: {:?}\nstripped segments: {:?}", path_str, &stripped_segments);
+
+    let stripped_path = stripped_segments.join("::");
+
+    if !stripped_path.is_empty() {
+        Ok(stripped_path)
+    } else {
+        Err(ResolutionFailure::MalformedGenerics(MalformedGenerics::MissingType))
+    }
+}
+
+fn strip_generics_from_path_segment(
+    segment: Vec<char>,
+) -> Result<String, ResolutionFailure<'static>> {
+    let mut stripped_segment = String::new();
+    let mut param_depth = 0;
+
+    let mut latest_generics_chunk = String::new();
+
+    for c in segment {
+        if c == '<' {
+            param_depth += 1;
+            latest_generics_chunk.clear();
+        } else if c == '>' {
+            param_depth -= 1;
+            if latest_generics_chunk.contains(" as ") {
+                // The segment tries to use fully-qualified syntax, which is currently unsupported.
+                // Give a helpful error message instead of completely ignoring the angle brackets.
+                return Err(ResolutionFailure::MalformedGenerics(
+                    MalformedGenerics::HasFullyQualifiedSyntax,
+                ));
+            }
+        } else {
+            if param_depth == 0 {
+                stripped_segment.push(c);
+            } else {
+                latest_generics_chunk.push(c);
+            }
+        }
+    }
+
+    if param_depth == 0 {
+        Ok(stripped_segment)
+    } else {
+        // The segment has unbalanced angle brackets, e.g. `Vec<T` or `Vec<T>>`
+        Err(ResolutionFailure::MalformedGenerics(MalformedGenerics::UnbalancedAngleBrackets))
+    }
 }
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index b2c4c30d8ff..5eb3f98b123 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -30,7 +30,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
     for &cnum in cx.tcx.crates().iter() {
         for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() {
             cx.tcx.sess.time("build_extern_trait_impl", || {
-                inline::build_impl(cx, did, None, &mut new_items);
+                inline::build_impl(cx, None, did, None, &mut new_items);
             });
         }
     }
@@ -38,7 +38,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
     // Also try to inline primitive impls from other crates.
     for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
         if !def_id.is_local() {
-            inline::build_impl(cx, def_id, None, &mut new_items);
+            inline::build_impl(cx, None, def_id, None, &mut new_items);
 
             // FIXME(eddyb) is this `doc(hidden)` check needed?
             if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) {
@@ -90,7 +90,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate {
         for &impl_node in cx.tcx.hir().trait_impls(trait_did) {
             let impl_did = cx.tcx.hir().local_def_id(impl_node);
             cx.tcx.sess.time("build_local_trait_impl", || {
-                inline::build_impl(cx, impl_did.to_def_id(), None, &mut new_items);
+                inline::build_impl(cx, None, impl_did.to_def_id(), None, &mut new_items);
             });
         }
     }
diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs
index 78af9f9b856..686ec51fb06 100644
--- a/src/librustdoc/passes/doc_test_lints.rs
+++ b/src/librustdoc/passes/doc_test_lints.rs
@@ -9,6 +9,7 @@ use crate::clean::*;
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString};
+use rustc_middle::lint::LintSource;
 use rustc_session::lint;
 
 pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
@@ -56,8 +57,8 @@ impl crate::doctest::Tester for Tests {
     }
 }
 
-pub fn should_have_doc_example(item_kind: &clean::ItemEnum) -> bool {
-    !matches!(item_kind,
+pub fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool {
+    if matches!(item.inner,
         clean::StructFieldItem(_)
         | clean::VariantItem(_)
         | clean::AssocConstItem(_, _)
@@ -69,7 +70,13 @@ pub fn should_have_doc_example(item_kind: &clean::ItemEnum) -> bool {
         | clean::ImportItem(_)
         | clean::PrimitiveItem(_)
         | clean::KeywordItem(_)
-    )
+    ) {
+        return false;
+    }
+    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_local());
+    let (level, source) =
+        cx.tcx.lint_level_at_node(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id);
+    level != lint::Level::Allow || matches!(source, LintSource::Default)
 }
 
 pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
@@ -88,7 +95,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
     if tests.found_tests == 0
         && rustc_feature::UnstableFeatures::from_environment().is_nightly_build()
     {
-        if should_have_doc_example(&item.inner) {
+        if should_have_doc_example(cx, &item) {
             debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
             let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span());
             cx.tcx.struct_span_lint_hir(
diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs
new file mode 100644
index 00000000000..1d9be619ec9
--- /dev/null
+++ b/src/librustdoc/passes/html_tags.rs
@@ -0,0 +1,226 @@
+use super::{span_of_attrs, Pass};
+use crate::clean::*;
+use crate::core::DocContext;
+use crate::fold::DocFolder;
+use crate::html::markdown::opts;
+use core::ops::Range;
+use pulldown_cmark::{Event, Parser};
+use rustc_feature::UnstableFeatures;
+use rustc_session::lint;
+use std::iter::Peekable;
+use std::str::CharIndices;
+
+pub const CHECK_INVALID_HTML_TAGS: Pass = Pass {
+    name: "check-invalid-html-tags",
+    run: check_invalid_html_tags,
+    description: "detects invalid HTML tags in doc comments",
+};
+
+struct InvalidHtmlTagsLinter<'a, 'tcx> {
+    cx: &'a DocContext<'tcx>,
+}
+
+impl<'a, 'tcx> InvalidHtmlTagsLinter<'a, 'tcx> {
+    fn new(cx: &'a DocContext<'tcx>) -> Self {
+        InvalidHtmlTagsLinter { cx }
+    }
+}
+
+pub fn check_invalid_html_tags(krate: Crate, cx: &DocContext<'_>) -> Crate {
+    if !UnstableFeatures::from_environment().is_nightly_build() {
+        krate
+    } else {
+        let mut coll = InvalidHtmlTagsLinter::new(cx);
+
+        coll.fold_crate(krate)
+    }
+}
+
+const ALLOWED_UNCLOSED: &[&str] = &[
+    "area", "base", "br", "col", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
+    "source", "track", "wbr",
+];
+
+fn drop_tag(
+    tags: &mut Vec<(String, Range<usize>)>,
+    tag_name: String,
+    range: Range<usize>,
+    f: &impl Fn(&str, &Range<usize>),
+) {
+    let tag_name_low = tag_name.to_lowercase();
+    if let Some(pos) = tags.iter().rposition(|(t, _)| t.to_lowercase() == tag_name_low) {
+        // If the tag is nested inside a "<script>" or a "<style>" tag, no warning should
+        // be emitted.
+        let should_not_warn = tags.iter().take(pos + 1).any(|(at, _)| {
+            let at = at.to_lowercase();
+            at == "script" || at == "style"
+        });
+        for (last_tag_name, last_tag_span) in tags.drain(pos + 1..) {
+            if should_not_warn {
+                continue;
+            }
+            let last_tag_name_low = last_tag_name.to_lowercase();
+            if ALLOWED_UNCLOSED.iter().any(|&at| at == &last_tag_name_low) {
+                continue;
+            }
+            // `tags` is used as a queue, meaning that everything after `pos` is included inside it.
+            // So `<h2><h3></h2>` will look like `["h2", "h3"]`. So when closing `h2`, we will still
+            // have `h3`, meaning the tag wasn't closed as it should have.
+            f(&format!("unclosed HTML tag `{}`", last_tag_name), &last_tag_span);
+        }
+        // Remove the `tag_name` that was originally closed
+        tags.pop();
+    } else {
+        // It can happen for example in this case: `<h2></script></h2>` (the `h2` tag isn't required
+        // but it helps for the visualization).
+        f(&format!("unopened HTML tag `{}`", tag_name), &range);
+    }
+}
+
+fn extract_html_tag(
+    tags: &mut Vec<(String, Range<usize>)>,
+    text: &str,
+    range: &Range<usize>,
+    start_pos: usize,
+    iter: &mut Peekable<CharIndices<'_>>,
+    f: &impl Fn(&str, &Range<usize>),
+) {
+    let mut tag_name = String::new();
+    let mut is_closing = false;
+    let mut prev_pos = start_pos;
+
+    loop {
+        let (pos, c) = match iter.peek() {
+            Some((pos, c)) => (*pos, *c),
+            // In case we reached the of the doc comment, we want to check that it's an
+            // unclosed HTML tag. For example "/// <h3".
+            None => (prev_pos, '\0'),
+        };
+        prev_pos = pos;
+        // Checking if this is a closing tag (like `</a>` for `<a>`).
+        if c == '/' && tag_name.is_empty() {
+            is_closing = true;
+        } else if c.is_ascii_alphanumeric() {
+            tag_name.push(c);
+        } else {
+            if !tag_name.is_empty() {
+                let mut r = Range { start: range.start + start_pos, end: range.start + pos };
+                if c == '>' {
+                    // In case we have a tag without attribute, we can consider the span to
+                    // refer to it fully.
+                    r.end += 1;
+                }
+                if is_closing {
+                    // In case we have "</div >" or even "</div         >".
+                    if c != '>' {
+                        if !c.is_whitespace() {
+                            // It seems like it's not a valid HTML tag.
+                            break;
+                        }
+                        let mut found = false;
+                        for (new_pos, c) in text[pos..].char_indices() {
+                            if !c.is_whitespace() {
+                                if c == '>' {
+                                    r.end = range.start + new_pos + 1;
+                                    found = true;
+                                }
+                                break;
+                            }
+                        }
+                        if !found {
+                            break;
+                        }
+                    }
+                    drop_tag(tags, tag_name, r, f);
+                } else {
+                    tags.push((tag_name, r));
+                }
+            }
+            break;
+        }
+        iter.next();
+    }
+}
+
+fn extract_tags(
+    tags: &mut Vec<(String, Range<usize>)>,
+    text: &str,
+    range: Range<usize>,
+    is_in_comment: &mut Option<Range<usize>>,
+    f: &impl Fn(&str, &Range<usize>),
+) {
+    let mut iter = text.char_indices().peekable();
+
+    while let Some((start_pos, c)) = iter.next() {
+        if is_in_comment.is_some() {
+            if text[start_pos..].starts_with("-->") {
+                *is_in_comment = None;
+            }
+        } else if c == '<' {
+            if text[start_pos..].starts_with("<!--") {
+                // We skip the "!--" part. (Once `advance_by` is stable, might be nice to use it!)
+                iter.next();
+                iter.next();
+                iter.next();
+                *is_in_comment = Some(Range {
+                    start: range.start + start_pos,
+                    end: range.start + start_pos + 3,
+                });
+            } else {
+                extract_html_tag(tags, text, &range, start_pos, &mut iter, f);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> {
+    fn fold_item(&mut self, item: Item) -> Option<Item> {
+        let hir_id = match self.cx.as_local_hir_id(item.def_id) {
+            Some(hir_id) => hir_id,
+            None => {
+                // If non-local, no need to check anything.
+                return self.fold_item_recur(item);
+            }
+        };
+        let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
+        if !dox.is_empty() {
+            let cx = &self.cx;
+            let report_diag = |msg: &str, range: &Range<usize>| {
+                let sp = match super::source_span_for_markdown_range(cx, &dox, range, &item.attrs) {
+                    Some(sp) => sp,
+                    None => span_of_attrs(&item.attrs).unwrap_or(item.source.span()),
+                };
+                cx.tcx.struct_span_lint_hir(lint::builtin::INVALID_HTML_TAGS, hir_id, sp, |lint| {
+                    lint.build(msg).emit()
+                });
+            };
+
+            let mut tags = Vec::new();
+            let mut is_in_comment = None;
+
+            let p = Parser::new_ext(&dox, opts()).into_offset_iter();
+
+            for (event, range) in p {
+                match event {
+                    Event::Html(text) | Event::Text(text) => {
+                        extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag)
+                    }
+                    _ => {}
+                }
+            }
+
+            for (tag, range) in tags.iter().filter(|(t, _)| {
+                let t = t.to_lowercase();
+                ALLOWED_UNCLOSED.iter().find(|&&at| at == t).is_none()
+            }) {
+                report_diag(&format!("unclosed HTML tag `{}`", tag), range);
+            }
+
+            if let Some(range) = is_in_comment {
+                report_diag("Unclosed HTML comment", &range);
+            }
+        }
+
+        self.fold_item_recur(item)
+    }
+}
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index f8e395bfb41..2591650e3f9 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -1,16 +1,15 @@
 //! Contains information about "passes", used to modify crate information during the documentation
 //! process.
 
-use rustc_hir::def_id::{DefId, DefIdSet};
-use rustc_middle::middle::privacy::AccessLevels;
 use rustc_span::{InnerSpan, Span, DUMMY_SP};
-use std::mem;
 use std::ops::Range;
 
 use self::Condition::*;
-use crate::clean::{self, DocFragmentKind, GetDefId, Item};
+use crate::clean::{self, DocFragmentKind};
 use crate::core::DocContext;
-use crate::fold::{DocFolder, StripItem};
+
+mod stripper;
+pub use stripper::*;
 
 mod collapse_docs;
 pub use self::collapse_docs::COLLAPSE_DOCS;
@@ -45,6 +44,9 @@ pub use self::check_code_block_syntax::CHECK_CODE_BLOCK_SYNTAX;
 mod calculate_doc_coverage;
 pub use self::calculate_doc_coverage::CALCULATE_DOC_COVERAGE;
 
+mod html_tags;
+pub use self::html_tags::CHECK_INVALID_HTML_TAGS;
+
 /// A single pass over the cleaned documentation.
 ///
 /// Runs in the compiler context, so it has access to types and traits and the like.
@@ -87,6 +89,7 @@ pub const PASSES: &[Pass] = &[
     CHECK_CODE_BLOCK_SYNTAX,
     COLLECT_TRAIT_IMPLS,
     CALCULATE_DOC_COVERAGE,
+    CHECK_INVALID_HTML_TAGS,
 ];
 
 /// The list of passes run by default.
@@ -100,6 +103,7 @@ pub const DEFAULT_PASSES: &[ConditionalPass] = &[
     ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
     ConditionalPass::always(COLLECT_INTRA_DOC_LINKS),
     ConditionalPass::always(CHECK_CODE_BLOCK_SYNTAX),
+    ConditionalPass::always(CHECK_INVALID_HTML_TAGS),
     ConditionalPass::always(PROPAGATE_DOC_CFG),
 ];
 
@@ -144,171 +148,6 @@ pub fn find_pass(pass_name: &str) -> Option<Pass> {
     PASSES.iter().find(|p| p.name == pass_name).copied()
 }
 
-struct Stripper<'a> {
-    retained: &'a mut DefIdSet,
-    access_levels: &'a AccessLevels<DefId>,
-    update_retained: bool,
-}
-
-impl<'a> DocFolder for Stripper<'a> {
-    fn fold_item(&mut self, i: Item) -> Option<Item> {
-        match i.inner {
-            clean::StrippedItem(..) => {
-                // We need to recurse into stripped modules to strip things
-                // like impl methods but when doing so we must not add any
-                // items to the `retained` set.
-                debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name);
-                let old = mem::replace(&mut self.update_retained, false);
-                let ret = self.fold_item_recur(i);
-                self.update_retained = old;
-                return ret;
-            }
-            // These items can all get re-exported
-            clean::OpaqueTyItem(..)
-            | clean::TypedefItem(..)
-            | clean::StaticItem(..)
-            | clean::StructItem(..)
-            | clean::EnumItem(..)
-            | clean::TraitItem(..)
-            | clean::FunctionItem(..)
-            | clean::VariantItem(..)
-            | clean::MethodItem(..)
-            | clean::ForeignFunctionItem(..)
-            | clean::ForeignStaticItem(..)
-            | clean::ConstantItem(..)
-            | clean::UnionItem(..)
-            | clean::AssocConstItem(..)
-            | clean::TraitAliasItem(..)
-            | clean::ForeignTypeItem => {
-                if i.def_id.is_local() {
-                    if !self.access_levels.is_exported(i.def_id) {
-                        debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
-                        return None;
-                    }
-                }
-            }
-
-            clean::StructFieldItem(..) => {
-                if i.visibility != clean::Public {
-                    return StripItem(i).strip();
-                }
-            }
-
-            clean::ModuleItem(..) => {
-                if i.def_id.is_local() && i.visibility != clean::Public {
-                    debug!("Stripper: stripping module {:?}", i.name);
-                    let old = mem::replace(&mut self.update_retained, false);
-                    let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
-                    self.update_retained = old;
-                    return ret;
-                }
-            }
-
-            // handled in the `strip-priv-imports` pass
-            clean::ExternCrateItem(..) | clean::ImportItem(..) => {}
-
-            clean::ImplItem(..) => {}
-
-            // tymethods/macros have no control over privacy
-            clean::MacroItem(..) | clean::TyMethodItem(..) => {}
-
-            // Proc-macros are always public
-            clean::ProcMacroItem(..) => {}
-
-            // Primitives are never stripped
-            clean::PrimitiveItem(..) => {}
-
-            // Associated types are never stripped
-            clean::AssocTypeItem(..) => {}
-
-            // Keywords are never stripped
-            clean::KeywordItem(..) => {}
-        }
-
-        let fastreturn = match i.inner {
-            // nothing left to do for traits (don't want to filter their
-            // methods out, visibility controlled by the trait)
-            clean::TraitItem(..) => true,
-
-            // implementations of traits are always public.
-            clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
-            // Struct variant fields have inherited visibility
-            clean::VariantItem(clean::Variant { kind: clean::VariantKind::Struct(..) }) => true,
-            _ => false,
-        };
-
-        let i = if fastreturn {
-            if self.update_retained {
-                self.retained.insert(i.def_id);
-            }
-            return Some(i);
-        } else {
-            self.fold_item_recur(i)
-        };
-
-        if let Some(ref i) = i {
-            if self.update_retained {
-                self.retained.insert(i.def_id);
-            }
-        }
-        i
-    }
-}
-
-// This stripper discards all impls which reference stripped items
-struct ImplStripper<'a> {
-    retained: &'a DefIdSet,
-}
-
-impl<'a> DocFolder for ImplStripper<'a> {
-    fn fold_item(&mut self, i: Item) -> Option<Item> {
-        if let clean::ImplItem(ref imp) = i.inner {
-            // emptied none trait impls can be stripped
-            if imp.trait_.is_none() && imp.items.is_empty() {
-                return None;
-            }
-            if let Some(did) = imp.for_.def_id() {
-                if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) {
-                    debug!("ImplStripper: impl item for stripped type; removing");
-                    return None;
-                }
-            }
-            if let Some(did) = imp.trait_.def_id() {
-                if did.is_local() && !self.retained.contains(&did) {
-                    debug!("ImplStripper: impl item for stripped trait; removing");
-                    return None;
-                }
-            }
-            if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
-                for typaram in generics {
-                    if let Some(did) = typaram.def_id() {
-                        if did.is_local() && !self.retained.contains(&did) {
-                            debug!(
-                                "ImplStripper: stripped item in trait's generics; removing impl"
-                            );
-                            return None;
-                        }
-                    }
-                }
-            }
-        }
-        self.fold_item_recur(i)
-    }
-}
-
-// This stripper discards all private import statements (`use`, `extern crate`)
-struct ImportStripper;
-impl DocFolder for ImportStripper {
-    fn fold_item(&mut self, i: Item) -> Option<Item> {
-        match i.inner {
-            clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => {
-                None
-            }
-            _ => self.fold_item_recur(i),
-        }
-    }
-}
-
 /// Returns a span encompassing all the given attributes.
 crate fn span_of_attrs(attrs: &clean::Attributes) -> Option<Span> {
     if attrs.doc_strings.is_empty() {
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
new file mode 100644
index 00000000000..9b4f62235f5
--- /dev/null
+++ b/src/librustdoc/passes/stripper.rs
@@ -0,0 +1,172 @@
+use rustc_hir::def_id::{DefId, DefIdSet};
+use rustc_middle::middle::privacy::AccessLevels;
+use std::mem;
+
+use crate::clean::{self, GetDefId, Item};
+use crate::fold::{DocFolder, StripItem};
+
+pub struct Stripper<'a> {
+    pub retained: &'a mut DefIdSet,
+    pub access_levels: &'a AccessLevels<DefId>,
+    pub update_retained: bool,
+}
+
+impl<'a> DocFolder for Stripper<'a> {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        match i.inner {
+            clean::StrippedItem(..) => {
+                // We need to recurse into stripped modules to strip things
+                // like impl methods but when doing so we must not add any
+                // items to the `retained` set.
+                debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name);
+                let old = mem::replace(&mut self.update_retained, false);
+                let ret = self.fold_item_recur(i);
+                self.update_retained = old;
+                return ret;
+            }
+            // These items can all get re-exported
+            clean::OpaqueTyItem(..)
+            | clean::TypedefItem(..)
+            | clean::StaticItem(..)
+            | clean::StructItem(..)
+            | clean::EnumItem(..)
+            | clean::TraitItem(..)
+            | clean::FunctionItem(..)
+            | clean::VariantItem(..)
+            | clean::MethodItem(..)
+            | clean::ForeignFunctionItem(..)
+            | clean::ForeignStaticItem(..)
+            | clean::ConstantItem(..)
+            | clean::UnionItem(..)
+            | clean::AssocConstItem(..)
+            | clean::TraitAliasItem(..)
+            | clean::ForeignTypeItem => {
+                if i.def_id.is_local() {
+                    if !self.access_levels.is_exported(i.def_id) {
+                        debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
+                        return None;
+                    }
+                }
+            }
+
+            clean::StructFieldItem(..) => {
+                if i.visibility != clean::Public {
+                    return StripItem(i).strip();
+                }
+            }
+
+            clean::ModuleItem(..) => {
+                if i.def_id.is_local() && i.visibility != clean::Public {
+                    debug!("Stripper: stripping module {:?}", i.name);
+                    let old = mem::replace(&mut self.update_retained, false);
+                    let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
+                    self.update_retained = old;
+                    return ret;
+                }
+            }
+
+            // handled in the `strip-priv-imports` pass
+            clean::ExternCrateItem(..) | clean::ImportItem(..) => {}
+
+            clean::ImplItem(..) => {}
+
+            // tymethods/macros have no control over privacy
+            clean::MacroItem(..) | clean::TyMethodItem(..) => {}
+
+            // Proc-macros are always public
+            clean::ProcMacroItem(..) => {}
+
+            // Primitives are never stripped
+            clean::PrimitiveItem(..) => {}
+
+            // Associated types are never stripped
+            clean::AssocTypeItem(..) => {}
+
+            // Keywords are never stripped
+            clean::KeywordItem(..) => {}
+        }
+
+        let fastreturn = match i.inner {
+            // nothing left to do for traits (don't want to filter their
+            // methods out, visibility controlled by the trait)
+            clean::TraitItem(..) => true,
+
+            // implementations of traits are always public.
+            clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
+            // Struct variant fields have inherited visibility
+            clean::VariantItem(clean::Variant { kind: clean::VariantKind::Struct(..) }) => true,
+            _ => false,
+        };
+
+        let i = if fastreturn {
+            if self.update_retained {
+                self.retained.insert(i.def_id);
+            }
+            return Some(i);
+        } else {
+            self.fold_item_recur(i)
+        };
+
+        if let Some(ref i) = i {
+            if self.update_retained {
+                self.retained.insert(i.def_id);
+            }
+        }
+        i
+    }
+}
+
+/// This stripper discards all impls which reference stripped items
+pub struct ImplStripper<'a> {
+    pub retained: &'a DefIdSet,
+}
+
+impl<'a> DocFolder for ImplStripper<'a> {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        if let clean::ImplItem(ref imp) = i.inner {
+            // emptied none trait impls can be stripped
+            if imp.trait_.is_none() && imp.items.is_empty() {
+                return None;
+            }
+            if let Some(did) = imp.for_.def_id() {
+                if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) {
+                    debug!("ImplStripper: impl item for stripped type; removing");
+                    return None;
+                }
+            }
+            if let Some(did) = imp.trait_.def_id() {
+                if did.is_local() && !self.retained.contains(&did) {
+                    debug!("ImplStripper: impl item for stripped trait; removing");
+                    return None;
+                }
+            }
+            if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
+                for typaram in generics {
+                    if let Some(did) = typaram.def_id() {
+                        if did.is_local() && !self.retained.contains(&did) {
+                            debug!(
+                                "ImplStripper: stripped item in trait's generics; removing impl"
+                            );
+                            return None;
+                        }
+                    }
+                }
+            }
+        }
+        self.fold_item_recur(i)
+    }
+}
+
+/// This stripper discards all private import statements (`use`, `extern crate`)
+pub struct ImportStripper;
+
+impl DocFolder for ImportStripper {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        match i.inner {
+            clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => {
+                None
+            }
+            _ => self.fold_item_recur(i),
+        }
+    }
+}
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 33578dc0619..cbfd2199d9f 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -399,6 +399,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 om.extern_crates.push(ExternCrate {
                     cnum: self.cx.tcx.extern_mod_stmt_cnum(def_id).unwrap_or(LOCAL_CRATE),
                     name: ident.name,
+                    hir_id: item.hir_id,
                     path: orig_name.map(|x| x.to_string()),
                     vis: &item.vis,
                     attrs: &item.attrs,
diff --git a/src/llvm-project b/src/llvm-project
-Subproject e8b556b6a8836147429abe391d6ed18806867b4
+Subproject 3c5d47c81d78e9316e971c9870e8bc7c2c449d2
diff --git a/src/stage0.txt b/src/stage0.txt
index f695b75c24d..98b4dfa9c74 100644
--- a/src/stage0.txt
+++ b/src/stage0.txt
@@ -12,7 +12,7 @@
 # source tarball for a stable release you'll likely see `1.x.0` for rustc and
 # `0.(x+1).0` for Cargo where they were released on `date`.
 
-date: 2020-08-26
+date: 2020-10-07
 rustc: beta
 cargo: beta
 
@@ -20,7 +20,7 @@ cargo: beta
 # bootstrapping issues with use of new syntax in this repo. If you're looking at
 # the beta/stable branch, this key should be omitted, as we don't want to depend
 # on rustfmt from nightly there.
-rustfmt: nightly-2020-07-12
+rustfmt: nightly-2020-10-07
 
 # When making a stable release the process currently looks like:
 #
diff --git a/src/test/assembly/asm/mips-types.rs b/src/test/assembly/asm/mips-types.rs
index b195ed88c72..04e840dc166 100644
--- a/src/test/assembly/asm/mips-types.rs
+++ b/src/test/assembly/asm/mips-types.rs
@@ -1,6 +1,8 @@
 // no-system-llvm
+// revisions: mips32 mips64
 // assembly-output: emit-asm
-// compile-flags: --target mips-unknown-linux-gnu
+//[mips32] compile-flags: --target mips-unknown-linux-gnu
+//[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
 // needs-llvm-components: mips
 
 #![feature(no_core, lang_items, rustc_attrs, repr_simd)]
@@ -32,7 +34,9 @@ impl Copy for i8 {}
 impl Copy for u8 {}
 impl Copy for i16 {}
 impl Copy for i32 {}
+impl Copy for i64 {}
 impl Copy for f32 {}
+impl Copy for f64 {}
 impl Copy for ptr {}
 extern "C" {
     fn extern_func();
@@ -44,148 +48,190 @@ extern "Rust" {
     fn dont_merge(s: &str);
 }
 
-macro_rules! check { ($func:ident, $ty:ty, $class:ident) => {
+macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => {
     #[no_mangle]
     pub unsafe fn $func(x: $ty) -> $ty {
         dont_merge(stringify!($func));
 
         let y;
-        asm!("move {}, {}", out($class) y, in($class) x);
+        asm!(concat!($mov," {}, {}"), out($class) y, in($class) x);
         y
     }
 };}
 
-macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt) => {
+macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => {
     #[no_mangle]
     pub unsafe fn $func(x: $ty) -> $ty {
         dont_merge(stringify!($func));
 
         let y;
-        asm!(concat!("move ", $reg, ", ", $reg), lateout($reg) y, in($reg) x);
+        asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x);
         y
     }
 };}
 
-// CHECK-LABEL: sym_static:
-// CHECK: #APP
-// CHECK: lw $3, %got(extern_static)
-// CHECK: #NO_APP
+// mips32-LABEL: sym_static_32:
+// mips32: #APP
+// mips32: lw $3, %got(extern_static)
+// mips32: #NO_APP
+#[cfg(mips32)]
 #[no_mangle]
-pub unsafe fn sym_static() {
-    dont_merge(stringify!($func));
+pub unsafe fn sym_static_32() {
+    asm!("lw $v1, {}", sym extern_static);
+}
 
-    asm!("la $v1, {}", sym extern_static);
+// mips32-LABEL: sym_fn_32:
+// mips32: #APP
+// mips32: lw $3, %got(extern_func)
+// mips32: #NO_APP
+#[cfg(mips32)]
+#[no_mangle]
+pub unsafe fn sym_fn_32() {
+    asm!("lw $v1, {}", sym extern_func);
 }
 
-// CHECK-LABEL: sym_fn:
-// CHECK: #APP
-// CHECK: lw $3, %got(extern_func)
-// CHECK: #NO_APP
+// mips64-LABEL: sym_static_64:
+// mips64: #APP
+// mips64: ld $3, %got_disp(extern_static)
+// mips64: #NO_APP
+#[cfg(mips64)]
 #[no_mangle]
-pub unsafe fn sym_fn() {
-    dont_merge(stringify!($func));
+pub unsafe fn sym_static_64() {
+    asm!("ld $v1, {}", sym extern_static);
+}
 
-    asm!("la $v1, {}", sym extern_func);
+// mips64-LABEL: sym_fn_64:
+// mips64: #APP
+// mips64: ld $3, %got_disp(extern_func)
+// mips64: #NO_APP
+#[cfg(mips64)]
+#[no_mangle]
+pub unsafe fn sym_fn_64() {
+    asm!("ld $v1, {}", sym extern_func);
 }
 
 // CHECK-LABEL: reg_f32:
 // CHECK: #APP
 // CHECK: mov.s $f{{[0-9]+}}, $f{{[0-9]+}}
 // CHECK: #NO_APP
-#[no_mangle]
-pub unsafe fn reg_f32(x: f32) -> f32 {
-    dont_merge("reg_f32");
-    let y;
-    asm!("mov.s {}, {}", out(freg) y, in(freg) x);
-    y
-}
+check!(reg_f32, f32, freg, "mov.s");
 
 // CHECK-LABEL: f0_f32:
 // CHECK: #APP
 // CHECK: mov.s $f0, $f0
 // CHECK: #NO_APP
 #[no_mangle]
-pub unsafe fn f0_f32(x: f32) -> f32 {
-    dont_merge("f0_f32");
-    let y;
-    asm!("mov.s $f0, $f0", lateout("$f0") y, in("$f0") x);
-    y
-}
+check_reg!(f0_f32, f32, "$f0", "mov.s");
+
+// CHECK-LABEL: reg_f32_64:
+// CHECK: #APP
+// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}}
+// CHECK: #NO_APP
+check!(reg_f32_64, f32, freg, "mov.d");
+
+// CHECK-LABEL: f0_f32_64:
+// CHECK: #APP
+// CHECK: mov.d $f0, $f0
+// CHECK: #NO_APP
+#[no_mangle]
+check_reg!(f0_f32_64, f32, "$f0", "mov.d");
+
+// CHECK-LABEL: reg_f64:
+// CHECK: #APP
+// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}}
+// CHECK: #NO_APP
+#[no_mangle]
+check!(reg_f64, f64, freg, "mov.d");
+
+// CHECK-LABEL: f0_f64:
+// CHECK: #APP
+// CHECK: mov.d $f0, $f0
+// CHECK: #NO_APP
+#[no_mangle]
+check_reg!(f0_f64, f64, "$f0", "mov.d");
 
 // CHECK-LABEL: reg_ptr:
 // CHECK: #APP
 // CHECK: move ${{[0-9]+}}, ${{[0-9]+}}
 // CHECK: #NO_APP
-check!(reg_ptr, ptr, reg);
+check!(reg_ptr, ptr, reg, "move");
 
 // CHECK-LABEL: reg_i32:
 // CHECK: #APP
 // CHECK: move ${{[0-9]+}}, ${{[0-9]+}}
 // CHECK: #NO_APP
-check!(reg_i32, i32, reg);
+check!(reg_i32, i32, reg, "move");
 
 // CHECK-LABEL: reg_f32_soft:
 // CHECK: #APP
 // CHECK: move ${{[0-9]+}}, ${{[0-9]+}}
 // CHECK: #NO_APP
-check!(reg_f32_soft, f32, reg);
+check!(reg_f32_soft, f32, reg, "move");
+
+// mips64-LABEL: reg_f64_soft:
+// mips64: #APP
+// mips64: move ${{[0-9]+}}, ${{[0-9]+}}
+// mips64: #NO_APP
+#[cfg(mips64)]
+check!(reg_f64_soft, f64, reg, "move");
 
 // CHECK-LABEL: reg_i8:
 // CHECK: #APP
 // CHECK: move ${{[0-9]+}}, ${{[0-9]+}}
 // CHECK: #NO_APP
-check!(reg_i8, i8, reg);
+check!(reg_i8, i8, reg, "move");
 
 // CHECK-LABEL: reg_u8:
 // CHECK: #APP
 // CHECK: move ${{[0-9]+}}, ${{[0-9]+}}
 // CHECK: #NO_APP
-check!(reg_u8, u8, reg);
+check!(reg_u8, u8, reg, "move");
 
 // CHECK-LABEL: reg_i16:
 // CHECK: #APP
 // CHECK: move ${{[0-9]+}}, ${{[0-9]+}}
 // CHECK: #NO_APP
-check!(reg_i16, i16, reg);
+check!(reg_i16, i16, reg, "move");
 
-// CHECK-LABEL: t0_ptr:
-// CHECK: #APP
-// CHECK: move $8, $8
-// CHECK: #NO_APP
-check_reg!(t0_ptr, ptr, "$t0");
+// mips64-LABEL: reg_i64:
+// mips64: #APP
+// mips64: move ${{[0-9]+}}, ${{[0-9]+}}
+// mips64: #NO_APP
+#[cfg(mips64)]
+check!(reg_i64, i64, reg, "move");
 
-// CHECK-LABEL: t0_i32:
+// CHECK-LABEL: r8_ptr:
 // CHECK: #APP
 // CHECK: move $8, $8
 // CHECK: #NO_APP
-check_reg!(t0_i32, i32, "$t0");
+check_reg!(r8_ptr, ptr, "$8", "move");
 
-// CHECK-LABEL: t0_f32:
+// CHECK-LABEL: r8_i32:
 // CHECK: #APP
 // CHECK: move $8, $8
 // CHECK: #NO_APP
-check_reg!(t0_f32, f32, "$t0");
+check_reg!(r8_i32, i32, "$8", "move");
 
-// CHECK-LABEL: t0_i8:
+// CHECK-LABEL: r8_f32:
 // CHECK: #APP
 // CHECK: move $8, $8
 // CHECK: #NO_APP
-check_reg!(t0_i8, i8, "$t0");
+check_reg!(r8_f32, f32, "$8", "move");
 
-// CHECK-LABEL: t0_u8:
+// CHECK-LABEL: r8_i8:
 // CHECK: #APP
 // CHECK: move $8, $8
 // CHECK: #NO_APP
-check_reg!(t0_u8, u8, "$t0");
+check_reg!(r8_i8, i8, "$8", "move");
 
-// CHECK-LABEL: t0_i16:
+// CHECK-LABEL: r8_u8:
 // CHECK: #APP
 // CHECK: move $8, $8
 // CHECK: #NO_APP
-check_reg!(t0_i16, i16, "$t0");
+check_reg!(r8_u8, u8, "$8", "move");
 
 // CHECK-LABEL: r8_i16:
 // CHECK: #APP
 // CHECK: move $8, $8
 // CHECK: #NO_APP
-check_reg!(r8_i16, i16, "$8");
+check_reg!(r8_i16, i16, "$8", "move");
diff --git a/src/test/codegen/len-is-bounded.rs b/src/test/codegen/len-is-bounded.rs
deleted file mode 100644
index bb74fc3b275..00000000000
--- a/src/test/codegen/len-is-bounded.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// min-llvm-version: 11.0
-// compile-flags: -O -C panic=abort
-#![crate_type = "lib"]
-
-#[no_mangle]
-pub fn len_range(a: &[u8], b: &[u8]) -> usize {
-    // CHECK-NOT: panic
-    a.len().checked_add(b.len()).unwrap()
-}
-
-#[no_mangle]
-pub fn len_range_on_non_byte(a: &[u16], b: &[u16]) -> usize {
-    // CHECK-NOT: panic
-    a.len().checked_add(b.len()).unwrap()
-}
-
-pub struct Zst;
-
-#[no_mangle]
-pub fn zst_range(a: &[Zst], b: &[Zst]) -> usize {
-    // Zsts may be arbitrarily large.
-    // CHECK: panic
-    a.len().checked_add(b.len()).unwrap()
-}
diff --git a/src/test/codegen/slice-windows-no-bounds-check.rs b/src/test/codegen/slice-windows-no-bounds-check.rs
new file mode 100644
index 00000000000..4f5f4425c27
--- /dev/null
+++ b/src/test/codegen/slice-windows-no-bounds-check.rs
@@ -0,0 +1,35 @@
+#![crate_type = "lib"]
+
+// compile-flags: -O
+
+use std::slice::Windows;
+
+// CHECK-LABEL: @naive_string_search
+#[no_mangle]
+pub fn naive_string_search(haystack: &str, needle: &str) -> Option<usize> {
+    if needle.is_empty() {
+        return Some(0);
+    }
+    // CHECK-NOT: panic
+    // CHECK-NOT: fail
+    haystack
+        .as_bytes()
+        .windows(needle.len())
+        .position(|sub| sub == needle.as_bytes())
+}
+
+// CHECK-LABEL: @next
+#[no_mangle]
+pub fn next<'a>(w: &mut Windows<'a, u32>) -> Option<&'a [u32]> {
+    // CHECK-NOT: panic
+    // CHECK-NOT: fail
+    w.next()
+}
+
+// CHECK-LABEL: @next_back
+#[no_mangle]
+pub fn next_back<'a>(w: &mut Windows<'a, u32>) -> Option<&'a [u32]> {
+    // CHECK-NOT: panic
+    // CHECK-NOT: fail
+    w.next_back()
+}
diff --git a/src/test/codegen/tune-cpu-on-functions.rs b/src/test/codegen/tune-cpu-on-functions.rs
new file mode 100644
index 00000000000..9121799cdbf
--- /dev/null
+++ b/src/test/codegen/tune-cpu-on-functions.rs
@@ -0,0 +1,21 @@
+// This test makes sure that functions get annotated with the proper
+// "tune-cpu" attribute in LLVM.
+
+// no-prefer-dynamic
+// ignore-tidy-linelength
+// compile-flags: -C no-prepopulate-passes -C panic=abort -C linker-plugin-lto -Cpasses=name-anon-globals -Z tune-cpu=generic
+
+#![crate_type = "staticlib"]
+
+// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0
+#[no_mangle]
+pub extern fn exported() {
+    not_exported();
+}
+
+// CHECK-LABEL: ; tune_cpu_on_functions::not_exported
+// CHECK-NEXT: ; Function Attrs:
+// CHECK-NEXT: define {{.*}}() {{.*}} #0
+fn not_exported() {}
+
+// CHECK: attributes #0 = {{.*}} "tune-cpu"="{{.*}}"
diff --git a/src/test/compile-fail/issue-27675-unchecked-bounds.rs b/src/test/compile-fail/issue-27675-unchecked-bounds.rs
new file mode 100644
index 00000000000..1cfc2304531
--- /dev/null
+++ b/src/test/compile-fail/issue-27675-unchecked-bounds.rs
@@ -0,0 +1,19 @@
+/// The compiler previously did not properly check the bound of `From` when it was used from type
+/// of the dyn trait object (use in `copy_any` below). Since the associated type is under user
+/// control in this usage, the compiler could be tricked to believe any type implemented any trait.
+/// This would ICE, except for pure marker traits like `Copy`. It did not require providing an
+/// instance of the dyn trait type, only name said type.
+trait Setup {
+    type From: Copy;
+}
+
+fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
+    *from
+}
+
+pub fn copy_any<T>(t: &T) -> T {
+    copy::<dyn Setup<From=T>>(t)
+    //~^ ERROR the trait bound `T: Copy` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/debuginfo/pretty-std-collections.rs b/src/test/debuginfo/pretty-std-collections.rs
index a4fbff5725c..c6d2090759f 100644
--- a/src/test/debuginfo/pretty-std-collections.rs
+++ b/src/test/debuginfo/pretty-std-collections.rs
@@ -34,17 +34,20 @@
 // gdb-check:$6 = BTreeMap(size=15) = {[0] = pretty_std_collections::MyLeafNode (0), [...]}
 // (abbreviated because it's boring but we need enough elements to include internal nodes)
 
+// gdb-command: print zst_btree_map
+// gdb-check:$7 = BTreeMap(size=1)
+
 // gdb-command: print vec_deque
-// gdb-check:$7 = VecDeque(size=3) = {5, 3, 7}
+// gdb-check:$8 = VecDeque(size=3) = {5, 3, 7}
 
 // gdb-command: print vec_deque2
-// gdb-check:$8 = VecDeque(size=7) = {2, 3, 4, 5, 6, 7, 8}
+// gdb-check:$9 = VecDeque(size=7) = {2, 3, 4, 5, 6, 7, 8}
 
 // gdb-command: print hash_map
-// gdb-check:$9 = HashMap(size=4) = {[1] = 10, [2] = 20, [3] = 30, [4] = 40}
+// gdb-check:$10 = HashMap(size=4) = {[1] = 10, [2] = 20, [3] = 30, [4] = 40}
 
 // gdb-command: print hash_set
-// gdb-check:$10 = HashSet(size=4) = {1, 2, 3, 4}
+// gdb-check:$11 = HashSet(size=4) = {1, 2, 3, 4}
 
 // === LLDB TESTS ==================================================================================
 
@@ -69,9 +72,9 @@
 #![allow(unused_variables)]
 use std::collections::BTreeMap;
 use std::collections::BTreeSet;
-use std::collections::VecDeque;
 use std::collections::HashMap;
 use std::collections::HashSet;
+use std::collections::VecDeque;
 use std::hash::{BuildHasherDefault, Hasher};
 
 struct MyLeafNode(i32); // helps to ensure we don't blindly replace substring "LeafNode"
@@ -111,6 +114,9 @@ fn main() {
         nasty_btree_map.insert(i, MyLeafNode(i));
     }
 
+    let mut zst_btree_map: BTreeMap<(), ()> = BTreeMap::new();
+    zst_btree_map.insert((), ());
+
     // VecDeque
     let mut vec_deque = VecDeque::new();
     vec_deque.push_back(5);
diff --git a/src/test/incremental/thinlto/cgu_invalidated_via_import.rs b/src/test/incremental/thinlto/cgu_invalidated_via_import.rs
index 8160f8f3a99..5fe435d796f 100644
--- a/src/test/incremental/thinlto/cgu_invalidated_via_import.rs
+++ b/src/test/incremental/thinlto/cgu_invalidated_via_import.rs
@@ -33,7 +33,9 @@ mod foo {
 
     #[cfg(not(cfail1))]
     pub fn inlined_fn() -> u32 {
-        1234
+        // See `cgu_keeps_identical_fn.rs` for why this is different
+        // from the other version of this function.
+        12345
     }
 }
 
diff --git a/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs b/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs
new file mode 100644
index 00000000000..0fd5abee118
--- /dev/null
+++ b/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs
@@ -0,0 +1,47 @@
+// This test is almost identical to `cgu_invalided_via_import`, except that
+// the two versions of `inline_fn` are identical. Neither version of `inlined_fn`
+// ends up with any spans in its LLVM bitecode, so LLVM is able to skip
+// re-building any modules which import 'inlined_fn'
+
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph -O
+// build-pass (FIXME(62277): could be check-pass?)
+
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-foo",
+                            cfg="cfail2",
+                            kind="no")]
+#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-foo",
+                            cfg="cfail3",
+                            kind="post-lto")]
+
+#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-bar",
+                            cfg="cfail2",
+                            kind="post-lto")]
+#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-bar",
+                            cfg="cfail3",
+                            kind="post-lto")]
+
+mod foo {
+
+    // Trivial functions like this one are imported very reliably by ThinLTO.
+    #[cfg(cfail1)]
+    pub fn inlined_fn() -> u32 {
+        1234
+    }
+
+    #[cfg(not(cfail1))]
+    pub fn inlined_fn() -> u32 {
+        1234
+    }
+}
+
+pub mod bar {
+    use foo::inlined_fn;
+
+    pub fn caller() -> u32 {
+        inlined_fn()
+    }
+}
diff --git a/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs b/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs
index 24e5d2438bd..045f2011958 100644
--- a/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs
+++ b/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs
@@ -37,7 +37,9 @@ mod foo {
 
     #[cfg(not(cfail1))]
     pub fn inlined_fn() -> u32 {
-        1234
+        // See `cgu_keeps_identical_fn.rs` for why this is different
+        // from the other version of this function.
+        12345
     }
 }
 
diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir
index d9c6b4f0029..0d5760b4cd5 100644
--- a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir
+++ b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir
@@ -5,8 +5,6 @@ promoted[0] in FOO: &[&i32; 1] = {
     let mut _1: [&i32; 1];               // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
     let mut _2: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45
     let mut _3: &i32;                    // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
-    scope 1 {
-    }
 
     bb0: {
         _3 = const {alloc2: &i32};       // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
index dd49ca67c67..0e1bef6f68d 100644
--- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
+++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
@@ -3,7 +3,6 @@
 extern crate rustc_codegen_ssa;
 extern crate rustc_errors;
 extern crate rustc_middle;
-#[macro_use]
 extern crate rustc_data_structures;
 extern crate rustc_driver;
 extern crate rustc_hir;
@@ -12,17 +11,19 @@ extern crate rustc_span;
 extern crate rustc_symbol_mangling;
 extern crate rustc_target;
 
+use rustc_codegen_ssa::back::linker::LinkerInfo;
 use rustc_codegen_ssa::traits::CodegenBackend;
-use rustc_data_structures::owning_ref::OwningRef;
+use rustc_codegen_ssa::{CodegenResults, CrateInfo};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::MetadataRef;
 use rustc_errors::ErrorReported;
 use rustc_middle::dep_graph::DepGraph;
+use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::OutputFilenames;
 use rustc_session::Session;
-use rustc_span::symbol::Symbol;
 use rustc_target::spec::Target;
 use std::any::Any;
 use std::path::Path;
@@ -31,14 +32,11 @@ pub struct NoLlvmMetadataLoader;
 
 impl MetadataLoader for NoLlvmMetadataLoader {
     fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> {
-        let buf =
-            std::fs::read(filename).map_err(|e| format!("metadata file open err: {:?}", e))?;
-        let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf);
-        Ok(rustc_erase_owner!(buf.map_owner_box()))
+        unreachable!("some_crate.rs shouldn't depend on any external crates");
     }
 
     fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> {
-        self.get_rlib_metadata(target, filename)
+        unreachable!("some_crate.rs shouldn't depend on any external crates");
     }
 }
 
@@ -49,53 +47,49 @@ impl CodegenBackend for TheBackend {
         Box::new(NoLlvmMetadataLoader)
     }
 
-    fn provide(&self, providers: &mut Providers) {
-        rustc_symbol_mangling::provide(providers);
-
-        providers.supported_target_features = |tcx, _cnum| {
-            Default::default() // Just a dummy
-        };
-        providers.is_reachable_non_generic = |_tcx, _defid| true;
-        providers.exported_symbols = |_tcx, _crate| &[];
-    }
-
-    fn provide_extern(&self, providers: &mut Providers) {
-        providers.is_reachable_non_generic = |_tcx, _defid| true;
-    }
+    fn provide(&self, providers: &mut Providers) {}
+    fn provide_extern(&self, providers: &mut Providers) {}
 
     fn codegen_crate<'a, 'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
-        _metadata: EncodedMetadata,
+        metadata: EncodedMetadata,
         _need_metadata_module: bool,
     ) -> Box<dyn Any> {
         use rustc_hir::def_id::LOCAL_CRATE;
 
-        Box::new(tcx.crate_name(LOCAL_CRATE) as Symbol)
+        Box::new(CodegenResults {
+            crate_name: tcx.crate_name(LOCAL_CRATE),
+            modules: vec![],
+            allocator_module: None,
+            metadata_module: None,
+            metadata,
+            windows_subsystem: None,
+            linker_info: LinkerInfo::new(tcx),
+            crate_info: CrateInfo::new(tcx),
+        })
     }
 
     fn join_codegen(
         &self,
         ongoing_codegen: Box<dyn Any>,
         _sess: &Session,
-        _dep_graph: &DepGraph,
-    ) -> Result<Box<dyn Any>, ErrorReported> {
-        let crate_name = ongoing_codegen
-            .downcast::<Symbol>()
-            .expect("in join_codegen: ongoing_codegen is not a Symbol");
-        Ok(crate_name)
+    ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
+        let codegen_results = ongoing_codegen
+            .downcast::<CodegenResults>()
+            .expect("in join_codegen: ongoing_codegen is not a CodegenResults");
+        Ok((*codegen_results, FxHashMap::default()))
     }
 
     fn link(
         &self,
         sess: &Session,
-        codegen_results: Box<dyn Any>,
+        codegen_results: CodegenResults,
         outputs: &OutputFilenames,
     ) -> Result<(), ErrorReported> {
         use rustc_session::{config::CrateType, output::out_filename};
         use std::io::Write;
-        let crate_name =
-            codegen_results.downcast::<Symbol>().expect("in link: codegen_results is not a Symbol");
+        let crate_name = codegen_results.crate_name;
         for &crate_type in sess.opts.crate_types.iter() {
             if crate_type != CrateType::Rlib {
                 sess.fatal(&format!("Crate type is {:?}", crate_type));
diff --git a/src/test/rustdoc-js/doc-alias-whitespace.js b/src/test/rustdoc-js/doc-alias-whitespace.js
new file mode 100644
index 00000000000..c9fc0c4311f
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias-whitespace.js
@@ -0,0 +1,19 @@
+// exact-check
+
+const QUERY = [
+    'Demon Lord',
+];
+
+const EXPECTED = [
+    {
+        'others': [
+            {
+                'path': 'doc_alias_whitespace',
+                'name': 'Struct',
+                'alias': 'Demon Lord',
+                'href': '../doc_alias_whitespace/struct.Struct.html',
+                'is_alias': true
+            },
+        ],
+    },
+];
diff --git a/src/test/rustdoc-js/doc-alias-whitespace.rs b/src/test/rustdoc-js/doc-alias-whitespace.rs
new file mode 100644
index 00000000000..bea3e382ae4
--- /dev/null
+++ b/src/test/rustdoc-js/doc-alias-whitespace.rs
@@ -0,0 +1,4 @@
+#![feature(doc_alias)]
+
+#[doc(alias = "Demon Lord")]
+pub struct Struct;
diff --git a/src/test/rustdoc-ui/auxiliary/intra-doc-broken.rs b/src/test/rustdoc-ui/auxiliary/intra-doc-broken.rs
new file mode 100644
index 00000000000..31a8310d472
--- /dev/null
+++ b/src/test/rustdoc-ui/auxiliary/intra-doc-broken.rs
@@ -0,0 +1,4 @@
+#![crate_name = "intra_doc_broken"]
+
+/// [not_found]
+pub fn foo() {}
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/rustdoc-ui/check-doc-alias-attr.rs
index c8bec39fad6..0ca2349a43b 100644
--- a/src/test/rustdoc-ui/check-doc-alias-attr.rs
+++ b/src/test/rustdoc-ui/check-doc-alias-attr.rs
@@ -11,6 +11,7 @@ pub struct Bar;
 #[doc(alias = "\n")] //~ ERROR
 #[doc(alias = "
 ")] //~^ ERROR
-#[doc(alias = " ")] //~ ERROR
 #[doc(alias = "\t")] //~ ERROR
+#[doc(alias = " hello")] //~ ERROR
+#[doc(alias = "hello ")] //~ ERROR
 pub struct Foo;
diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr
index be7d7b3dbea..2c417a3bb65 100644
--- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr
+++ b/src/test/rustdoc-ui/check-doc-alias-attr.stderr
@@ -36,17 +36,23 @@ LL |   #[doc(alias = "
 LL | | ")]
    | |_^
 
-error: ' ' character isn't allowed in `#[doc(alias = "...")]`
+error: '\t' character isn't allowed in `#[doc(alias = "...")]`
   --> $DIR/check-doc-alias-attr.rs:14:7
    |
-LL | #[doc(alias = " ")]
-   |       ^^^^^^^^^^^
+LL | #[doc(alias = "\t")]
+   |       ^^^^^^^^^^^^
 
-error: '\t' character isn't allowed in `#[doc(alias = "...")]`
+error: `#[doc(alias = "...")]` cannot start or end with ' '
   --> $DIR/check-doc-alias-attr.rs:15:7
    |
-LL | #[doc(alias = "\t")]
-   |       ^^^^^^^^^^^^
+LL | #[doc(alias = " hello")]
+   |       ^^^^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` cannot start or end with ' '
+  --> $DIR/check-doc-alias-attr.rs:16:7
+   |
+LL | #[doc(alias = "hello ")]
+   |       ^^^^^^^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.rs b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs
new file mode 100644
index 00000000000..c077be31b20
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs
@@ -0,0 +1,41 @@
+// compile-flags:-Z unstable-options --show-coverage
+// check-pass
+
+//! Make sure to have some docs on your crate root
+
+#[allow(missing_docs)]
+pub mod mod_foo {
+    pub struct Bar;
+}
+
+/// This is a struct with a `#[allow(missing_docs)]`
+pub struct AllowTheMissingDocs {
+    #[allow(missing_docs)]
+    pub empty_str: String,
+
+    /// This has
+    #[allow(missing_docs)]
+    /// but also has documentation comments
+    pub hello: usize,
+
+    /// The doc id just to create a boilerplate comment
+    pub doc_id: Vec<u8>,
+}
+
+/// A function that has a documentation
+pub fn this_is_func() {}
+
+#[allow(missing_docs)]
+pub struct DemoStruct {
+    something: usize,
+}
+
+#[allow(missing_docs)]
+pub mod bar {
+    #[warn(missing_docs)]
+    pub struct Bar { //~ WARN
+        pub f: u32, //~ WARN
+    }
+
+    pub struct NeedsNoDocs;
+}
diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr b/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr
new file mode 100644
index 00000000000..3d5b512d14d
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr
@@ -0,0 +1,20 @@
+warning: missing documentation for a struct
+  --> $DIR/allow_missing_docs.rs:36:5
+   |
+LL |     pub struct Bar {
+   |     ^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/allow_missing_docs.rs:35:12
+   |
+LL |     #[warn(missing_docs)]
+   |            ^^^^^^^^^^^^
+
+warning: missing documentation for a struct field
+  --> $DIR/allow_missing_docs.rs:37:9
+   |
+LL |         pub f: u32,
+   |         ^^^^^^^^^^
+
+warning: 2 warnings emitted
+
diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout b/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout
new file mode 100644
index 00000000000..17e8ee9e23d
--- /dev/null
+++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout
@@ -0,0 +1,7 @@
++-------------------------------------+------------+------------+------------+------------+
+| File                                | Documented | Percentage |   Examples | Percentage |
++-------------------------------------+------------+------------+------------+------------+
+| ...i/coverage/allow_missing_docs.rs |          5 |      71.4% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+
+| Total                               |          5 |      71.4% |          0 |       0.0% |
++-------------------------------------+------------+------------+------------+------------+
diff --git a/src/test/rustdoc-ui/intra-doc-broken-reexport.rs b/src/test/rustdoc-ui/intra-doc-broken-reexport.rs
new file mode 100644
index 00000000000..ef261359ebd
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc-broken-reexport.rs
@@ -0,0 +1,8 @@
+// aux-build:intra-doc-broken.rs
+// check-pass
+
+#![deny(broken_intra_doc_links)]
+
+extern crate intra_doc_broken;
+
+pub use intra_doc_broken::foo;
diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs
index ef928ae02f3..81e42643ae8 100644
--- a/src/test/rustdoc-ui/intra-link-errors.rs
+++ b/src/test/rustdoc-ui/intra-link-errors.rs
@@ -2,7 +2,7 @@
 //~^ NOTE lint level is defined
 
 // FIXME: this should say that it was skipped (maybe an allowed by default lint?)
-/// [<invalid syntax>]
+/// [invalid intra-doc syntax!!]
 
 /// [path::to::nonexistent::module]
 //~^ ERROR unresolved link
diff --git a/src/test/rustdoc-ui/intra-link-malformed-generics.rs b/src/test/rustdoc-ui/intra-link-malformed-generics.rs
new file mode 100644
index 00000000000..9c54092146f
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-link-malformed-generics.rs
@@ -0,0 +1,19 @@
+#![deny(broken_intra_doc_links)]
+
+//! [Vec<] //~ ERROR
+//! [Vec<Box<T] //~ ERROR
+//! [Vec<Box<T>] //~ ERROR
+//! [Vec<Box<T>>>] //~ ERROR
+//! [Vec<T>>>] //~ ERROR
+//! [<Vec] //~ ERROR
+//! [Vec::<] //~ ERROR
+//! [<T>] //~ ERROR
+//! [<invalid syntax>] //~ ERROR
+//! [Vec:<T>:new()] //~ ERROR
+//! [Vec<<T>>] //~ ERROR
+//! [Vec<>] //~ ERROR
+//! [Vec<<>>] //~ ERROR
+
+// FIXME(#74563) support UFCS
+//! [<Vec as IntoIterator>::into_iter] //~ ERROR
+//! [<Vec<T> as IntoIterator>::iter] //~ ERROR
diff --git a/src/test/rustdoc-ui/intra-link-malformed-generics.stderr b/src/test/rustdoc-ui/intra-link-malformed-generics.stderr
new file mode 100644
index 00000000000..fe5d4cd1bbf
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-link-malformed-generics.stderr
@@ -0,0 +1,102 @@
+error: unresolved link to `Vec<`
+  --> $DIR/intra-link-malformed-generics.rs:3:6
+   |
+LL | //! [Vec<]
+   |      ^^^^ unbalanced angle brackets
+   |
+note: the lint level is defined here
+  --> $DIR/intra-link-malformed-generics.rs:1:9
+   |
+LL | #![deny(broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+
+error: unresolved link to `Vec<Box<T`
+  --> $DIR/intra-link-malformed-generics.rs:4:6
+   |
+LL | //! [Vec<Box<T]
+   |      ^^^^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `Vec<Box<T>`
+  --> $DIR/intra-link-malformed-generics.rs:5:6
+   |
+LL | //! [Vec<Box<T>]
+   |      ^^^^^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `Vec<Box<T>>>`
+  --> $DIR/intra-link-malformed-generics.rs:6:6
+   |
+LL | //! [Vec<Box<T>>>]
+   |      ^^^^^^^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `Vec<T>>>`
+  --> $DIR/intra-link-malformed-generics.rs:7:6
+   |
+LL | //! [Vec<T>>>]
+   |      ^^^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `<Vec`
+  --> $DIR/intra-link-malformed-generics.rs:8:6
+   |
+LL | //! [<Vec]
+   |      ^^^^ unbalanced angle brackets
+
+error: unresolved link to `Vec::<`
+  --> $DIR/intra-link-malformed-generics.rs:9:6
+   |
+LL | //! [Vec::<]
+   |      ^^^^^^ unbalanced angle brackets
+
+error: unresolved link to `<T>`
+  --> $DIR/intra-link-malformed-generics.rs:10:6
+   |
+LL | //! [<T>]
+   |      ^^^ missing type for generic parameters
+
+error: unresolved link to `<invalid syntax>`
+  --> $DIR/intra-link-malformed-generics.rs:11:6
+   |
+LL | //! [<invalid syntax>]
+   |      ^^^^^^^^^^^^^^^^ missing type for generic parameters
+
+error: unresolved link to `Vec:<T>:new`
+  --> $DIR/intra-link-malformed-generics.rs:12:6
+   |
+LL | //! [Vec:<T>:new()]
+   |      ^^^^^^^^^^^^^ has invalid path separator
+
+error: unresolved link to `Vec<<T>>`
+  --> $DIR/intra-link-malformed-generics.rs:13:6
+   |
+LL | //! [Vec<<T>>]
+   |      ^^^^^^^^ too many angle brackets
+
+error: unresolved link to `Vec<>`
+  --> $DIR/intra-link-malformed-generics.rs:14:6
+   |
+LL | //! [Vec<>]
+   |      ^^^^^ empty angle brackets
+
+error: unresolved link to `Vec<<>>`
+  --> $DIR/intra-link-malformed-generics.rs:15:6
+   |
+LL | //! [Vec<<>>]
+   |      ^^^^^^^ too many angle brackets
+
+error: unresolved link to `<Vec as IntoIterator>::into_iter`
+  --> $DIR/intra-link-malformed-generics.rs:18:6
+   |
+LL | //! [<Vec as IntoIterator>::into_iter]
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported
+   |
+   = note: see https://github.com/rust-lang/rust/issues/74563 for more information
+
+error: unresolved link to `<Vec<T> as IntoIterator>::iter`
+  --> $DIR/intra-link-malformed-generics.rs:19:6
+   |
+LL | //! [<Vec<T> as IntoIterator>::iter]
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported
+   |
+   = note: see https://github.com/rust-lang/rust/issues/74563 for more information
+
+error: aborting due to 15 previous errors
+
diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.rs b/src/test/rustdoc-ui/intra-links-ambiguity.rs
index d1597cdca66..f63435337cf 100644
--- a/src/test/rustdoc-ui/intra-links-ambiguity.rs
+++ b/src/test/rustdoc-ui/intra-links-ambiguity.rs
@@ -34,3 +34,7 @@ pub mod foo {
 ///
 /// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar`
 pub struct Docs {}
+
+/// [true] //~ ERROR `true` is both a module and a builtin type
+/// [primitive@true]
+pub mod r#true {}
diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
index 17891ca05ef..21b92a96737 100644
--- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr
+++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr
@@ -82,5 +82,20 @@ help: to link to the function, add parentheses
 LL | /// Ambiguous non-implied shortcut link [`foo::bar()`].
    |                                          ^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: `true` is both a module and a builtin type
+  --> $DIR/intra-links-ambiguity.rs:38:6
+   |
+LL | /// [true]
+   |      ^^^^ ambiguous link
+   |
+help: to link to the module, prefix with `mod@`
+   |
+LL | /// [mod@true]
+   |      ^^^^^^^^
+help: to link to the builtin type, prefix with `prim@`
+   |
+LL | /// [prim@true]
+   |      ^^^^^^^^^
+
+error: aborting due to 6 previous errors
 
diff --git a/src/test/rustdoc-ui/invalid-html-tags.rs b/src/test/rustdoc-ui/invalid-html-tags.rs
new file mode 100644
index 00000000000..56ca7e79d43
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-html-tags.rs
@@ -0,0 +1,89 @@
+#![deny(invalid_html_tags)]
+
+//! <p>💩<p>
+//~^ ERROR unclosed HTML tag `p`
+//~^^ ERROR unclosed HTML tag `p`
+
+/// <img><input>
+/// <script>
+/// <img><input>
+/// </script>
+/// <unknown>
+//~^ ERROR unclosed HTML tag `unknown`
+/// < ok
+/// <script>
+//~^ ERROR unclosed HTML tag `script`
+pub fn foo() {}
+
+/// <h1>
+///   <h2>
+//~^ ERROR unclosed HTML tag `h2`
+///     <h3>
+//~^ ERROR unclosed HTML tag `h3`
+/// </h1>
+/// </hello>
+//~^ ERROR unopened HTML tag `hello`
+pub fn bar() {}
+
+/// <div>
+///    <br/> <p>
+//~^ ERROR unclosed HTML tag `p`
+/// </div>
+pub fn a() {}
+
+/// <div>
+///   <p>
+///      <div></div>
+///   </p>
+/// </div>
+pub fn b() {}
+
+/// <div style="hello">
+//~^ ERROR unclosed HTML tag `div`
+///   <h3>
+//~^ ERROR unclosed HTML tag `h3`
+/// <script
+//~^ ERROR unclosed HTML tag `script`
+pub fn c() {}
+
+// Unclosed tags shouldn't warn if they are nested inside a <script> elem.
+/// <script>
+///   <h3><div>
+/// </script>
+/// <script>
+///   <div>
+///     <p>
+///   </div>
+/// </script>
+pub fn d() {}
+
+// Unclosed tags shouldn't warn if they are nested inside a <style> elem.
+/// <style>
+///   <h3><div>
+/// </style>
+/// <stYle>
+///   <div>
+///     <p>
+///   </div>
+/// </style>
+pub fn e() {}
+
+// Closing tags need to have ">" at the end, otherwise it's not a closing tag!
+/// <div></div >
+/// <div></div
+//~^ ERROR unclosed HTML tag `div`
+pub fn f() {}
+
+/// <!---->
+/// <!-- -->
+/// <!-- <div> -->
+/// <!-- <!-- -->
+pub fn g() {}
+
+/// <!--
+/// -->
+pub fn h() {}
+
+/// <!--
+//~^ ERROR Unclosed HTML comment
+pub fn i() {}
diff --git a/src/test/rustdoc-ui/invalid-html-tags.stderr b/src/test/rustdoc-ui/invalid-html-tags.stderr
new file mode 100644
index 00000000000..aa9ace006bd
--- /dev/null
+++ b/src/test/rustdoc-ui/invalid-html-tags.stderr
@@ -0,0 +1,86 @@
+error: unclosed HTML tag `p`
+  --> $DIR/invalid-html-tags.rs:3:5
+   |
+LL | //! <p>💩<p>
+   |     ^^^
+   |
+note: the lint level is defined here
+  --> $DIR/invalid-html-tags.rs:1:9
+   |
+LL | #![deny(invalid_html_tags)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: unclosed HTML tag `p`
+  --> $DIR/invalid-html-tags.rs:3:9
+   |
+LL | //! <p>💩<p>
+   |          ^^^
+
+error: unclosed HTML tag `unknown`
+  --> $DIR/invalid-html-tags.rs:11:5
+   |
+LL | /// <unknown>
+   |     ^^^^^^^^^
+
+error: unclosed HTML tag `script`
+  --> $DIR/invalid-html-tags.rs:14:5
+   |
+LL | /// <script>
+   |     ^^^^^^^^
+
+error: unclosed HTML tag `h2`
+  --> $DIR/invalid-html-tags.rs:19:7
+   |
+LL | ///   <h2>
+   |       ^^^^
+
+error: unclosed HTML tag `h3`
+  --> $DIR/invalid-html-tags.rs:21:9
+   |
+LL | ///     <h3>
+   |         ^^^^
+
+error: unopened HTML tag `hello`
+  --> $DIR/invalid-html-tags.rs:24:5
+   |
+LL | /// </hello>
+   |     ^^^^^^^^
+
+error: unclosed HTML tag `p`
+  --> $DIR/invalid-html-tags.rs:29:14
+   |
+LL | ///    <br/> <p>
+   |              ^^^
+
+error: unclosed HTML tag `div`
+  --> $DIR/invalid-html-tags.rs:41:5
+   |
+LL | /// <div style="hello">
+   |     ^^^^
+
+error: unclosed HTML tag `h3`
+  --> $DIR/invalid-html-tags.rs:43:7
+   |
+LL | ///   <h3>
+   |       ^^^^
+
+error: unclosed HTML tag `script`
+  --> $DIR/invalid-html-tags.rs:45:5
+   |
+LL | /// <script
+   |     ^^^^^^
+
+error: unclosed HTML tag `div`
+  --> $DIR/invalid-html-tags.rs:73:5
+   |
+LL | /// <div></div
+   |     ^^^^^
+
+error: Unclosed HTML comment
+  --> $DIR/invalid-html-tags.rs:87:5
+   |
+LL | /// <!--
+   |     ^^^
+
+error: aborting due to 13 previous errors
+
diff --git a/src/test/rustdoc-ui/lint-group.rs b/src/test/rustdoc-ui/lint-group.rs
index e58c8b12f68..1446f7f1c1f 100644
--- a/src/test/rustdoc-ui/lint-group.rs
+++ b/src/test/rustdoc-ui/lint-group.rs
@@ -22,3 +22,8 @@ pub fn no_doctest() {} //~^ ERROR missing code example in this documentation
 /// println!("sup");
 /// ```
 fn private_doctest() {} //~^^^^^ ERROR documentation test in private item
+
+/// <unknown>
+//~^ ERROR unclosed HTML tag `unknown`
+//~^^ ERROR missing code example
+pub fn c() {}
diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr
index 32be90193fe..0c111a33b65 100644
--- a/src/test/rustdoc-ui/lint-group.stderr
+++ b/src/test/rustdoc-ui/lint-group.stderr
@@ -28,6 +28,12 @@ LL | #![deny(rustdoc)]
    |         ^^^^^^^
    = note: `#[deny(private_doc_tests)]` implied by `#[deny(rustdoc)]`
 
+error: missing code example in this documentation
+  --> $DIR/lint-group.rs:26:1
+   |
+LL | /// <unknown>
+   | ^^^^^^^^^^^^^
+
 error: unresolved link to `error`
   --> $DIR/lint-group.rs:9:29
    |
@@ -42,5 +48,18 @@ LL | #![deny(rustdoc)]
    = note: `#[deny(broken_intra_doc_links)]` implied by `#[deny(rustdoc)]`
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
-error: aborting due to 3 previous errors
+error: unclosed HTML tag `unknown`
+  --> $DIR/lint-group.rs:26:5
+   |
+LL | /// <unknown>
+   |     ^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/lint-group.rs:7:9
+   |
+LL | #![deny(rustdoc)]
+   |         ^^^^^^^
+   = note: `#[deny(invalid_html_tags)]` implied by `#[deny(rustdoc)]`
+
+error: aborting due to 5 previous errors
 
diff --git a/src/test/rustdoc-ui/pub-export-lint.rs b/src/test/rustdoc-ui/pub-export-lint.rs
new file mode 100644
index 00000000000..3fd3f774009
--- /dev/null
+++ b/src/test/rustdoc-ui/pub-export-lint.rs
@@ -0,0 +1,5 @@
+#![deny(broken_intra_doc_links)]
+
+/// [aloha]
+//~^ ERROR unresolved link to `aloha`
+pub use std::task::RawWakerVTable;
diff --git a/src/test/rustdoc-ui/pub-export-lint.stderr b/src/test/rustdoc-ui/pub-export-lint.stderr
new file mode 100644
index 00000000000..c345def794c
--- /dev/null
+++ b/src/test/rustdoc-ui/pub-export-lint.stderr
@@ -0,0 +1,15 @@
+error: unresolved link to `aloha`
+  --> $DIR/pub-export-lint.rs:3:6
+   |
+LL | /// [aloha]
+   |      ^^^^^ no item named `aloha` in scope
+   |
+note: the lint level is defined here
+  --> $DIR/pub-export-lint.rs:1:9
+   |
+LL | #![deny(broken_intra_doc_links)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs
new file mode 100644
index 00000000000..fc51995a94e
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs
@@ -0,0 +1,6 @@
+#![crate_name = "inner"]
+
+/// Links to [f()]
+pub struct Inner;
+
+pub fn f() {}
diff --git a/src/test/rustdoc/auxiliary/reexport-check.rs b/src/test/rustdoc/auxiliary/reexport-check.rs
new file mode 100644
index 00000000000..672ccb1cf0e
--- /dev/null
+++ b/src/test/rustdoc/auxiliary/reexport-check.rs
@@ -0,0 +1,2 @@
+/// Docs in original
+pub struct S;
diff --git a/src/test/rustdoc/doc-cfg-simplification.rs b/src/test/rustdoc/doc-cfg-simplification.rs
new file mode 100644
index 00000000000..633df661be0
--- /dev/null
+++ b/src/test/rustdoc/doc-cfg-simplification.rs
@@ -0,0 +1,182 @@
+#![crate_name = "globuliferous"]
+#![feature(doc_cfg)]
+
+// @has 'globuliferous/index.html'
+// @count   - '//*[@class="stab portability"]' 1
+// @matches - '//*[@class="stab portability"]' '^ratel$'
+
+// @has 'globuliferous/ratel/index.html'
+// @count   - '//*[@class="stab portability"]' 8
+// @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+// @matches - '//*[@class="stab portability"]' '^zoonosology$'
+// @matches - '//*[@class="stab portability"]' '^yusho$'
+// @matches - '//*[@class="stab portability"]' '^nunciative$'
+// @matches - '//*[@class="stab portability"]' '^thionic$'
+// @matches - '//*[@class="stab portability"]' '^zincic$'
+// @matches - '//*[@class="stab portability"]' '^cosmotellurian$'
+// @matches - '//*[@class="stab portability"]' '^aposiopesis$'
+#[doc(cfg(feature = "ratel"))]
+pub mod ratel {
+    // @has 'globuliferous/ratel/fn.ovicide.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+    pub fn ovicide() {}
+
+    // @has 'globuliferous/ratel/fn.zoonosology.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and zoonosology'
+    #[doc(cfg(feature = "zoonosology"))]
+    pub fn zoonosology() {}
+
+    // @has 'globuliferous/ratel/constant.DIAGRAPHICS.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+    pub const DIAGRAPHICS: () = ();
+
+    // @has 'globuliferous/ratel/constant.YUSHO.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and yusho'
+    #[doc(cfg(feature = "yusho"))]
+    pub const YUSHO: () = ();
+
+    // @has 'globuliferous/ratel/static.KEYBUGLE.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+    pub static KEYBUGLE: () = ();
+
+    // @has 'globuliferous/ratel/static.NUNCIATIVE.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and nunciative'
+    #[doc(cfg(feature = "nunciative"))]
+    pub static NUNCIATIVE: () = ();
+
+    // @has 'globuliferous/ratel/type.Wrick.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+    pub type Wrick = ();
+
+    // @has 'globuliferous/ratel/type.Thionic.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and thionic'
+    #[doc(cfg(feature = "thionic"))]
+    pub type Thionic = ();
+
+    // @has 'globuliferous/ratel/struct.Eventration.html'
+    // @count   - '//*[@class="stab portability"]' 1
+    // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+    pub struct Eventration;
+
+    // @has 'globuliferous/ratel/struct.Zincic.html'
+    // @count   - '//*[@class="stab portability"]' 2
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and zincic'
+    // @matches - '//*[@class="stab portability"]' 'crate feature rutherford'
+    #[doc(cfg(feature = "zincic"))]
+    pub struct Zincic {
+        pub rectigrade: (),
+
+        #[doc(cfg(feature = "rutherford"))]
+        pub rutherford: (),
+    }
+
+    // @has 'globuliferous/ratel/enum.Cosmotellurian.html'
+    // @count   - '//*[@class="stab portability"]' 10
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and cosmotellurian'
+    // @matches - '//*[@class="stab portability"]' 'crate feature biotaxy'
+    // @matches - '//*[@class="stab portability"]' 'crate feature xiphopagus'
+    // @matches - '//*[@class="stab portability"]' 'crate feature juxtapositive'
+    // @matches - '//*[@class="stab portability"]' 'crate feature fuero'
+    // @matches - '//*[@class="stab portability"]' 'crate feature palaeophile'
+    // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth'
+    // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and xanthocomic'
+    // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth'
+    // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and whosoever'
+    #[doc(cfg(feature = "cosmotellurian"))]
+    pub enum Cosmotellurian {
+        Groundsel {
+            jagger: (),
+
+            #[doc(cfg(feature = "xiphopagus"))]
+            xiphopagus: (),
+        },
+
+        #[doc(cfg(feature = "biotaxy"))]
+        Biotaxy {
+            glossography: (),
+
+            #[doc(cfg(feature = "juxtapositive"))]
+            juxtapositive: (),
+        },
+    }
+
+    impl Cosmotellurian {
+        pub fn uxoricide() {}
+
+        #[doc(cfg(feature = "fuero"))]
+        pub fn fuero() {}
+
+        pub const MAMELLE: () = ();
+
+        #[doc(cfg(feature = "palaeophile"))]
+        pub const PALAEOPHILE: () = ();
+    }
+
+    #[doc(cfg(feature = "broadcloth"))]
+    impl Cosmotellurian {
+        pub fn trabeculated() {}
+
+        #[doc(cfg(feature = "xanthocomic"))]
+        pub fn xanthocomic() {}
+
+        pub const BRACHIFEROUS: () = ();
+
+        #[doc(cfg(feature = "whosoever"))]
+        pub const WHOSOEVER: () = ();
+    }
+
+    // @has 'globuliferous/ratel/trait.Gnotobiology.html'
+    // @count   - '//*[@class="stab portability"]' 4
+    // @matches - '//*[@class="stab portability"]' 'crate feature ratel'
+    // @matches - '//*[@class="stab portability"]' 'crate feature unzymotic'
+    // @matches - '//*[@class="stab portability"]' 'crate feature summate'
+    // @matches - '//*[@class="stab portability"]' 'crate feature unctuous'
+    pub trait Gnotobiology {
+        const XYLOTHERAPY: ();
+
+        #[doc(cfg(feature = "unzymotic"))]
+        const UNZYMOTIC: ();
+
+        type Lepadoid;
+
+        #[doc(cfg(feature = "summate"))]
+        type Summate;
+
+        fn decalcomania();
+
+        #[doc(cfg(feature = "unctuous"))]
+        fn unctuous();
+    }
+
+    // @has 'globuliferous/ratel/trait.Aposiopesis.html'
+    // @count   - '//*[@class="stab portability"]' 4
+    // @matches - '//*[@class="stab portability"]' 'crate features ratel and aposiopesis'
+    // @matches - '//*[@class="stab portability"]' 'crate feature umbracious'
+    // @matches - '//*[@class="stab portability"]' 'crate feature uakari'
+    // @matches - '//*[@class="stab portability"]' 'crate feature rotograph'
+    #[doc(cfg(feature = "aposiopesis"))]
+    pub trait Aposiopesis {
+        const REDHIBITION: ();
+
+        #[doc(cfg(feature = "umbracious"))]
+        const UMBRACIOUS: ();
+
+        type Ophthalmoscope;
+
+        #[doc(cfg(feature = "uakari"))]
+        type Uakari;
+
+        fn meseems();
+
+        #[doc(cfg(feature = "rotograph"))]
+        fn rotograph();
+    }
+}
diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs
index aa407b7e926..d7041ee2f1a 100644
--- a/src/test/rustdoc/doc-cfg.rs
+++ b/src/test/rustdoc/doc-cfg.rs
@@ -10,9 +10,8 @@ pub struct Portable;
 // @has doc_cfg/unix_only/index.html \
 //  '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \
 //  'This is supported on Unix only.'
-// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AUnix\Z'
-// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AUnix and ARM\Z'
-// @count - '//*[@class="stab portability"]' 3
+// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AARM\Z'
+// @count - '//*[@class="stab portability"]' 2
 #[doc(cfg(unix))]
 pub mod unix_only {
     // @has doc_cfg/unix_only/fn.unix_only_function.html \
@@ -26,7 +25,7 @@ pub mod unix_only {
     // @has doc_cfg/unix_only/trait.ArmOnly.html \
     //  '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \
     //  'This is supported on Unix and ARM only.'
-    // @count - '//*[@class="stab portability"]' 3
+    // @count - '//*[@class="stab portability"]' 2
     #[doc(cfg(target_arch = "arm"))]
     pub trait ArmOnly {
         fn unix_and_arm_only_function();
diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs
index 47ba362c977..7b938af3c7d 100644
--- a/src/test/rustdoc/duplicate-cfg.rs
+++ b/src/test/rustdoc/duplicate-cfg.rs
@@ -14,45 +14,41 @@
 pub struct Foo;
 
 // @has 'foo/bar/index.html'
-// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync$'
-// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` only'
-
-// @has 'foo/bar/struct.Bar.html'
 // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.'
 #[doc(cfg(feature = "sync"))]
 pub mod bar {
+    // @has 'foo/bar/struct.Bar.html'
+    // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.'
     #[doc(cfg(feature = "sync"))]
     pub struct Bar;
 }
 
 // @has 'foo/baz/index.html'
-// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send$'
-// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate features `sync` and `send` only'
-
-// @has 'foo/baz/struct.Baz.html'
 // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.'
 #[doc(cfg(all(feature = "sync", feature = "send")))]
 pub mod baz {
+    // @has 'foo/baz/struct.Baz.html'
+    // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.'
     #[doc(cfg(feature = "sync"))]
     pub struct Baz;
 }
 
-// @has 'foo/qux/struct.Qux.html'
-// @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.'
+// @has 'foo/qux/index.html'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.'
 #[doc(cfg(feature = "sync"))]
 pub mod qux {
+    // @has 'foo/qux/struct.Qux.html'
+    // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.'
     #[doc(cfg(all(feature = "sync", feature = "send")))]
     pub struct Qux;
 }
 
 // @has 'foo/quux/index.html'
-// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send and foo and bar$'
-// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` and crate feature `send` and `foo` and `bar` only'
-
-// @has 'foo/quux/struct.Quux.html'
-// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.'
+// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo only.'
 #[doc(cfg(all(feature = "sync", feature = "send", foo)))]
 pub mod quux {
+    // @has 'foo/quux/struct.Quux.html'
+    // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.'
     #[doc(cfg(all(feature = "send", feature = "sync", bar)))]
     pub struct Quux;
 }
diff --git a/src/test/rustdoc/intra-doc-link-generic-params.rs b/src/test/rustdoc/intra-doc-link-generic-params.rs
new file mode 100644
index 00000000000..7d7289437ff
--- /dev/null
+++ b/src/test/rustdoc/intra-doc-link-generic-params.rs
@@ -0,0 +1,59 @@
+// ignore-tidy-linelength
+
+#![crate_name = "foo"]
+
+//! Here's a link to [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`].
+//! Here's a link to [`Iterator<Box<T>>::Item`].
+//!
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html"]' 'Vec<T>'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item'
+
+//! And what about a link to [just `Option`](Option) and, [with the generic, `Option<T>`](Option<T>)?
+//!
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'just Option'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'with the generic, Option<T>'
+
+//! We should also try linking to [`Result<T, E>`]; it has *two* generics!
+//!
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, E>'
+
+//! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it
+//! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()].
+//! And what about something even harder? That would be [`Vec::<Box<T>>::new()`].
+//!
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()'
+
+//! This is also pretty tricky: [`TypeId::of::<String>()`].
+//! And this too: [`Vec::<std::error::Error>::len`].
+//!
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len'
+
+//! We unofficially and implicitly support things that aren't valid in the actual Rust syntax, like
+//! [`Box::<T>new()`]. We may not support them in the future!
+//!
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()'
+
+//! These will be resolved as regular links:
+//! - [`this is <invalid syntax> first`](https://www.rust-lang.org)
+//! - [`this is <invalid syntax> twice`]
+//! - [`<invalid syntax> thrice`](https://www.rust-lang.org)
+//! - [`<invalid syntax> four times`][rlo]
+//! - [a < b][rlo]
+//! - [c > d]
+//!
+//! [`this is <invalid syntax> twice`]: https://www.rust-lang.org
+//! [rlo]: https://www.rust-lang.org
+//! [c > d]: https://www.rust-lang.org
+//!
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'this is <invalid syntax> first'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'this is <invalid syntax> twice'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' '<invalid syntax> thrice'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' '<invalid syntax> four times'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'a < b'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'c > d'
+
+use std::any::TypeId;
diff --git a/src/test/rustdoc/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/intra-link-reexport-additional-docs.rs
new file mode 100644
index 00000000000..96f3580f305
--- /dev/null
+++ b/src/test/rustdoc/intra-link-reexport-additional-docs.rs
@@ -0,0 +1,23 @@
+// aux-build:intra-link-reexport-additional-docs.rs
+// build-aux-docs
+#![crate_name = "foo"]
+extern crate inner;
+
+// @has foo/struct.Inner.html '//a[@href="../foo/fn.with_code.html"]' 'crate::with_code'
+/// [crate::with_code]
+// @has - '//a[@href="../foo/fn.with_code.html"]' 'different text'
+/// [different text][with_code]
+// @has - '//a[@href="../foo/fn.me_too.html"]' 'me_too'
+#[doc = "[me_too]"]
+// @has - '//a[@href="../foo/fn.me_three.html"]' 'reference link'
+/// This [reference link]
+#[doc = "has an attr in the way"]
+///
+/// [reference link]: me_three
+// Should still resolve links from the original module in that scope
+// @has - '//a[@href="../inner/fn.f.html"]' 'f()'
+pub use inner::Inner;
+
+pub fn with_code() {}
+pub fn me_too() {}
+pub fn me_three() {}
diff --git a/src/test/rustdoc/primitive-link.rs b/src/test/rustdoc/primitive-link.rs
index 8f69b894a22..3041ff77684 100644
--- a/src/test/rustdoc/primitive-link.rs
+++ b/src/test/rustdoc/primitive-link.rs
@@ -7,8 +7,7 @@
 // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'std::primitive::i32'
 // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'std::primitive::str'
 
-// FIXME: this doesn't resolve
-// @ has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
+// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX'
 
 /// It contains [`u32`] and [i64].
 /// It also links to [std::primitive::i32], [std::primitive::str],
diff --git a/src/test/rustdoc/reexport-check.rs b/src/test/rustdoc/reexport-check.rs
new file mode 100644
index 00000000000..066b0cfe5e8
--- /dev/null
+++ b/src/test/rustdoc/reexport-check.rs
@@ -0,0 +1,17 @@
+// aux-build:reexport-check.rs
+#![crate_name = "foo"]
+
+extern crate reexport_check;
+
+// @!has 'foo/index.html' '//code' 'pub use self::i32;'
+// @has 'foo/index.html' '//tr[@class="module-item"]' 'i32'
+// @has 'foo/i32/index.html'
+pub use std::i32;
+// @!has 'foo/index.html' '//code' 'pub use self::string::String;'
+// @has 'foo/index.html' '//tr[@class="module-item"]' 'String'
+pub use std::string::String;
+
+// @has 'foo/index.html' '//td[@class="docblock-short"]' 'Docs in original'
+// this is a no-op, but shows what happens if there's an attribute that isn't a doc-comment
+#[doc(inline)]
+pub use reexport_check::S;
diff --git a/src/test/ui-fulldeps/compiler-calls.rs b/src/test/ui-fulldeps/compiler-calls.rs
index 0025b47403d..a9520b59277 100644
--- a/src/test/ui-fulldeps/compiler-calls.rs
+++ b/src/test/ui-fulldeps/compiler-calls.rs
@@ -26,13 +26,8 @@ fn main() {
     let mut count = 1;
     let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
     rustc_driver::catch_fatal_errors(|| {
-        rustc_driver::run_compiler(
-            &args,
-            &mut TestCalls { count: &mut count },
-            None,
-            None,
-            None,
-        ).ok();
-    }).ok();
+        rustc_driver::RunCompiler::new(&args, &mut TestCalls { count: &mut count }).run().ok();
+    })
+    .ok();
     assert_eq!(count, 2);
 }
diff --git a/src/test/ui/arg-count-mismatch.stderr b/src/test/ui/arg-count-mismatch.stderr
index 7bc06134a69..d0577e4864a 100644
--- a/src/test/ui/arg-count-mismatch.stderr
+++ b/src/test/ui/arg-count-mismatch.stderr
@@ -1,13 +1,16 @@
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/arg-count-mismatch.rs:5:28
    |
-LL | fn f(x: isize) { }
-   | -------------- defined here
-LL | 
 LL | fn main() { let i: (); i = f(); }
    |                            ^-- supplied 0 arguments
    |                            |
    |                            expected 1 argument
+   |
+note: function defined here
+  --> $DIR/arg-count-mismatch.rs:3:4
+   |
+LL | fn f(x: isize) { }
+   |    ^ --------
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/asm/interpolated-idents.rs b/src/test/ui/asm/interpolated-idents.rs
new file mode 100644
index 00000000000..f4cb749307d
--- /dev/null
+++ b/src/test/ui/asm/interpolated-idents.rs
@@ -0,0 +1,24 @@
+// only-x86_64
+
+#![feature(asm)]
+
+macro_rules! m {
+    ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident
+     $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident
+     $noreturn:ident $nostack:ident $att_syntax:ident $options:ident) => {
+        unsafe {
+            asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
+            //~^ ERROR asm outputs are not allowed with the `noreturn` option
+            const x, sym x,
+            $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
+            //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
+            //~| ERROR the `pure` and `noreturn` options are mutually exclusive
+        }
+    };
+}
+
+fn main() {
+    m!(in out lateout inout inlateout const sym
+       pure nomem readonly preserves_flags
+       noreturn nostack att_syntax options);
+}
diff --git a/src/test/ui/asm/interpolated-idents.stderr b/src/test/ui/asm/interpolated-idents.stderr
new file mode 100644
index 00000000000..6ffe8d97b05
--- /dev/null
+++ b/src/test/ui/asm/interpolated-idents.stderr
@@ -0,0 +1,51 @@
+error: the `nomem` and `readonly` options are mutually exclusive
+  --> $DIR/interpolated-idents.rs:13:13
+   |
+LL |               $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | /     m!(in out lateout inout inlateout const sym
+LL | |        pure nomem readonly preserves_flags
+LL | |        noreturn nostack att_syntax options);
+   | |____________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: the `pure` and `noreturn` options are mutually exclusive
+  --> $DIR/interpolated-idents.rs:13:13
+   |
+LL |               $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | /     m!(in out lateout inout inlateout const sym
+LL | |        pure nomem readonly preserves_flags
+LL | |        noreturn nostack att_syntax options);
+   | |____________________________________________- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm outputs are not allowed with the `noreturn` option
+  --> $DIR/interpolated-idents.rs:10:32
+   |
+LL |               asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
+   |                                  ^^^^^^^^^  ^^^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^^^^^
+...
+LL |       m!(in out lateout inout inlateout const sym
+   |  _____-
+   | |_____|
+   | |_____|
+   | |_____|
+   | |
+LL | |        pure nomem readonly preserves_flags
+LL | |        noreturn nostack att_syntax options);
+   | |                                            -
+   | |____________________________________________|
+   | |____________________________________________in this macro invocation
+   | |____________________________________________in this macro invocation
+   | |____________________________________________in this macro invocation
+   |                                              in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/associated-type-bounds/issue-70292.rs b/src/test/ui/associated-type-bounds/issue-70292.rs
new file mode 100644
index 00000000000..945d7688ce6
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-70292.rs
@@ -0,0 +1,21 @@
+// check-pass
+
+#![feature(associated_type_bounds)]
+
+fn foo<F>(_: F)
+where
+    F: for<'a> Trait<Output: 'a>,
+{
+}
+
+trait Trait {
+    type Output;
+}
+
+impl<T> Trait for T {
+    type Output = ();
+}
+
+fn main() {
+    foo(());
+}
diff --git a/src/test/ui/associated-type-bounds/issue-71443-1.rs b/src/test/ui/associated-type-bounds/issue-71443-1.rs
new file mode 100644
index 00000000000..5d2a3e6cbad
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-71443-1.rs
@@ -0,0 +1,9 @@
+#![feature(associated_type_bounds)]
+
+struct Incorrect;
+
+fn hello<F: for<'a> Iterator<Item: 'a>>() {
+    Incorrect //~ERROR: mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-type-bounds/issue-71443-1.stderr b/src/test/ui/associated-type-bounds/issue-71443-1.stderr
new file mode 100644
index 00000000000..a9459ee7432
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-71443-1.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-71443-1.rs:6:5
+   |
+LL | fn hello<F: for<'a> Iterator<Item: 'a>>() {
+   |                                           - help: try adding a return type: `-> Incorrect`
+LL |     Incorrect
+   |     ^^^^^^^^^ expected `()`, found struct `Incorrect`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/associated-type-bounds/issue-71443-2.rs b/src/test/ui/associated-type-bounds/issue-71443-2.rs
new file mode 100644
index 00000000000..813dcd60ad1
--- /dev/null
+++ b/src/test/ui/associated-type-bounds/issue-71443-2.rs
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(associated_type_bounds)]
+
+fn hello<'b, F>()
+where
+    for<'a> F: Iterator<Item: 'a> + 'b,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-types/issue-54108.rs b/src/test/ui/associated-types/issue-54108.rs
new file mode 100644
index 00000000000..87f67ce4b52
--- /dev/null
+++ b/src/test/ui/associated-types/issue-54108.rs
@@ -0,0 +1,41 @@
+use std::ops::Add;
+
+pub trait Encoder {
+    type Size: Add<Output = Self::Size>;
+
+    fn foo(&self) -> Self::Size;
+}
+
+pub trait SubEncoder: Encoder {
+    type ActualSize;
+
+    fn bar(&self) -> Self::Size;
+}
+
+impl<T> Encoder for T
+where
+    T: SubEncoder,
+{
+    type Size = <Self as SubEncoder>::ActualSize;
+    //~^ ERROR: cannot add `<T as SubEncoder>::ActualSize` to `<T as SubEncoder>::ActualSize`
+
+    fn foo(&self) -> Self::Size {
+        self.bar() + self.bar()
+    }
+}
+
+pub struct UnitEncoder;
+
+impl SubEncoder for UnitEncoder {
+    type ActualSize = ();
+
+    fn bar(&self) {}
+}
+
+pub fn fun<R: Encoder>(encoder: &R) {
+    encoder.foo();
+}
+
+fn main() {
+    fun(&UnitEncoder {});
+}
diff --git a/src/test/ui/associated-types/issue-54108.stderr b/src/test/ui/associated-types/issue-54108.stderr
new file mode 100644
index 00000000000..927a2de9965
--- /dev/null
+++ b/src/test/ui/associated-types/issue-54108.stderr
@@ -0,0 +1,18 @@
+error[E0277]: cannot add `<T as SubEncoder>::ActualSize` to `<T as SubEncoder>::ActualSize`
+  --> $DIR/issue-54108.rs:19:5
+   |
+LL |     type Size: Add<Output = Self::Size>;
+   |                ------------------------ required by this bound in `Encoder::Size`
+...
+LL |     type Size = <Self as SubEncoder>::ActualSize;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `<T as SubEncoder>::ActualSize + <T as SubEncoder>::ActualSize`
+   |
+   = help: the trait `Add` is not implemented for `<T as SubEncoder>::ActualSize`
+help: consider further restricting the associated type
+   |
+LL |     T: SubEncoder, <T as SubEncoder>::ActualSize: Add
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/associated-types/issue-65934.rs b/src/test/ui/associated-types/issue-65934.rs
new file mode 100644
index 00000000000..e17b11c5eae
--- /dev/null
+++ b/src/test/ui/associated-types/issue-65934.rs
@@ -0,0 +1,17 @@
+// check-pass
+
+trait Trait {
+    type Assoc;
+}
+
+impl Trait for () {
+    type Assoc = ();
+}
+
+fn unit() -> impl Into<<() as Trait>::Assoc> {}
+
+pub fn ice() {
+    Into::into(unit());
+}
+
+fn main() {}
diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs
index b67d494866b..97f96ab6929 100644
--- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs
+++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs
@@ -3,8 +3,6 @@
 #![feature(or_patterns)]
 #![feature(box_patterns)]
 
-#![feature(move_ref_pattern)]
-
 enum Test {
     Foo,
     Bar,
diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
index 1bf81589275..96e313b39ed 100644
--- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
+++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
@@ -1,5 +1,5 @@
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:40:9
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:38:9
    |
 LL |         ref foo @ [.., ref mut bar] => (),
    |         -------^^^^^^^^-----------^
@@ -8,7 +8,7 @@ LL |         ref foo @ [.., ref mut bar] => (),
    |         immutable borrow, by `foo`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:124:9
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:122:9
    |
 LL |         ref foo @ Some(box ref mut s) => (),
    |         -------^^^^^^^^^^^^---------^
@@ -17,7 +17,7 @@ LL |         ref foo @ Some(box ref mut s) => (),
    |         immutable borrow, by `foo`, occurs here
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:22:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:20:5
    |
 LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) {
    |                                                  - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait
@@ -29,7 +29,7 @@ LL |     &x;
    |     ^^ value borrowed here after move
 
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:32:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:30:5
    |
 LL |         ref mut foo @ [.., _] => Some(foo),
    |         --------------------- mutable borrow occurs here
@@ -41,7 +41,7 @@ LL |     drop(r);
    |          - mutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:54:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:52:5
    |
 LL |         [ref foo @ .., ref bar] => Some(foo),
    |          ------------ immutable borrow occurs here
@@ -53,7 +53,7 @@ LL |     drop(r);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:66:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:64:5
    |
 LL |         ref foo @ [.., ref bar] => Some(foo),
    |         ----------------------- immutable borrow occurs here
@@ -65,7 +65,7 @@ LL |     drop(r);
    |          - immutable borrow later used here
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:80:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:78:5
    |
 LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) {
    |                                       - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait
@@ -80,7 +80,7 @@ LL |     &x;
    |     ^^ value borrowed here after move
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:90:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:88:5
    |
 LL |         ref foo @ Some(Test::Foo | Test::Bar) => Some(foo),
    |         ------------------------------------- immutable borrow occurs here
@@ -92,7 +92,7 @@ LL |     drop(r);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:102:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:100:5
    |
 LL |         ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo),
    |         ----------------------------------------- mutable borrow occurs here
@@ -104,7 +104,7 @@ LL |     drop(r);
    |          - mutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:116:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:114:5
    |
 LL |         ref foo @ Some(box ref s) => Some(foo),
    |         ------------------------- immutable borrow occurs here
@@ -116,7 +116,7 @@ LL |     drop(r);
    |          - immutable borrow later used here
 
 error[E0382]: borrow of moved value: `x`
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:138:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:136:5
    |
 LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4]) {
    |                                                       - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait
@@ -131,7 +131,7 @@ LL |     &x;
    |     ^^ value borrowed here after move
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:148:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:146:5
    |
 LL |         ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a),
    |         ------------------------------------------------- immutable borrow occurs here
@@ -143,7 +143,7 @@ LL |     drop(r);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:160:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:158:5
    |
 LL |         ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b),
    |                  ---------- immutable borrow occurs here
@@ -155,7 +155,7 @@ LL |     drop(r);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:174:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:172:5
    |
 LL |         [_, ref a @ Some(box ref b), ..] => Some(a),
    |             ----------------------- immutable borrow occurs here
@@ -167,7 +167,7 @@ LL |     drop(r);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:190:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:188:5
    |
 LL |         [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
    |             ------------------------------------------- immutable borrow occurs here
@@ -179,7 +179,7 @@ LL |     drop(r);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:204:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:202:5
    |
 LL |         [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
    |             ----------------------------------------------- mutable borrow occurs here
@@ -191,7 +191,7 @@ LL |     drop(r);
    |          - mutable borrow later used here
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
-  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:218:5
+  --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:216:5
    |
 LL |         ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a),
    |         ------------------------------------------------------------ immutable borrow occurs here
diff --git a/src/test/ui/borrowck/mut-borrow-of-mut-ref.rs b/src/test/ui/borrowck/mut-borrow-of-mut-ref.rs
index 212f706953e..59b541a24d1 100644
--- a/src/test/ui/borrowck/mut-borrow-of-mut-ref.rs
+++ b/src/test/ui/borrowck/mut-borrow-of-mut-ref.rs
@@ -1,11 +1,11 @@
 // Suggest not mutably borrowing a mutable reference
+#![crate_type = "rlib"]
 
-fn main() {
-    f(&mut 0)
+pub fn f(b: &mut i32) {
+    g(&mut b);
+    //~^ ERROR cannot borrow
+    g(&mut &mut b);
+    //~^ ERROR cannot borrow
 }
 
-fn f(b: &mut i32) {
-    g(&mut b) //~ ERROR cannot borrow
-}
-
-fn g(_: &mut i32) {}
+pub fn g(_: &mut i32) {}
diff --git a/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr b/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr
index 09dabbc89b4..8710f204698 100644
--- a/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr
+++ b/src/test/ui/borrowck/mut-borrow-of-mut-ref.stderr
@@ -1,11 +1,21 @@
 error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
-  --> $DIR/mut-borrow-of-mut-ref.rs:8:7
+  --> $DIR/mut-borrow-of-mut-ref.rs:5:7
    |
-LL | fn f(b: &mut i32) {
-   |      - help: consider changing this to be mutable: `mut b`
-LL |     g(&mut b)
-   |       ^^^^^^ cannot borrow as mutable
+LL |     g(&mut b);
+   |       ^^^^^^
+   |       |
+   |       cannot borrow as mutable
+   |       try removing `&mut` here
 
-error: aborting due to previous error
+error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
+  --> $DIR/mut-borrow-of-mut-ref.rs:7:12
+   |
+LL |     g(&mut &mut b);
+   |            ^^^^^^
+   |            |
+   |            cannot borrow as mutable
+   |            try removing `&mut` here
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr
index 89ea65fd43f..6f2a6c359b5 100644
--- a/src/test/ui/c-variadic/variadic-ffi-1.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr
@@ -7,24 +7,30 @@ LL |     fn printf(_: *const u8, ...);
 error[E0060]: this function takes at least 2 arguments but 0 arguments were supplied
   --> $DIR/variadic-ffi-1.rs:17:9
    |
-LL |     fn foo(f: isize, x: u8, ...);
-   |     ----------------------------- defined here
-...
 LL |         foo();
    |         ^^^-- supplied 0 arguments
    |         |
    |         expected at least 2 arguments
+   |
+note: function defined here
+  --> $DIR/variadic-ffi-1.rs:10:8
+   |
+LL |     fn foo(f: isize, x: u8, ...);
+   |        ^^^
 
 error[E0060]: this function takes at least 2 arguments but 1 argument was supplied
   --> $DIR/variadic-ffi-1.rs:18:9
    |
-LL |     fn foo(f: isize, x: u8, ...);
-   |     ----------------------------- defined here
-...
 LL |         foo(1);
    |         ^^^ - supplied 1 argument
    |         |
    |         expected at least 2 arguments
+   |
+note: function defined here
+  --> $DIR/variadic-ffi-1.rs:10:8
+   |
+LL |     fn foo(f: isize, x: u8, ...);
+   |        ^^^
 
 error[E0308]: mismatched types
   --> $DIR/variadic-ffi-1.rs:20:56
diff --git a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr
index 7af38c88f43..e11ba43ca2a 100644
--- a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr
@@ -2,7 +2,7 @@ error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-no-fixed-args.rs:2:12
    |
 LL |     fn foo(...);
-   |            ^^^^
+   |            ^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/check-doc-alias-attr.rs b/src/test/ui/check-doc-alias-attr.rs
index c8bec39fad6..0ca2349a43b 100644
--- a/src/test/ui/check-doc-alias-attr.rs
+++ b/src/test/ui/check-doc-alias-attr.rs
@@ -11,6 +11,7 @@ pub struct Bar;
 #[doc(alias = "\n")] //~ ERROR
 #[doc(alias = "
 ")] //~^ ERROR
-#[doc(alias = " ")] //~ ERROR
 #[doc(alias = "\t")] //~ ERROR
+#[doc(alias = " hello")] //~ ERROR
+#[doc(alias = "hello ")] //~ ERROR
 pub struct Foo;
diff --git a/src/test/ui/check-doc-alias-attr.stderr b/src/test/ui/check-doc-alias-attr.stderr
index be7d7b3dbea..2c417a3bb65 100644
--- a/src/test/ui/check-doc-alias-attr.stderr
+++ b/src/test/ui/check-doc-alias-attr.stderr
@@ -36,17 +36,23 @@ LL |   #[doc(alias = "
 LL | | ")]
    | |_^
 
-error: ' ' character isn't allowed in `#[doc(alias = "...")]`
+error: '\t' character isn't allowed in `#[doc(alias = "...")]`
   --> $DIR/check-doc-alias-attr.rs:14:7
    |
-LL | #[doc(alias = " ")]
-   |       ^^^^^^^^^^^
+LL | #[doc(alias = "\t")]
+   |       ^^^^^^^^^^^^
 
-error: '\t' character isn't allowed in `#[doc(alias = "...")]`
+error: `#[doc(alias = "...")]` cannot start or end with ' '
   --> $DIR/check-doc-alias-attr.rs:15:7
    |
-LL | #[doc(alias = "\t")]
-   |       ^^^^^^^^^^^^
+LL | #[doc(alias = " hello")]
+   |       ^^^^^^^^^^^^^^^^
+
+error: `#[doc(alias = "...")]` cannot start or end with ' '
+  --> $DIR/check-doc-alias-attr.rs:16:7
+   |
+LL | #[doc(alias = "hello ")]
+   |       ^^^^^^^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
index 0fc45513cd7..cfaacf7a5be 100644
--- a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
+++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/array-size-in-generic-struct-param.rs:9:48
    |
 LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
-   |                                                ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                                ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/array-size-in-generic-struct-param.rs:20:15
    |
 LL |     arr: [u8; CFG.arr_size],
-   |               ^^^ non-trivial anonymous constants must not depend on the parameter `CFG`
+   |               ^^^ cannot perform const operation using `CFG`
    |
-   = help: it is currently only allowed to use either `CFG` or `{ CFG }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `CFG`
 
 error: `Config` is forbidden as the type of a const generic parameter
   --> $DIR/array-size-in-generic-struct-param.rs:18:21
diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs
index dd45b6ed278..768180d0813 100644
--- a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs
+++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs
@@ -8,7 +8,7 @@
 #[allow(dead_code)]
 struct ArithArrayLen<const N: usize>([u32; 0 + N]);
 //[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values
+//[min]~^^ ERROR generic parameters may not be used in const operations
 
 #[derive(PartialEq, Eq)]
 struct Config {
@@ -19,7 +19,7 @@ struct B<const CFG: Config> {
     //[min]~^ ERROR `Config` is forbidden
     arr: [u8; CFG.arr_size],
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non-trivial
+    //[min]~^^ ERROR generic parameters may not be used in const operations
 }
 
 const C: Config = Config { arr_size: 5 };
diff --git a/src/test/ui/const-generics/const-argument-if-length.min.stderr b/src/test/ui/const-generics/const-argument-if-length.min.stderr
index c666dce479f..bce701ade86 100644
--- a/src/test/ui/const-generics/const-argument-if-length.min.stderr
+++ b/src/test/ui/const-generics/const-argument-if-length.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/const-argument-if-length.rs:19:24
    |
 LL |     pad: [u8; is_zst::<T>()],
-   |                        ^ non-trivial anonymous constants must not depend on the parameter `T`
+   |                        ^ cannot perform const operation using `T`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/const-argument-if-length.rs:17:12
diff --git a/src/test/ui/const-generics/const-argument-if-length.rs b/src/test/ui/const-generics/const-argument-if-length.rs
index 481ff97d68d..a8bffd17b91 100644
--- a/src/test/ui/const-generics/const-argument-if-length.rs
+++ b/src/test/ui/const-generics/const-argument-if-length.rs
@@ -17,7 +17,7 @@ pub struct AtLeastByte<T: ?Sized> {
     value: T,
     //~^ ERROR the size for values of type `T` cannot be known at compilation time
     pad: [u8; is_zst::<T>()],
-    //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
+    //[min]~^ ERROR generic parameters may not be used in const operations
     //[full]~^^ ERROR evaluation of constant value failed
 }
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr
index 4b3235fd087..359c2d2a22f 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/feature-gate-const_evaluatable_checked.rs:6:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
-   |                                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                 ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs
index d552e0f5430..9746adab29b 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs
@@ -4,7 +4,7 @@
 #![cfg_attr(min, feature(min_const_generics))]
 
 type Arr<const N: usize> = [u8; N - 1];
-//[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
+//[min]~^ ERROR generic parameters may not be used in const operations
 
 fn test<const N: usize>() -> Arr<N> where Arr<N>: Default {
     //[full]~^ ERROR constant expression depends
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
index 85a15b1e75f..46485262cc4 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/simple.rs:8:53
    |
 LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
-   |                                                     ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                                     ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/simple.rs:8:35
    |
 LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default {
-   |                                   ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                   ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
index 2eac9505624..981d993f589 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/simple_fail.rs:7:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
-   |                                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                 ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
index 637c940f714..5e2c080927f 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
@@ -5,7 +5,7 @@
 #![allow(incomplete_features)]
 
 type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant
-//[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
+//[min]~^ ERROR generic parameters may not be used in const operations
 
 fn test<const N: usize>() -> Arr<N> where Arr<N>: Sized {
     todo!()
diff --git a/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr b/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr
index e7e968e4c2a..84449018e46 100644
--- a/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr
+++ b/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/generic-function-call-in-array-length.rs:9:39
    |
 LL | fn bar<const N: usize>() -> [u32; foo(N)] {
-   |                                       ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                       ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/generic-function-call-in-array-length.rs:12:13
    |
 LL |     [0; foo(N)]
-   |             ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |             ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/generic-function-call-in-array-length.rs b/src/test/ui/const-generics/generic-function-call-in-array-length.rs
index c8bbae29343..c838070dc95 100644
--- a/src/test/ui/const-generics/generic-function-call-in-array-length.rs
+++ b/src/test/ui/const-generics/generic-function-call-in-array-length.rs
@@ -7,10 +7,10 @@
 const fn foo(n: usize) -> usize { n * 2 }
 
 fn bar<const N: usize>() -> [u32; foo(N)] {
-    //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
+    //[min]~^ ERROR generic parameters may not be used in const operations
     //[full]~^^ ERROR constant expression depends on a generic parameter
     [0; foo(N)]
-    //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
+    //[min]~^ ERROR generic parameters may not be used in const operations
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr b/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr
index 6f157fbbbbb..d3f7143327e 100644
--- a/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr
+++ b/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/generic-sum-in-array-length.rs:7:53
    |
 LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
-   |                                                     ^ non-trivial anonymous constants must not depend on the parameter `A`
+   |                                                     ^ cannot perform const operation using `A`
    |
-   = help: it is currently only allowed to use either `A` or `{ A }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `A`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/generic-sum-in-array-length.rs:7:57
    |
 LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
-   |                                                         ^ non-trivial anonymous constants must not depend on the parameter `B`
+   |                                                         ^ cannot perform const operation using `B`
    |
-   = help: it is currently only allowed to use either `B` or `{ B }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `B`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/generic-sum-in-array-length.rs b/src/test/ui/const-generics/generic-sum-in-array-length.rs
index 810095b384b..84ddfe055dc 100644
--- a/src/test/ui/const-generics/generic-sum-in-array-length.rs
+++ b/src/test/ui/const-generics/generic-sum-in-array-length.rs
@@ -5,8 +5,8 @@
 #![cfg_attr(min, feature(min_const_generics))]
 
 fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {}
-//[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
-//[min]~| ERROR generic parameters must not be used inside of non-trivial constant values
+//[min]~^ ERROR generic parameters may not be used in const operations
+//[min]~| ERROR generic parameters may not be used in const operations
 //[full]~^^^ ERROR constant expression depends on a generic parameter
 
 fn main() {}
diff --git a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
index 307db088bf8..20a8d9fdaab 100644
--- a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
+++ b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/intrinsics-type_name-as-const-argument.rs:15:44
    |
 LL |     T: Trait<{std::intrinsics::type_name::<T>()}>
-   |                                            ^ non-trivial anonymous constants must not depend on the parameter `T`
+   |                                            ^ cannot perform const operation using `T`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error: `&'static str` is forbidden as the type of a const generic parameter
   --> $DIR/intrinsics-type_name-as-const-argument.rs:10:22
diff --git a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs
index 37b6cf4bab9..8971c00ed5a 100644
--- a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs
+++ b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs
@@ -13,7 +13,7 @@ trait Trait<const S: &'static str> {}
 struct Bug<T>
 where
     T: Trait<{std::intrinsics::type_name::<T>()}>
-    //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
+    //[min]~^ ERROR generic parameters may not be used in const operations
     //[full]~^^ ERROR constant expression depends on a generic parameter
 {
     t: T
diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr
index 2c1bc055b28..526807f0a24 100644
--- a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr
+++ b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-61522-array-len-succ.rs:7:45
    |
 LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
-   |                                             ^^^^^ non-trivial anonymous constants must not depend on the parameter `COUNT`
+   |                                             ^^^^^ cannot perform const operation using `COUNT`
    |
-   = help: it is currently only allowed to use either `COUNT` or `{ COUNT }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-61522-array-len-succ.rs:12:30
    |
 LL |     fn inner(&self) -> &[u8; COUNT + 1] {
-   |                              ^^^^^ non-trivial anonymous constants must not depend on the parameter `COUNT`
+   |                              ^^^^^ cannot perform const operation using `COUNT`
    |
-   = help: it is currently only allowed to use either `COUNT` or `{ COUNT }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.rs b/src/test/ui/const-generics/issue-61522-array-len-succ.rs
index 81443b90d61..8c0a3a03774 100644
--- a/src/test/ui/const-generics/issue-61522-array-len-succ.rs
+++ b/src/test/ui/const-generics/issue-61522-array-len-succ.rs
@@ -6,12 +6,12 @@
 
 pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
 //[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters must not be used
+//[min]~^^ ERROR generic parameters may not be used
 
 impl<const COUNT: usize> MyArray<COUNT> {
     fn inner(&self) -> &[u8; COUNT + 1] {
         //[full]~^ ERROR constant expression depends on a generic parameter
-        //[min]~^^ ERROR generic parameters must not be used
+        //[min]~^^ ERROR generic parameters may not be used
         &self.0
     }
 }
diff --git a/src/test/ui/const-generics/issue-67375.min.stderr b/src/test/ui/const-generics/issue-67375.min.stderr
index b13d9fdab0d..3c344edbf1d 100644
--- a/src/test/ui/const-generics/issue-67375.min.stderr
+++ b/src/test/ui/const-generics/issue-67375.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-67375.rs:9:25
    |
 LL |     inner: [(); { [|_: &T| {}; 0].len() }],
-   |                         ^ non-trivial anonymous constants must not depend on the parameter `T`
+   |                         ^ cannot perform const operation using `T`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error[E0392]: parameter `T` is never used
   --> $DIR/issue-67375.rs:7:12
diff --git a/src/test/ui/const-generics/issue-67375.rs b/src/test/ui/const-generics/issue-67375.rs
index 994ec92cfb5..ecc76bcae06 100644
--- a/src/test/ui/const-generics/issue-67375.rs
+++ b/src/test/ui/const-generics/issue-67375.rs
@@ -7,7 +7,7 @@
 struct Bug<T> {
     //~^ ERROR parameter `T` is never used
     inner: [(); { [|_: &T| {}; 0].len() }],
-    //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
+    //[min]~^ ERROR generic parameters may not be used in const operations
     //[full]~^^ WARN cannot use constants which depend on generic parameters in types
     //[full]~^^^ WARN this was previously accepted by the compiler
 }
diff --git a/src/test/ui/const-generics/issue-67945-1.min.stderr b/src/test/ui/const-generics/issue-67945-1.min.stderr
index 949b5da5920..804236c30bd 100644
--- a/src/test/ui/const-generics/issue-67945-1.min.stderr
+++ b/src/test/ui/const-generics/issue-67945-1.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-67945-1.rs:14:16
    |
 LL |         let x: S = MaybeUninit::uninit();
-   |                ^ non-trivial anonymous constants must not depend on the parameter `S`
+   |                ^ cannot perform const operation using `S`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-67945-1.rs:17:45
    |
 LL |         let b = &*(&x as *const _ as *const S);
-   |                                             ^ non-trivial anonymous constants must not depend on the parameter `S`
+   |                                             ^ cannot perform const operation using `S`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error[E0392]: parameter `S` is never used
   --> $DIR/issue-67945-1.rs:11:12
diff --git a/src/test/ui/const-generics/issue-67945-1.rs b/src/test/ui/const-generics/issue-67945-1.rs
index d1a83e978d1..6771603f259 100644
--- a/src/test/ui/const-generics/issue-67945-1.rs
+++ b/src/test/ui/const-generics/issue-67945-1.rs
@@ -12,10 +12,10 @@ struct Bug<S> {
     //~^ ERROR parameter `S` is never used
     A: [(); {
         let x: S = MaybeUninit::uninit();
-        //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
+        //[min]~^ ERROR generic parameters may not be used in const operations
         //[full]~^^ ERROR mismatched types
         let b = &*(&x as *const _ as *const S);
-        //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
+        //[min]~^ ERROR generic parameters may not be used in const operations
         0
     }],
 }
diff --git a/src/test/ui/const-generics/issue-67945-2.min.stderr b/src/test/ui/const-generics/issue-67945-2.min.stderr
index ed445b3e8f7..2de942c1220 100644
--- a/src/test/ui/const-generics/issue-67945-2.min.stderr
+++ b/src/test/ui/const-generics/issue-67945-2.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-67945-2.rs:12:16
    |
 LL |         let x: S = MaybeUninit::uninit();
-   |                ^ non-trivial anonymous constants must not depend on the parameter `S`
+   |                ^ cannot perform const operation using `S`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-67945-2.rs:15:45
    |
 LL |         let b = &*(&x as *const _ as *const S);
-   |                                             ^ non-trivial anonymous constants must not depend on the parameter `S`
+   |                                             ^ cannot perform const operation using `S`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error[E0392]: parameter `S` is never used
   --> $DIR/issue-67945-2.rs:9:12
diff --git a/src/test/ui/const-generics/issue-67945-2.rs b/src/test/ui/const-generics/issue-67945-2.rs
index 7f789297df0..72dbb674e66 100644
--- a/src/test/ui/const-generics/issue-67945-2.rs
+++ b/src/test/ui/const-generics/issue-67945-2.rs
@@ -10,10 +10,10 @@ struct Bug<S> {
     //~^ ERROR parameter `S` is never used
     A: [(); {
         let x: S = MaybeUninit::uninit();
-        //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
+        //[min]~^ ERROR generic parameters may not be used in const operations
         //[full]~^^ ERROR mismatched types
         let b = &*(&x as *const _ as *const S);
-        //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
+        //[min]~^ ERROR generic parameters may not be used in const operations
         0
     }],
 }
diff --git a/src/test/ui/const-generics/issues/issue-61747.min.stderr b/src/test/ui/const-generics/issues/issue-61747.min.stderr
index fdd9a569748..b176f9d1c75 100644
--- a/src/test/ui/const-generics/issues/issue-61747.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-61747.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-61747.rs:8:30
    |
 LL |     fn successor() -> Const<{C + 1}> {
-   |                              ^ non-trivial anonymous constants must not depend on the parameter `C`
+   |                              ^ cannot perform const operation using `C`
    |
-   = help: it is currently only allowed to use either `C` or `{ C }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `C`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs
index 4e5cde17f39..3a4dd1cdd18 100644
--- a/src/test/ui/const-generics/issues/issue-61747.rs
+++ b/src/test/ui/const-generics/issues/issue-61747.rs
@@ -7,7 +7,7 @@ struct Const<const N: usize>;
 impl<const C: usize> Const<{C}> {
     fn successor() -> Const<{C + 1}> {
         //[full]~^ ERROR constant expression depends on a generic parameter
-        //[min]~^^ ERROR generic parameters must not be used
+        //[min]~^^ ERROR generic parameters may not be used
         Const
     }
 }
diff --git a/src/test/ui/const-generics/issues/issue-61935.min.stderr b/src/test/ui/const-generics/issues/issue-61935.min.stderr
index f461a31eeae..9e31466259f 100644
--- a/src/test/ui/const-generics/issues/issue-61935.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-61935.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-61935.rs:10:23
    |
 LL |         Self:FooImpl<{N==0}>
-   |                       ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                       ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs
index a181a8dabe5..9fa02329a71 100644
--- a/src/test/ui/const-generics/issues/issue-61935.rs
+++ b/src/test/ui/const-generics/issues/issue-61935.rs
@@ -9,7 +9,7 @@ impl<const N: usize> Foo for [(); N]
     where
         Self:FooImpl<{N==0}>
 //[full]~^ERROR constant expression depends on a generic parameter
-//[min]~^^ERROR generic parameters must not be used inside of non-trivial constant values
+//[min]~^^ERROR generic parameters may not be used in const operations
 {}
 
 trait FooImpl<const IS_ZERO: bool>{}
diff --git a/src/test/ui/const-generics/issues/issue-62220.min.stderr b/src/test/ui/const-generics/issues/issue-62220.min.stderr
index 84975e8f3be..3bd127ee74a 100644
--- a/src/test/ui/const-generics/issues/issue-62220.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-62220.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-62220.rs:8:59
    |
 LL | pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
-   |                                                           ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                                           ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs
index 5694dc6d04d..2017473fa9e 100644
--- a/src/test/ui/const-generics/issues/issue-62220.rs
+++ b/src/test/ui/const-generics/issues/issue-62220.rs
@@ -6,7 +6,7 @@
 pub struct Vector<T, const N: usize>([T; N]);
 
 pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>;
-//[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
+//[min]~^ ERROR generic parameters may not be used in const operations
 
 impl<T, const N: usize> Vector<T, { N }> {
     /// Drop the last component and return the vector with one fewer dimension.
diff --git a/src/test/ui/const-generics/issues/issue-62456.min.stderr b/src/test/ui/const-generics/issues/issue-62456.min.stderr
index f94ba8c0c9b..c73f62a4a07 100644
--- a/src/test/ui/const-generics/issues/issue-62456.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-62456.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-62456.rs:7:20
    |
 LL |     let _ = [0u64; N + 1];
-   |                    ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                    ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs
index 338ec42799d..cbb2a11a931 100644
--- a/src/test/ui/const-generics/issues/issue-62456.rs
+++ b/src/test/ui/const-generics/issues/issue-62456.rs
@@ -6,7 +6,7 @@
 fn foo<const N: usize>() {
     let _ = [0u64; N + 1];
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values
+    //[min]~^^ ERROR generic parameters may not be used in const operations
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-64494.min.stderr b/src/test/ui/const-generics/issues/issue-64494.min.stderr
index f712171bbac..8b02fd108bd 100644
--- a/src/test/ui/const-generics/issues/issue-64494.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-64494.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-64494.rs:16:38
    |
 LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
-   |                                      ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T`
+   |                                      ^^^^^^ cannot perform const operation using `T`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-64494.rs:19:38
    |
 LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
-   |                                      ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T`
+   |                                      ^^^^^^ cannot perform const operation using `T`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error[E0119]: conflicting implementations of trait `MyTrait`:
   --> $DIR/issue-64494.rs:19:1
diff --git a/src/test/ui/const-generics/issues/issue-64494.rs b/src/test/ui/const-generics/issues/issue-64494.rs
index b62ebf846d5..014742be03d 100644
--- a/src/test/ui/const-generics/issues/issue-64494.rs
+++ b/src/test/ui/const-generics/issues/issue-64494.rs
@@ -15,10 +15,10 @@ impl True for Is<{true}> {}
 
 impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
 //[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values
+//[min]~^^ ERROR generic parameters may not be used in const operations
 impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
 //[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values
+//[min]~^^ ERROR generic parameters may not be used in const operations
 //[min]~| ERROR conflicting implementations of trait `MyTrait`
 
 fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-66205.min.stderr b/src/test/ui/const-generics/issues/issue-66205.min.stderr
index a18126ccfef..282f72be6da 100644
--- a/src/test/ui/const-generics/issues/issue-66205.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-66205.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-66205.rs:8:14
    |
 LL |     fact::<{ N - 1 }>();
-   |              ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |              ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs
index 668f49852e1..4e37c247d00 100644
--- a/src/test/ui/const-generics/issues/issue-66205.rs
+++ b/src/test/ui/const-generics/issues/issue-66205.rs
@@ -7,7 +7,7 @@
 fn fact<const N: usize>() {
     fact::<{ N - 1 }>();
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values
+    //[min]~^^ ERROR generic parameters may not be used in const operations
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-67739.min.stderr b/src/test/ui/const-generics/issues/issue-67739.min.stderr
index ba378de4156..35d97c46248 100644
--- a/src/test/ui/const-generics/issues/issue-67739.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-67739.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-67739.rs:12:30
    |
 LL |         [0u8; mem::size_of::<Self::Associated>()];
-   |                              ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
+   |                              ^^^^^^^^^^^^^^^^ cannot perform const operation using `Self`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs
index 296e4d423c4..21d13de22eb 100644
--- a/src/test/ui/const-generics/issues/issue-67739.rs
+++ b/src/test/ui/const-generics/issues/issue-67739.rs
@@ -11,7 +11,7 @@ pub trait Trait {
     fn associated_size(&self) -> usize {
         [0u8; mem::size_of::<Self::Associated>()];
         //[full]~^ ERROR constant expression depends on a generic parameter
-        //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values
+        //[min]~^^ ERROR generic parameters may not be used in const operations
         0
     }
 }
diff --git a/src/test/ui/const-generics/issues/issue-68366.min.stderr b/src/test/ui/const-generics/issues/issue-68366.min.stderr
index 73d6fec6f9b..b900a0d096a 100644
--- a/src/test/ui/const-generics/issues/issue-68366.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-68366.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-68366.rs:12:37
    |
 LL | impl <const N: usize> Collatz<{Some(N)}> {}
-   |                                     ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                     ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
   --> $DIR/issue-68366.rs:12:13
diff --git a/src/test/ui/const-generics/issues/issue-68366.rs b/src/test/ui/const-generics/issues/issue-68366.rs
index ac313eb3b2f..474cdb7258d 100644
--- a/src/test/ui/const-generics/issues/issue-68366.rs
+++ b/src/test/ui/const-generics/issues/issue-68366.rs
@@ -11,7 +11,7 @@ struct Collatz<const N: Option<usize>>;
 
 impl <const N: usize> Collatz<{Some(N)}> {}
 //~^ ERROR the const parameter
-//[min]~^^ generic parameters must not be used inside of non-trivial constant values
+//[min]~^^ generic parameters may not be used in const operations
 
 struct Foo;
 
diff --git a/src/test/ui/const-generics/issues/issue-68977.min.stderr b/src/test/ui/const-generics/issues/issue-68977.min.stderr
index 59d2be3ce4b..7828d859394 100644
--- a/src/test/ui/const-generics/issues/issue-68977.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-68977.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-68977.rs:29:17
    |
 LL |     PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
-   |                 ^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `INT_BITS`
+   |                 ^^^^^^^^ cannot perform const operation using `INT_BITS`
    |
-   = help: it is currently only allowed to use either `INT_BITS` or `{ INT_BITS }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `INT_BITS`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-68977.rs:29:28
    |
 LL |     PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
-   |                            ^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `FRAC_BITS`
+   |                            ^^^^^^^^^ cannot perform const operation using `FRAC_BITS`
    |
-   = help: it is currently only allowed to use either `FRAC_BITS` or `{ FRAC_BITS }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `FRAC_BITS`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issues/issue-68977.rs b/src/test/ui/const-generics/issues/issue-68977.rs
index 49b305a5a78..4fea94cb465 100644
--- a/src/test/ui/const-generics/issues/issue-68977.rs
+++ b/src/test/ui/const-generics/issues/issue-68977.rs
@@ -27,8 +27,8 @@ fxp_storage_impls! {
 
 type FxpStorageHelper<const INT_BITS: u8, const FRAC_BITS: u8> =
     PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>;
-    //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values
-    //[min]~| ERROR generic parameters must not be used inside of non-trivial constant values
+    //[min]~^ ERROR generic parameters may not be used in const operations
+    //[min]~| ERROR generic parameters may not be used in const operations
 
 struct Fxp<const INT_BITS: u8, const FRAC_BITS: u8>
 where
diff --git a/src/test/ui/const-generics/issues/issue-72787.min.stderr b/src/test/ui/const-generics/issues/issue-72787.min.stderr
index a4c80b1d8c0..d960d9513b7 100644
--- a/src/test/ui/const-generics/issues/issue-72787.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-72787.min.stderr
@@ -1,34 +1,34 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-72787.rs:11:17
    |
 LL |     Condition<{ LHS <= RHS }>: True
-   |                 ^^^ non-trivial anonymous constants must not depend on the parameter `LHS`
+   |                 ^^^ cannot perform const operation using `LHS`
    |
-   = help: it is currently only allowed to use either `LHS` or `{ LHS }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `LHS`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-72787.rs:11:24
    |
 LL |     Condition<{ LHS <= RHS }>: True
-   |                        ^^^ non-trivial anonymous constants must not depend on the parameter `RHS`
+   |                        ^^^ cannot perform const operation using `RHS`
    |
-   = help: it is currently only allowed to use either `RHS` or `{ RHS }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `RHS`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-72787.rs:26:25
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
-   |                         ^ non-trivial anonymous constants must not depend on the parameter `I`
+   |                         ^ cannot perform const operation using `I`
    |
-   = help: it is currently only allowed to use either `I` or `{ I }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `I`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-72787.rs:26:36
    |
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
-   |                                    ^ non-trivial anonymous constants must not depend on the parameter `J`
+   |                                    ^ cannot perform const operation using `J`
    |
-   = help: it is currently only allowed to use either `J` or `{ J }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `J`
 
 error[E0283]: type annotations needed
   --> $DIR/issue-72787.rs:22:26
diff --git a/src/test/ui/const-generics/issues/issue-72787.rs b/src/test/ui/const-generics/issues/issue-72787.rs
index 779c1d2950e..57572e23aa4 100644
--- a/src/test/ui/const-generics/issues/issue-72787.rs
+++ b/src/test/ui/const-generics/issues/issue-72787.rs
@@ -10,8 +10,8 @@ pub trait True {}
 impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where
     Condition<{ LHS <= RHS }>: True
 //[full]~^ Error constant expression depends on a generic parameter
-//[min]~^^ Error generic parameters must not be used inside of non-trivial constant values
-//[min]~| Error generic parameters must not be used inside of non-trivial constant values
+//[min]~^^ Error generic parameters may not be used in const operations
+//[min]~| Error generic parameters may not be used in const operations
 {
 }
 impl True for Condition<true> {}
@@ -28,8 +28,8 @@ where
 //[full]~| constant expression depends on a generic parameter
 //[full]~| constant expression depends on a generic parameter
 //[full]~| constant expression depends on a generic parameter
-//[min]~^^^^^ Error generic parameters must not be used inside of non-trivial constant values
-//[min]~| Error generic parameters must not be used inside of non-trivial constant values
+//[min]~^^^^^ Error generic parameters may not be used in const operations
+//[min]~| Error generic parameters may not be used in const operations
     // Condition<{ 8 - I <= 8 - J }>: True,
 {
     fn print() {
diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr
index afc14c7dcff..9fec3eb946d 100644
--- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-72819-generic-in-const-eval.rs:9:17
    |
 LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue,
-   |                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                 ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs
index 65c7f00a72a..6182042bde7 100644
--- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs
+++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs
@@ -8,7 +8,7 @@
 struct Arr<const N: usize>
 where Assert::<{N < usize::max_value() / 2}>: IsTrue,
 //[full]~^ ERROR constant expression depends on a generic parameter
-//[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values
+//[min]~^^ ERROR generic parameters may not be used in const operations
 {
 }
 
diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr
index 0db948d0a45..c10db84ea6e 100644
--- a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-76701-ty-param-in-const.rs:6:46
    |
 LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
-   |                                              ^ non-trivial anonymous constants must not depend on the parameter `T`
+   |                                              ^ cannot perform const operation using `T`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/issue-76701-ty-param-in-const.rs:12:42
    |
 LL | fn const_param<const N: usize>() -> [u8; N + 1] {
-   |                                          ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                          ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs
index 3c5bfb03f08..9051c36fe81 100644
--- a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs
+++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs
@@ -5,13 +5,13 @@
 
 fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values
+    //[min]~^^ ERROR generic parameters may not be used in const operations
     todo!()
 }
 
 fn const_param<const N: usize>() -> [u8; N + 1] {
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values
+    //[min]~^^ ERROR generic parameters may not be used in const operations
     todo!()
 }
 
diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.rs b/src/test/ui/const-generics/min_const_generics/complex-expression.rs
index c6380f6394d..8257ffbf491 100644
--- a/src/test/ui/const-generics/min_const_generics/complex-expression.rs
+++ b/src/test/ui/const-generics/min_const_generics/complex-expression.rs
@@ -7,19 +7,19 @@ fn ok<const M: usize>() -> [u8; M] {
 }
 
 struct Break0<const N: usize>([u8; { N + 1 }]);
-//~^ ERROR generic parameters must not be used inside of non-trivial constant values
+//~^ ERROR generic parameters may not be used in const operations
 
 struct Break1<const N: usize>([u8; { { N } }]);
-//~^ ERROR generic parameters must not be used inside of non-trivial constant values
+//~^ ERROR generic parameters may not be used in const operations
 
 fn break2<const N: usize>() {
     let _: [u8; N + 1];
-    //~^ ERROR generic parameters must not be used inside of non-trivial constant values
+    //~^ ERROR generic parameters may not be used in const operations
 }
 
 fn break3<const N: usize>() {
     let _ = [0; N + 1];
-    //~^ ERROR generic parameters must not be used inside of non-trivial constant values
+    //~^ ERROR generic parameters may not be used in const operations
 }
 
 trait Foo {
diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
index d8897f53d7f..73768ac03a4 100644
--- a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
+++ b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr
@@ -1,34 +1,34 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:9:38
    |
 LL | struct Break0<const N: usize>([u8; { N + 1 }]);
-   |                                      ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                      ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:12:40
    |
 LL | struct Break1<const N: usize>([u8; { { N } }]);
-   |                                        ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                                        ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:16:17
    |
 LL |     let _: [u8; N + 1];
-   |                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                 ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/complex-expression.rs:21:17
    |
 LL |     let _ = [0; N + 1];
-   |                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                 ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr
index 7dc81bf45af..64da5e07df2 100644
--- a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr
+++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr
@@ -1,10 +1,10 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/self-ty-in-const-1.rs:4:41
    |
 LL |     fn t1() -> [u8; std::mem::size_of::<Self>()];
-   |                                         ^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
+   |                                         ^^^^ cannot perform const operation using `Self`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error: generic `Self` types are currently not permitted in anonymous constants
   --> $DIR/self-ty-in-const-1.rs:14:41
diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
index 0dd591d891f..39aa8087cec 100644
--- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
+++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr
@@ -6,13 +6,13 @@ LL | struct Bar<T = [u8; N], const N: usize>(T);
    |
    = note: using type defaults and const parameters in the same parameter list is currently not permitted
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:44
    |
 LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
-   |                                            ^ non-trivial anonymous constants must not depend on the parameter `T`
+   |                                            ^ cannot perform const operation using `T`
    |
-   = note: type parameters are currently not permitted in anonymous constants
+   = note: type parameters may not be used in const expressions
 
 error: constant values inside of type parameter defaults must not depend on generic parameters
   --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21
diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
index b9d74850f37..51f0cff3f21 100644
--- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
+++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs
@@ -6,7 +6,7 @@
 
 struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
 //[full]~^ ERROR constant values inside of type parameter defaults
-//[min]~^^ ERROR generic parameters must not be used inside of non-trivial
+//[min]~^^ ERROR generic parameters may not be used in const operations
 
 // FIXME(const_generics:defaults): We still don't know how to we deal with type defaults.
 struct Bar<T = [u8; N], const N: usize>(T);
diff --git a/src/test/ui/const-generics/wf-misc.min.stderr b/src/test/ui/const-generics/wf-misc.min.stderr
index 1c52d601749..935f12dd2c3 100644
--- a/src/test/ui/const-generics/wf-misc.min.stderr
+++ b/src/test/ui/const-generics/wf-misc.min.stderr
@@ -1,18 +1,18 @@
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/wf-misc.rs:9:17
    |
 LL |     let _: [u8; N + 1];
-   |                 ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                 ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
-error: generic parameters must not be used inside of non-trivial constant values
+error: generic parameters may not be used in const operations
   --> $DIR/wf-misc.rs:17:21
    |
 LL |     let _: Const::<{N + 1}>;
-   |                     ^ non-trivial anonymous constants must not depend on the parameter `N`
+   |                     ^ cannot perform const operation using `N`
    |
-   = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+   = help: const parameters may only be used as standalone arguments, i.e. `N`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/wf-misc.rs b/src/test/ui/const-generics/wf-misc.rs
index f8c41404c46..103c580f28f 100644
--- a/src/test/ui/const-generics/wf-misc.rs
+++ b/src/test/ui/const-generics/wf-misc.rs
@@ -8,7 +8,7 @@
 pub fn arr_len<const N: usize>() {
     let _: [u8; N + 1];
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non-trivial
+    //[min]~^^ ERROR generic parameters may not be used in const operations
 }
 
 struct Const<const N: usize>;
@@ -16,7 +16,7 @@ struct Const<const N: usize>;
 pub fn func_call<const N: usize>() {
     let _: Const::<{N + 1}>;
     //[full]~^ ERROR constant expression depends on a generic parameter
-    //[min]~^^ ERROR generic parameters must not be used inside of non-trivial
+    //[min]~^^ ERROR generic parameters may not be used in const operations
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs
index 9cc9b69ac0b..e062c9f0aa3 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.rs
@@ -1,9 +1,10 @@
+// gate-test-const_impl_trait
+
 struct AlanTuring<T>(T);
-const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> {
-    //~^ ERROR `impl Trait` in const fn is unstable
+const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { //~ `impl Trait`
     AlanTuring(0)
 }
 
-const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
+const fn no_rpit() -> impl std::fmt::Debug {} //~ `impl Trait`
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr
index a62a340332d..01c797cd96b 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_impl_trait.stderr
@@ -1,21 +1,21 @@
-error[E0723]: `impl Trait` in const fn is unstable
-  --> $DIR/min_const_fn_impl_trait.rs:2:24
+error[E0658]: `impl Trait` is not allowed in constant functions
+  --> $DIR/min_const_fn_impl_trait.rs:4:24
    |
 LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> {
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = note: see issue #77463 <https://github.com/rust-lang/rust/issues/77463> for more information
+   = help: add `#![feature(const_impl_trait)]` to the crate attributes to enable
 
-error[E0723]: `impl Trait` in const fn is unstable
-  --> $DIR/min_const_fn_impl_trait.rs:7:23
+error[E0658]: `impl Trait` is not allowed in constant functions
+  --> $DIR/min_const_fn_impl_trait.rs:8:23
    |
 LL | const fn no_rpit() -> impl std::fmt::Debug {}
    |                       ^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
-   = help: add `#![feature(const_fn)]` to the crate attributes to enable
+   = note: see issue #77463 <https://github.com/rust-lang/rust/issues/77463> for more information
+   = help: add `#![feature(const_impl_trait)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0723`.
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr
index 2140fd3a5a0..e1325b789d2 100644
--- a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr
+++ b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr
@@ -2,46 +2,33 @@ error[E0423]: expected function, tuple struct or tuple variant, found enum `Opti
   --> $DIR/issue-43871-enum-instead-of-variant.rs:19:13
    |
 LL |     let x = Option(1);
-   |             ^^^^^^
+   |             ^^^^^^ help: try using one of the enum's variants: `std::option::Option::Some`
    |
-help: try using one of the enum's variants
-   |
-LL |     let x = std::option::Option::None(1);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |     let x = std::option::Option::Some(1);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: you might have meant to construct the enum's non-tuple variant
 
 error[E0532]: expected tuple struct or tuple variant, found enum `Option`
   --> $DIR/issue-43871-enum-instead-of-variant.rs:21:12
    |
 LL |     if let Option(_) = x {
-   |            ^^^^^^
-   |
-help: try using one of the enum's variants
+   |            ^^^^^^ help: try using one of the enum's variants: `std::option::Option::Some`
    |
-LL |     if let std::option::Option::None(_) = x {
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |     if let std::option::Option::Some(_) = x {
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   = help: you might have meant to match against the enum's non-tuple variant
 
 error[E0532]: expected tuple struct or tuple variant, found enum `Example`
   --> $DIR/issue-43871-enum-instead-of-variant.rs:27:12
    |
 LL |     if let Example(_) = y {
-   |            ^^^^^^^
-   |
-help: try using one of the enum's variants
+   |            ^^^^^^^ help: try using one of the enum's variants: `Example::Ex`
    |
-LL |     if let Example::Ex(_) = y {
-   |            ^^^^^^^^^^^
-LL |     if let Example::NotEx(_) = y {
-   |            ^^^^^^^^^^^^^^
+   = help: you might have meant to match against the enum's non-tuple variant
 
 error[E0423]: expected function, tuple struct or tuple variant, found enum `Void`
   --> $DIR/issue-43871-enum-instead-of-variant.rs:31:13
    |
 LL |     let y = Void();
    |             ^^^^
+   |
+   = help: the enum has no tuple variants to construct
 
 error[E0423]: expected function, tuple struct or tuple variant, found enum `ManyVariants`
   --> $DIR/issue-43871-enum-instead-of-variant.rs:33:13
@@ -49,17 +36,8 @@ error[E0423]: expected function, tuple struct or tuple variant, found enum `Many
 LL |     let z = ManyVariants();
    |             ^^^^^^^^^^^^
    |
-help: try using one of the enum's variants
-   |
-LL |     let z = ManyVariants::One();
-   |             ^^^^^^^^^^^^^^^^^
-LL |     let z = ManyVariants::Two();
-   |             ^^^^^^^^^^^^^^^^^
-LL |     let z = ManyVariants::Three();
-   |             ^^^^^^^^^^^^^^^^^^^
-LL |     let z = ManyVariants::Four();
-   |             ^^^^^^^^^^^^^^^^^^
-     and 6 other candidates
+   = help: the enum has no tuple variants to construct
+   = help: you might have meant to construct one of the enum's non-tuple variants
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs
index 88d36ab6aa6..b027faa9d7c 100644
--- a/src/test/ui/drop/dynamic-drop-async.rs
+++ b/src/test/ui/drop/dynamic-drop-async.rs
@@ -7,8 +7,6 @@
 // edition:2018
 // ignore-wasm32-bare compiled with panic=abort by default
 
-#![feature(move_ref_pattern)]
-
 #![allow(unused)]
 
 use std::{
diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs
index d31736f142c..ada61bf0df0 100644
--- a/src/test/ui/drop/dynamic-drop.rs
+++ b/src/test/ui/drop/dynamic-drop.rs
@@ -2,7 +2,6 @@
 // ignore-wasm32-bare compiled with panic=abort by default
 
 #![feature(generators, generator_trait, untagged_unions)]
-#![feature(move_ref_pattern)]
 #![feature(bindings_after_at)]
 
 #![allow(unused_assignments)]
diff --git a/src/test/ui/error-codes/E0007.rs b/src/test/ui/error-codes/E0007.rs
deleted file mode 100644
index 022ac5fc113..00000000000
--- a/src/test/ui/error-codes/E0007.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(bindings_after_at)]
-
-fn main() {
-    let x = Some("s".to_string());
-    match x {
-        op_string @ Some(s) => {},
-        //~^ ERROR E0007
-        //~| ERROR E0382
-        None => {},
-    }
-}
diff --git a/src/test/ui/error-codes/E0007.stderr b/src/test/ui/error-codes/E0007.stderr
deleted file mode 100644
index 89c10516194..00000000000
--- a/src/test/ui/error-codes/E0007.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0007]: cannot bind by-move with sub-bindings
-  --> $DIR/E0007.rs:6:9
-   |
-LL |         op_string @ Some(s) => {},
-   |         ^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it
-
-error[E0382]: use of moved value
-  --> $DIR/E0007.rs:6:26
-   |
-LL |     let x = Some("s".to_string());
-   |         - move occurs because `x` has type `Option<String>`, which does not implement the `Copy` trait
-LL |     match x {
-LL |         op_string @ Some(s) => {},
-   |         -----------------^-
-   |         |                |
-   |         |                value used here after move
-   |         value moved here
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0007, E0382.
-For more information about an error, try `rustc --explain E0007`.
diff --git a/src/test/ui/error-codes/E0060.stderr b/src/test/ui/error-codes/E0060.stderr
index a600592c6c2..c80014d1476 100644
--- a/src/test/ui/error-codes/E0060.stderr
+++ b/src/test/ui/error-codes/E0060.stderr
@@ -1,13 +1,16 @@
 error[E0060]: this function takes at least 1 argument but 0 arguments were supplied
   --> $DIR/E0060.rs:6:14
    |
-LL |     fn printf(_: *const u8, ...) -> u32;
-   |     ------------------------------------ defined here
-...
 LL |     unsafe { printf(); }
    |              ^^^^^^-- supplied 0 arguments
    |              |
    |              expected at least 1 argument
+   |
+note: function defined here
+  --> $DIR/E0060.rs:2:8
+   |
+LL |     fn printf(_: *const u8, ...) -> u32;
+   |        ^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/error-codes/E0061.stderr b/src/test/ui/error-codes/E0061.stderr
index dfefa0df313..98488a2d298 100644
--- a/src/test/ui/error-codes/E0061.stderr
+++ b/src/test/ui/error-codes/E0061.stderr
@@ -1,24 +1,30 @@
 error[E0061]: this function takes 2 arguments but 1 argument was supplied
   --> $DIR/E0061.rs:6:5
    |
-LL | fn f(a: u16, b: &str) {}
-   | --------------------- defined here
-...
 LL |     f(0);
    |     ^ - supplied 1 argument
    |     |
    |     expected 2 arguments
+   |
+note: function defined here
+  --> $DIR/E0061.rs:1:4
+   |
+LL | fn f(a: u16, b: &str) {}
+   |    ^ ------  -------
 
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/E0061.rs:10:5
    |
-LL | fn f2(a: u16) {}
-   | ------------- defined here
-...
 LL |     f2();
    |     ^^-- supplied 0 arguments
    |     |
    |     expected 1 argument
+   |
+note: function defined here
+  --> $DIR/E0061.rs:3:4
+   |
+LL | fn f2(a: u16) {}
+   |    ^^ ------
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/error-codes/E0778.rs b/src/test/ui/error-codes/E0778.rs
new file mode 100644
index 00000000000..60e5c2598f1
--- /dev/null
+++ b/src/test/ui/error-codes/E0778.rs
@@ -0,0 +1,8 @@
+#![feature(isa_attribute)]
+
+#[instruction_set()] //~ ERROR
+fn no_isa_defined() {
+}
+
+fn main() {
+}
diff --git a/src/test/ui/error-codes/E0778.stderr b/src/test/ui/error-codes/E0778.stderr
new file mode 100644
index 00000000000..6ecae792423
--- /dev/null
+++ b/src/test/ui/error-codes/E0778.stderr
@@ -0,0 +1,9 @@
+error[E0778]: `#[instruction_set]` requires an argument
+  --> $DIR/E0778.rs:3:1
+   |
+LL | #[instruction_set()]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0778`.
diff --git a/src/test/ui/error-codes/E0779.rs b/src/test/ui/error-codes/E0779.rs
new file mode 100644
index 00000000000..1b4dbce2036
--- /dev/null
+++ b/src/test/ui/error-codes/E0779.rs
@@ -0,0 +1,6 @@
+#![feature(isa_attribute)]
+
+#[instruction_set(arm::magic)] //~ ERROR
+fn main() {
+
+}
diff --git a/src/test/ui/error-codes/E0779.stderr b/src/test/ui/error-codes/E0779.stderr
new file mode 100644
index 00000000000..da787260d4f
--- /dev/null
+++ b/src/test/ui/error-codes/E0779.stderr
@@ -0,0 +1,9 @@
+error[E0779]: invalid instruction set specified
+  --> $DIR/E0779.rs:3:1
+   |
+LL | #[instruction_set(arm::magic)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0779`.
diff --git a/src/test/ui/feature-gate-isa_attribute.rs b/src/test/ui/feature-gate-isa_attribute.rs
new file mode 100644
index 00000000000..cb02a0955e9
--- /dev/null
+++ b/src/test/ui/feature-gate-isa_attribute.rs
@@ -0,0 +1,6 @@
+#[instruction_set]
+//~^ ERROR the `#[instruction_set]` attribute is an experimental feature [E0658]
+//~| ERROR malformed `instruction_set` attribute input
+//~| ERROR must specify an instruction set [E0778]
+fn main() {
+}
diff --git a/src/test/ui/feature-gate-isa_attribute.stderr b/src/test/ui/feature-gate-isa_attribute.stderr
new file mode 100644
index 00000000000..2a95a80ca61
--- /dev/null
+++ b/src/test/ui/feature-gate-isa_attribute.stderr
@@ -0,0 +1,25 @@
+error: malformed `instruction_set` attribute input
+  --> $DIR/feature-gate-isa_attribute.rs:1:1
+   |
+LL | #[instruction_set]
+   | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[instruction_set(set)]`
+
+error[E0658]: the `#[instruction_set]` attribute is an experimental feature
+  --> $DIR/feature-gate-isa_attribute.rs:1:1
+   |
+LL | #[instruction_set]
+   | ^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #74727 <https://github.com/rust-lang/rust/issues/74727> for more information
+   = help: add `#![feature(isa_attribute)]` to the crate attributes to enable
+
+error[E0778]: must specify an instruction set
+  --> $DIR/feature-gate-isa_attribute.rs:1:1
+   |
+LL | #[instruction_set]
+   | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0658, E0778.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-negate-unsigned.stderr b/src/test/ui/feature-gates/feature-gate-negate-unsigned.stderr
index aa84c27e40f..d1f4ed5cb04 100644
--- a/src/test/ui/feature-gates/feature-gate-negate-unsigned.stderr
+++ b/src/test/ui/feature-gates/feature-gate-negate-unsigned.stderr
@@ -2,7 +2,10 @@ error[E0600]: cannot apply unary operator `-` to type `usize`
   --> $DIR/feature-gate-negate-unsigned.rs:10:23
    |
 LL |     let _max: usize = -1;
-   |                       ^^ cannot apply unary operator `-`
+   |                       ^^
+   |                       |
+   |                       cannot apply unary operator `-`
+   |                       help: you may have meant the maximum value of `usize`: `usize::MAX`
    |
    = note: unsigned values cannot be negated
 
diff --git a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
index 16a5ab2cc86..5043a3be91d 100644
--- a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
+++ b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]`
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6]`
   --> $DIR/generator-yielding-or-returning-itself.rs:15:5
    |
 LL | pub fn want_cyclic_generator_return<T>(_: T)
@@ -14,7 +14,7 @@ LL |     want_cyclic_generator_return(|| {
            see issue #46062 <https://github.com/rust-lang/rust/issues/46062>
            for more information
 
-error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]`
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6]`
   --> $DIR/generator-yielding-or-returning-itself.rs:28:5
    |
 LL | pub fn want_cyclic_generator_yield<T>(_: T)
diff --git a/src/test/ui/generator/print/generator-print-verbose-2.stderr b/src/test/ui/generator/print/generator-print-verbose-2.stderr
index cc45d5631cb..f23949091d9 100644
--- a/src/test/ui/generator/print/generator-print-verbose-2.stderr
+++ b/src/test/ui/generator/print/generator-print-verbose-2.stderr
@@ -9,7 +9,7 @@ LL |     assert_send(|| {
    |
    = help: the trait `Sync` is not implemented for `Cell<i32>`
    = note: required because of the requirements on the impl of `Send` for `&'_#3r Cell<i32>`
-   = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell<i32>) _#16t]`
+   = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell<i32>) _#17t]`
 
 error: generator cannot be shared between threads safely
   --> $DIR/generator-print-verbose-2.rs:12:5
diff --git a/src/test/ui/generator/print/generator-print-verbose-3.stderr b/src/test/ui/generator/print/generator-print-verbose-3.stderr
index 0ce108dfd62..d15646259b2 100644
--- a/src/test/ui/generator/print/generator-print-verbose-3.stderr
+++ b/src/test/ui/generator/print/generator-print-verbose-3.stderr
@@ -12,7 +12,7 @@ LL | |     };
    | |_____^ expected `()`, found generator
    |
    = note: expected unit type `()`
-              found generator `[main::{closure#0} upvar_tys=(unavailable) _#5t]`
+              found generator `[main::{closure#0} upvar_tys=(unavailable)]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr
index 216b707bb16..881064d2f84 100644
--- a/src/test/ui/generator/static-not-unpin.stderr
+++ b/src/test/ui/generator/static-not-unpin.stderr
@@ -1,11 +1,11 @@
-error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` cannot be unpinned
+error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]` cannot be unpinned
   --> $DIR/static-not-unpin.rs:14:18
    |
 LL | fn assert_unpin<T: Unpin>(_: T) {
    |                    ----- required by this bound in `assert_unpin`
 ...
 LL |     assert_unpin(generator);
-   |                  ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]`
+   |                  ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
index 8f6f87f78de..9e111d68a55 100644
--- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr
+++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr
@@ -7,7 +7,7 @@ LL |         5
    = note: expected type `std::result::Result<{integer}, _>`
               found type `{integer}`
 
-error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6 _] as Generator>::Return == i32`
+error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6] as Generator>::Return == i32`
   --> $DIR/type-mismatch-signature-deduction.rs:5:13
    |
 LL | fn foo() -> impl Generator<Return = i32> {
diff --git a/src/test/ui/generator/yielding-in-match-guards.rs b/src/test/ui/generator/yielding-in-match-guards.rs
new file mode 100644
index 00000000000..d8aa354b1c6
--- /dev/null
+++ b/src/test/ui/generator/yielding-in-match-guards.rs
@@ -0,0 +1,24 @@
+// check-pass
+// edition:2018
+
+// This test is derived from
+// https://github.com/rust-lang/rust/issues/72651#issuecomment-668720468
+
+// This test demonstrates that, in `async fn g()`,
+// indeed a temporary borrow `y` from `x` is live
+// while `f().await` is being evaluated.
+// Thus, `&'_ u8` should be included in type signature
+// of the underlying generator.
+
+async fn f() -> u8 { 1 }
+
+pub async fn g(x: u8) {
+    match x {
+        y if f().await == y => (),
+        _ => (),
+    }
+}
+
+fn main() {
+    let _ = g(10);
+}
diff --git a/src/test/ui/hrtb/issue-58451.stderr b/src/test/ui/hrtb/issue-58451.stderr
index bd08fc1bfae..2cc1c7a2e72 100644
--- a/src/test/ui/hrtb/issue-58451.stderr
+++ b/src/test/ui/hrtb/issue-58451.stderr
@@ -1,16 +1,16 @@
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/issue-58451.rs:12:9
    |
-LL | / fn f<I>(i: I)
-LL | | where
-LL | |     I: IntoIterator,
-LL | |     I::Item: for<'a> Into<&'a ()>,
-   | |__________________________________- defined here
-...
-LL |       f(&[f()]);
-   |           ^-- supplied 0 arguments
-   |           |
-   |           expected 1 argument
+LL |     f(&[f()]);
+   |         ^-- supplied 0 arguments
+   |         |
+   |         expected 1 argument
+   |
+note: function defined here
+  --> $DIR/issue-58451.rs:5:4
+   |
+LL | fn f<I>(i: I)
+   |    ^    ----
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/impl-trait/issues/issue-65581.rs b/src/test/ui/impl-trait/issues/issue-65581.rs
new file mode 100644
index 00000000000..af65b79d3e8
--- /dev/null
+++ b/src/test/ui/impl-trait/issues/issue-65581.rs
@@ -0,0 +1,33 @@
+// check-pass
+
+#![allow(dead_code)]
+
+trait Trait1<T, U> {
+    fn f1(self) -> U;
+}
+
+trait Trait2 {
+    type T;
+    type U: Trait2<T = Self::T>;
+    fn f2(f: impl FnOnce(&Self::U));
+}
+
+fn f3<T: Trait2>() -> impl Trait1<T, T::T> {
+    Struct1
+}
+
+struct Struct1;
+
+impl<T: Trait2> Trait1<T, T::T> for Struct1 {
+    fn f1(self) -> T::T {
+        unimplemented!()
+    }
+}
+
+fn f4<T: Trait2>() {
+    T::f2(|_| {
+        f3::<T::U>().f1();
+    });
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-18075.rs b/src/test/ui/issues/issue-18075.rs
deleted file mode 100644
index 56ec629c613..00000000000
--- a/src/test/ui/issues/issue-18075.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// run-pass
-// rustc-env:RUSTC_LOG=rustc::middle=debug
-
-fn main() {
-    let b = 1isize;
-    println!("{}", b);
-}
diff --git a/src/test/ui/issues/issue-18819.stderr b/src/test/ui/issues/issue-18819.stderr
index a952c9b46c9..b10d26abe34 100644
--- a/src/test/ui/issues/issue-18819.stderr
+++ b/src/test/ui/issues/issue-18819.stderr
@@ -1,13 +1,16 @@
 error[E0061]: this function takes 2 arguments but 1 argument was supplied
   --> $DIR/issue-18819.rs:16:5
    |
-LL | fn print_x(_: &dyn Foo<Item=bool>, extra: &str) {
-   | ----------------------------------------------- defined here
-...
 LL |     print_x(X);
    |     ^^^^^^^ - supplied 1 argument
    |     |
    |     expected 2 arguments
+   |
+note: function defined here
+  --> $DIR/issue-18819.rs:11:4
+   |
+LL | fn print_x(_: &dyn Foo<Item=bool>, extra: &str) {
+   |    ^^^^^^^ ----------------------  -----------
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-26094.stderr b/src/test/ui/issues/issue-26094.stderr
index 2038d88bf46..a6f1ac9286c 100644
--- a/src/test/ui/issues/issue-26094.stderr
+++ b/src/test/ui/issues/issue-26094.stderr
@@ -4,11 +4,14 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied
 LL |         $other(None)
    |                ---- supplied 1 argument
 ...
-LL | fn some_function() {}
-   | ------------------ defined here
-...
 LL |     some_macro!(some_function);
    |                 ^^^^^^^^^^^^^ expected 0 arguments
+   |
+note: function defined here
+  --> $DIR/issue-26094.rs:7:4
+   |
+LL | fn some_function() {}
+   |    ^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-4935.stderr b/src/test/ui/issues/issue-4935.stderr
index 0cc686e1cf8..03b9b91edef 100644
--- a/src/test/ui/issues/issue-4935.stderr
+++ b/src/test/ui/issues/issue-4935.stderr
@@ -1,13 +1,16 @@
 error[E0061]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/issue-4935.rs:5:13
    |
-LL | fn foo(a: usize) {}
-   | ---------------- defined here
-LL |
 LL | fn main() { foo(5, 6) }
    |             ^^^ -  - supplied 2 arguments
    |             |
    |             expected 1 argument
+   |
+note: function defined here
+  --> $DIR/issue-4935.rs:3:4
+   |
+LL | fn foo(a: usize) {}
+   |    ^^^ --------
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-73427.rs b/src/test/ui/issues/issue-73427.rs
new file mode 100644
index 00000000000..3c62782a897
--- /dev/null
+++ b/src/test/ui/issues/issue-73427.rs
@@ -0,0 +1,44 @@
+enum A {
+    StructWithFields { x: () },
+    TupleWithFields(()),
+    Struct {},
+    Tuple(),
+    Unit,
+}
+
+enum B {
+    StructWithFields { x: () },
+    TupleWithFields(()),
+}
+
+enum C {
+    StructWithFields { x: () },
+    TupleWithFields(()),
+    Unit,
+}
+
+enum D {
+    TupleWithFields(()),
+    Unit,
+}
+
+fn main() {
+    // Only variants without fields are suggested (and others mentioned in a note) where an enum
+    // is used rather than a variant.
+
+    A.foo();
+    //~^ ERROR expected value, found enum `A`
+    B.foo();
+    //~^ ERROR expected value, found enum `B`
+    C.foo();
+    //~^ ERROR expected value, found enum `C`
+    D.foo();
+    //~^ ERROR expected value, found enum `D`
+
+    // Only tuple variants are suggested in calls or tuple struct pattern matching.
+
+    let x = A(3);
+    //~^ ERROR expected function, tuple struct or tuple variant, found enum `A`
+    if let A(3) = x { }
+    //~^ ERROR expected tuple struct or tuple variant, found enum `A`
+}
diff --git a/src/test/ui/issues/issue-73427.stderr b/src/test/ui/issues/issue-73427.stderr
new file mode 100644
index 00000000000..88d19943f02
--- /dev/null
+++ b/src/test/ui/issues/issue-73427.stderr
@@ -0,0 +1,72 @@
+error[E0423]: expected value, found enum `A`
+  --> $DIR/issue-73427.rs:29:5
+   |
+LL |     A.foo();
+   |     ^
+   |
+   = help: you might have meant to use one of the enum's other variants that have fields
+help: try using one of the enum's variants
+   |
+LL |     (A::Struct {}).foo();
+   |     ^^^^^^^^^^^^^^
+LL |     (A::Tuple()).foo();
+   |     ^^^^^^^^^^^^
+LL |     A::Unit.foo();
+   |     ^^^^^^^
+
+error[E0423]: expected value, found enum `B`
+  --> $DIR/issue-73427.rs:31:5
+   |
+LL |     B.foo();
+   |     ^
+   |
+   = help: you might have meant to use one of the enum's variants
+
+error[E0423]: expected value, found enum `C`
+  --> $DIR/issue-73427.rs:33:5
+   |
+LL |     C.foo();
+   |     ^ help: try using one of the enum's variants: `C::Unit`
+   |
+   = help: you might have meant to use one of the enum's other variants that have fields
+
+error[E0423]: expected value, found enum `D`
+  --> $DIR/issue-73427.rs:35:5
+   |
+LL |     D.foo();
+   |     ^ help: try using one of the enum's variants: `D::Unit`
+   |
+   = help: you might have meant to use the enum's other variant that has fields
+
+error[E0423]: expected function, tuple struct or tuple variant, found enum `A`
+  --> $DIR/issue-73427.rs:40:13
+   |
+LL |     let x = A(3);
+   |             ^
+   |
+   = help: you might have meant to construct one of the enum's non-tuple variants
+help: try using one of the enum's variants
+   |
+LL |     let x = A::TupleWithFields(3);
+   |             ^^^^^^^^^^^^^^^^^^
+LL |     let x = A::Tuple(3);
+   |             ^^^^^^^^
+
+error[E0532]: expected tuple struct or tuple variant, found enum `A`
+  --> $DIR/issue-73427.rs:42:12
+   |
+LL |     if let A(3) = x { }
+   |            ^
+   |
+   = help: you might have meant to match against one of the enum's non-tuple variants
+help: try using one of the enum's variants
+   |
+LL |     if let A::TupleWithFields(3) = x { }
+   |            ^^^^^^^^^^^^^^^^^^
+LL |     if let A::Tuple(3) = x { }
+   |            ^^^^^^^^
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0423, E0532.
+For more information about an error, try `rustc --explain E0423`.
diff --git a/src/test/ui/lto-opt-level-s.rs b/src/test/ui/lto-opt-level-s.rs
new file mode 100644
index 00000000000..a7d9d5024d3
--- /dev/null
+++ b/src/test/ui/lto-opt-level-s.rs
@@ -0,0 +1,7 @@
+// compile-flags: -Clinker-plugin-lto -Copt-level=s
+// build-pass
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
diff --git a/src/test/ui/lto-opt-level-z.rs b/src/test/ui/lto-opt-level-z.rs
new file mode 100644
index 00000000000..bf1f5e2b263
--- /dev/null
+++ b/src/test/ui/lto-opt-level-z.rs
@@ -0,0 +1,7 @@
+// compile-flags: -Clinker-plugin-lto -Copt-level=z
+// build-pass
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr
index b0d1bb9823b..60f9eeeca27 100644
--- a/src/test/ui/methods/method-call-err-msg.stderr
+++ b/src/test/ui/methods/method-call-err-msg.stderr
@@ -1,35 +1,44 @@
 error[E0061]: this function takes 0 arguments but 1 argument was supplied
   --> $DIR/method-call-err-msg.rs:13:7
    |
-LL |     fn zero(self) -> Foo { self }
-   |     -------------------- defined here
-...
 LL |     x.zero(0)
    |       ^^^^ - supplied 1 argument
    |       |
    |       expected 0 arguments
+   |
+note: associated function defined here
+  --> $DIR/method-call-err-msg.rs:5:8
+   |
+LL |     fn zero(self) -> Foo { self }
+   |        ^^^^ ----
 
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/method-call-err-msg.rs:14:7
    |
-LL |     fn one(self, _: isize) -> Foo { self }
-   |     ----------------------------- defined here
-...
 LL |      .one()
    |       ^^^- supplied 0 arguments
    |       |
    |       expected 1 argument
+   |
+note: associated function defined here
+  --> $DIR/method-call-err-msg.rs:6:8
+   |
+LL |     fn one(self, _: isize) -> Foo { self }
+   |        ^^^ ----  --------
 
 error[E0061]: this function takes 2 arguments but 1 argument was supplied
   --> $DIR/method-call-err-msg.rs:15:7
    |
-LL |     fn two(self, _: isize, _: isize) -> Foo { self }
-   |     --------------------------------------- defined here
-...
 LL |      .two(0);
    |       ^^^ - supplied 1 argument
    |       |
    |       expected 2 arguments
+   |
+note: associated function defined here
+  --> $DIR/method-call-err-msg.rs:7:8
+   |
+LL |     fn two(self, _: isize, _: isize) -> Foo { self }
+   |        ^^^ ----  --------  --------
 
 error[E0599]: no method named `take` found for struct `Foo` in the current scope
   --> $DIR/method-call-err-msg.rs:19:7
@@ -53,13 +62,16 @@ LL |      .take()
 error[E0061]: this function takes 3 arguments but 0 arguments were supplied
   --> $DIR/method-call-err-msg.rs:21:7
    |
-LL |     fn three<T>(self, _: T, _: T, _: T) -> Foo { self }
-   |     ------------------------------------------ defined here
-...
 LL |     y.three::<usize>();
    |       ^^^^^--------- supplied 0 arguments
    |       |
    |       expected 3 arguments
+   |
+note: associated function defined here
+  --> $DIR/method-call-err-msg.rs:8:8
+   |
+LL |     fn three<T>(self, _: T, _: T, _: T) -> Foo { self }
+   |        ^^^^^    ----  ----  ----  ----
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr
index 63c04bcd7ba..0b1fcf58e2e 100644
--- a/src/test/ui/mismatched_types/issue-36053-2.stderr
+++ b/src/test/ui/mismatched_types/issue-36053-2.stderr
@@ -1,3 +1,11 @@
+error[E0631]: type mismatch in closure arguments
+  --> $DIR/issue-36053-2.rs:7:32
+   |
+LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
+   |                                ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _`
+   |                                |
+   |                                expected signature of `for<'r> fn(&'r &str) -> _`
+
 error[E0599]: no method named `count` found for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope
   --> $DIR/issue-36053-2.rs:7:55
    |
@@ -20,14 +28,6 @@ LL | pub struct Filter<I, P> {
            `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator`
            which is required by `&mut Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator`
 
-error[E0631]: type mismatch in closure arguments
-  --> $DIR/issue-36053-2.rs:7:32
-   |
-LL |     once::<&str>("str").fuse().filter(|a: &str| true).count();
-   |                                ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _`
-   |                                |
-   |                                expected signature of `for<'r> fn(&'r &str) -> _`
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0599, E0631.
diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr
index c2bce305877..5d2ce9302ec 100644
--- a/src/test/ui/mismatched_types/issue-38371.stderr
+++ b/src/test/ui/mismatched_types/issue-38371.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/issue-38371.rs:4:8
    |
 LL | fn foo(&foo: Foo) {
-   |        ^^^^------
+   |        ^^^^-----
    |        |     |
    |        |     expected due to this
    |        expected struct `Foo`, found reference
diff --git a/src/test/ui/not-enough-arguments.rs b/src/test/ui/not-enough-arguments.rs
index 631bb1dd274..42476255188 100644
--- a/src/test/ui/not-enough-arguments.rs
+++ b/src/test/ui/not-enough-arguments.rs
@@ -6,7 +6,26 @@ fn foo(a: isize, b: isize, c: isize, d:isize) {
   panic!();
 }
 
+// Check that all arguments are shown in the error message, even if they're across multiple lines.
+fn bar(
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+    e: i32,
+    f: i32,
+) {
+    println!("{}", a);
+    println!("{}", b);
+    println!("{}", c);
+    println!("{}", d);
+    println!("{}", e);
+    println!("{}", f);
+}
+
 fn main() {
   foo(1, 2, 3);
   //~^ ERROR this function takes 4 arguments but 3
+  bar(1, 2, 3);
+  //~^ ERROR this function takes 6 arguments but 3
 }
diff --git a/src/test/ui/not-enough-arguments.stderr b/src/test/ui/not-enough-arguments.stderr
index f2b57f71400..df957837241 100644
--- a/src/test/ui/not-enough-arguments.stderr
+++ b/src/test/ui/not-enough-arguments.stderr
@@ -1,14 +1,43 @@
 error[E0061]: this function takes 4 arguments but 3 arguments were supplied
-  --> $DIR/not-enough-arguments.rs:10:3
+  --> $DIR/not-enough-arguments.rs:27:3
    |
-LL | fn foo(a: isize, b: isize, c: isize, d:isize) {
-   | --------------------------------------------- defined here
-...
 LL |   foo(1, 2, 3);
    |   ^^^ -  -  - supplied 3 arguments
    |   |
    |   expected 4 arguments
+   |
+note: function defined here
+  --> $DIR/not-enough-arguments.rs:5:4
+   |
+LL | fn foo(a: isize, b: isize, c: isize, d:isize) {
+   |    ^^^ --------  --------  --------  -------
+
+error[E0061]: this function takes 6 arguments but 3 arguments were supplied
+  --> $DIR/not-enough-arguments.rs:29:3
+   |
+LL |   bar(1, 2, 3);
+   |   ^^^ -  -  - supplied 3 arguments
+   |   |
+   |   expected 6 arguments
+   |
+note: function defined here
+  --> $DIR/not-enough-arguments.rs:10:4
+   |
+LL | fn bar(
+   |    ^^^
+LL |     a: i32,
+   |     ------
+LL |     b: i32,
+   |     ------
+LL |     c: i32,
+   |     ------
+LL |     d: i32,
+   |     ------
+LL |     e: i32,
+   |     ------
+LL |     f: i32,
+   |     ------
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0061`.
diff --git a/src/test/ui/parser/bare-struct-body.rs b/src/test/ui/parser/bare-struct-body.rs
new file mode 100644
index 00000000000..a557e861dee
--- /dev/null
+++ b/src/test/ui/parser/bare-struct-body.rs
@@ -0,0 +1,15 @@
+struct Foo {
+    val: (),
+}
+
+fn foo() -> Foo { //~ ERROR struct literal body without path
+    val: (),
+}
+
+fn main() {
+    let x = foo();
+    x.val == 42; //~ ERROR mismatched types
+    let x = { //~ ERROR struct literal body without path
+        val: (),
+    };
+}
diff --git a/src/test/ui/parser/bare-struct-body.stderr b/src/test/ui/parser/bare-struct-body.stderr
new file mode 100644
index 00000000000..df10b0ec2d2
--- /dev/null
+++ b/src/test/ui/parser/bare-struct-body.stderr
@@ -0,0 +1,41 @@
+error: struct literal body without path
+  --> $DIR/bare-struct-body.rs:5:17
+   |
+LL |   fn foo() -> Foo {
+   |  _________________^
+LL | |     val: (),
+LL | | }
+   | |_^
+   |
+help: you might have forgotten to add the struct literal inside the block
+   |
+LL | fn foo() -> Foo { SomeStruct {
+LL |     val: (),
+LL | } }
+   |
+
+error: struct literal body without path
+  --> $DIR/bare-struct-body.rs:12:13
+   |
+LL |       let x = {
+   |  _____________^
+LL | |         val: (),
+LL | |     };
+   | |_____^
+   |
+help: you might have forgotten to add the struct literal inside the block
+   |
+LL |     let x = { SomeStruct {
+LL |         val: (),
+LL |     } };
+   |
+
+error[E0308]: mismatched types
+  --> $DIR/bare-struct-body.rs:11:14
+   |
+LL |     x.val == 42;
+   |              ^^ expected `()`, found integer
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/parser/float-field.stderr b/src/test/ui/parser/float-field.stderr
index 62202b99964..7090efc5014 100644
--- a/src/test/ui/parser/float-field.stderr
+++ b/src/test/ui/parser/float-field.stderr
@@ -271,10 +271,10 @@ LL |     s.1e1;
    = note: available fields are: `0`, `1`
 
 error[E0609]: no field `1e1` on type `(u8, u8)`
-  --> $DIR/float-field.rs:9:7
+  --> $DIR/float-field.rs:9:9
    |
 LL |     s.1.1e1;
-   |       ^^^^^
+   |         ^^^
 
 error[E0609]: no field `0x1e1` on type `S`
   --> $DIR/float-field.rs:24:7
@@ -288,7 +288,7 @@ error[E0609]: no field `0x1` on type `S`
   --> $DIR/float-field.rs:25:7
    |
 LL |     s.0x1.;
-   |       ^^^^ unknown field
+   |       ^^^ unknown field
    |
    = note: available fields are: `0`, `1`
 
@@ -296,7 +296,7 @@ error[E0609]: no field `0x1` on type `S`
   --> $DIR/float-field.rs:28:7
    |
 LL |     s.0x1.1;
-   |       ^^^^^ unknown field
+   |       ^^^ unknown field
    |
    = note: available fields are: `0`, `1`
 
@@ -304,7 +304,7 @@ error[E0609]: no field `0x1` on type `S`
   --> $DIR/float-field.rs:30:7
    |
 LL |     s.0x1.1e1;
-   |       ^^^^^^^ unknown field
+   |       ^^^ unknown field
    |
    = note: available fields are: `0`, `1`
 
diff --git a/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr
index 21992a29670..3f3ddfed14a 100644
--- a/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr
+++ b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr
@@ -2,205 +2,205 @@ error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:5:19
    |
 LL | fn f1_1(x: isize, ...) {}
-   |                   ^^^^
+   |                   ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9
    |
 LL | fn f1_2(...) {}
-   |         ^^^^
+   |         ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9
    |
 LL | fn f1_2(...) {}
-   |         ^^^^
+   |         ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30
    |
 LL | extern "C" fn f2_1(x: isize, ...) {}
-   |                              ^^^^
+   |                              ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20
    |
 LL | extern "C" fn f2_2(...) {}
-   |                    ^^^^
+   |                    ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20
    |
 LL | extern "C" fn f2_2(...) {}
-   |                    ^^^^
+   |                    ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20
    |
 LL | extern "C" fn f2_3(..., x: isize) {}
-   |                    ^^^^
+   |                    ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20
    |
 LL | extern "C" fn f2_3(..., x: isize) {}
-   |                    ^^^^
+   |                    ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:23:26
    |
 LL | extern fn f3_1(x: isize, ...) {}
-   |                          ^^^^
+   |                          ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16
    |
 LL | extern fn f3_2(...) {}
-   |                ^^^^
+   |                ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16
    |
 LL | extern fn f3_2(...) {}
-   |                ^^^^
+   |                ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16
    |
 LL | extern fn f3_3(..., x: isize) {}
-   |                ^^^^
+   |                ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16
    |
 LL | extern fn f3_3(..., x: isize) {}
-   |                ^^^^
+   |                ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:35:13
    |
 LL |     fn e_f1(...);
-   |             ^^^^
+   |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:37:13
    |
 LL |     fn e_f2(..., x: isize);
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:44:23
    |
 LL |     fn i_f1(x: isize, ...) {}
-   |                       ^^^^
+   |                       ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13
    |
 LL |     fn i_f2(...) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13
    |
 LL |     fn i_f2(...) {}
-   |             ^^^^
+   |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13
    |
 LL |     fn i_f3(..., x: isize, ...) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13
    |
 LL |     fn i_f3(..., x: isize, ...) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:49:28
    |
 LL |     fn i_f3(..., x: isize, ...) {}
-   |                            ^^^^
+   |                            ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13
    |
 LL |     fn i_f4(..., x: isize, ...) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13
    |
 LL |     fn i_f4(..., x: isize, ...) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:53:28
    |
 LL |     fn i_f4(..., x: isize, ...) {}
-   |                            ^^^^
+   |                            ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:60:23
    |
 LL |     fn t_f1(x: isize, ...) {}
-   |                       ^^^^
+   |                       ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:62:23
    |
 LL |     fn t_f2(x: isize, ...);
-   |                       ^^^^
+   |                       ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13
    |
 LL |     fn t_f3(...) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13
    |
 LL |     fn t_f3(...) {}
-   |             ^^^^
+   |             ^^^
 
 error: C-variadic function must be declared with at least one named argument
   --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13
    |
 LL |     fn t_f4(...);
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13
    |
 LL |     fn t_f4(...);
-   |             ^^^^
+   |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13
    |
 LL |     fn t_f5(..., x: isize) {}
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13
    |
 LL |     fn t_f5(..., x: isize) {}
-   |             ^^^^
+   |             ^^^
 
 error: `...` must be the last argument of a C-variadic function
   --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13
    |
 LL |     fn t_f6(..., x: isize);
-   |             ^^^^
+   |             ^^^
 
 error: only foreign or `unsafe extern "C" functions may be C-variadic
   --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13
    |
 LL |     fn t_f6(..., x: isize);
-   |             ^^^^
+   |             ^^^
 
 error: aborting due to 34 previous errors
 
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs
index c00296c34c4..ba9543bf738 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs
@@ -3,7 +3,6 @@
 // where one side is by-ref and the other is by-move.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 struct X {
     x: (),
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
index 8a6ea8e91a2..44dbcb9a754 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
@@ -1,5 +1,5 @@
 error: cannot move out of value because it is borrowed
-  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:15:14
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:14:14
    |
 LL |         Some(ref _y @ _z) => {}
    |              ------^^^--
@@ -8,7 +8,7 @@ LL |         Some(ref _y @ _z) => {}
    |              value borrowed, by `_y`, here
 
 error: borrow of moved value
-  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:14
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:20:14
    |
 LL |         Some(_z @ ref _y) => {}
    |              --^^^------
@@ -18,7 +18,7 @@ LL |         Some(_z @ ref _y) => {}
    |              move occurs because `_z` has type `X` which does not implement the `Copy` trait
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:29:14
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:28:14
    |
 LL |         Some(ref mut _y @ _z) => {}
    |              ----------^^^--
@@ -27,7 +27,7 @@ LL |         Some(ref mut _y @ _z) => {}
    |              value borrowed, by `_y`, here
 
 error: borrow of moved value
-  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:14
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:34:14
    |
 LL |         Some(_z @ ref mut _y) => {}
    |              --^^^----------
@@ -37,7 +37,7 @@ LL |         Some(_z @ ref mut _y) => {}
    |              move occurs because `_z` has type `X` which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:19
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:20:19
    |
 LL |         Some(_z @ ref _y) => {}
    |              -----^^^^^^
@@ -52,7 +52,7 @@ LL |         Some(ref _z @ ref _y) => {}
    |              ^^^
 
 error[E0382]: borrow of moved value
-  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:19
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:34:19
    |
 LL |         Some(_z @ ref mut _y) => {}
    |              -----^^^^^^^^^^
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs
index 7a2e5128b85..3ab6f40725c 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs
@@ -1,7 +1,6 @@
 // See issue #12534.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {}
 
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
index cfd978e1327..f25d5a2d9b8 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value
-  --> $DIR/bind-by-move-no-subbindings-fun-param.rs:10:12
+  --> $DIR/bind-by-move-no-subbindings-fun-param.rs:9:12
    |
 LL | fn f(a @ A(u): A) -> Box<u8> {
    |      ------^-
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs
index 10865b92393..d014c9828da 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs
@@ -1,7 +1,6 @@
 // Test that moving on both sides of an `@` pattern is not allowed.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {
     struct U; // Not copy!
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
index d28edd11e12..5039f580ff6 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:14:13
+  --> $DIR/borrowck-move-and-move.rs:13:13
    |
 LL |     let a @ b = U;
    |         ----^   - move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -8,7 +8,7 @@ LL |     let a @ b = U;
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:16:17
+  --> $DIR/borrowck-move-and-move.rs:15:17
    |
 LL |     let a @ (b, c) = (U, U);
    |         --------^-   ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
@@ -17,7 +17,7 @@ LL |     let a @ (b, c) = (U, U);
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:18:17
+  --> $DIR/borrowck-move-and-move.rs:17:17
    |
 LL |     let a @ (b, c) = (u(), u());
    |         --------^-   ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
@@ -26,7 +26,7 @@ LL |     let a @ (b, c) = (u(), u());
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:21:16
+  --> $DIR/borrowck-move-and-move.rs:20:16
    |
 LL |     match Ok(U) {
    |           ----- move occurs because value has type `std::result::Result<U, U>`, which does not implement the `Copy` trait
@@ -37,7 +37,7 @@ LL |         a @ Ok(b) | a @ Err(b) => {}
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:21:29
+  --> $DIR/borrowck-move-and-move.rs:20:29
    |
 LL |     match Ok(U) {
    |           ----- move occurs because value has type `std::result::Result<U, U>`, which does not implement the `Copy` trait
@@ -48,7 +48,7 @@ LL |         a @ Ok(b) | a @ Err(b) => {}
    |                     value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:28:22
+  --> $DIR/borrowck-move-and-move.rs:27:22
    |
 LL |     match [u(), u(), u(), u()] {
    |           -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait
@@ -59,7 +59,7 @@ LL |         xs @ [a, .., b] => {}
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:32:18
+  --> $DIR/borrowck-move-and-move.rs:31:18
    |
 LL |     match [u(), u(), u(), u()] {
    |           -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait
@@ -70,7 +70,7 @@ LL |         xs @ [_, ys @ .., _] => {}
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-move-and-move.rs:25:16
+  --> $DIR/borrowck-move-and-move.rs:24:16
    |
 LL |     fn fun(a @ b: U) {}
    |            ----^
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs
index 271f4bca0fc..f1ee87bc9c6 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs
@@ -3,7 +3,6 @@
 // Test `@` patterns combined with `box` patterns.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 #![feature(box_patterns)]
 
 #[derive(Copy, Clone)]
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs
index f1680e9e888..236710ed854 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs
@@ -1,7 +1,6 @@
 // Test `@` patterns combined with `box` patterns.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 #![feature(box_patterns)]
 
 #[derive(Copy, Clone)]
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
index 44888369ab2..d9a8bbfb6b1 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
@@ -1,5 +1,5 @@
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-at-and-box.rs:37:9
+  --> $DIR/borrowck-pat-at-and-box.rs:36:9
    |
 LL |     let ref a @ box b = Box::new(NC);
    |         -----^^^^^^^-
@@ -8,7 +8,7 @@ LL |     let ref a @ box b = Box::new(NC);
    |         value borrowed, by `a`, here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-at-and-box.rs:39:9
+  --> $DIR/borrowck-pat-at-and-box.rs:38:9
    |
 LL |     let ref a @ box ref mut b = Box::new(nc());
    |         -----^^^^^^^---------
@@ -17,7 +17,7 @@ LL |     let ref a @ box ref mut b = Box::new(nc());
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-at-and-box.rs:41:9
+  --> $DIR/borrowck-pat-at-and-box.rs:40:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         -----^^^^^^^---------
@@ -26,7 +26,7 @@ LL |     let ref a @ box ref mut b = Box::new(NC);
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-at-and-box.rs:43:9
+  --> $DIR/borrowck-pat-at-and-box.rs:42:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         -----^^^^^^^---------
@@ -35,7 +35,7 @@ LL |     let ref a @ box ref mut b = Box::new(NC);
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-at-and-box.rs:46:9
+  --> $DIR/borrowck-pat-at-and-box.rs:45:9
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         -----^^^^^^^---------
@@ -44,7 +44,7 @@ LL |     let ref a @ box ref mut b = Box::new(NC);
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-at-and-box.rs:52:9
+  --> $DIR/borrowck-pat-at-and-box.rs:51:9
    |
 LL |     let ref mut a @ box ref b = Box::new(NC);
    |         ---------^^^^^^^-----
@@ -53,7 +53,7 @@ LL |     let ref mut a @ box ref b = Box::new(NC);
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-at-and-box.rs:66:9
+  --> $DIR/borrowck-pat-at-and-box.rs:65:9
    |
 LL |         ref mut a @ box ref b => {
    |         ---------^^^^^^^-----
@@ -62,7 +62,7 @@ LL |         ref mut a @ box ref b => {
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-at-and-box.rs:58:11
+  --> $DIR/borrowck-pat-at-and-box.rs:57:11
    |
 LL |     fn f5(ref mut a @ box ref b: Box<NC>) {
    |           ---------^^^^^^^-----
@@ -71,7 +71,7 @@ LL |     fn f5(ref mut a @ box ref b: Box<NC>) {
    |           mutable borrow, by `a`, occurs here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-at-and-box.rs:21:18
+  --> $DIR/borrowck-pat-at-and-box.rs:20:18
    |
 LL |     let a @ box &b = Box::new(&C);
    |         ---------^   ------------ move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait
@@ -80,7 +80,7 @@ LL |     let a @ box &b = Box::new(&C);
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-at-and-box.rs:24:17
+  --> $DIR/borrowck-pat-at-and-box.rs:23:17
    |
 LL |     let a @ box b = Box::new(C);
    |         --------^   ----------- move occurs because value has type `Box<C>`, which does not implement the `Copy` trait
@@ -89,7 +89,7 @@ LL |     let a @ box b = Box::new(C);
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-at-and-box.rs:34:17
+  --> $DIR/borrowck-pat-at-and-box.rs:33:17
    |
 LL |     match Box::new(C) {
    |           ----------- move occurs because value has type `Box<C>`, which does not implement the `Copy` trait
@@ -100,7 +100,7 @@ LL |         a @ box b => {}
    |         value moved here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-at-and-box.rs:46:21
+  --> $DIR/borrowck-pat-at-and-box.rs:45:21
    |
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         ------------^^^^^^^^^
@@ -112,7 +112,7 @@ LL |     drop(a);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-at-and-box.rs:52:25
+  --> $DIR/borrowck-pat-at-and-box.rs:51:25
    |
 LL |     let ref mut a @ box ref b = Box::new(NC);
    |         ----------------^^^^^
@@ -124,7 +124,7 @@ LL |     *a = Box::new(NC);
    |     -- mutable borrow later used here
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-at-and-box.rs:66:25
+  --> $DIR/borrowck-pat-at-and-box.rs:65:25
    |
 LL |         ref mut a @ box ref b => {
    |         ----------------^^^^^
@@ -136,7 +136,7 @@ LL |             *a = Box::new(NC);
    |             -- mutable borrow later used here
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-at-and-box.rs:27:20
+  --> $DIR/borrowck-pat-at-and-box.rs:26:20
    |
 LL |     fn f1(a @ box &b: Box<&C>) {}
    |           ---------^
@@ -146,7 +146,7 @@ LL |     fn f1(a @ box &b: Box<&C>) {}
    |           move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-at-and-box.rs:30:19
+  --> $DIR/borrowck-pat-at-and-box.rs:29:19
    |
 LL |     fn f2(a @ box b: Box<C>) {}
    |           --------^
@@ -156,7 +156,7 @@ LL |     fn f2(a @ box b: Box<C>) {}
    |           move occurs because value has type `Box<C>`, which does not implement the `Copy` trait
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-at-and-box.rs:58:27
+  --> $DIR/borrowck-pat-at-and-box.rs:57:27
    |
 LL |     fn f5(ref mut a @ box ref b: Box<NC>) {
    |           ----------------^^^^^
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs
index 993954b450e..a22d27763d2 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs
@@ -2,7 +2,6 @@
 // Currently this logic exists in THIR match checking as opposed to borrowck.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {
     struct U;
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
index dacf23f9ded..0e09d478e3a 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
@@ -1,5 +1,5 @@
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:9:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:8:9
    |
 LL |     let a @ ref b = U;
    |         -^^^-----
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs
index 7d9618c8df7..3e5a543c4c3 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs
@@ -1,7 +1,6 @@
 // Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {
     struct U;
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
index 86e09e55585..282031aeb07 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
@@ -1,5 +1,5 @@
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:28:9
    |
 LL |     let a @ ref b = U;
    |         -^^^-----
@@ -9,7 +9,7 @@ LL |     let a @ ref b = U;
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:9
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |         -^^^^^^^^^^^^---------^^^^^^-----^
@@ -20,7 +20,7 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:14
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:14
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |              -----^^^---------
@@ -30,7 +30,7 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |              move occurs because `b` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:33
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |                                 -^^^-----
@@ -40,7 +40,7 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |                                 move occurs because `d` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:37:9
    |
 LL |     let a @ [ref mut b, ref c] = [U, U];
    |         -^^^^---------^^-----^
@@ -51,7 +51,7 @@ LL |     let a @ [ref mut b, ref c] = [U, U];
    |         move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:40:9
    |
 LL |     let a @ ref b = u();
    |         -^^^-----
@@ -61,7 +61,7 @@ LL |     let a @ ref b = u();
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:9
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |         -^^^^^^^^^^^^---------^^^^^^-----^
@@ -72,7 +72,7 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:14
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:14
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |              -----^^^---------
@@ -82,7 +82,7 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |              move occurs because `b` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:33
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |                                 -^^^-----
@@ -92,7 +92,7 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |                                 move occurs because `d` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:50:9
    |
 LL |     let a @ [ref mut b, ref c] = [u(), u()];
    |         -^^^^---------^^-----^
@@ -103,7 +103,7 @@ LL |     let a @ [ref mut b, ref c] = [u(), u()];
    |         move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:56:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9
    |
 LL |         a @ Some(ref b) => {}
    |         -^^^^^^^^-----^
@@ -113,7 +113,7 @@ LL |         a @ Some(ref b) => {}
    |         move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:9
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^
@@ -124,7 +124,7 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:19
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:19
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   -----^^^---------
@@ -134,7 +134,7 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   move occurs because `b` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:38
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      -^^^-----
@@ -144,7 +144,7 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      move occurs because `d` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:70:9
    |
 LL |         mut a @ Some([ref b, ref mut c]) => {}
    |         -----^^^^^^^^^-----^^---------^^
@@ -155,7 +155,7 @@ LL |         mut a @ Some([ref b, ref mut c]) => {}
    |         move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:76:9
    |
 LL |         a @ Some(ref b) => {}
    |         -^^^^^^^^-----^
@@ -165,7 +165,7 @@ LL |         a @ Some(ref b) => {}
    |         move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:9
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^
@@ -176,7 +176,7 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:19
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:19
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   -----^^^---------
@@ -186,7 +186,7 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   move occurs because `b` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:38
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      -^^^-----
@@ -196,7 +196,7 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      move occurs because `d` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:9
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:92:9
    |
 LL |         mut a @ Some([ref b, ref mut c]) => {}
    |         -----^^^^^^^^^-----^^---------^^
@@ -207,7 +207,7 @@ LL |         mut a @ Some([ref b, ref mut c]) => {}
    |         move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:13:11
    |
 LL |     fn f1(a @ ref b: U) {}
    |           -^^^-----
@@ -217,7 +217,7 @@ LL |     fn f1(a @ ref b: U) {}
    |           move occurs because `a` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:11
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:11
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |           -----^^^^^^^^-----^^^^^^^^^^-----^
@@ -228,7 +228,7 @@ LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |           move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:20
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:20
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                    -^^^-----
@@ -238,7 +238,7 @@ LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                    move occurs because `b` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:31
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                               -----^^^-----
@@ -248,7 +248,7 @@ LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                               move occurs because `d` has type `U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:11
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:11
    |
 LL |     fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
    |           -^^^^---------^^-----^
@@ -259,7 +259,7 @@ LL |     fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
    |           move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:22
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:22
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |              --------^^^^^^^^^
@@ -270,7 +270,7 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:33
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |         ------------------------^^^^^^^^^-   ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
@@ -279,7 +279,7 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:37
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:37
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |                                 ----^^^^^
@@ -290,7 +290,7 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:25
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:37:25
    |
 LL |     let a @ [ref mut b, ref c] = [U, U];
    |         ----------------^^^^^-   ------ move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait
@@ -299,7 +299,7 @@ LL |     let a @ [ref mut b, ref c] = [U, U];
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:13
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:40:13
    |
 LL |     let a @ ref b = u();
    |         ----^^^^^   --- move occurs because value has type `U`, which does not implement the `Copy` trait
@@ -308,7 +308,7 @@ LL |     let a @ ref b = u();
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:22
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:22
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |              --------^^^^^^^^^
@@ -319,7 +319,7 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:33
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |         ------------------------^^^^^^^^^-   ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
@@ -328,7 +328,7 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:37
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:37
    |
 LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |                                 ----^^^^^
@@ -339,7 +339,7 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:25
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:50:25
    |
 LL |     let a @ [ref mut b, ref c] = [u(), u()];
    |         ----------------^^^^^-   ---------- move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait
@@ -348,7 +348,7 @@ LL |     let a @ [ref mut b, ref c] = [u(), u()];
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:27
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:27
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   --------^^^^^^^^^
@@ -363,7 +363,7 @@ LL |         a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
    |                   ^^^
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:38
    |
 LL |     match Some((U, U)) {
    |           ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
@@ -374,7 +374,7 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:42
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:42
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      ----^^^^^
@@ -389,7 +389,7 @@ LL |         a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
    |                                      ^^^
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:30
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:70:30
    |
 LL |     match Some([U, U]) {
    |           ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
@@ -400,7 +400,7 @@ LL |         mut a @ Some([ref b, ref mut c]) => {}
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:18
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:76:18
    |
 LL |     match Some(u()) {
    |           --------- move occurs because value has type `Option<U>`, which does not implement the `Copy` trait
@@ -411,7 +411,7 @@ LL |         a @ Some(ref b) => {}
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:27
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:27
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   --------^^^^^^^^^
@@ -426,7 +426,7 @@ LL |         a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
    |                   ^^^
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:38
    |
 LL |     match Some((u(), u())) {
    |           ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
@@ -437,7 +437,7 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:42
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:42
    |
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      ----^^^^^
@@ -452,7 +452,7 @@ LL |         a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
    |                                      ^^^
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:30
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:92:30
    |
 LL |     match Some([u(), u()]) {
    |           ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
@@ -463,7 +463,7 @@ LL |         mut a @ Some([ref b, ref mut c]) => {}
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:15
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:13:15
    |
 LL |     fn f1(a @ ref b: U) {}
    |           ----^^^^^
@@ -473,7 +473,7 @@ LL |     fn f1(a @ ref b: U) {}
    |           move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:24
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:24
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                    ----^^^^^
@@ -484,7 +484,7 @@ LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: use of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:31
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |           --------------------^^^^^^^^^^^^^-
@@ -494,7 +494,7 @@ LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |           move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:39
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:39
    |
 LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                               --------^^^^^
@@ -505,7 +505,7 @@ LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:27
+  --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:27
    |
 LL |     fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
    |           ----------------^^^^^-
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs
index b7c8c8766c0..42c3290ddfb 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs
@@ -1,7 +1,6 @@
 // Test that `ref mut? @ pat_with_by_move_bindings` is prevented.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {
     struct U;
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
index e5419efa00b..a275705b193 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
@@ -1,5 +1,5 @@
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:23:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:22:9
    |
 LL |     let ref a @ b = U;
    |         -----^^^-
@@ -8,7 +8,7 @@ LL |     let ref a @ b = U;
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:25:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:24:9
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |         -----^^^^^^^^^^^^-----^^^^^^^^^^-^
@@ -18,7 +18,7 @@ LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:25:18
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:24:18
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |                  -----^^^-----
@@ -27,7 +27,7 @@ LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |                  value borrowed, by `b`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:25:33
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:24:33
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |                                 -----^^^-
@@ -36,7 +36,7 @@ LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |                                 value borrowed, by `d`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:29:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:28:9
    |
 LL |     let ref mut a @ [b, mut c] = [U, U];
    |         ---------^^^^-^^-----^
@@ -46,7 +46,7 @@ LL |     let ref mut a @ [b, mut c] = [U, U];
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:31:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
    |
 LL |     let ref a @ b = u();
    |         -----^^^-
@@ -55,7 +55,7 @@ LL |     let ref a @ b = u();
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:32:9
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |         -----^^^^^^^^^^^^-----^^^^^^^^^^-^
@@ -65,7 +65,7 @@ LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:33:18
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:32:18
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                  -----^^^-----
@@ -74,7 +74,7 @@ LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                  value borrowed, by `b`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:33:33
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:32:33
    |
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                                 -----^^^-
@@ -83,7 +83,7 @@ LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                                 value borrowed, by `d`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:37:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9
    |
 LL |     let ref mut a @ [b, mut c] = [u(), u()];
    |         ---------^^^^-^^-----^
@@ -93,7 +93,7 @@ LL |     let ref mut a @ [b, mut c] = [u(), u()];
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:41:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:40:9
    |
 LL |         ref a @ Some(b) => {}
    |         -----^^^^^^^^-^
@@ -102,7 +102,7 @@ LL |         ref a @ Some(b) => {}
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:46:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:45:9
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |         -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
@@ -112,7 +112,7 @@ LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:46:23
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:45:23
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                       -----^^^-----
@@ -121,7 +121,7 @@ LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                       value borrowed, by `b`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:46:38
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:45:38
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                                      -----^^^-
@@ -130,7 +130,7 @@ LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                                      value borrowed, by `d`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:53:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9
    |
 LL |         ref mut a @ Some([b, mut c]) => {}
    |         ---------^^^^^^^^^-^^-----^^
@@ -140,7 +140,7 @@ LL |         ref mut a @ Some([b, mut c]) => {}
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:58:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:57:9
    |
 LL |         ref a @ Some(b) => {}
    |         -----^^^^^^^^-^
@@ -149,7 +149,7 @@ LL |         ref a @ Some(b) => {}
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:63:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:62:9
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |         -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
@@ -159,7 +159,7 @@ LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:63:23
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:62:23
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                       -----^^^-----
@@ -168,7 +168,7 @@ LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                       value borrowed, by `b`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:63:38
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:62:38
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                                      -----^^^-
@@ -177,7 +177,7 @@ LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                                      value borrowed, by `d`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:70:9
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9
    |
 LL |         ref mut a @ Some([b, mut c]) => {}
    |         ---------^^^^^^^^^-^^-----^^
@@ -187,7 +187,7 @@ LL |         ref mut a @ Some([b, mut c]) => {}
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:13:11
    |
 LL |     fn f1(ref a @ b: U) {}
    |           -----^^^-
@@ -196,7 +196,7 @@ LL |     fn f1(ref a @ b: U) {}
    |           value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:16:11
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:15:11
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |           -----^^^^^^^^^^^^-----^^^^^^^^^^-^
@@ -206,7 +206,7 @@ LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |           value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:16:20
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:15:20
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |                    -----^^^-----
@@ -215,7 +215,7 @@ LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |                    value borrowed, by `b`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:16:35
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:15:35
    |
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |                                   -----^^^-
@@ -224,7 +224,7 @@ LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |                                   value borrowed, by `d`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:19:11
    |
 LL |     fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
    |           ---------^^^^-^^-----^
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs
index 2b5e339c639..f67cd45ca95 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs
@@ -1,5 +1,4 @@
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 enum Option<T> {
     None,
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
index 695da9639af..e6231dd49ba 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
@@ -1,5 +1,5 @@
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:10:9
    |
 LL |         ref mut z @ &mut Some(ref a) => {
    |         ---------^^^^^^^^^^^^^-----^
@@ -8,7 +8,7 @@ LL |         ref mut z @ &mut Some(ref a) => {
    |         mutable borrow, by `z`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:35:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:34:9
    |
 LL |     let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
    |         ---------^^^^-----------------^
@@ -18,7 +18,7 @@ LL |     let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:35:22
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:34:22
    |
 LL |     let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
    |                      -----^^^---------
@@ -27,7 +27,7 @@ LL |     let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
    |                      immutable borrow, by `b`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:38:9
    |
 LL |     let ref a @ ref mut b = U;
    |         -----^^^---------
@@ -36,7 +36,7 @@ LL |     let ref a @ ref mut b = U;
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:40:9
    |
 LL |     let ref mut a @ ref b = U;
    |         ---------^^^-----
@@ -45,7 +45,7 @@ LL |     let ref mut a @ ref b = U;
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:42:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
@@ -55,7 +55,7 @@ LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:45:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:44:9
    |
 LL |     let ref mut a @ (ref b, ref c) = (U, U);
    |         ---------^^^^-----^^-----^
@@ -65,7 +65,7 @@ LL |     let ref mut a @ (ref b, ref c) = (U, U);
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:48:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:47:9
    |
 LL |     let ref mut a @ ref b = u();
    |         ---------^^^-----
@@ -74,7 +74,7 @@ LL |     let ref mut a @ ref b = u();
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:53:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:52:9
    |
 LL |     let ref a @ ref mut b = u();
    |         -----^^^---------
@@ -83,7 +83,7 @@ LL |     let ref a @ ref mut b = u();
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:59:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:58:9
    |
 LL |     let ref mut a @ ref b = U;
    |         ---------^^^-----
@@ -92,7 +92,7 @@ LL |     let ref mut a @ ref b = U;
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:63:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:62:9
    |
 LL |     let ref a @ ref mut b = U;
    |         -----^^^---------
@@ -101,7 +101,7 @@ LL |     let ref a @ ref mut b = U;
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:69:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:68:9
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
    |         ---------^^^^^^-----^
@@ -110,7 +110,7 @@ LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:69:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:68:33
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
    |                                 ---------^^^^^^^-----^
@@ -119,7 +119,7 @@ LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
    |                                 mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:9
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |         -----^^^^^^---------^
@@ -128,7 +128,7 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:33
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |                                 -----^^^^^^^---------^
@@ -137,7 +137,7 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |                                 immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:9
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
    |         -----^^^^^^---------^
@@ -146,7 +146,7 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false }
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:33
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
    |                                 -----^^^^^^^---------^
@@ -155,7 +155,7 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false }
    |                                 immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:9
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
    |         ---------^^^^^^-----^
@@ -164,7 +164,7 @@ LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:33
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
    |                                 ---------^^^^^^^-----^
@@ -173,7 +173,7 @@ LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa
    |                                 mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:9
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
    |         -----^^^^^^---------^
@@ -182,7 +182,7 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:33
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
    |                                 -----^^^^^^^---------^
@@ -191,7 +191,7 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false
    |                                 immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:9
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |         ---------^^^^^^-----^
@@ -200,7 +200,7 @@ LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:33
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:33
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |                                 ---------^^^^^^^-----^
@@ -209,7 +209,7 @@ LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false
    |                                 mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:118:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
@@ -219,7 +219,7 @@ LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
@@ -229,7 +229,7 @@ LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:9
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
@@ -239,7 +239,7 @@ LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:136:9
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:135:9
    |
 LL |     let ref mut a @ (ref b, ref c) = (U, U);
    |         ---------^^^^-----^^-----^
@@ -249,7 +249,7 @@ LL |     let ref mut a @ (ref b, ref c) = (U, U);
    |         mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:25:11
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11
    |
 LL |     fn f1(ref a @ ref mut b: U) {}
    |           -----^^^---------
@@ -258,7 +258,7 @@ LL |     fn f1(ref a @ ref mut b: U) {}
    |           immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:27:11
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11
    |
 LL |     fn f2(ref mut a @ ref b: U) {}
    |           ---------^^^-----
@@ -267,7 +267,7 @@ LL |     fn f2(ref mut a @ ref b: U) {}
    |           mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:29:11
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:11
    |
 LL |     fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {}
    |           -----^^^^^^^^^^^----------------^^^^^^^^
@@ -276,7 +276,7 @@ LL |     fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {}
    |           immutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:31:22
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:22
    |
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
    |                      -----^^^-------------
@@ -286,7 +286,7 @@ LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
    |                      immutable borrow, by `a`, occurs here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:31:30
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:30
    |
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
    |                              ---------^^^-
@@ -295,7 +295,7 @@ LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
    |                              value borrowed, by `b`, here
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:31
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:10:31
    |
 LL |         ref mut z @ &mut Some(ref a) => {
    |         ----------------------^^^^^-
@@ -307,7 +307,7 @@ LL |             **z = None;
    |             ---------- mutable borrow later used here
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:48:21
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:47:21
    |
 LL |     let ref mut a @ ref b = u();
    |         ------------^^^^^
@@ -319,7 +319,7 @@ LL |     *a = u();
    |     -------- mutable borrow later used here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:53:17
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:52:17
    |
 LL |     let ref a @ ref mut b = u();
    |         --------^^^^^^^^^
@@ -331,7 +331,7 @@ LL |     drop(a);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:20
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:20
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |         -----------^^^^^^^^^-
@@ -343,7 +343,7 @@ LL |             drop(a);
    |                  - immutable borrow later used here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:45
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:45
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |                                 ------------^^^^^^^^^-
@@ -355,7 +355,7 @@ LL |             drop(a);
    |                  - immutable borrow later used here
 
 error[E0594]: cannot assign to `*b`, as it is immutable for the pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:61
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:61
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
    |                                                             ^^^^^^ cannot assign
@@ -363,7 +363,7 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false }
    = note: variables bound in patterns are immutable until the end of the pattern guard
 
 error[E0594]: cannot assign to `*a`, as it is immutable for the pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:61
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:61
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
    |                                                             ^^^^^^^^^^^ cannot assign
@@ -371,7 +371,7 @@ LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa
    = note: variables bound in patterns are immutable until the end of the pattern guard
 
 error[E0507]: cannot move out of `b` in pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:66
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
    |                                                                  ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait
@@ -379,7 +379,7 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
 error[E0507]: cannot move out of `b` in pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:66
    |
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
    |                                                                  ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait
@@ -387,7 +387,7 @@ LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
 error[E0507]: cannot move out of `a` in pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:66
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |                                                                  ^ move occurs because `a` has type `&mut std::result::Result<U, U>`, which does not implement the `Copy` trait
@@ -395,7 +395,7 @@ LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
 error[E0507]: cannot move out of `a` in pattern guard
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:66
    |
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |                                                                  ^ move occurs because `a` has type `&mut std::result::Result<U, U>`, which does not implement the `Copy` trait
@@ -403,7 +403,7 @@ LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false
    = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:18
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:18
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         ---------^^^^^^^^^------------
@@ -415,7 +415,7 @@ LL |     drop(a);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:29
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:29
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         --------------------^^^^^^^^^-
@@ -427,7 +427,7 @@ LL |     drop(a);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:18
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:18
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         ---------^^^^^^^^^------------
@@ -439,7 +439,7 @@ LL |     drop(a);
    |          - immutable borrow later used here
 
 error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:29
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:29
    |
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         --------------------^^^^^^^^^-
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs
index a208d0087ff..8faaa1c881f 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs
@@ -1,7 +1,6 @@
 // Test that `ref mut x @ ref mut y` and varieties of that are not allowed.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {
     struct U;
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
index 1cd3e267b99..2e0f5fcabdd 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
@@ -1,5 +1,5 @@
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:28:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:27:9
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
@@ -8,7 +8,7 @@ LL |     let ref mut a @ ref mut b = U;
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:32:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:31:9
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
@@ -17,7 +17,7 @@ LL |     let ref mut a @ ref mut b = U;
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:35:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:34:9
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
@@ -26,7 +26,7 @@ LL |     let ref mut a @ ref mut b = U;
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:38:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:37:9
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
@@ -35,7 +35,7 @@ LL |     let ref mut a @ ref mut b = U;
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:42:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:41:9
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
@@ -44,7 +44,7 @@ LL |     let ref mut a @ ref mut b = U;
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:46:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:45:9
    |
 LL |       let ref mut a @ (
    |           ^--------
@@ -66,7 +66,7 @@ LL | |     ) = (U, [U, U, U]);
    | |_____^
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:56:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:55:9
    |
 LL |       let ref mut a @ (
    |           ^--------
@@ -88,7 +88,7 @@ LL | |         ) = (u(), [u(), u(), u()]);
    | |_________^
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:66:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:65:9
    |
 LL |     let a @ (ref mut b, ref mut c) = (U, U);
    |         -^^^^---------^^---------^
@@ -99,7 +99,7 @@ LL |     let a @ (ref mut b, ref mut c) = (U, U);
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:69:9
    |
 LL |     let a @ (b, [c, d]) = &mut val; // Same as ^--
    |         -^^^^-^^^-^^-^^
@@ -111,7 +111,7 @@ LL |     let a @ (b, [c, d]) = &mut val; // Same as ^--
    |         move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:74:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:73:9
    |
 LL |     let a @ &mut ref mut b = &mut U;
    |         -^^^^^^^^---------
@@ -121,7 +121,7 @@ LL |     let a @ &mut ref mut b = &mut U;
    |         move occurs because `a` has type `&mut U` which does not implement the `Copy` trait
 
 error: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:77:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9
    |
 LL |     let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
    |         -^^^^^^^^^---------^^---------^
@@ -132,7 +132,7 @@ LL |     let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
    |         move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:81:9
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
@@ -141,7 +141,7 @@ LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:81:37
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
@@ -150,7 +150,7 @@ LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:88:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:87:9
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
@@ -159,7 +159,7 @@ LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:88:37
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:87:37
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
@@ -168,7 +168,7 @@ LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:95:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:94:9
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
@@ -177,7 +177,7 @@ LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:95:37
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:94:37
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
@@ -186,7 +186,7 @@ LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:107:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:106:9
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
@@ -195,7 +195,7 @@ LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:107:37
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:106:37
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
@@ -204,7 +204,7 @@ LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:11:11
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11
    |
 LL |     fn f1(ref mut a @ ref mut b: U) {}
    |           ---------^^^---------
@@ -213,7 +213,7 @@ LL |     fn f1(ref mut a @ ref mut b: U) {}
    |           first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:13:11
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:12:11
    |
 LL |     fn f2(ref mut a @ ref mut b: U) {}
    |           ---------^^^---------
@@ -222,7 +222,7 @@ LL |     fn f2(ref mut a @ ref mut b: U) {}
    |           first mutable borrow, by `a`, occurs here
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:16:9
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:15:9
    |
 LL |           ref mut a @ [
    |           ^--------
@@ -240,7 +240,7 @@ LL | |         ] : [[U; 4]; 5]
    | |_________^
 
 error: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:24:22
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:23:22
    |
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
    |                      ---------^^^-------------
@@ -250,7 +250,7 @@ LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
    |                      first mutable borrow, by `a`, occurs here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:24:34
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:23:34
    |
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
    |                                  ---------^^^-
@@ -259,7 +259,7 @@ LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
    |                                  value borrowed, by `b`, here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:28:21
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:27:21
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ------------^^^^^^^^^
@@ -271,7 +271,7 @@ LL |     drop(a);
    |          - first borrow later used here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:38:21
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:37:21
    |
 LL |     let ref mut a @ ref mut b = U;
    |         ------------^^^^^^^^^
@@ -283,7 +283,7 @@ LL |     *a = U;
    |     ------ first borrow later used here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:66:25
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:65:25
    |
 LL |     let a @ (ref mut b, ref mut c) = (U, U);
    |         ----------------^^^^^^^^^-   ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait
@@ -292,7 +292,7 @@ LL |     let a @ (ref mut b, ref mut c) = (U, U);
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:70:21
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:69:21
    |
 LL |     let a @ (b, [c, d]) = &mut val; // Same as ^--
    |         ------------^--   -------- move occurs because value has type `&mut (U, [U; 2])`, which does not implement the `Copy` trait
@@ -301,7 +301,7 @@ LL |     let a @ (b, [c, d]) = &mut val; // Same as ^--
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:74:18
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:73:18
    |
 LL |     let a @ &mut ref mut b = &mut U;
    |         ---------^^^^^^^^^   ------ move occurs because value has type `&mut U`, which does not implement the `Copy` trait
@@ -310,7 +310,7 @@ LL |     let a @ &mut ref mut b = &mut U;
    |         value moved here
 
 error[E0382]: borrow of moved value
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:77:30
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:76:30
    |
 LL |     let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
    |         ---------------------^^^^^^^^^-   ----------- move occurs because value has type `&mut (U, U)`, which does not implement the `Copy` trait
@@ -319,7 +319,7 @@ LL |     let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
    |         value moved here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:95:24
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:94:24
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------------^^^^^^^^^-
@@ -331,7 +331,7 @@ LL |             *a = Err(U);
    |             ----------- first borrow later used here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:95:53
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:94:53
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ----------------^^^^^^^^^-
@@ -343,7 +343,7 @@ LL |             *a = Err(U);
    |             ----------- first borrow later used here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:107:24
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:106:24
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------------^^^^^^^^^-
@@ -355,7 +355,7 @@ LL |             drop(a);
    |                  - first borrow later used here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
-  --> $DIR/borrowck-pat-ref-mut-twice.rs:107:53
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:106:53
    |
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ----------------^^^^^^^^^-
diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs
index 821d4b42962..3954d17e1c2 100644
--- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs
+++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs
@@ -1,7 +1,6 @@
 // Test that mixing `Copy` and non-`Copy` types in `@` patterns is forbidden.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 #[derive(Copy, Clone)]
 struct C;
diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
index 7e89008a604..cc2786a13f4 100644
--- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
+++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value
-  --> $DIR/copy-and-move-mixed.rs:12:19
+  --> $DIR/copy-and-move-mixed.rs:11:19
    |
 LL |     let a @ NC(b, c) = NC(C, C);
    |         ----------^-   -------- move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait
@@ -8,7 +8,7 @@ LL |     let a @ NC(b, c) = NC(C, C);
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/copy-and-move-mixed.rs:15:19
+  --> $DIR/copy-and-move-mixed.rs:14:19
    |
 LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
    |         ----------^^^^^^^^^^^^-   --------------- move occurs because value has type `NC<C, NC<C, C>>`, which does not implement the `Copy` trait
@@ -17,7 +17,7 @@ LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
    |         value moved here
 
 error[E0382]: use of moved value
-  --> $DIR/copy-and-move-mixed.rs:15:29
+  --> $DIR/copy-and-move-mixed.rs:14:29
    |
 LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
    |                   ----------^-
diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs
index a45497229ac..276088b9a9e 100644
--- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs
+++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs
@@ -8,7 +8,6 @@
 // this would create problems for the generalization aforementioned.
 
 #![feature(bindings_after_at)]
-#![feature(move_ref_pattern)]
 
 fn main() {
     struct NotCopy;
diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
index a63a5a1e6c7..11d5e24f34e 100644
--- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
+++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
@@ -1,5 +1,5 @@
 error: cannot move out of value because it is borrowed
-  --> $DIR/default-binding-modes-both-sides-independent.rs:28:9
+  --> $DIR/default-binding-modes-both-sides-independent.rs:27:9
    |
 LL |     let ref a @ b = NotCopy;
    |         -----^^^-
@@ -8,7 +8,7 @@ LL |     let ref a @ b = NotCopy;
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/default-binding-modes-both-sides-independent.rs:31:9
+  --> $DIR/default-binding-modes-both-sides-independent.rs:30:9
    |
 LL |     let ref mut a @ b = NotCopy;
    |         ---------^^^-
@@ -17,7 +17,7 @@ LL |     let ref mut a @ b = NotCopy;
    |         value borrowed, by `a`, here
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/default-binding-modes-both-sides-independent.rs:36:12
+  --> $DIR/default-binding-modes-both-sides-independent.rs:35:12
    |
 LL |         Ok(ref a @ b) | Err(b @ ref a) => {
    |            -----^^^-
@@ -26,7 +26,7 @@ LL |         Ok(ref a @ b) | Err(b @ ref a) => {
    |            value borrowed, by `a`, here
 
 error: borrow of moved value
-  --> $DIR/default-binding-modes-both-sides-independent.rs:36:29
+  --> $DIR/default-binding-modes-both-sides-independent.rs:35:29
    |
 LL |         Ok(ref a @ b) | Err(b @ ref a) => {
    |                             -^^^-----
@@ -36,7 +36,7 @@ LL |         Ok(ref a @ b) | Err(b @ ref a) => {
    |                             move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait
 
 error: cannot move out of value because it is borrowed
-  --> $DIR/default-binding-modes-both-sides-independent.rs:44:9
+  --> $DIR/default-binding-modes-both-sides-independent.rs:43:9
    |
 LL |         ref a @ b => {
    |         -----^^^-
@@ -45,7 +45,7 @@ LL |         ref a @ b => {
    |         value borrowed, by `a`, here
 
 error[E0505]: cannot move out of value because it is borrowed
-  --> $DIR/default-binding-modes-both-sides-independent.rs:31:21
+  --> $DIR/default-binding-modes-both-sides-independent.rs:30:21
    |
 LL |     let ref mut a @ b = NotCopy;
    |         ------------^
diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs
index d2d4e61e049..5445696fdff 100644
--- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs
@@ -1,7 +1,5 @@
 // check-pass
 
-#![feature(move_ref_pattern)]
-
 fn main() {}
 
 struct U;
diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs
index 3ee008fd84f..9c320edc4dc 100644
--- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs
@@ -1,5 +1,3 @@
-#![feature(move_ref_pattern)]
-
 fn main() {}
 
 struct U;
diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
index d718ee29cf9..285c203f382 100644
--- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
@@ -1,5 +1,5 @@
 error[E0505]: cannot move out of `arr[..]` because it is borrowed
-  --> $DIR/borrowck-move-ref-pattern.rs:10:24
+  --> $DIR/borrowck-move-ref-pattern.rs:8:24
    |
 LL |     let hold_all = &arr;
    |                    ---- borrow of `arr` occurs here
@@ -10,7 +10,7 @@ LL |     drop(hold_all);
    |          -------- borrow later used here
 
 error[E0384]: cannot assign twice to immutable variable `_x1`
-  --> $DIR/borrowck-move-ref-pattern.rs:11:5
+  --> $DIR/borrowck-move-ref-pattern.rs:9:5
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
    |                        ---
@@ -21,7 +21,7 @@ LL |     _x1 = U;
    |     ^^^^^^^ cannot assign twice to immutable variable
 
 error[E0505]: cannot move out of `arr[..]` because it is borrowed
-  --> $DIR/borrowck-move-ref-pattern.rs:13:10
+  --> $DIR/borrowck-move-ref-pattern.rs:11:10
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
    |          ------------ borrow of `arr[..]` occurs here
@@ -32,7 +32,7 @@ LL |     drop(_x0_hold);
    |          -------- borrow later used here
 
 error[E0502]: cannot borrow `arr[..]` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-move-ref-pattern.rs:15:16
+  --> $DIR/borrowck-move-ref-pattern.rs:13:16
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
    |                             ---------------- immutable borrow occurs here
@@ -44,7 +44,7 @@ LL |     drop(xs_hold);
    |          ------- immutable borrow later used here
 
 error[E0505]: cannot move out of `arr[..]` because it is borrowed
-  --> $DIR/borrowck-move-ref-pattern.rs:15:29
+  --> $DIR/borrowck-move-ref-pattern.rs:13:29
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
    |                             ---------------- borrow of `arr[..]` occurs here
@@ -56,7 +56,7 @@ LL |     drop(xs_hold);
    |          ------- borrow later used here
 
 error[E0505]: cannot move out of `arr[..]` because it is borrowed
-  --> $DIR/borrowck-move-ref-pattern.rs:15:34
+  --> $DIR/borrowck-move-ref-pattern.rs:13:34
    |
 LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
    |                             ---------------- borrow of `arr[..]` occurs here
@@ -68,7 +68,7 @@ LL |     drop(xs_hold);
    |          ------- borrow later used here
 
 error[E0384]: cannot assign twice to immutable variable `_x1`
-  --> $DIR/borrowck-move-ref-pattern.rs:25:5
+  --> $DIR/borrowck-move-ref-pattern.rs:23:5
    |
 LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
    |                   ---
@@ -79,7 +79,7 @@ LL |     _x1 = U;
    |     ^^^^^^^ cannot assign twice to immutable variable
 
 error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-move-ref-pattern.rs:26:20
+  --> $DIR/borrowck-move-ref-pattern.rs:24:20
    |
 LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
    |          ------- immutable borrow occurs here
@@ -91,7 +91,7 @@ LL |     *_x0 = U;
    |     -------- immutable borrow later used here
 
 error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable
-  --> $DIR/borrowck-move-ref-pattern.rs:27:10
+  --> $DIR/borrowck-move-ref-pattern.rs:25:10
    |
 LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
    |          ------- immutable borrow occurs here
@@ -102,7 +102,7 @@ LL |     *_x0 = U;
    |     -------- immutable borrow later used here
 
 error[E0594]: cannot assign to `*_x0` which is behind a `&` reference
-  --> $DIR/borrowck-move-ref-pattern.rs:28:5
+  --> $DIR/borrowck-move-ref-pattern.rs:26:5
    |
 LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
    |          ------- help: consider changing this to be a mutable reference: `ref mut _x0`
@@ -111,7 +111,7 @@ LL |     *_x0 = U;
    |     ^^^^^^^^ `_x0` is a `&` reference, so the data it refers to cannot be written
 
 error[E0594]: cannot assign to `*_x2` which is behind a `&` reference
-  --> $DIR/borrowck-move-ref-pattern.rs:29:5
+  --> $DIR/borrowck-move-ref-pattern.rs:27:5
    |
 LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
    |                        ------- help: consider changing this to be a mutable reference: `ref mut _x2`
@@ -120,7 +120,7 @@ LL |     *_x2 = U;
    |     ^^^^^^^^ `_x2` is a `&` reference, so the data it refers to cannot be written
 
 error[E0382]: use of moved value: `tup.1`
-  --> $DIR/borrowck-move-ref-pattern.rs:30:10
+  --> $DIR/borrowck-move-ref-pattern.rs:28:10
    |
 LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
    |                   --- value moved here
@@ -131,7 +131,7 @@ LL |     drop(tup.1);
    = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait
 
 error[E0382]: borrow of moved value: `tup.1`
-  --> $DIR/borrowck-move-ref-pattern.rs:31:20
+  --> $DIR/borrowck-move-ref-pattern.rs:29:20
    |
 LL |     drop(tup.1);
    |          ----- value moved here
@@ -141,7 +141,7 @@ LL |     let _x1_hold = &tup.1;
    = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait
 
 error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-move-ref-pattern.rs:33:20
+  --> $DIR/borrowck-move-ref-pattern.rs:31:20
    |
 LL |     let (.., ref mut _x3) = tup;
    |              ----------- mutable borrow occurs here
@@ -152,7 +152,7 @@ LL |     drop(_x3);
    |          --- mutable borrow later used here
 
 error[E0499]: cannot borrow `tup.3` as mutable more than once at a time
-  --> $DIR/borrowck-move-ref-pattern.rs:34:20
+  --> $DIR/borrowck-move-ref-pattern.rs:32:20
    |
 LL |     let (.., ref mut _x3) = tup;
    |              ----------- first mutable borrow occurs here
@@ -164,7 +164,7 @@ LL |     drop(_x3);
    |          --- first borrow later used here
 
 error[E0499]: cannot borrow `tup.3` as mutable more than once at a time
-  --> $DIR/borrowck-move-ref-pattern.rs:35:14
+  --> $DIR/borrowck-move-ref-pattern.rs:33:14
    |
 LL |     let (.., ref mut _x3) = tup;
    |              ----------- first mutable borrow occurs here
@@ -176,7 +176,7 @@ LL |     drop(_x3);
    |          --- first borrow later used here
 
 error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable
-  --> $DIR/borrowck-move-ref-pattern.rs:36:14
+  --> $DIR/borrowck-move-ref-pattern.rs:34:14
    |
 LL |     let (.., ref mut _x3) = tup;
    |              ----------- mutable borrow occurs here
@@ -187,7 +187,7 @@ LL |     drop(_x3);
    |          --- mutable borrow later used here
 
 error[E0382]: use of moved value: `tup`
-  --> $DIR/borrowck-move-ref-pattern.rs:45:14
+  --> $DIR/borrowck-move-ref-pattern.rs:43:14
    |
 LL |     let mut tup = (U, U, U);
    |         ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs
index 08fb5cd2e16..18663c3fe3f 100644
--- a/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs
+++ b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs
@@ -4,7 +4,6 @@
 
 // check-pass
 
-#![feature(move_ref_pattern)]
 #![feature(bindings_after_at)]
 
 fn main() {
diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs
deleted file mode 100644
index fb92eb1ba32..00000000000
--- a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-fn main() {
-    #[derive(Clone)]
-    struct X {
-        x: (),
-    }
-    let mut tup = (X { x: () }, X { x: () });
-    match Some(tup.clone()) {
-        Some((y, ref z)) => {}
-        //~^ ERROR binding by-move and by-ref in the same pattern is unstable
-        None => panic!(),
-    }
-
-    let (ref a, b) = tup.clone();
-    //~^ ERROR binding by-move and by-ref in the same pattern is unstable
-
-    let (a, mut b) = &tup;
-    //~^ ERROR binding by-move and by-ref in the same pattern is unstable
-    //~| ERROR cannot move out of a shared reference
-
-    let (mut a, b) = &mut tup;
-    //~^ ERROR binding by-move and by-ref in the same pattern is unstable
-    //~| ERROR cannot move out of a mutable reference
-}
diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr
deleted file mode 100644
index 5335569a972..00000000000
--- a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr
+++ /dev/null
@@ -1,66 +0,0 @@
-error[E0658]: binding by-move and by-ref in the same pattern is unstable
-  --> $DIR/feature-gate-move_ref_pattern.rs:8:15
-   |
-LL |         Some((y, ref z)) => {}
-   |               ^  ----- by-ref pattern here
-   |               |
-   |               by-move pattern here
-   |
-   = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information
-   = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable
-
-error[E0658]: binding by-move and by-ref in the same pattern is unstable
-  --> $DIR/feature-gate-move_ref_pattern.rs:13:17
-   |
-LL |     let (ref a, b) = tup.clone();
-   |          -----  ^ by-move pattern here
-   |          |
-   |          by-ref pattern here
-   |
-   = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information
-   = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable
-
-error[E0658]: binding by-move and by-ref in the same pattern is unstable
-  --> $DIR/feature-gate-move_ref_pattern.rs:16:13
-   |
-LL |     let (a, mut b) = &tup;
-   |          -  ^^^^^ by-move pattern here
-   |          |
-   |          by-ref pattern here
-   |
-   = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information
-   = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable
-
-error[E0658]: binding by-move and by-ref in the same pattern is unstable
-  --> $DIR/feature-gate-move_ref_pattern.rs:20:10
-   |
-LL |     let (mut a, b) = &mut tup;
-   |          ^^^^^  - by-ref pattern here
-   |          |
-   |          by-move pattern here
-   |
-   = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information
-   = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable
-
-error[E0507]: cannot move out of a shared reference
-  --> $DIR/feature-gate-move_ref_pattern.rs:16:22
-   |
-LL |     let (a, mut b) = &tup;
-   |             -----    ^^^^
-   |             |
-   |             data moved here
-   |             move occurs because `b` has type `X`, which does not implement the `Copy` trait
-
-error[E0507]: cannot move out of a mutable reference
-  --> $DIR/feature-gate-move_ref_pattern.rs:20:22
-   |
-LL |     let (mut a, b) = &mut tup;
-   |          -----       ^^^^^^^^
-   |          |
-   |          data moved here
-   |          move occurs because `a` has type `X`, which does not implement the `Copy` trait
-
-error: aborting due to 6 previous errors
-
-Some errors have detailed explanations: E0507, E0658.
-For more information about an error, try `rustc --explain E0507`.
diff --git a/src/test/ui/pattern/move-ref-patterns/issue-53840.rs b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs
index ab7d10d9f83..80effc497ed 100644
--- a/src/test/ui/pattern/move-ref-patterns/issue-53840.rs
+++ b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs
@@ -1,7 +1,5 @@
 // check-pass
 
-#![feature(move_ref_pattern)]
-
 enum E {
     Foo(String, String, String),
 }
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs
index 4c3ca62e165..ebb1683af7d 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs
@@ -1,5 +1,3 @@
-#![feature(move_ref_pattern)]
-
 fn main() {
     struct S; // Not `Copy`.
 
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr
index 9ad84879595..f19fed08917 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr
@@ -1,5 +1,5 @@
 error[E0382]: borrow of moved value: `tup0`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:31:10
    |
 LL |     let mut tup0 = (S, S);
    |         -------- move occurs because `tup0` has type `(S, S)`, which does not implement the `Copy` trait
@@ -14,7 +14,7 @@ LL |     drop(&tup0);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup1`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:32:10
    |
 LL |     let mut tup1 = (S, S, S);
    |         -------- move occurs because `tup1` has type `(S, S, S)`, which does not implement the `Copy` trait
@@ -29,7 +29,7 @@ LL |     drop(&tup1);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup2`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:35:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10
    |
 LL |     let tup2 = (S, S);
    |         ---- move occurs because `tup2` has type `(S, S)`, which does not implement the `Copy` trait
@@ -44,7 +44,7 @@ LL |     drop(&tup2);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup3`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:36:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10
    |
 LL |     let tup3 = (S, S, S);
    |         ---- move occurs because `tup3` has type `(S, S, S)`, which does not implement the `Copy` trait
@@ -59,7 +59,7 @@ LL |     drop(&tup3);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup4`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:39:10
    |
 LL |     let tup4 = (S, S);
    |         ---- move occurs because `tup4` has type `(S, S)`, which does not implement the `Copy` trait
@@ -74,7 +74,7 @@ LL |     drop(&tup4.0);
    |          ^^^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr0`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10
    |
 LL |     let mut arr0 = [S, S, S];
    |         -------- move occurs because `arr0` has type `[S; 3]`, which does not implement the `Copy` trait
@@ -89,7 +89,7 @@ LL |     drop(&arr0);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr1`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:42:36
    |
 LL |     let mut arr1 = [S, S, S, S, S];
    |         -------- move occurs because `arr1` has type `[S; 5]`, which does not implement the `Copy` trait
@@ -104,7 +104,7 @@ LL |     let [_, mov1, mov2, mov3, _] = &arr1;
    |                                    ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr2`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:45:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10
    |
 LL |     let arr2 = [S, S, S];
    |         ---- move occurs because `arr2` has type `[S; 3]`, which does not implement the `Copy` trait
@@ -119,7 +119,7 @@ LL |     drop(&arr2);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr3`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:46:36
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36
    |
 LL |     let arr3 = [S, S, S, S, S];
    |         ---- move occurs because `arr3` has type `[S; 5]`, which does not implement the `Copy` trait
@@ -134,7 +134,7 @@ LL |     let [_, mov1, mov2, mov3, _] = &arr3;
    |                                    ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup0`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:75:10
    |
 LL |     let mut tup0: Option<(S, S)> = None;
    |         -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait
@@ -148,7 +148,7 @@ LL |     drop(&tup0);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup1`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:76:10
    |
 LL |     let mut tup1: Option<(S, S, S)> = None;
    |         -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait
@@ -163,7 +163,7 @@ LL |     drop(&tup1);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup2`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10
    |
 LL |     let tup2: Option<(S, S)> = None;
    |         ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait
@@ -178,7 +178,7 @@ LL |     drop(&tup2);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup3`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10
    |
 LL |     let tup3: Option<(S, S, S)> = None;
    |         ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait
@@ -193,7 +193,7 @@ LL |     drop(&tup3);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup4`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:21
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:21
    |
 LL |     let tup4: Option<(S, S)> = None;
    |         ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait
@@ -208,7 +208,7 @@ LL |     m!((ref x, _) = &tup4);
    |                     ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr0`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10
    |
 LL |     let mut arr0: Option<[S; 3]> = None;
    |         -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait
@@ -223,7 +223,7 @@ LL |     drop(&arr0);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr1`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:35
    |
 LL |     let mut arr1: Option<[S; 5]> = None;
    |         -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait
@@ -238,7 +238,7 @@ LL |     m!([_, mov1, mov2, mov3, _] = &arr1);
    |                                   ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr2`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:84:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10
    |
 LL |     let arr2: Option<[S; 3]> = None;
    |         ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait
@@ -253,7 +253,7 @@ LL |     drop(&arr2);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr3`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:85:35
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35
    |
 LL |     let arr3: Option<[S; 5]> = None;
    |         ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait
@@ -267,7 +267,7 @@ LL |     m!([_, mov1, mov2, mov3, _] = &arr3);
    |                                   ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup0`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:111:10
    |
 LL |     let mut tup0: Option<(S, S)> = None;
    |         -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait
@@ -281,7 +281,7 @@ LL |     drop(&tup0);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup1`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:112:10
    |
 LL |     let mut tup1: Option<(S, S, S)> = None;
    |         -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait
@@ -296,7 +296,7 @@ LL |     drop(&tup1);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup2`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10
    |
 LL |     let tup2: Option<(S, S)> = None;
    |         ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait
@@ -311,7 +311,7 @@ LL |     drop(&tup2);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup3`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10
    |
 LL |     let tup3: Option<(S, S, S)> = None;
    |         ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait
@@ -326,7 +326,7 @@ LL |     drop(&tup3);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `tup4`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:21
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:21
    |
 LL |     let tup4: Option<(S, S)> = None;
    |         ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait
@@ -341,7 +341,7 @@ LL |     m!((ref x, _) = &tup4);
    |                     ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr0`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10
    |
 LL |     let mut arr0: Option<[S; 3]> = None;
    |         -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait
@@ -356,7 +356,7 @@ LL |     drop(&arr0);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr1`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:35
    |
 LL |     let mut arr1: Option<[S; 5]> = None;
    |         -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait
@@ -371,7 +371,7 @@ LL |     m!([_, mov1, mov2, mov3, _] = &arr1);
    |                                   ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr2`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:120:10
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10
    |
 LL |     let arr2: Option<[S; 3]> = None;
    |         ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait
@@ -386,7 +386,7 @@ LL |     drop(&arr2);
    |          ^^^^^ value borrowed here after move
 
 error[E0382]: borrow of moved value: `arr3`
-  --> $DIR/move-ref-patterns-closure-captures-inside.rs:121:35
+  --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35
    |
 LL |     let arr3: Option<[S; 5]> = None;
    |         ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs
index e1844d36e4a..583f70f41aa 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs
@@ -1,7 +1,5 @@
 // check-pass
 
-#![feature(move_ref_pattern)]
-
 fn main() {
     struct U;
     fn accept_fn_once(_: impl FnOnce()) {}
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs
index 7f1c02c05cb..cd619cc41eb 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs
@@ -1,5 +1,3 @@
-#![feature(move_ref_pattern)]
-
 fn main() {
     struct U;
     fn accept_fn_once(_: &impl FnOnce()) {}
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
index ca82353c1c9..d96e863939c 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
@@ -1,5 +1,5 @@
 error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
-  --> $DIR/move-ref-patterns-closure-captures.rs:11:14
+  --> $DIR/move-ref-patterns-closure-captures.rs:9:14
    |
 LL |     let c1 = || {
    |              ^^ this closure implements `FnOnce`, not `FnMut`
@@ -11,7 +11,7 @@ LL |     accept_fn_mut(&c1);
    |     ------------- the requirement to implement `FnMut` derives from here
 
 error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
-  --> $DIR/move-ref-patterns-closure-captures.rs:11:14
+  --> $DIR/move-ref-patterns-closure-captures.rs:9:14
    |
 LL |     let c1 = || {
    |              ^^ this closure implements `FnOnce`, not `Fn`
@@ -23,7 +23,7 @@ LL |     accept_fn(&c1);
    |     --------- the requirement to implement `Fn` derives from here
 
 error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
-  --> $DIR/move-ref-patterns-closure-captures.rs:22:14
+  --> $DIR/move-ref-patterns-closure-captures.rs:20:14
    |
 LL |     let c2 = || {
    |              ^^ this closure implements `FnMut`, not `Fn`
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs
index 5c51c47d979..1dd66aad57a 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs
@@ -1,5 +1,3 @@
-#![feature(move_ref_pattern)]
-
 fn main() {
     struct U;
 
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr
index f92699f5c3c..6952c743a30 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of a shared reference
-  --> $DIR/move-ref-patterns-default-binding-modes.rs:10:22
+  --> $DIR/move-ref-patterns-default-binding-modes.rs:8:22
    |
 LL |     let (a, mut b) = &p;
    |             -----    ^^
@@ -8,7 +8,7 @@ LL |     let (a, mut b) = &p;
    |             move occurs because `b` has type `U`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of a mutable reference
-  --> $DIR/move-ref-patterns-default-binding-modes.rs:14:22
+  --> $DIR/move-ref-patterns-default-binding-modes.rs:12:22
    |
 LL |     let (a, mut b) = &mut p;
    |             -----    ^^^^^^
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs
index c78695390b5..1d6d9acead1 100644
--- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs
@@ -3,8 +3,6 @@
 // This test checks the dynamic semantics and drop order of pattern matching
 // where a product pattern has both a by-move and by-ref binding.
 
-#![feature(move_ref_pattern)]
-
 use std::cell::RefCell;
 use std::rc::Rc;
 
diff --git a/src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs
new file mode 100644
index 00000000000..2d4f6010012
--- /dev/null
+++ b/src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs
@@ -0,0 +1,7 @@
+// ignore-test this is not a test
+
+macro_rules! tuple_from_req {
+    ($T:ident) => {
+        #[my_macro] struct Three($T);
+    }
+}
diff --git a/src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs
new file mode 100644
index 00000000000..2d4f6010012
--- /dev/null
+++ b/src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs
@@ -0,0 +1,7 @@
+// ignore-test this is not a test
+
+macro_rules! tuple_from_req {
+    ($T:ident) => {
+        #[my_macro] struct Three($T);
+    }
+}
diff --git a/src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs
new file mode 100644
index 00000000000..9ec6aba63f3
--- /dev/null
+++ b/src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs
@@ -0,0 +1,7 @@
+// ignore-test this is not a test
+
+macro_rules! tuple_from_req {
+    ($T:ident) => {
+        #[my_macro] struct Four($T);
+    }
+}
diff --git a/src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs
new file mode 100644
index 00000000000..9ec6aba63f3
--- /dev/null
+++ b/src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs
@@ -0,0 +1,7 @@
+// ignore-test this is not a test
+
+macro_rules! tuple_from_req {
+    ($T:ident) => {
+        #[my_macro] struct Four($T);
+    }
+}
diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs
index bc82a2ff196..652fabf34ac 100644
--- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs
+++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs
@@ -45,5 +45,33 @@ mod with_version {
     other!(Foo);
 }
 
+mod actix_web_test {
+    include!("actix-web/src/extract.rs");
+
+    struct Foo;
+    tuple_from_req!(Foo);
+}
+
+mod actix_web_version_test {
+    include!("actix-web-2.0.0/src/extract.rs");
+
+    struct Foo;
+    tuple_from_req!(Foo);
+}
+
+mod actori_web_test {
+    include!("actori-web/src/extract.rs");
+
+    struct Foo;
+    tuple_from_req!(Foo);
+}
+
+mod actori_web_version_test {
+    include!("actori-web-2.0.0/src/extract.rs");
+
+    struct Foo;
+    tuple_from_req!(Foo);
+}
+
 
 fn main() {}
diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout
index e83bc9f8fca..c6b18ab674b 100644
--- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout
+++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout
@@ -4,3 +4,7 @@ Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/gro
 Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }]
 Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:13: 44:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }]
 Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:12: 45:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#28) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#28) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:52:21: 52:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:59:21: 59:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:66:21: 66:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:73:21: 73:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }]
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.rs b/src/test/ui/proc-macro/invalid-punct-ident-1.rs
index 3f78dea917b..a3133a1a790 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-1.rs
+++ b/src/test/ui/proc-macro/invalid-punct-ident-1.rs
@@ -9,6 +9,9 @@
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "query stack during panic:\n" -> ""
+// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> ""
+// normalize-stderr-test "end of query stack\n" -> ""
 
 #[macro_use]
 extern crate invalid_punct_ident;
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr
index fc821d29d5a..5ef22709cb3 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr
+++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr
@@ -1,5 +1,5 @@
 error: proc macro panicked
-  --> $DIR/invalid-punct-ident-1.rs:16:1
+  --> $DIR/invalid-punct-ident-1.rs:19:1
    |
 LL | invalid_punct!();
    | ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.rs b/src/test/ui/proc-macro/invalid-punct-ident-2.rs
index 4e89e80ae7c..04a0a873311 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-2.rs
+++ b/src/test/ui/proc-macro/invalid-punct-ident-2.rs
@@ -9,6 +9,9 @@
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "query stack during panic:\n" -> ""
+// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> ""
+// normalize-stderr-test "end of query stack\n" -> ""
 
 #[macro_use]
 extern crate invalid_punct_ident;
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr
index 8b30edaf85c..4bd7a5351d3 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr
+++ b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr
@@ -1,5 +1,5 @@
 error: proc macro panicked
-  --> $DIR/invalid-punct-ident-2.rs:16:1
+  --> $DIR/invalid-punct-ident-2.rs:19:1
    |
 LL | invalid_ident!();
    | ^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.rs b/src/test/ui/proc-macro/invalid-punct-ident-3.rs
index 8d8ce8f932e..aebba341625 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-3.rs
+++ b/src/test/ui/proc-macro/invalid-punct-ident-3.rs
@@ -9,6 +9,9 @@
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "query stack during panic:\n" -> ""
+// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> ""
+// normalize-stderr-test "end of query stack\n" -> ""
 
 #[macro_use]
 extern crate invalid_punct_ident;
diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr
index d46fab08e14..072d13956ac 100644
--- a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr
+++ b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr
@@ -1,5 +1,5 @@
 error: proc macro panicked
-  --> $DIR/invalid-punct-ident-3.rs:16:1
+  --> $DIR/invalid-punct-ident-3.rs:19:1
    |
 LL | invalid_raw_ident!();
    | ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/proc-macro/issue-75734-pp-paren.rs b/src/test/ui/proc-macro/issue-75734-pp-paren.rs
new file mode 100644
index 00000000000..faa93787d13
--- /dev/null
+++ b/src/test/ui/proc-macro/issue-75734-pp-paren.rs
@@ -0,0 +1,26 @@
+// Regression test for issue #75734
+// Ensures that we don't lose tokens when pretty-printing would
+// normally insert extra parentheses.
+
+// check-pass
+// aux-build:test-macros.rs
+// compile-flags: -Z span-debug
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[macro_use]
+extern crate test_macros;
+
+macro_rules! mul_2 {
+    ($val:expr) => {
+        print_bang!($val * 2);
+    };
+}
+
+
+#[print_attr]
+fn main() {
+    &|_: u8| {};
+    mul_2!(1 + 1);
+}
diff --git a/src/test/ui/proc-macro/issue-75734-pp-paren.stdout b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout
new file mode 100644
index 00000000000..b33b85f1705
--- /dev/null
+++ b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout
@@ -0,0 +1,134 @@
+PRINT-ATTR INPUT (DISPLAY): fn main() { & | _ : u8 | { } ; mul_2 ! (1 + 1) ; }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+    Ident {
+        ident: "fn",
+        span: $DIR/issue-75734-pp-paren.rs:23:1: 23:3 (#0),
+    },
+    Ident {
+        ident: "main",
+        span: $DIR/issue-75734-pp-paren.rs:23:4: 23:8 (#0),
+    },
+    Group {
+        delimiter: Parenthesis,
+        stream: TokenStream [],
+        span: $DIR/issue-75734-pp-paren.rs:23:8: 23:10 (#0),
+    },
+    Group {
+        delimiter: Brace,
+        stream: TokenStream [
+            Punct {
+                ch: '&',
+                spacing: Joint,
+                span: $DIR/issue-75734-pp-paren.rs:24:5: 24:6 (#0),
+            },
+            Punct {
+                ch: '|',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:24:6: 24:7 (#0),
+            },
+            Ident {
+                ident: "_",
+                span: $DIR/issue-75734-pp-paren.rs:24:7: 24:8 (#0),
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:24:8: 24:9 (#0),
+            },
+            Ident {
+                ident: "u8",
+                span: $DIR/issue-75734-pp-paren.rs:24:10: 24:12 (#0),
+            },
+            Punct {
+                ch: '|',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:24:12: 24:13 (#0),
+            },
+            Group {
+                delimiter: Brace,
+                stream: TokenStream [],
+                span: $DIR/issue-75734-pp-paren.rs:24:14: 24:16 (#0),
+            },
+            Punct {
+                ch: ';',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:24:16: 24:17 (#0),
+            },
+            Ident {
+                ident: "mul_2",
+                span: $DIR/issue-75734-pp-paren.rs:25:5: 25:10 (#0),
+            },
+            Punct {
+                ch: '!',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:25:10: 25:11 (#0),
+            },
+            Group {
+                delimiter: Parenthesis,
+                stream: TokenStream [
+                    Literal {
+                        kind: Integer,
+                        symbol: "1",
+                        suffix: None,
+                        span: $DIR/issue-75734-pp-paren.rs:25:12: 25:13 (#0),
+                    },
+                    Punct {
+                        ch: '+',
+                        spacing: Alone,
+                        span: $DIR/issue-75734-pp-paren.rs:25:14: 25:15 (#0),
+                    },
+                    Literal {
+                        kind: Integer,
+                        symbol: "1",
+                        suffix: None,
+                        span: $DIR/issue-75734-pp-paren.rs:25:16: 25:17 (#0),
+                    },
+                ],
+                span: $DIR/issue-75734-pp-paren.rs:25:11: 25:18 (#0),
+            },
+            Punct {
+                ch: ';',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:25:18: 25:19 (#0),
+            },
+        ],
+        span: $DIR/issue-75734-pp-paren.rs:23:11: 26:2 (#0),
+    },
+]
+PRINT-BANG INPUT (DISPLAY): 1 + 1 * 2
+PRINT-BANG INPUT (DEBUG): TokenStream [
+    Group {
+        delimiter: None,
+        stream: TokenStream [
+            Literal {
+                kind: Integer,
+                symbol: "1",
+                suffix: None,
+                span: $DIR/issue-75734-pp-paren.rs:25:12: 25:13 (#0),
+            },
+            Punct {
+                ch: '+',
+                spacing: Alone,
+                span: $DIR/issue-75734-pp-paren.rs:25:14: 25:15 (#0),
+            },
+            Literal {
+                kind: Integer,
+                symbol: "1",
+                suffix: None,
+                span: $DIR/issue-75734-pp-paren.rs:25:16: 25:17 (#0),
+            },
+        ],
+        span: $DIR/issue-75734-pp-paren.rs:17:21: 17:25 (#7),
+    },
+    Punct {
+        ch: '*',
+        spacing: Alone,
+        span: $DIR/issue-75734-pp-paren.rs:17:26: 17:27 (#7),
+    },
+    Literal {
+        kind: Integer,
+        symbol: "2",
+        suffix: None,
+        span: $DIR/issue-75734-pp-paren.rs:17:28: 17:29 (#7),
+    },
+]
diff --git a/src/test/ui/proc-macro/load-panic-backtrace.rs b/src/test/ui/proc-macro/load-panic-backtrace.rs
index 90fe109abb8..4a3ba9aee74 100644
--- a/src/test/ui/proc-macro/load-panic-backtrace.rs
+++ b/src/test/ui/proc-macro/load-panic-backtrace.rs
@@ -10,6 +10,9 @@
 // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> ""
 // normalize-stderr-test "note: compiler flags.*\n\n" -> ""
 // normalize-stderr-test "note: rustc.*running on.*\n\n" -> ""
+// normalize-stderr-test "query stack during panic:\n" -> ""
+// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> ""
+// normalize-stderr-test "end of query stack\n" -> ""
 
 #[macro_use]
 extern crate test_macros;
diff --git a/src/test/ui/proc-macro/load-panic-backtrace.stderr b/src/test/ui/proc-macro/load-panic-backtrace.stderr
index 63378b5735a..f825047e331 100644
--- a/src/test/ui/proc-macro/load-panic-backtrace.stderr
+++ b/src/test/ui/proc-macro/load-panic-backtrace.stderr
@@ -1,6 +1,6 @@
 at 'panic-derive', $DIR/auxiliary/test-macros.rs:43:5
 error: proc-macro derive panicked
-  --> $DIR/load-panic-backtrace.rs:17:10
+  --> $DIR/load-panic-backtrace.rs:20:10
    |
 LL | #[derive(Panic)]
    |          ^^^^^
diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr
index 32eff151196..77429f800f1 100644
--- a/src/test/ui/resolve/privacy-enum-ctor.stderr
+++ b/src/test/ui/resolve/privacy-enum-ctor.stderr
@@ -2,31 +2,17 @@ error[E0423]: expected value, found enum `n::Z`
   --> $DIR/privacy-enum-ctor.rs:23:9
    |
 LL |         n::Z;
-   |         ^^^^
+   |         ^^^^ help: try using one of the enum's variants: `m::Z::Unit`
    |
-help: try using one of the enum's variants
-   |
-LL |         m::Z::Fn;
-   |         ^^^^^^^^
-LL |         m::Z::Struct;
-   |         ^^^^^^^^^^^^
-LL |         m::Z::Unit;
-   |         ^^^^^^^^^^
+   = help: you might have meant to use one of the enum's other variants that have fields
 
 error[E0423]: expected value, found enum `Z`
   --> $DIR/privacy-enum-ctor.rs:25:9
    |
 LL |         Z;
-   |         ^
+   |         ^ help: try using one of the enum's variants: `m::Z::Unit`
    |
-help: try using one of the enum's variants
-   |
-LL |         m::Z::Fn;
-   |         ^^^^^^^^
-LL |         m::Z::Struct;
-   |         ^^^^^^^^^^^^
-LL |         m::Z::Unit;
-   |         ^^^^^^^^^^
+   = help: you might have meant to use one of the enum's other variants that have fields
 
 error[E0423]: expected value, found struct variant `Z::Struct`
   --> $DIR/privacy-enum-ctor.rs:29:20
@@ -48,12 +34,9 @@ LL |     fn f() {
 LL |     let _: E = m::E;
    |                ^^^^
    |
+   = help: you might have meant to use one of the enum's other variants that have fields
 help: try using one of the enum's variants
    |
-LL |     let _: E = E::Fn;
-   |                ^^^^^
-LL |     let _: E = E::Struct;
-   |                ^^^^^^^^^
 LL |     let _: E = E::Unit;
    |                ^^^^^^^
 help: a function with a similar name exists
@@ -84,12 +67,9 @@ error[E0423]: expected value, found enum `E`
 LL |     let _: E = E;
    |                ^
    |
+   = help: you might have meant to use one of the enum's other variants that have fields
 help: try using one of the enum's variants
    |
-LL |     let _: E = E::Fn;
-   |                ^^^^^
-LL |     let _: E = E::Struct;
-   |                ^^^^^^^^^
 LL |     let _: E = E::Unit;
    |                ^^^^^^^
 help: consider importing one of these items instead
@@ -132,16 +112,9 @@ error[E0423]: expected value, found enum `m::n::Z`
   --> $DIR/privacy-enum-ctor.rs:57:16
    |
 LL |     let _: Z = m::n::Z;
-   |                ^^^^^^^
+   |                ^^^^^^^ help: try using one of the enum's variants: `m::Z::Unit`
    |
-help: try using one of the enum's variants
-   |
-LL |     let _: Z = m::Z::Fn;
-   |                ^^^^^^^^
-LL |     let _: Z = m::Z::Struct;
-   |                ^^^^^^^^^^^^
-LL |     let _: Z = m::Z::Unit;
-   |                ^^^^^^^^^^
+   = help: you might have meant to use one of the enum's other variants that have fields
 
 error[E0412]: cannot find type `Z` in this scope
   --> $DIR/privacy-enum-ctor.rs:61:12
diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.rs b/src/test/ui/rfc-2005-default-binding-mode/for.rs
index aa42c7bb9c2..d6c5a13b1bd 100644
--- a/src/test/ui/rfc-2005-default-binding-mode/for.rs
+++ b/src/test/ui/rfc-2005-default-binding-mode/for.rs
@@ -1,5 +1,3 @@
-#![feature(move_ref_pattern)]
-
 struct Foo {}
 
 pub fn main() {
diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.stderr b/src/test/ui/rfc-2005-default-binding-mode/for.stderr
index ef624313880..9cc20a7bf31 100644
--- a/src/test/ui/rfc-2005-default-binding-mode/for.stderr
+++ b/src/test/ui/rfc-2005-default-binding-mode/for.stderr
@@ -1,5 +1,5 @@
 error[E0507]: cannot move out of a shared reference
-  --> $DIR/for.rs:8:23
+  --> $DIR/for.rs:6:23
    |
 LL |     for (n, mut m) in &tups {
    |             -----     ^^^^^
diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr
index 40c3219bf27..5cda17fd6a1 100644
--- a/src/test/ui/span/issue-34264.stderr
+++ b/src/test/ui/span/issue-34264.stderr
@@ -53,13 +53,16 @@ LL | fn bar(_: x, y: usize) {}
 error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/issue-34264.rs:7:5
    |
-LL | fn foo(Option<i32>, String) {}
-   | --------------------------- defined here
-...
 LL |     foo(Some(42), 2, "");
    |     ^^^ --------  -  -- supplied 3 arguments
    |     |
    |     expected 2 arguments
+   |
+note: function defined here
+  --> $DIR/issue-34264.rs:1:4
+   |
+LL | fn foo(Option<i32>, String) {}
+   |    ^^^ -----------  ------
 
 error[E0308]: mismatched types
   --> $DIR/issue-34264.rs:8:13
@@ -70,13 +73,16 @@ LL |     bar("", "");
 error[E0061]: this function takes 2 arguments but 3 arguments were supplied
   --> $DIR/issue-34264.rs:10:5
    |
-LL | fn bar(x, y: usize) {}
-   | ------------------- defined here
-...
 LL |     bar(1, 2, 3);
    |     ^^^ -  -  - supplied 3 arguments
    |     |
    |     expected 2 arguments
+   |
+note: function defined here
+  --> $DIR/issue-34264.rs:3:4
+   |
+LL | fn bar(x, y: usize) {}
+   |    ^^^ -  --------
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr
index f6344fba3d3..b15da2cb479 100644
--- a/src/test/ui/span/missing-unit-argument.stderr
+++ b/src/test/ui/span/missing-unit-argument.stderr
@@ -12,34 +12,42 @@ LL |     let _: Result<(), String> = Ok(());
 error[E0061]: this function takes 2 arguments but 0 arguments were supplied
   --> $DIR/missing-unit-argument.rs:12:5
    |
-LL | fn foo(():(), ():()) {}
-   | -------------------- defined here
-...
 LL |     foo();
    |     ^^^-- supplied 0 arguments
    |     |
    |     expected 2 arguments
+   |
+note: function defined here
+  --> $DIR/missing-unit-argument.rs:1:4
+   |
+LL | fn foo(():(), ():()) {}
+   |    ^^^ -----  -----
 
 error[E0061]: this function takes 2 arguments but 1 argument was supplied
   --> $DIR/missing-unit-argument.rs:13:5
    |
-LL | fn foo(():(), ():()) {}
-   | -------------------- defined here
-...
 LL |     foo(());
    |     ^^^ -- supplied 1 argument
    |     |
    |     expected 2 arguments
+   |
+note: function defined here
+  --> $DIR/missing-unit-argument.rs:1:4
+   |
+LL | fn foo(():(), ():()) {}
+   |    ^^^ -----  -----
 
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/missing-unit-argument.rs:14:5
    |
-LL | fn bar(():()) {}
-   | ------------- defined here
-...
 LL |     bar();
    |     ^^^-- supplied 0 arguments
    |
+note: function defined here
+  --> $DIR/missing-unit-argument.rs:2:4
+   |
+LL | fn bar(():()) {}
+   |    ^^^ -----
 help: expected the unit value `()`; create it with empty parentheses
    |
 LL |     bar(());
@@ -48,12 +56,14 @@ LL |     bar(());
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/missing-unit-argument.rs:15:7
    |
-LL |     fn baz(self, (): ()) { }
-   |     -------------------- defined here
-...
 LL |     S.baz();
    |       ^^^- supplied 0 arguments
    |
+note: associated function defined here
+  --> $DIR/missing-unit-argument.rs:6:8
+   |
+LL |     fn baz(self, (): ()) { }
+   |        ^^^ ----  ------
 help: expected the unit value `()`; create it with empty parentheses
    |
 LL |     S.baz(());
@@ -62,12 +72,14 @@ LL |     S.baz(());
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/missing-unit-argument.rs:16:7
    |
-LL |     fn generic<T>(self, _: T) { }
-   |     ------------------------- defined here
-...
 LL |     S.generic::<()>();
    |       ^^^^^^^------ supplied 0 arguments
    |
+note: associated function defined here
+  --> $DIR/missing-unit-argument.rs:7:8
+   |
+LL |     fn generic<T>(self, _: T) { }
+   |        ^^^^^^^    ----  ----
 help: expected the unit value `()`; create it with empty parentheses
    |
 LL |     S.generic::<()>(());
diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
index c1eea56f70d..8a9a1e57935 100644
--- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
+++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
@@ -13,7 +13,7 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis
 LL |     let fp = BufWriter::new(fp);
    |              ^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
    | 
-  ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL
+  ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
    |
 LL | pub struct BufWriter<W: Write> {
    |                         ----- required by this bound in `BufWriter`
@@ -26,7 +26,7 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis
 LL |     let fp = BufWriter::new(fp);
    |              ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
    | 
-  ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL
+  ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
    |
 LL | pub struct BufWriter<W: Write> {
    |                         ----- required by this bound in `BufWriter`
@@ -39,7 +39,7 @@ error[E0599]: no method named `write_fmt` found for struct `BufWriter<&dyn std::
 LL |     writeln!(fp, "hello world").unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `BufWriter<&dyn std::io::Write>`
    | 
-  ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL
+  ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
    |
 LL | pub struct BufWriter<W: Write> {
    | ------------------------------ doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write`
diff --git a/src/test/ui/symbol-names/issue-75326.legacy.stderr b/src/test/ui/symbol-names/issue-75326.legacy.stderr
new file mode 100644
index 00000000000..5f822f6660c
--- /dev/null
+++ b/src/test/ui/symbol-names/issue-75326.legacy.stderr
@@ -0,0 +1,20 @@
+error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17SYMBOL_HASH)
+  --> $DIR/issue-75326.rs:43:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next::SYMBOL_HASH)
+  --> $DIR/issue-75326.rs:43:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next)
+  --> $DIR/issue-75326.rs:43:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/symbol-names/issue-75326.rs b/src/test/ui/symbol-names/issue-75326.rs
new file mode 100644
index 00000000000..ce315164cef
--- /dev/null
+++ b/src/test/ui/symbol-names/issue-75326.rs
@@ -0,0 +1,58 @@
+// build-fail
+// ignore-tidy-linelength
+// revisions: legacy v0
+//[legacy]compile-flags: -Z symbol-mangling-version=legacy
+//[v0]compile-flags: -Z symbol-mangling-version=v0
+//[legacy]normalize-stderr-32bit: "h[\d\w]+" -> "SYMBOL_HASH"
+//[legacy]normalize-stderr-64bit: "h[\d\w]+" -> "SYMBOL_HASH"
+
+#![feature(rustc_attrs)]
+
+pub(crate) struct Foo<I, E>(I, E);
+
+pub trait Iterator2 {
+    type Item;
+
+    fn next(&mut self) -> Option<Self::Item>;
+
+    fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
+    where
+        Self: Sized,
+        P: FnMut(&Self::Item) -> bool,
+    {
+        unimplemented!()
+    }
+}
+
+struct Bar;
+
+impl Iterator2 for Bar {
+    type Item = (u32, u16);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        unimplemented!()
+    }
+}
+
+impl<I, T, E> Iterator2 for Foo<I, E>
+where
+    I: Iterator2<Item = (T, E)>,
+{
+    type Item = T;
+
+    #[rustc_symbol_name]
+    //[legacy]~^ ERROR symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next
+    //[legacy]~| ERROR demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next
+    //[legacy]~| ERROR demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next)
+    //[v0]~^^^^  ERROR symbol-name(_RNvXINICs4fqI2P2rA04_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
+    //[v0]~|     ERROR demangling(<issue_75326[317d481089b8c8fe]::Foo<_, _> as issue_75326[317d481089b8c8fe]::Iterator2>::next)
+    //[v0]~|     ERROR demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next)
+    fn next(&mut self) -> Option<Self::Item> {
+        self.find(|_| true)
+    }
+}
+
+fn main() {
+    let mut a = Foo(Bar, 1u16);
+    let _ = a.next();
+}
diff --git a/src/test/ui/symbol-names/issue-75326.v0.stderr b/src/test/ui/symbol-names/issue-75326.v0.stderr
new file mode 100644
index 00000000000..59bdfa8ca36
--- /dev/null
+++ b/src/test/ui/symbol-names/issue-75326.v0.stderr
@@ -0,0 +1,20 @@
+error: symbol-name(_RNvXINICs4fqI2P2rA04_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
+  --> $DIR/issue-75326.rs:43:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<issue_75326[317d481089b8c8fe]::Foo<_, _> as issue_75326[317d481089b8c8fe]::Iterator2>::next)
+  --> $DIR/issue-75326.rs:43:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next)
+  --> $DIR/issue-75326.rs:43:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/traits/assoc_type_bound_with_struct.rs b/src/test/ui/traits/assoc_type_bound_with_struct.rs
new file mode 100644
index 00000000000..c66009fe24c
--- /dev/null
+++ b/src/test/ui/traits/assoc_type_bound_with_struct.rs
@@ -0,0 +1,19 @@
+trait Bar {
+    type Baz;
+}
+
+struct Foo<T> where T: Bar, <T as Bar>::Baz: String { //~ ERROR expected trait, found struct
+    t: T,
+}
+
+struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String { //~ ERROR expected trait, found struct
+    t: &'a T,
+}
+
+fn foo<T: Bar>(_: T) where <T as Bar>::Baz: String { //~ ERROR expected trait, found struct
+}
+
+fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String { //~ ERROR expected trait, found
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/assoc_type_bound_with_struct.stderr b/src/test/ui/traits/assoc_type_bound_with_struct.stderr
new file mode 100644
index 00000000000..7cf872eb6ac
--- /dev/null
+++ b/src/test/ui/traits/assoc_type_bound_with_struct.stderr
@@ -0,0 +1,83 @@
+error[E0404]: expected trait, found struct `String`
+  --> $DIR/assoc_type_bound_with_struct.rs:5:46
+   |
+LL | struct Foo<T> where T: Bar, <T as Bar>::Baz: String {
+   |                                              ^^^^^^ not a trait
+   | 
+  ::: $SRC_DIR/alloc/src/string.rs:LL:COL
+   |
+LL | pub trait ToString {
+   | ------------------ similarly named trait `ToString` defined here
+   |
+help: constrain the associated type to `String`
+   |
+LL | struct Foo<T> where T: Bar, T: Bar<Baz = String> {
+   |                             ^^^^^^^^^^^^^^^^^^^^
+help: a trait with a similar name exists
+   |
+LL | struct Foo<T> where T: Bar, <T as Bar>::Baz: ToString {
+   |                                              ^^^^^^^^
+
+error[E0404]: expected trait, found struct `String`
+  --> $DIR/assoc_type_bound_with_struct.rs:9:54
+   |
+LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String {
+   |                                                      ^^^^^^ not a trait
+   | 
+  ::: $SRC_DIR/alloc/src/string.rs:LL:COL
+   |
+LL | pub trait ToString {
+   | ------------------ similarly named trait `ToString` defined here
+   |
+help: constrain the associated type to `String`
+   |
+LL | struct Qux<'a, T> where T: Bar, &'a T: Bar<Baz = String> {
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^
+help: a trait with a similar name exists
+   |
+LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: ToString {
+   |                                                      ^^^^^^^^
+
+error[E0404]: expected trait, found struct `String`
+  --> $DIR/assoc_type_bound_with_struct.rs:13:45
+   |
+LL | fn foo<T: Bar>(_: T) where <T as Bar>::Baz: String {
+   |                                             ^^^^^^ not a trait
+   | 
+  ::: $SRC_DIR/alloc/src/string.rs:LL:COL
+   |
+LL | pub trait ToString {
+   | ------------------ similarly named trait `ToString` defined here
+   |
+help: constrain the associated type to `String`
+   |
+LL | fn foo<T: Bar>(_: T) where T: Bar<Baz = String> {
+   |                            ^^^^^^^^^^^^^^^^^^^^
+help: a trait with a similar name exists
+   |
+LL | fn foo<T: Bar>(_: T) where <T as Bar>::Baz: ToString {
+   |                                             ^^^^^^^^
+
+error[E0404]: expected trait, found struct `String`
+  --> $DIR/assoc_type_bound_with_struct.rs:16:57
+   |
+LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String {
+   |                                                         ^^^^^^ not a trait
+   | 
+  ::: $SRC_DIR/alloc/src/string.rs:LL:COL
+   |
+LL | pub trait ToString {
+   | ------------------ similarly named trait `ToString` defined here
+   |
+help: constrain the associated type to `String`
+   |
+LL | fn qux<'a, T: Bar>(_: &'a T) where &'a T: Bar<Baz = String> {
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^
+help: a trait with a similar name exists
+   |
+LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: ToString {
+   |                                                         ^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0404`.
diff --git a/src/test/ui/traits/trait-bounds-not-on-struct.rs b/src/test/ui/traits/trait-bounds-not-on-struct.rs
index c6e93e75525..8633e9d7a4c 100644
--- a/src/test/ui/traits/trait-bounds-not-on-struct.rs
+++ b/src/test/ui/traits/trait-bounds-not-on-struct.rs
@@ -1,9 +1,38 @@
+// We don't need those errors. Ideally we would silence them, but to do so we need to move the
+// lint from being an early-lint during parsing to a late-lint, because it needs to be aware of
+// the types involved.
 #![allow(bare_trait_objects)]
 
 struct Foo;
 
 fn foo(_x: Box<Foo + Send>) { } //~ ERROR expected trait, found struct `Foo`
 
-type A<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
+type TypeAlias<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec`
 
-fn main() { }
+struct A;
+fn a() -> A + 'static { //~ ERROR expected trait, found
+    A
+}
+fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) { //~ ERROR expected trait, found
+    panic!()
+}
+fn c() -> 'static + A { //~ ERROR expected trait, found
+    A
+}
+fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) { //~ ERROR expected trait, found
+    panic!()
+}
+fn e() -> 'static + A + 'static { //~ ERROR expected trait, found
+//~^ ERROR only a single explicit lifetime bound is permitted
+    A
+}
+fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) { //~ ERROR expected trait, found
+//~^ ERROR only a single explicit lifetime bound is permitted
+    panic!()
+}
+struct Traitor;
+trait Trait {}
+fn g() -> Traitor + 'static { //~ ERROR expected trait, found struct `Traitor`
+    A
+}
+fn main() {}
diff --git a/src/test/ui/traits/trait-bounds-not-on-struct.stderr b/src/test/ui/traits/trait-bounds-not-on-struct.stderr
index a649a4eee55..0f97e3bdf18 100644
--- a/src/test/ui/traits/trait-bounds-not-on-struct.stderr
+++ b/src/test/ui/traits/trait-bounds-not-on-struct.stderr
@@ -1,15 +1,168 @@
+error[E0226]: only a single explicit lifetime bound is permitted
+  --> $DIR/trait-bounds-not-on-struct.rs:25:25
+   |
+LL | fn e() -> 'static + A + 'static {
+   |                         ^^^^^^^
+
+error[E0226]: only a single explicit lifetime bound is permitted
+  --> $DIR/trait-bounds-not-on-struct.rs:29:53
+   |
+LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
+   |                                                     ^^
+
 error[E0404]: expected trait, found struct `Foo`
-  --> $DIR/trait-bounds-not-on-struct.rs:5:16
+  --> $DIR/trait-bounds-not-on-struct.rs:8:16
    |
 LL | fn foo(_x: Box<Foo + Send>) { }
    |                ^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:8:22
+   |
+LL | fn foo(_x: Box<Foo + Send>) { }
+   |                ---   ^^^^ ...because of this bound
+   |                |
+   |                expected this type to be a trait...
 
 error[E0404]: expected trait, found struct `Vec`
-  --> $DIR/trait-bounds-not-on-struct.rs:7:21
+  --> $DIR/trait-bounds-not-on-struct.rs:10:29
+   |
+LL | type TypeAlias<T> = Box<dyn Vec<T>>;
+   |                             ^^^^^^ not a trait
+
+error[E0404]: expected trait, found struct `A`
+  --> $DIR/trait-bounds-not-on-struct.rs:13:11
+   |
+LL | fn a() -> A + 'static {
+   |           ^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:13:15
+   |
+LL | fn a() -> A + 'static {
+   |           -   ^^^^^^^ ...because of this bound
+   |           |
+   |           expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn a() -> A {
+   |           --
+
+error[E0404]: expected trait, found enum `Result`
+  --> $DIR/trait-bounds-not-on-struct.rs:16:34
+   |
+LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) {
+   |                                  ^^^^^^^^^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:16:48
+   |
+LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) {
+   |                                  -----------   ^^ ...because of this bound
+   |                                  |
+   |                                  expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
+   |                                            --
+
+error[E0404]: expected trait, found struct `A`
+  --> $DIR/trait-bounds-not-on-struct.rs:19:21
+   |
+LL | fn c() -> 'static + A {
+   |                     ^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:19:11
+   |
+LL | fn c() -> 'static + A {
+   |           ^^^^^^^   - expected this type to be a trait...
+   |           |
+   |           ...because of this bound
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn c() -> A {
+   |          --
+
+error[E0404]: expected trait, found enum `Result`
+  --> $DIR/trait-bounds-not-on-struct.rs:22:39
+   |
+LL | fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) {
+   |                                       ^^^^^^^^^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:22:34
+   |
+LL | fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) {
+   |                                  ^^   ----------- expected this type to be a trait...
+   |                                  |
+   |                                  ...because of this bound
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn d<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
+   |                                 --
+
+error[E0404]: expected trait, found struct `A`
+  --> $DIR/trait-bounds-not-on-struct.rs:25:21
+   |
+LL | fn e() -> 'static + A + 'static {
+   |                     ^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:25:11
+   |
+LL | fn e() -> 'static + A + 'static {
+   |           ^^^^^^^   -   ^^^^^^^ ...because of these bounds
+   |                     |
+   |                     expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn e() -> A {
+   |          ---
+
+error[E0404]: expected trait, found enum `Result`
+  --> $DIR/trait-bounds-not-on-struct.rs:29:39
+   |
+LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
+   |                                       ^^^^^^^^^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:29:34
+   |
+LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) {
+   |                                  ^^   -----------   ^^ ...because of these bounds
+   |                                       |
+   |                                       expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn f<'a,T,E>(iter: Iterator<Item=Result<T,E>>) {
+   |                                 --         --
+
+error[E0404]: expected trait, found struct `Traitor`
+  --> $DIR/trait-bounds-not-on-struct.rs:35:11
+   |
+LL | trait Trait {}
+   | ----------- similarly named trait `Trait` defined here
+LL | fn g() -> Traitor + 'static {
+   |           ^^^^^^^ not a trait
+   |
+help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way
+  --> $DIR/trait-bounds-not-on-struct.rs:35:21
+   |
+LL | fn g() -> Traitor + 'static {
+   |           -------   ^^^^^^^ ...because of this bound
+   |           |
+   |           expected this type to be a trait...
+help: if you meant to use a type and not a trait here, remove the bounds
+   |
+LL | fn g() -> Traitor {
+   |                 --
+help: a trait with a similar name exists
    |
-LL | type A<T> = Box<dyn Vec<T>>;
-   |                     ^^^^^^ not a trait
+LL | fn g() -> Trait + 'static {
+   |           ^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 11 previous errors
 
-For more information about this error, try `rustc --explain E0404`.
+Some errors have detailed explanations: E0226, E0404.
+For more information about an error, try `rustc --explain E0226`.
diff --git a/src/test/ui/tuple/index-invalid.stderr b/src/test/ui/tuple/index-invalid.stderr
index 800b5a31d98..8d22f458a6c 100644
--- a/src/test/ui/tuple/index-invalid.stderr
+++ b/src/test/ui/tuple/index-invalid.stderr
@@ -2,19 +2,19 @@ error[E0609]: no field `1` on type `(((),),)`
   --> $DIR/index-invalid.rs:2:22
    |
 LL |     let _ = (((),),).1.0;
-   |                      ^^^
+   |                      ^
 
 error[E0609]: no field `1` on type `((),)`
-  --> $DIR/index-invalid.rs:4:22
+  --> $DIR/index-invalid.rs:4:24
    |
 LL |     let _ = (((),),).0.1;
-   |                      ^^^
+   |                        ^
 
 error[E0609]: no field `000` on type `(((),),)`
   --> $DIR/index-invalid.rs:6:22
    |
 LL |     let _ = (((),),).000.000;
-   |                      ^^^^^^^
+   |                      ^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr
index 46e7dd0c517..20e26058451 100644
--- a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr
+++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr
@@ -1,13 +1,16 @@
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
   --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:21:5
    |
-LL |     V(u8)
-   |     ----- defined here
-...
 LL |     <E>::V();
    |     ^^^^^^-- supplied 0 arguments
    |     |
    |     expected 1 argument
+   |
+note: tuple variant defined here
+  --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:5:5
+   |
+LL |     V(u8)
+   |     ^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:22:17
diff --git a/src/test/ui/type-alias-impl-trait/issue-52843.rs b/src/test/ui/type-alias-impl-trait/issue-52843.rs
new file mode 100644
index 00000000000..b24959d7207
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-52843.rs
@@ -0,0 +1,15 @@
+#![feature(type_alias_impl_trait)]
+
+type Foo<T> = impl Default;
+//~^ ERROR: the trait bound `T: Default` is not satisfied
+
+#[allow(unused)]
+fn foo<T: Default>(t: T) -> Foo<T> {
+    t
+}
+
+struct NotDefault;
+
+fn main() {
+    let _ = Foo::<NotDefault>::default();
+}
diff --git a/src/test/ui/type-alias-impl-trait/issue-52843.stderr b/src/test/ui/type-alias-impl-trait/issue-52843.stderr
new file mode 100644
index 00000000000..25db8dfabfc
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-52843.stderr
@@ -0,0 +1,14 @@
+error[E0277]: the trait bound `T: Default` is not satisfied
+  --> $DIR/issue-52843.rs:3:15
+   |
+LL | type Foo<T> = impl Default;
+   |               ^^^^^^^^^^^^ the trait `Default` is not implemented for `T`
+   |
+help: consider restricting type parameter `T`
+   |
+LL | type Foo<T: Default> = impl Default;
+   |           ^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-53096.rs b/src/test/ui/type-alias-impl-trait/issue-53096.rs
index bdf426bbd37..6e1973bd18a 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53096.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-53096.rs
@@ -1,5 +1,5 @@
 // check-pass
-#![feature(const_fn, const_fn_fn_ptr_basics)]
+#![feature(const_impl_trait, const_fn_fn_ptr_basics)]
 #![feature(type_alias_impl_trait)]
 
 type Foo = impl Fn() -> usize;
diff --git a/src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs b/src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs
index e7f93732430..4582d5386f0 100644
--- a/src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-53678-generator-and-const-fn.rs
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(const_fn, generators, generator_trait, type_alias_impl_trait)]
+#![feature(const_impl_trait, generators, generator_trait, type_alias_impl_trait)]
 
 use std::ops::Generator;
 
diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
index d50835608fa..58f0f5b2f65 100644
--- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
+++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs
@@ -1,4 +1,4 @@
-#![feature(const_fn, type_alias_impl_trait)]
+#![feature(const_impl_trait, type_alias_impl_trait)]
 
 type Bar = impl Send;
 
diff --git a/src/test/ui/type-alias-impl-trait/structural-match.rs b/src/test/ui/type-alias-impl-trait/structural-match.rs
index a3ff4ad1d47..74ffa608426 100644
--- a/src/test/ui/type-alias-impl-trait/structural-match.rs
+++ b/src/test/ui/type-alias-impl-trait/structural-match.rs
@@ -1,4 +1,4 @@
-#![feature(const_fn, type_alias_impl_trait)]
+#![feature(const_impl_trait, type_alias_impl_trait)]
 
 type Foo = impl Send;
 
diff --git a/src/test/ui/unboxed-closures/issue-53448.rs b/src/test/ui/unboxed-closures/issue-53448.rs
new file mode 100644
index 00000000000..5c82a56e77e
--- /dev/null
+++ b/src/test/ui/unboxed-closures/issue-53448.rs
@@ -0,0 +1,15 @@
+#![feature(unboxed_closures)]
+
+trait Lt<'a> {
+    type T;
+}
+impl<'a> Lt<'a> for () {
+    type T = ();
+}
+
+fn main() {
+    let v: <() as Lt<'_>>::T = ();
+    let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {};
+    //~^ ERROR: the size for values of type `<() as Lt<'_>>::T` cannot be known
+    f(v);
+}
diff --git a/src/test/ui/unboxed-closures/issue-53448.stderr b/src/test/ui/unboxed-closures/issue-53448.stderr
new file mode 100644
index 00000000000..bece9eedc7f
--- /dev/null
+++ b/src/test/ui/unboxed-closures/issue-53448.stderr
@@ -0,0 +1,20 @@
+error[E0277]: the size for values of type `<() as Lt<'_>>::T` cannot be known at compilation time
+  --> $DIR/issue-53448.rs:12:54
+   |
+LL |     let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {};
+   |                                                      ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `<() as Lt<'_>>::T`
+   = help: unsized locals are gated as an unstable feature
+help: consider further restricting the associated type
+   |
+LL | fn main() where <() as Lt<'_>>::T: Sized {
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL |     let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: &<() as Lt<'_>>::T| {};
+   |                                                         ^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/union/union-deref.stderr b/src/test/ui/union/union-deref.stderr
index fb16649767f..f7722764cd3 100644
--- a/src/test/ui/union/union-deref.stderr
+++ b/src/test/ui/union/union-deref.stderr
@@ -29,7 +29,7 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field
   --> $DIR/union-deref.rs:23:14
    |
 LL |     unsafe { u.f.0.0 = Vec::new() };
-   |              ^^^^^^^
+   |              ^^^^^
    |
    = help: writing to this reference calls the destructor for the old value
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
@@ -38,7 +38,7 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field
   --> $DIR/union-deref.rs:25:19
    |
 LL |     unsafe { &mut u.f.0.0 };
-   |                   ^^^^^^^
+   |                   ^^^^^
    |
    = help: writing to this reference calls the destructor for the old value
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
@@ -47,7 +47,7 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field
   --> $DIR/union-deref.rs:27:14
    |
 LL |     unsafe { u.f.0.0.push(0) };
-   |              ^^^^^^^
+   |              ^^^^^
    |
    = help: writing to this reference calls the destructor for the old value
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
diff --git a/src/test/ui/unsigned-literal-negation.rs b/src/test/ui/unsigned-literal-negation.rs
new file mode 100644
index 00000000000..943c7f79742
--- /dev/null
+++ b/src/test/ui/unsigned-literal-negation.rs
@@ -0,0 +1,5 @@
+fn main() {
+    let x = -1 as usize; //~ ERROR: cannot apply unary operator `-`
+    let x = (-1) as usize; //~ ERROR: cannot apply unary operator `-`
+    let x: u32 = -1; //~ ERROR: cannot apply unary operator `-`
+}
diff --git a/src/test/ui/unsigned-literal-negation.stderr b/src/test/ui/unsigned-literal-negation.stderr
new file mode 100644
index 00000000000..0aaa8c3b72f
--- /dev/null
+++ b/src/test/ui/unsigned-literal-negation.stderr
@@ -0,0 +1,36 @@
+error[E0600]: cannot apply unary operator `-` to type `usize`
+  --> $DIR/unsigned-literal-negation.rs:2:13
+   |
+LL |     let x = -1 as usize;
+   |             ^^
+   |             |
+   |             cannot apply unary operator `-`
+   |             help: you may have meant the maximum value of `usize`: `usize::MAX`
+   |
+   = note: unsigned values cannot be negated
+
+error[E0600]: cannot apply unary operator `-` to type `usize`
+  --> $DIR/unsigned-literal-negation.rs:3:13
+   |
+LL |     let x = (-1) as usize;
+   |             ^^^^
+   |             |
+   |             cannot apply unary operator `-`
+   |             help: you may have meant the maximum value of `usize`: `usize::MAX`
+   |
+   = note: unsigned values cannot be negated
+
+error[E0600]: cannot apply unary operator `-` to type `u32`
+  --> $DIR/unsigned-literal-negation.rs:4:18
+   |
+LL |     let x: u32 = -1;
+   |                  ^^
+   |                  |
+   |                  cannot apply unary operator `-`
+   |                  help: you may have meant the maximum value of `u32`: `u32::MAX`
+   |
+   = note: unsigned values cannot be negated
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0600`.
diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml
index 4ae4dbfc06e..4a2c710811f 100644
--- a/src/tools/build-manifest/Cargo.toml
+++ b/src/tools/build-manifest/Cargo.toml
@@ -14,3 +14,4 @@ tar = "0.4.29"
 sha2 = "0.9.1"
 rayon = "1.3.1"
 hex = "0.4.2"
+num_cpus = "1.13.0"
diff --git a/src/tools/build-manifest/README.md b/src/tools/build-manifest/README.md
index 26e96c9fd8f..b77c5a907c1 100644
--- a/src/tools/build-manifest/README.md
+++ b/src/tools/build-manifest/README.md
@@ -21,8 +21,8 @@ Then, you can generate the manifest and all the packages from `path/to/dist` to
 
 ```
 $ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com \
-    CHANNEL path/to/rust/repo
+    CHANNEL VERSION
 ```
 
 Remember to replace `CHANNEL` with the channel you produced dist artifacts of
-and `path/to/rust/repo` with the path to your checkout of the Rust repository.
+and `VERSION` with the current Rust version.
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index c7e7d88c68f..1b780110456 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -22,6 +22,8 @@ use std::sync::Mutex;
 use std::time::Instant;
 
 static HOSTS: &[&str] = &[
+    "aarch64-apple-darwin",
+    "aarch64-pc-windows-msvc",
     "aarch64-unknown-linux-gnu",
     "aarch64-unknown-linux-musl",
     "arm-unknown-linux-gnueabi",
@@ -55,6 +57,7 @@ static HOSTS: &[&str] = &[
 ];
 
 static TARGETS: &[&str] = &[
+    "aarch64-apple-darwin",
     "aarch64-apple-ios",
     "aarch64-fuchsia",
     "aarch64-linux-android",
@@ -205,15 +208,20 @@ fn main() {
     //
     // Once the old release process is fully decommissioned, the environment variable, all the
     // related code in this tool and ./x.py dist hash-and-sign can be removed.
-    let legacy = env::var("BUILD_MANIFEST_LEGACY").is_ok();
-
-    // Avoid overloading the old server in legacy mode.
-    if legacy {
-        rayon::ThreadPoolBuilder::new()
-            .num_threads(1)
-            .build_global()
-            .expect("failed to initialize Rayon");
-    }
+    let legacy = env::var_os("BUILD_MANIFEST_LEGACY").is_some();
+
+    let num_threads = if legacy {
+        // Avoid overloading the old server in legacy mode.
+        1
+    } else if let Some(num) = env::var_os("BUILD_MANIFEST_NUM_THREADS") {
+        num.to_str().unwrap().parse().expect("invalid number for BUILD_MANIFEST_NUM_THREADS")
+    } else {
+        num_cpus::get()
+    };
+    rayon::ThreadPoolBuilder::new()
+        .num_threads(num_threads)
+        .build_global()
+        .expect("failed to initialize Rayon");
 
     let mut args = env::args().skip(1);
     let input = PathBuf::from(args.next().unwrap());
@@ -221,7 +229,6 @@ fn main() {
     let date = args.next().unwrap();
     let s3_address = args.next().unwrap();
     let channel = args.next().unwrap();
-    let monorepo_path = args.next().unwrap();
 
     // Do not ask for a passphrase while manually testing
     let mut passphrase = String::new();
@@ -231,7 +238,7 @@ fn main() {
     }
 
     Builder {
-        versions: Versions::new(&channel, &input, Path::new(&monorepo_path)).unwrap(),
+        versions: Versions::new(&channel, &input).unwrap(),
 
         input,
         output,
@@ -252,12 +259,13 @@ impl Builder {
         }
         let manifest = self.build_manifest();
 
-        let rust_version = self.versions.package_version(&PkgType::Rust).unwrap();
         self.write_channel_files(self.versions.channel(), &manifest);
-        if self.versions.channel() != rust_version {
-            self.write_channel_files(&rust_version, &manifest);
-        }
         if self.versions.channel() == "stable" {
+            // channel-rust-1.XX.YY.toml
+            let rust_version = self.versions.rustc_version();
+            self.write_channel_files(rust_version, &manifest);
+
+            // channel-rust-1.XX.toml
             let major_minor = rust_version.split('.').take(2).collect::<Vec<_>>().join(".");
             self.write_channel_files(&major_minor, &manifest);
         }
diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs
index d949dff7279..79f2ef8dfc4 100644
--- a/src/tools/build-manifest/src/versions.rs
+++ b/src/tools/build-manifest/src/versions.rs
@@ -1,4 +1,4 @@
-use anyhow::{Context, Error};
+use anyhow::Error;
 use flate2::read::GzDecoder;
 use std::collections::HashMap;
 use std::fs::File;
@@ -7,6 +7,7 @@ use std::path::{Path, PathBuf};
 use tar::Archive;
 
 const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu";
+const RUSTC_VERSION: &str = include_str!("../../../version");
 
 #[derive(Debug, Hash, Eq, PartialEq, Clone)]
 pub(crate) enum PkgType {
@@ -38,23 +39,6 @@ impl PkgType {
         }
     }
 
-    /// The directory containing the `Cargo.toml` of this component inside the monorepo, to
-    /// retrieve the source code version. If `None` is returned Rust's version will be used.
-    fn rust_monorepo_path(&self) -> Option<&'static str> {
-        match self {
-            PkgType::Cargo => Some("src/tools/cargo"),
-            PkgType::Rls => Some("src/tools/rls"),
-            PkgType::RustAnalyzer => Some("src/tools/rust-analyzer/crates/rust-analyzer"),
-            PkgType::Clippy => Some("src/tools/clippy"),
-            PkgType::Rustfmt => Some("src/tools/rustfmt"),
-            PkgType::Miri => Some("src/tools/miri"),
-            PkgType::Rust => None,
-            PkgType::RustSrc => None,
-            PkgType::LlvmTools => None,
-            PkgType::Other(_) => None,
-        }
-    }
-
     /// First part of the tarball name.
     fn tarball_component_name(&self) -> &str {
         match self {
@@ -104,30 +88,13 @@ pub(crate) struct VersionInfo {
 
 pub(crate) struct Versions {
     channel: String,
-    rustc_version: String,
-    monorepo_root: PathBuf,
     dist_path: PathBuf,
-    package_versions: HashMap<PkgType, String>,
     versions: HashMap<PkgType, VersionInfo>,
 }
 
 impl Versions {
-    pub(crate) fn new(
-        channel: &str,
-        dist_path: &Path,
-        monorepo_root: &Path,
-    ) -> Result<Self, Error> {
-        Ok(Self {
-            channel: channel.into(),
-            rustc_version: std::fs::read_to_string(monorepo_root.join("src").join("version"))
-                .context("failed to read the rustc version from src/version")?
-                .trim()
-                .to_string(),
-            monorepo_root: monorepo_root.into(),
-            dist_path: dist_path.into(),
-            package_versions: HashMap::new(),
-            versions: HashMap::new(),
-        })
+    pub(crate) fn new(channel: &str, dist_path: &Path) -> Result<Self, Error> {
+        Ok(Self { channel: channel.into(), dist_path: dist_path.into(), versions: HashMap::new() })
     }
 
     pub(crate) fn channel(&self) -> &str {
@@ -204,9 +171,13 @@ impl Versions {
         target: &str,
     ) -> Result<String, Error> {
         let component_name = package.tarball_component_name();
-        let version = self.package_version(package).with_context(|| {
-            format!("failed to get the package version for component {:?}", package,)
-        })?;
+        let version = match self.channel.as_str() {
+            "stable" => RUSTC_VERSION.into(),
+            "beta" => "beta".into(),
+            "nightly" => "nightly".into(),
+            _ => format!("{}-dev", RUSTC_VERSION),
+        };
+
         if package.target_independent() {
             Ok(format!("{}-{}.tar.gz", component_name, version))
         } else {
@@ -214,39 +185,7 @@ impl Versions {
         }
     }
 
-    pub(crate) fn package_version(&mut self, package: &PkgType) -> Result<String, Error> {
-        match self.package_versions.get(package) {
-            Some(release) => Ok(release.clone()),
-            None => {
-                let version = match package.rust_monorepo_path() {
-                    Some(path) => {
-                        let path = self.monorepo_root.join(path).join("Cargo.toml");
-                        let cargo_toml: CargoToml = toml::from_slice(&std::fs::read(path)?)?;
-                        cargo_toml.package.version
-                    }
-                    None => self.rustc_version.clone(),
-                };
-
-                let release = match self.channel.as_str() {
-                    "stable" => version,
-                    "beta" => "beta".into(),
-                    "nightly" => "nightly".into(),
-                    _ => format!("{}-dev", version),
-                };
-
-                self.package_versions.insert(package.clone(), release.clone());
-                Ok(release)
-            }
-        }
+    pub(crate) fn rustc_version(&self) -> &str {
+        RUSTC_VERSION
     }
 }
-
-#[derive(serde::Deserialize)]
-struct CargoToml {
-    package: CargoTomlPackage,
-}
-
-#[derive(serde::Deserialize)]
-struct CargoTomlPackage {
-    version: String,
-}
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 75615f8e69f748d7ef0df7bc0b064a9b1f5c78b
+Subproject 12db56cdedbc2c26a9aa18f994c0188cdcc67df
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index d1dfe36ffd8..0bd13320dc9 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,129 @@ document.
 
 ## Unreleased / In Rust Nightly
 
-[09bd400...master](https://github.com/rust-lang/rust-clippy/compare/09bd400...master)
+[e636b88...master](https://github.com/rust-lang/rust-clippy/compare/e636b88...master)
+
+## Rust 1.48
+
+Current beta, release 2020-11-19
+
+[09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88)
+
+### New lints
+
+* [`self_assignment`] [#5894](https://github.com/rust-lang/rust-clippy/pull/5894)
+* [`unnecessary_lazy_evaluations`] [#5720](https://github.com/rust-lang/rust-clippy/pull/5720)
+* [`manual_strip`] [#6038](https://github.com/rust-lang/rust-clippy/pull/6038)
+* [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998)
+* [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044)
+* [`to_string_in_display`] [#5831](https://github.com/rust-lang/rust-clippy/pull/5831)
+* [`single_char_push_str`] [#5881](https://github.com/rust-lang/rust-clippy/pull/5881)
+
+### Moves and Deprecations
+
+* Downgrade [`verbose_bit_mask`] to pedantic
+  [#6036](https://github.com/rust-lang/rust-clippy/pull/6036)
+
+### Enhancements
+
+* Extend [`precedence`] to handle chains of methods combined with unary negation
+  [#5928](https://github.com/rust-lang/rust-clippy/pull/5928)
+* [`useless_vec`]: add a configuration value for the maximum allowed size on the stack
+  [#5907](https://github.com/rust-lang/rust-clippy/pull/5907)
+* [`suspicious_arithmetic_impl`]: extend to implementations of `BitAnd`, `BitOr`, `BitXor`, `Rem`, `Shl`, and `Shr`
+  [#5884](https://github.com/rust-lang/rust-clippy/pull/5884)
+* [`invalid_atomic_ordering`]: detect misuse of `compare_exchange`, `compare_exchange_weak`, and `fetch_update`
+  [#6025](https://github.com/rust-lang/rust-clippy/pull/6025)
+* Avoid [`redundant_pattern_matching`] triggering in macros
+  [#6069](https://github.com/rust-lang/rust-clippy/pull/6069)
+* [`option_if_let_else`]: distinguish pure from impure `else` expressions
+  [#5937](https://github.com/rust-lang/rust-clippy/pull/5937)
+* [`needless_doctest_main`]: parse doctests instead of using textual search
+  [#5912](https://github.com/rust-lang/rust-clippy/pull/5912)
+* [`wildcard_imports`]: allow `prelude` to appear in any segment of an import
+  [#5929](https://github.com/rust-lang/rust-clippy/pull/5929)
+* Re-enable [`len_zero`] for ranges now that `range_is_empty` is stable
+  [#5961](https://github.com/rust-lang/rust-clippy/pull/5961)
+* [`option_as_ref_deref`]: catch fully-qualified calls to `Deref::deref` and `DerefMut::deref_mut`
+  [#5933](https://github.com/rust-lang/rust-clippy/pull/5933)
+
+### False Positive Fixes
+
+* [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`]
+  [#5994](https://github.com/rust-lang/rust-clippy/pull/5994)
+* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts 
+  [#5999](https://github.com/rust-lang/rust-clippy/pull/5999)
+* [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures
+  [#5920](https://github.com/rust-lang/rust-clippy/pull/5920)
+* Fix false positive in [`borrow_interior_mutable_const`] when referencing a field behind a pointer
+  [#5949](https://github.com/rust-lang/rust-clippy/pull/5949)
+* [`doc_markdown`]: allow using "GraphQL" without backticks
+  [#5996](https://github.com/rust-lang/rust-clippy/pull/5996)
+* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self` 
+  [#5971](https://github.com/rust-lang/rust-clippy/pull/5971)
+* [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays
+  [#6034](https://github.com/rust-lang/rust-clippy/pull/6034)
+* [`should_implement_trait`]: ignore methods with lifetime parameters
+  [#5725](https://github.com/rust-lang/rust-clippy/pull/5725)
+* [`needless_return`]: avoid linting if a temporary borrows a local variable
+  [#5903](https://github.com/rust-lang/rust-clippy/pull/5903)
+* Restrict [`unnecessary_sort_by`] to non-reference, Copy types
+  [#6006](https://github.com/rust-lang/rust-clippy/pull/6006)
+* Avoid suggesting `from_bits`/`to_bits` in const contexts in [`transmute_int_to_float`]
+  [#5919](https://github.com/rust-lang/rust-clippy/pull/5919)
+* [`declare_interior_mutable_const`] and [`borrow_interior_mutable_const`]: improve detection of interior mutable types
+  [#6046](https://github.com/rust-lang/rust-clippy/pull/6046)
+
+### Suggestion Fixes/Improvements
+
+* [`let_and_return`]: add a cast to the suggestion when the return expression has adjustments
+  [#5946](https://github.com/rust-lang/rust-clippy/pull/5946)
+* [`useless_conversion`]: show the type in the error message
+  [#6035](https://github.com/rust-lang/rust-clippy/pull/6035)
+* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message 
+  [#5892](https://github.com/rust-lang/rust-clippy/pull/5892)
+* [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous
+  [#6043](https://github.com/rust-lang/rust-clippy/pull/6043)
+* [`default_trait_access`]: do not use unnecessary type parameters in the suggestion
+  [#5993](https://github.com/rust-lang/rust-clippy/pull/5993)
+* [`collapsible_if`]: don't use expanded code in the suggestion 
+  [#5992](https://github.com/rust-lang/rust-clippy/pull/5992)
+* Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`]
+  [#6042](https://github.com/rust-lang/rust-clippy/pull/6042)
+* [`unit_arg`]: improve the readability of the suggestion
+  [#5931](https://github.com/rust-lang/rust-clippy/pull/5931)
+* [`stable_sort_primitive`]: print the type that is being sorted in the lint message 
+  [#5935](https://github.com/rust-lang/rust-clippy/pull/5935)
+* Show line count and max lines in [`too_many_lines`] lint message
+  [#6009](https://github.com/rust-lang/rust-clippy/pull/6009)
+* Keep parentheses in the suggestion of [`useless_conversion`] where applicable
+  [#5900](https://github.com/rust-lang/rust-clippy/pull/5900)
+* [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly
+  [#6024](https://github.com/rust-lang/rust-clippy/pull/6024)
+* [`redundant_allocation`]: suggest replacing `Rc<Box<T>>` with `Rc<T>` 
+  [#5899](https://github.com/rust-lang/rust-clippy/pull/5899)
+* Make lint messages adhere to rustc dev guide conventions
+  [#5893](https://github.com/rust-lang/rust-clippy/pull/5893)
+
+### ICE Fixes
+
+* Fix ICE in [`repeat_once`]
+  [#5948](https://github.com/rust-lang/rust-clippy/pull/5948)
+
+### Documentation Improvements
+
+* [`mutable_key_type`]: explain potential for false positives when the interior mutable type is not accessed in the `Hash` implementation
+  [#6019](https://github.com/rust-lang/rust-clippy/pull/6019)
+* [`unnecessary_mut_passed`]: fix typo
+  [#5913](https://github.com/rust-lang/rust-clippy/pull/5913)
+* Add example of false positive to [`ptr_arg`] docs.
+  [#5885](https://github.com/rust-lang/rust-clippy/pull/5885)
+* [`box_vec`], [`vec_box`] and [`borrowed_box`]: add link to the documentation of `Box`
+  [#6023](https://github.com/rust-lang/rust-clippy/pull/6023)
 
 ## Rust 1.47
 
-Current beta, release 2020-10-08
+Current stable, released 2020-10-08
 
 [c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400)
 
@@ -112,7 +230,7 @@ Current beta, release 2020-10-08
 
 ## Rust 1.46
 
-Current stable, released 2020-08-27
+Released 2020-08-27
 
 [7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...c2c07fa)
 
@@ -1559,6 +1677,7 @@ Released 2018-09-13
 [`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
 [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
 [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
+[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
@@ -1634,6 +1753,8 @@ Released 2018-09-13
 [`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string
 [`inherent_to_string_shadow_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string_shadow_display
 [`inline_always`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_always
+[`inline_asm_x86_att_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_att_syntax
+[`inline_asm_x86_intel_syntax`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_asm_x86_intel_syntax
 [`inline_fn_without_body`]: https://rust-lang.github.io/rust-clippy/master/index.html#inline_fn_without_body
 [`int_plus_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#int_plus_one
 [`integer_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_arithmetic
@@ -1644,6 +1765,7 @@ Released 2018-09-13
 [`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
 [`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
 [`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
+[`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters
 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements
 [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect
 [`iter_next_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_next_loop
@@ -1919,6 +2041,5 @@ Released 2018-09-13
 [`zero_divided_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_divided_by_zero
 [`zero_prefixed_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_prefixed_literal
 [`zero_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_ptr
-[`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space
 [`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
 <!-- end autogenerated links to lint list -->
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index a2984d73641..62a8be0abf2 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -5,7 +5,7 @@
 
 A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 
-[There are over 350 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 
 We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
 
diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml
index c861efc8afb..b8a4a20114b 100644
--- a/src/tools/clippy/clippy_dev/Cargo.toml
+++ b/src/tools/clippy/clippy_dev/Cargo.toml
@@ -8,8 +8,8 @@ edition = "2018"
 bytecount = "0.6"
 clap = "2.33"
 itertools = "0.9"
+opener = "0.4"
 regex = "1"
-lazy_static = "1.0"
 shell-escape = "0.1"
 walkdir = "2"
 
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 5baa31d5cde..43cb2954b74 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -1,42 +1,47 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
+#![feature(once_cell)]
 
 use itertools::Itertools;
-use lazy_static::lazy_static;
 use regex::Regex;
 use std::collections::HashMap;
 use std::ffi::OsStr;
 use std::fs;
+use std::lazy::SyncLazy;
 use std::path::{Path, PathBuf};
 use walkdir::WalkDir;
 
 pub mod fmt;
 pub mod new_lint;
 pub mod ra_setup;
+pub mod serve;
 pub mod stderr_length_check;
 pub mod update_lints;
 
-lazy_static! {
-    static ref DEC_CLIPPY_LINT_RE: Regex = Regex::new(
+static DEC_CLIPPY_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
+    Regex::new(
         r#"(?x)
-        declare_clippy_lint!\s*[\{(]
-        (?:\s+///.*)*
-        \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
-        (?P<cat>[a-z_]+)\s*,\s*
-        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
-    "#
+    declare_clippy_lint!\s*[\{(]
+    (?:\s+///.*)*
+    \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
+    (?P<cat>[a-z_]+)\s*,\s*
+    "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
+"#,
     )
-    .unwrap();
-    static ref DEC_DEPRECATED_LINT_RE: Regex = Regex::new(
+    .unwrap()
+});
+
+static DEC_DEPRECATED_LINT_RE: SyncLazy<Regex> = SyncLazy::new(|| {
+    Regex::new(
         r#"(?x)
-        declare_deprecated_lint!\s*[{(]\s*
-        (?:\s+///.*)*
-        \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
-        "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
-    "#
+    declare_deprecated_lint!\s*[{(]\s*
+    (?:\s+///.*)*
+    \s+pub\s+(?P<name>[A-Z_][A-Z_0-9]*)\s*,\s*
+    "(?P<desc>(?:[^"\\]+|\\(?s).(?-s))*)"\s*[})]
+"#,
     )
-    .unwrap();
-    static ref NL_ESCAPE_RE: Regex = Regex::new(r#"\\\n\s*"#).unwrap();
-}
+    .unwrap()
+});
+static NL_ESCAPE_RE: SyncLazy<Regex> = SyncLazy::new(|| Regex::new(r#"\\\n\s*"#).unwrap());
 
 pub static DOCS_LINK: &str = "https://rust-lang.github.io/rust-clippy/master/index.html";
 
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 281037ae37c..7a8cbd5251d 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -1,7 +1,7 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 
 use clap::{App, Arg, SubCommand};
-use clippy_dev::{fmt, new_lint, ra_setup, stderr_length_check, update_lints};
+use clippy_dev::{fmt, new_lint, ra_setup, serve, stderr_length_check, update_lints};
 
 fn main() {
     let matches = App::new("Clippy developer tooling")
@@ -100,6 +100,19 @@ fn main() {
                         .required(true),
                 ),
         )
+        .subcommand(
+            SubCommand::with_name("serve")
+                .about("Launch a local 'ALL the Clippy Lints' website in a browser")
+                .arg(
+                    Arg::with_name("port")
+                        .long("port")
+                        .short("p")
+                        .help("Local port for the http server")
+                        .default_value("8000")
+                        .validator_os(serve::validate_port),
+                )
+                .arg(Arg::with_name("lint").help("Which lint's page to load initially (optional)")),
+        )
         .get_matches();
 
     match matches.subcommand() {
@@ -129,6 +142,11 @@ fn main() {
             stderr_length_check::check();
         },
         ("ra-setup", Some(matches)) => ra_setup::run(matches.value_of("rustc-repo-path")),
+        ("serve", Some(matches)) => {
+            let port = matches.value_of("port").unwrap().parse().unwrap();
+            let lint = matches.value_of("lint");
+            serve::run(port, lint);
+        },
         _ => {},
     }
 }
diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs
new file mode 100644
index 00000000000..a46c0e4d3f0
--- /dev/null
+++ b/src/tools/clippy/clippy_dev/src/serve.rs
@@ -0,0 +1,64 @@
+use std::ffi::{OsStr, OsString};
+use std::path::Path;
+use std::process::Command;
+use std::thread;
+use std::time::{Duration, SystemTime};
+
+pub fn run(port: u16, lint: Option<&str>) -> ! {
+    let mut url = Some(match lint {
+        None => format!("http://localhost:{}", port),
+        Some(lint) => format!("http://localhost:{}/#{}", port, lint),
+    });
+
+    loop {
+        if mtime("util/gh-pages/lints.json") < mtime("clippy_lints/src") {
+            Command::new("python3")
+                .arg("util/export.py")
+                .spawn()
+                .unwrap()
+                .wait()
+                .unwrap();
+        }
+        if let Some(url) = url.take() {
+            thread::spawn(move || {
+                Command::new("python3")
+                    .arg("-m")
+                    .arg("http.server")
+                    .arg(port.to_string())
+                    .current_dir("util/gh-pages")
+                    .spawn()
+                    .unwrap();
+                // Give some time for python to start
+                thread::sleep(Duration::from_millis(500));
+                // Launch browser after first export.py has completed and http.server is up
+                let _ = opener::open(url);
+            });
+        }
+        thread::sleep(Duration::from_millis(1000));
+    }
+}
+
+fn mtime(path: impl AsRef<Path>) -> SystemTime {
+    let path = path.as_ref();
+    if path.is_dir() {
+        path.read_dir()
+            .into_iter()
+            .flatten()
+            .flatten()
+            .map(|entry| mtime(&entry.path()))
+            .max()
+            .unwrap_or(SystemTime::UNIX_EPOCH)
+    } else {
+        path.metadata()
+            .and_then(|metadata| metadata.modified())
+            .unwrap_or(SystemTime::UNIX_EPOCH)
+    }
+}
+
+#[allow(clippy::missing_errors_doc)]
+pub fn validate_port(arg: &OsStr) -> Result<(), OsString> {
+    match arg.to_string_lossy().parse::<u16>() {
+        Ok(_port) => Ok(()),
+        Err(err) => Err(OsString::from(err.to_string())),
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 341d9e601ee..fcf817b82c8 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -20,7 +20,6 @@ edition = "2018"
 cargo_metadata = "0.11.1"
 if_chain = "1.0.0"
 itertools = "0.9"
-lazy_static = "1.0.2"
 pulldown-cmark = { version = "0.8", default-features = false }
 quine-mc_cluskey = "0.2.2"
 regex-syntax = "0.6"
diff --git a/src/tools/clippy/clippy_lints/src/asm_syntax.rs b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
new file mode 100644
index 00000000000..ef1f1a14afc
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/asm_syntax.rs
@@ -0,0 +1,125 @@
+use std::fmt;
+
+use crate::utils::span_lint_and_help;
+use rustc_ast::ast::{Expr, ExprKind, InlineAsmOptions};
+use rustc_lint::{EarlyContext, EarlyLintPass, Lint};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum AsmStyle {
+    Intel,
+    Att,
+}
+
+impl fmt::Display for AsmStyle {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            AsmStyle::Intel => f.write_str("Intel"),
+            AsmStyle::Att => f.write_str("AT&T"),
+        }
+    }
+}
+
+impl std::ops::Not for AsmStyle {
+    type Output = AsmStyle;
+
+    fn not(self) -> AsmStyle {
+        match self {
+            AsmStyle::Intel => AsmStyle::Att,
+            AsmStyle::Att => AsmStyle::Intel,
+        }
+    }
+}
+
+fn check_expr_asm_syntax(lint: &'static Lint, cx: &EarlyContext<'_>, expr: &Expr, check_for: AsmStyle) {
+    if let ExprKind::InlineAsm(ref inline_asm) = expr.kind {
+        let style = if inline_asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
+            AsmStyle::Att
+        } else {
+            AsmStyle::Intel
+        };
+
+        if style == check_for {
+            span_lint_and_help(
+                cx,
+                lint,
+                expr.span,
+                &format!("{} x86 assembly syntax used", style),
+                None,
+                &format!("use {} x86 assembly syntax", !style),
+            );
+        }
+    }
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of Intel x86 assembly syntax.
+    ///
+    /// **Why is this bad?** The lint has been enabled to indicate a preference
+    /// for AT&T x86 assembly syntax.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust,no_run
+    /// # #![feature(asm)]
+    /// # unsafe { let ptr = "".as_ptr();
+    /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
+    /// # }
+    /// ```
+    /// Use instead:
+    /// ```rust,no_run
+    /// # #![feature(asm)]
+    /// # unsafe { let ptr = "".as_ptr();
+    /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
+    /// # }
+    /// ```
+    pub INLINE_ASM_X86_INTEL_SYNTAX,
+    restriction,
+    "prefer AT&T x86 assembly syntax"
+}
+
+declare_lint_pass!(InlineAsmX86IntelSyntax => [INLINE_ASM_X86_INTEL_SYNTAX]);
+
+impl EarlyLintPass for InlineAsmX86IntelSyntax {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        check_expr_asm_syntax(Self::get_lints()[0], cx, expr, AsmStyle::Intel);
+    }
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for usage of AT&T x86 assembly syntax.
+    ///
+    /// **Why is this bad?** The lint has been enabled to indicate a preference
+    /// for Intel x86 assembly syntax.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust,no_run
+    /// # #![feature(asm)]
+    /// # unsafe { let ptr = "".as_ptr();
+    /// asm!("lea ({}), {}", in(reg) ptr, lateout(reg) _, options(att_syntax));
+    /// # }
+    /// ```
+    /// Use instead:
+    /// ```rust,no_run
+    /// # #![feature(asm)]
+    /// # unsafe { let ptr = "".as_ptr();
+    /// asm!("lea {}, [{}]", lateout(reg) _, in(reg) ptr);
+    /// # }
+    /// ```
+    pub INLINE_ASM_X86_ATT_SYNTAX,
+    restriction,
+    "prefer Intel x86 assembly syntax"
+}
+
+declare_lint_pass!(InlineAsmX86AttSyntax => [INLINE_ASM_X86_ATT_SYNTAX]);
+
+impl EarlyLintPass for InlineAsmX86AttSyntax {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        check_expr_asm_syntax(Self::get_lints()[0], cx, expr, AsmStyle::Att);
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index c8f153e7201..f6eadbdef0b 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -137,17 +137,17 @@ declare_clippy_lint! {
     /// **Example:**
     /// ```rust
     /// // Good (as inner attribute)
-    /// #![inline(always)]
+    /// #![allow(dead_code)]
     ///
     /// fn this_is_fine() { }
     ///
     /// // Bad
-    /// #[inline(always)]
+    /// #[allow(dead_code)]
     ///
     /// fn not_quite_good_code() { }
     ///
     /// // Good (as outer attribute)
-    /// #[inline(always)]
+    /// #[allow(dead_code)]
     /// fn this_is_fine_too() { }
     /// ```
     pub EMPTY_LINE_AFTER_OUTER_ATTR,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_method.rs b/src/tools/clippy/clippy_lints/src/disallowed_method.rs
new file mode 100644
index 00000000000..581c3242e37
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/disallowed_method.rs
@@ -0,0 +1,73 @@
+use crate::utils::span_lint;
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Symbol;
+
+declare_clippy_lint! {
+    /// **What it does:** Lints for specific trait methods defined in clippy.toml
+    ///
+    /// **Why is this bad?** Some methods are undesirable in certain contexts,
+    /// and it would be beneficial to lint for them as needed.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust,ignore
+    /// // example code where clippy issues a warning
+    /// foo.bad_method(); // Foo::bad_method is disallowed in the configuration
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// // example code which does not raise clippy warning
+    /// goodStruct.bad_method(); // GoodStruct::bad_method is not disallowed
+    /// ```
+    pub DISALLOWED_METHOD,
+    nursery,
+    "use of a disallowed method call"
+}
+
+#[derive(Clone, Debug)]
+pub struct DisallowedMethod {
+    disallowed: FxHashSet<Vec<Symbol>>,
+}
+
+impl DisallowedMethod {
+    pub fn new(disallowed: &FxHashSet<String>) -> Self {
+        Self {
+            disallowed: disallowed
+                .iter()
+                .map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>())
+                .collect(),
+        }
+    }
+}
+
+impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]);
+
+impl<'tcx> LateLintPass<'tcx> for DisallowedMethod {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::MethodCall(_path, _, _args, _) = &expr.kind {
+            let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
+
+            let method_call = cx.get_def_path(def_id);
+            if self.disallowed.contains(&method_call) {
+                let method = method_call
+                    .iter()
+                    .map(|s| s.to_ident_string())
+                    .collect::<Vec<_>>()
+                    .join("::");
+
+                span_lint(
+                    cx,
+                    DISALLOWED_METHOD,
+                    expr.span,
+                    &format!("use of a disallowed method `{}`", method),
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 82549c12d0a..8b022912573 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -6,6 +6,7 @@ use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_target::abi::LayoutOf;
+use rustc_target::spec::abi::Abi;
 use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
 
 use crate::utils::span_lint;
@@ -60,12 +61,18 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
-        _: intravisit::FnKind<'tcx>,
+        fn_kind: intravisit::FnKind<'tcx>,
         _: &'tcx FnDecl<'_>,
         body: &'tcx Body<'_>,
         _: Span,
         hir_id: HirId,
     ) {
+        if let Some(header) = fn_kind.header() {
+            if header.abi != Abi::Rust {
+                return;
+            }
+        }
+
         // If the method is an impl for a trait, don't warn.
         let parent_id = cx.tcx.hir().get_parent_item(hir_id);
         let parent_node = cx.tcx.hir().find(parent_id);
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 70efdaeb9c6..93b5d9e178c 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -7,6 +7,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(drain_filter)]
 #![feature(in_band_lifetimes)]
+#![feature(once_cell)]
 #![feature(or_patterns)]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
@@ -153,6 +154,7 @@ mod utils;
 mod approx_const;
 mod arithmetic;
 mod as_conversions;
+mod asm_syntax;
 mod assertions_on_constants;
 mod assign_ops;
 mod async_yields_async;
@@ -176,6 +178,7 @@ mod dbg_macro;
 mod default_trait_access;
 mod dereference;
 mod derive;
+mod disallowed_method;
 mod doc;
 mod double_comparison;
 mod double_parens;
@@ -489,6 +492,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &arithmetic::FLOAT_ARITHMETIC,
         &arithmetic::INTEGER_ARITHMETIC,
         &as_conversions::AS_CONVERSIONS,
+        &asm_syntax::INLINE_ASM_X86_ATT_SYNTAX,
+        &asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX,
         &assertions_on_constants::ASSERTIONS_ON_CONSTANTS,
         &assign_ops::ASSIGN_OP_PATTERN,
         &assign_ops::MISREFACTORED_ASSIGN_OP,
@@ -529,6 +534,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &derive::DERIVE_ORD_XOR_PARTIAL_ORD,
         &derive::EXPL_IMPL_CLONE_ON_COPY,
         &derive::UNSAFE_DERIVE_DESERIALIZE,
+        &disallowed_method::DISALLOWED_METHOD,
         &doc::DOC_MARKDOWN,
         &doc::MISSING_ERRORS_DOC,
         &doc::MISSING_SAFETY_DOC,
@@ -851,9 +857,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &types::UNIT_CMP,
         &types::UNNECESSARY_CAST,
         &types::VEC_BOX,
+        &unicode::INVISIBLE_CHARACTERS,
         &unicode::NON_ASCII_LITERAL,
         &unicode::UNICODE_NOT_NFC,
-        &unicode::ZERO_WIDTH_SPACE,
         &unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
         &unnamed_address::FN_ADDRESS_COMPARISONS,
         &unnamed_address::VTABLE_ADDRESS_COMPARISONS,
@@ -1120,11 +1126,18 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
     store.register_late_pass(|| box manual_strip::ManualStrip);
     store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
+    let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
+    store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
+    store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
+
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
         LintId::of(&arithmetic::INTEGER_ARITHMETIC),
         LintId::of(&as_conversions::AS_CONVERSIONS),
+        LintId::of(&asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
+        LintId::of(&asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
         LintId::of(&create_dir::CREATE_DIR),
         LintId::of(&dbg_macro::DBG_MACRO),
         LintId::of(&else_if_without_else::ELSE_IF_WITHOUT_ELSE),
@@ -1159,6 +1172,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&shadow::SHADOW_REUSE),
         LintId::of(&shadow::SHADOW_SAME),
         LintId::of(&strings::STRING_ADD),
+        LintId::of(&types::RC_BUFFER),
         LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT),
         LintId::of(&verbose_file_reads::VERBOSE_FILE_READS),
         LintId::of(&write::PRINT_STDOUT),
@@ -1463,7 +1477,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
         LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
         LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
-        LintId::of(&strings::STRING_LIT_AS_BYTES),
         LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
         LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
         LintId::of(&swap::ALMOST_SWAPPED),
@@ -1492,14 +1505,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::CHAR_LIT_AS_U8),
         LintId::of(&types::FN_TO_NUMERIC_CAST),
         LintId::of(&types::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
-        LintId::of(&types::RC_BUFFER),
         LintId::of(&types::REDUNDANT_ALLOCATION),
         LintId::of(&types::TYPE_COMPLEXITY),
         LintId::of(&types::UNIT_ARG),
         LintId::of(&types::UNIT_CMP),
         LintId::of(&types::UNNECESSARY_CAST),
         LintId::of(&types::VEC_BOX),
-        LintId::of(&unicode::ZERO_WIDTH_SPACE),
+        LintId::of(&unicode::INVISIBLE_CHARACTERS),
         LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
         LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
         LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
@@ -1592,6 +1604,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&mut_reference::UNNECESSARY_MUT_PASSED),
         LintId::of(&neg_multiply::NEG_MULTIPLY),
         LintId::of(&new_without_default::NEW_WITHOUT_DEFAULT),
+        LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
+        LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
         LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
         LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES),
         LintId::of(&panic_unimplemented::PANIC_PARAMS),
@@ -1604,7 +1618,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&returns::LET_AND_RETURN),
         LintId::of(&returns::NEEDLESS_RETURN),
         LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
-        LintId::of(&strings::STRING_LIT_AS_BYTES),
         LintId::of(&tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
         LintId::of(&to_digit_is_some::TO_DIGIT_IS_SOME),
         LintId::of(&try_err::TRY_ERR),
@@ -1747,8 +1760,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&misc::FLOAT_CMP),
         LintId::of(&misc::MODULO_ONE),
         LintId::of(&mut_key::MUTABLE_KEY_TYPE),
-        LintId::of(&non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
-        LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
         LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
         LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
         LintId::of(&ptr::MUT_FROM_REF),
@@ -1766,7 +1777,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&types::ABSURD_EXTREME_COMPARISONS),
         LintId::of(&types::CAST_REF_TO_MUT),
         LintId::of(&types::UNIT_CMP),
-        LintId::of(&unicode::ZERO_WIDTH_SPACE),
+        LintId::of(&unicode::INVISIBLE_CHARACTERS),
         LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
         LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
         LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
@@ -1793,7 +1804,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
         LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE),
         LintId::of(&types::BOX_VEC),
-        LintId::of(&types::RC_BUFFER),
         LintId::of(&types::REDUNDANT_ALLOCATION),
         LintId::of(&vec::USELESS_VEC),
     ]);
@@ -1807,6 +1817,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
         LintId::of(&attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
         LintId::of(&cognitive_complexity::COGNITIVE_COMPLEXITY),
+        LintId::of(&disallowed_method::DISALLOWED_METHOD),
         LintId::of(&fallible_impl_from::FALLIBLE_IMPL_FROM),
         LintId::of(&floating_point_arithmetic::IMPRECISE_FLOPS),
         LintId::of(&floating_point_arithmetic::SUBOPTIMAL_FLOPS),
@@ -1818,6 +1829,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&needless_borrow::NEEDLESS_BORROW),
         LintId::of(&path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
         LintId::of(&redundant_pub_crate::REDUNDANT_PUB_CRATE),
+        LintId::of(&strings::STRING_LIT_AS_BYTES),
         LintId::of(&transmute::USELESS_TRANSMUTE),
         LintId::of(&use_self::USE_SELF),
     ]);
@@ -1896,6 +1908,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
     ls.register_renamed("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles");
     ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles");
     ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion");
+    ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters");
 }
 
 // only exists to let the dogfood integration test works.
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 4df6827d77f..d7043e7bd8f 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -1,21 +1,22 @@
+use crate::utils::paths;
+use crate::utils::{get_trait_def_id, in_macro, span_lint, trait_ref_of_method};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::{
-    walk_fn_decl, walk_generic_param, walk_generics, walk_param_bound, walk_ty, NestedVisitorMap, Visitor,
+    walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty,
+    NestedVisitorMap, Visitor,
 };
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::{
-    BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item,
-    ItemKind, Lifetime, LifetimeName, ParamName, QPath, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty,
-    TyKind, WhereClause, WherePredicate,
+    BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem,
+    ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier, TraitFn,
+    TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, Symbol};
-
-use crate::utils::{in_macro, last_path_segment, span_lint, trait_ref_of_method};
+use std::iter::FromIterator;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for lifetime annotations which can be removed by
@@ -25,8 +26,11 @@ declare_clippy_lint! {
     /// complicated, while there is nothing out of the ordinary going on. Removing
     /// them leads to more readable code.
     ///
-    /// **Known problems:** Potential false negatives: we bail out if the function
-    /// has a `where` clause where lifetimes are mentioned.
+    /// **Known problems:**
+    /// - We bail out if the function has a `where` clause where lifetimes
+    /// are mentioned due to potenial false positives.
+    /// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the
+    /// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`.
     ///
     /// **Example:**
     /// ```rust
@@ -108,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
 }
 
 /// The lifetime of a &-reference.
-#[derive(PartialEq, Eq, Hash, Debug)]
+#[derive(PartialEq, Eq, Hash, Debug, Clone)]
 enum RefLt {
     Unnamed,
     Static,
@@ -127,7 +131,6 @@ fn check_fn_inner<'tcx>(
         return;
     }
 
-    let mut bounds_lts = Vec::new();
     let types = generics
         .params
         .iter()
@@ -156,13 +159,12 @@ fn check_fn_inner<'tcx>(
                         if bound.name != LifetimeName::Static && !bound.is_elided() {
                             return;
                         }
-                        bounds_lts.push(bound);
                     }
                 }
             }
         }
     }
-    if could_use_elision(cx, decl, body, &generics.params, bounds_lts) {
+    if could_use_elision(cx, decl, body, &generics.params) {
         span_lint(
             cx,
             NEEDLESS_LIFETIMES,
@@ -181,7 +183,6 @@ fn could_use_elision<'tcx>(
     func: &'tcx FnDecl<'_>,
     body: Option<BodyId>,
     named_generics: &'tcx [GenericParam<'_>],
-    bounds_lts: Vec<&'tcx Lifetime>,
 ) -> bool {
     // There are two scenarios where elision works:
     // * no output references, all input references have different LT
@@ -204,15 +205,31 @@ fn could_use_elision<'tcx>(
     if let Return(ref ty) = func.output {
         output_visitor.visit_ty(ty);
     }
+    for lt in named_generics {
+        input_visitor.visit_generic_param(lt)
+    }
+
+    if input_visitor.abort() || output_visitor.abort() {
+        return false;
+    }
 
-    let input_lts = match input_visitor.into_vec() {
-        Some(lts) => lts_from_bounds(lts, bounds_lts.into_iter()),
-        None => return false,
-    };
-    let output_lts = match output_visitor.into_vec() {
-        Some(val) => val,
-        None => return false,
-    };
+    if allowed_lts
+        .intersection(&FxHashSet::from_iter(
+            input_visitor
+                .nested_elision_site_lts
+                .iter()
+                .chain(output_visitor.nested_elision_site_lts.iter())
+                .cloned()
+                .filter(|v| matches!(v, RefLt::Named(_))),
+        ))
+        .next()
+        .is_some()
+    {
+        return false;
+    }
+
+    let input_lts = input_visitor.lts;
+    let output_lts = output_visitor.lts;
 
     if let Some(body_id) = body {
         let mut checker = BodyLifetimeChecker {
@@ -277,27 +294,20 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
     allowed_lts
 }
 
-fn lts_from_bounds<'a, T: Iterator<Item = &'a Lifetime>>(mut vec: Vec<RefLt>, bounds_lts: T) -> Vec<RefLt> {
-    for lt in bounds_lts {
-        if lt.name != LifetimeName::Static {
-            vec.push(RefLt::Named(lt.name.ident().name));
-        }
-    }
-
-    vec
-}
-
 /// Number of unique lifetimes in the given vector.
 #[must_use]
 fn unique_lifetimes(lts: &[RefLt]) -> usize {
     lts.iter().collect::<FxHashSet<_>>().len()
 }
 
+const CLOSURE_TRAIT_BOUNDS: [&[&str]; 3] = [&paths::FN, &paths::FN_MUT, &paths::FN_ONCE];
+
 /// A visitor usable for `rustc_front::visit::walk_ty()`.
 struct RefVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     lts: Vec<RefLt>,
-    abort: bool,
+    nested_elision_site_lts: Vec<RefLt>,
+    unelided_trait_object_lifetime: bool,
 }
 
 impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
@@ -305,7 +315,8 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
         Self {
             cx,
             lts: Vec::new(),
-            abort: false,
+            nested_elision_site_lts: Vec::new(),
+            unelided_trait_object_lifetime: false,
         }
     }
 
@@ -325,40 +336,16 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
         }
     }
 
-    fn into_vec(self) -> Option<Vec<RefLt>> {
-        if self.abort {
-            None
-        } else {
-            Some(self.lts)
-        }
+    fn all_lts(&self) -> Vec<RefLt> {
+        self.lts
+            .iter()
+            .chain(self.nested_elision_site_lts.iter())
+            .cloned()
+            .collect::<Vec<_>>()
     }
 
-    fn collect_anonymous_lifetimes(&mut self, qpath: &QPath<'_>, ty: &Ty<'_>) {
-        if let Some(ref last_path_segment) = last_path_segment(qpath).args {
-            if !last_path_segment.parenthesized
-                && !last_path_segment
-                    .args
-                    .iter()
-                    .any(|arg| matches!(arg, GenericArg::Lifetime(_)))
-            {
-                let hir_id = ty.hir_id;
-                match self.cx.qpath_res(qpath, hir_id) {
-                    Res::Def(DefKind::TyAlias | DefKind::Struct, def_id) => {
-                        let generics = self.cx.tcx.generics_of(def_id);
-                        for _ in generics.params.as_slice() {
-                            self.record(&None);
-                        }
-                    },
-                    Res::Def(DefKind::Trait, def_id) => {
-                        let trait_def = self.cx.tcx.trait_def(def_id);
-                        for _ in &self.cx.tcx.generics_of(trait_def.def_id).params {
-                            self.record(&None);
-                        }
-                    },
-                    _ => (),
-                }
-            }
-        }
+    fn abort(&self) -> bool {
+        self.unelided_trait_object_lifetime
     }
 }
 
@@ -370,30 +357,37 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
         self.record(&Some(*lifetime));
     }
 
+    fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>, tbm: TraitBoundModifier) {
+        let trait_ref = &poly_tref.trait_ref;
+        if CLOSURE_TRAIT_BOUNDS
+            .iter()
+            .any(|trait_path| trait_ref.trait_def_id() == get_trait_def_id(self.cx, trait_path))
+        {
+            let mut sub_visitor = RefVisitor::new(self.cx);
+            sub_visitor.visit_trait_ref(trait_ref);
+            self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
+        } else {
+            walk_poly_trait_ref(self, poly_tref, tbm);
+        }
+    }
+
     fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
         match ty.kind {
-            TyKind::Rptr(ref lt, _) if lt.is_elided() => {
-                self.record(&None);
-            },
-            TyKind::Path(ref path) => {
-                self.collect_anonymous_lifetimes(path, ty);
-            },
             TyKind::OpaqueDef(item, _) => {
                 let map = self.cx.tcx.hir();
-                if let ItemKind::OpaqueTy(ref exist_ty) = map.expect_item(item.id).kind {
-                    for bound in exist_ty.bounds {
-                        if let GenericBound::Outlives(_) = *bound {
-                            self.record(&None);
-                        }
-                    }
-                } else {
-                    unreachable!()
-                }
+                let item = map.expect_item(item.id);
+                walk_item(self, item);
                 walk_ty(self, ty);
             },
+            TyKind::BareFn(&BareFnTy { decl, .. }) => {
+                let mut sub_visitor = RefVisitor::new(self.cx);
+                sub_visitor.visit_fn_decl(decl);
+                self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
+                return;
+            },
             TyKind::TraitObject(bounds, ref lt) => {
                 if !lt.is_elided() {
-                    self.abort = true;
+                    self.unelided_trait_object_lifetime = true;
                 }
                 for bound in bounds {
                     self.visit_poly_trait_ref(bound, TraitBoundModifier::None);
@@ -430,16 +424,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereCl
                     walk_param_bound(&mut visitor, bound);
                 }
                 // and check that all lifetimes are allowed
-                match visitor.into_vec() {
-                    None => return false,
-                    Some(lts) => {
-                        for lt in lts {
-                            if !allowed_lts.contains(&lt) {
-                                return true;
-                            }
-                        }
-                    },
-                }
+                return visitor.all_lts().iter().any(|it| !allowed_lts.contains(it));
             },
             WherePredicate::EqPredicate(ref pred) => {
                 let mut visitor = RefVisitor::new(cx);
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index a36fdca5d5d..c54103b25c2 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -264,13 +264,10 @@ impl LiteralDigitGrouping {
 
         let (part, mistyped_suffixes, missing_char) = if let Some((_, exponent)) = &mut num_lit.exponent {
             (exponent, &["32", "64"][..], 'f')
+        } else if num_lit.fraction.is_some() {
+            (&mut num_lit.integer, &["32", "64"][..], 'f')
         } else {
-            num_lit
-                .fraction
-                .as_mut()
-                .map_or((&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i'), |fraction| {
-                    (fraction, &["32", "64"][..], 'f')
-                })
+            (&mut num_lit.integer, &["8", "16", "32", "64"][..], 'i')
         };
 
         let mut split = part.rsplit('_');
diff --git a/src/tools/clippy/clippy_lints/src/loops.rs b/src/tools/clippy/clippy_lints/src/loops.rs
index 3410341a1e3..61b63597b16 100644
--- a/src/tools/clippy/clippy_lints/src/loops.rs
+++ b/src/tools/clippy/clippy_lints/src/loops.rs
@@ -3,7 +3,7 @@ use crate::utils::paths;
 use crate::utils::sugg::Sugg;
 use crate::utils::usage::{is_unused, mutated_variables};
 use crate::utils::{
-    get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
+    contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
     is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment, match_trait_method,
     match_type, match_var, multispan_sugg, qpath_res, snippet, snippet_opt, snippet_with_applicability,
     snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg,
@@ -1276,6 +1276,8 @@ fn check_for_loop_range<'tcx>(
 
                 let skip = if starts_at_zero {
                     String::new()
+                } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start) {
+                    return;
                 } else {
                     format!(".skip({})", snippet(cx, start.span, ".."))
                 };
@@ -1302,6 +1304,8 @@ fn check_for_loop_range<'tcx>(
 
                     if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
                         String::new()
+                    } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr) {
+                        return;
                     } else {
                         match limits {
                             ast::RangeLimits::Closed => {
@@ -2134,7 +2138,7 @@ enum VarState {
     DontWarn,
 }
 
-/// Scan a for loop for variables that are incremented exactly once.
+/// Scan a for loop for variables that are incremented exactly once and not used after that.
 struct IncrementVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,          // context reference
     states: FxHashMap<HirId, VarState>, // incremented variables
@@ -2154,6 +2158,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
         if let Some(def_id) = var_def_id(self.cx, expr) {
             if let Some(parent) = get_parent_expr(self.cx, expr) {
                 let state = self.states.entry(def_id).or_insert(VarState::Initial);
+                if *state == VarState::IncrOnce {
+                    *state = VarState::DontWarn;
+                    return;
+                }
 
                 match parent.kind {
                     ExprKind::AssignOp(op, ref lhs, ref rhs) => {
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index 065c7c042d3..b4b4b3dc18d 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -18,9 +18,9 @@ declare_clippy_lint! {
     /// **Known problems:** None.
     ///
     /// **Example:**
-    /// ```rust
+    /// ```rust,ignore
     /// #[macro_use]
-    /// use lazy_static;
+    /// use some_macro;
     /// ```
     pub MACRO_USE_IMPORTS,
     pedantic,
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index e0651f9ab5d..c0824bacbc7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -400,8 +400,8 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `_.map(_).flatten(_)`,
     ///
-    /// **Why is this bad?** Readability, this can be written more concisely as a
-    /// single method call using `_.flat_map(_)`
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.flat_map(_)`
     ///
     /// **Known problems:**
     ///
@@ -424,8 +424,8 @@ declare_clippy_lint! {
     /// **What it does:** Checks for usage of `_.filter(_).map(_)`,
     /// `_.filter(_).flat_map(_)`, `_.filter_map(_).flat_map(_)` and similar.
     ///
-    /// **Why is this bad?** Readability, this can be written more concisely as a
-    /// single method call.
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.filter_map(_)`.
     ///
     /// **Known problems:** Often requires a condition + Option/Iterator creation
     /// inside the closure.
@@ -452,8 +452,8 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `_.filter_map(_).next()`.
     ///
-    /// **Why is this bad?** Readability, this can be written more concisely as a
-    /// single method call.
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.find_map(_)`.
     ///
     /// **Known problems:** None
     ///
@@ -496,8 +496,8 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `_.find(_).map(_)`.
     ///
-    /// **Why is this bad?** Readability, this can be written more concisely as a
-    /// single method call.
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.find_map(_)`.
     ///
     /// **Known problems:** Often requires a condition + Option/Iterator creation
     /// inside the closure.
@@ -1276,8 +1276,8 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `_.as_ref().map(Deref::deref)` or it's aliases (such as String::as_str).
     ///
-    /// **Why is this bad?** Readability, this can be written more concisely as a
-    /// single method call.
+    /// **Why is this bad?** Readability, this can be written more concisely as
+    /// `_.as_deref()`.
     ///
     /// **Known problems:** None.
     ///
@@ -1668,9 +1668,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             if let ty::Opaque(def_id, _) = *ret_ty.kind() {
                 // one of the associated types must be Self
                 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
-                    if let ty::PredicateAtom::Projection(projection_predicate) =
-                        predicate.skip_binders()
-                    {
+                    if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() {
                         // walk the associated type and check for Self
                         if contains_ty(projection_predicate.ty, self_ty) {
                             return;
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 80da04fb7de..25245b3dbf0 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -1,10 +1,10 @@
+use crate::utils::qualify_min_const_fn::is_min_const_fn;
 use crate::utils::{fn_has_unsatisfiable_preds, has_drop, is_entrypoint_fn, span_lint, trait_ref_of_method};
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
-use crate::utils::qualify_min_const_fn::is_min_const_fn;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 use rustc_typeck::hir_ty_to_ty;
diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
index 38bdd0f7ed2..7687962bdd9 100644
--- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -1,4 +1,4 @@
-use crate::utils::span_lint_and_sugg;
+use crate::utils::{in_macro, span_lint_and_sugg};
 use if_chain::if_chain;
 use rustc_ast::ast::{BindingMode, Lifetime, Mutability, Param, PatKind, Path, TyKind};
 use rustc_errors::Applicability;
@@ -69,11 +69,30 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
         if let [segment] = &path.segments[..];
         if segment.ident.name == kw::SelfUpper;
         then {
+            // In case we have a named lifetime, we check if the name comes from expansion.
+            // If it does, at this point we know the rest of the parameter was written by the user,
+            // so let them decide what the name of the lifetime should be.
+            // See #6089 for more details.
+            let mut applicability = Applicability::MachineApplicable;
             let self_param = match (binding_mode, mutbl) {
                 (Mode::Ref(None), Mutability::Mut) => "&mut self".to_string(),
-                (Mode::Ref(Some(lifetime)), Mutability::Mut) => format!("&{} mut self", &lifetime.ident.name),
+                (Mode::Ref(Some(lifetime)), Mutability::Mut) => {
+                    if in_macro(lifetime.ident.span) {
+                        applicability = Applicability::HasPlaceholders;
+                        "&'_ mut self".to_string()
+                    } else {
+                        format!("&{} mut self", &lifetime.ident.name)
+                    }
+                },
                 (Mode::Ref(None), Mutability::Not) => "&self".to_string(),
-                (Mode::Ref(Some(lifetime)), Mutability::Not) => format!("&{} self", &lifetime.ident.name),
+                (Mode::Ref(Some(lifetime)), Mutability::Not) => {
+                    if in_macro(lifetime.ident.span) {
+                        applicability = Applicability::HasPlaceholders;
+                        "&'_ self".to_string()
+                    } else {
+                        format!("&{} self", &lifetime.ident.name)
+                    }
+                },
                 (Mode::Value, Mutability::Mut) => "mut self".to_string(),
                 (Mode::Value, Mutability::Not) => "self".to_string(),
             };
@@ -85,7 +104,7 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
                 "the type of the `self` parameter does not need to be arbitrary",
                 "consider to change this parameter to",
                 self_param,
-                Applicability::MachineApplicable,
+                applicability,
             )
         }
     }
@@ -93,7 +112,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
 
 impl EarlyLintPass for NeedlessArbitrarySelfType {
     fn check_param(&mut self, cx: &EarlyContext<'_>, p: &Param) {
-        if !p.is_self() {
+        // Bail out if the parameter it's not a receiver or was not written by the user
+        if !p.is_self() || in_macro(p.span) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index bb44eeb6adc..7b662eae775 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -1,6 +1,6 @@
 //! Checks for uses of const which the type is not `Freeze` (`Cell`-free).
 //!
-//! This lint is **deny** by default.
+//! This lint is **warn** by default.
 
 use std::ptr;
 
@@ -17,6 +17,8 @@ use rustc_typeck::hir_ty_to_ty;
 use crate::utils::{in_constant, qpath_res, span_lint_and_then};
 use if_chain::if_chain;
 
+// FIXME: this is a correctness problem but there's no suitable
+// warn-by-default category.
 declare_clippy_lint! {
     /// **What it does:** Checks for declaration of `const` items which is interior
     /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.).
@@ -34,6 +36,15 @@ declare_clippy_lint! {
     /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit,
     /// and this lint should be suppressed.
     ///
+    /// When an enum has variants with interior mutability, use of its non interior mutable
+    /// variants can generate false positives. See issue
+    /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962)
+    ///
+    /// Types that have underlying or potential interior mutability trigger the lint whether
+    /// the interior mutable field is used or not. See issues
+    /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
+    /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
+    ///
     /// **Example:**
     /// ```rust
     /// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
@@ -49,10 +60,12 @@ declare_clippy_lint! {
     /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
     /// ```
     pub DECLARE_INTERIOR_MUTABLE_CONST,
-    correctness,
+    style,
     "declaring `const` with interior mutability"
 }
 
+// FIXME: this is a correctness problem but there's no suitable
+// warn-by-default category.
 declare_clippy_lint! {
     /// **What it does:** Checks if `const` items which is interior mutable (e.g.,
     /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly.
@@ -64,7 +77,14 @@ declare_clippy_lint! {
     ///
     /// The `const` value should be stored inside a `static` item.
     ///
-    /// **Known problems:** None
+    /// **Known problems:** When an enum has variants with interior mutability, use of its non
+    /// interior mutable variants can generate false positives. See issue
+    /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962)
+    ///
+    /// Types that have underlying or potential interior mutability trigger the lint whether
+    /// the interior mutable field is used or not. See issues
+    /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
+    /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
     ///
     /// **Example:**
     /// ```rust
@@ -81,7 +101,7 @@ declare_clippy_lint! {
     /// assert_eq!(STATIC_ATOM.load(SeqCst), 9); // use a `static` item to refer to the same instance
     /// ```
     pub BORROW_INTERIOR_MUTABLE_CONST,
-    correctness,
+    style,
     "referencing `const` with interior mutability"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index dfc158661cb..95594e38c9e 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -143,7 +143,7 @@ fn check_set<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
 
 fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
     let mut parser = regex_syntax::ParserBuilder::new()
-        .unicode(utf8)
+        .unicode(true)
         .allow_invalid_utf8(!utf8)
         .build();
 
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 15b66684eab..3783bd78de2 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -69,7 +69,27 @@ declare_clippy_lint! {
     /// **Why is this bad?** Byte string literals (e.g., `b"foo"`) can be used
     /// instead. They are shorter but less discoverable than `as_bytes()`.
     ///
-    /// **Known Problems:** None.
+    /// **Known Problems:**
+    /// `"str".as_bytes()` and the suggested replacement of `b"str"` are not
+    /// equivalent because they have different types. The former is `&[u8]`
+    /// while the latter is `&[u8; 3]`. That means in general they will have a
+    /// different set of methods and different trait implementations.
+    ///
+    /// ```compile_fail
+    /// fn f(v: Vec<u8>) {}
+    ///
+    /// f("...".as_bytes().to_owned()); // works
+    /// f(b"...".to_owned()); // does not work, because arg is [u8; 3] not Vec<u8>
+    ///
+    /// fn g(r: impl std::io::Read) {}
+    ///
+    /// g("...".as_bytes()); // works
+    /// g(b"..."); // does not work
+    /// ```
+    ///
+    /// The actual equivalent of `"str".as_bytes()` with the same type is not
+    /// `b"str"` but `&b"str"[..]`, which is a great deal of punctuation and not
+    /// more readable than a function call.
     ///
     /// **Example:**
     /// ```rust
@@ -80,7 +100,7 @@ declare_clippy_lint! {
     /// let bs = b"a byte string";
     /// ```
     pub STRING_LIT_AS_BYTES,
-    style,
+    nursery,
     "calling `as_bytes` on a string literal instead of using a byte string literal"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs b/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs
index 1f06d2dbe91..d92eb86fb2e 100644
--- a/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs
@@ -9,10 +9,10 @@ use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_session::config::Config as SessionConfig;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
 use rustc_target::abi::LayoutOf;
+use rustc_target::spec::Target;
 use rustc_target::spec::abi::Abi;
 
 declare_clippy_lint! {
@@ -60,9 +60,9 @@ pub struct TriviallyCopyPassByRef {
 }
 
 impl<'tcx> TriviallyCopyPassByRef {
-    pub fn new(limit: Option<u64>, target: &SessionConfig) -> Self {
+    pub fn new(limit: Option<u64>, target: &Target) -> Self {
         let limit = limit.unwrap_or_else(|| {
-            let bit_width = u64::from(target.ptr_width);
+            let bit_width = u64::from(target.pointer_width);
             // Cap the calculated bit width at 32-bits to reduce
             // portability problems between 32 and 64-bit targets
             let bit_width = cmp::min(bit_width, 32);
diff --git a/src/tools/clippy/clippy_lints/src/types.rs b/src/tools/clippy/clippy_lints/src/types.rs
index a29a199b8c3..5e83b6c81ec 100644
--- a/src/tools/clippy/clippy_lints/src/types.rs
+++ b/src/tools/clippy/clippy_lints/src/types.rs
@@ -216,18 +216,19 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for Rc<T> and Arc<T> when T is a mutable buffer type such as String or Vec
+    /// **What it does:** Checks for `Rc<T>` and `Arc<T>` when `T` is a mutable buffer type such as `String` or `Vec`.
     ///
-    /// **Why is this bad?** Expressions such as Rc<String> have no advantage over Rc<str>, since
-    /// it is larger and involves an extra level of indirection, and doesn't implement Borrow<str>.
+    /// **Why is this bad?** Expressions such as `Rc<String>` usually have no advantage over `Rc<str>`, since
+    /// it is larger and involves an extra level of indirection, and doesn't implement `Borrow<str>`.
     ///
-    /// While mutating a buffer type would still be possible with Rc::get_mut(), it only
-    /// works if there are no additional references yet, which defeats the purpose of
+    /// While mutating a buffer type would still be possible with `Rc::get_mut()`, it only
+    /// works if there are no additional references yet, which usually defeats the purpose of
     /// enclosing it in a shared ownership type. Instead, additionally wrapping the inner
-    /// type with an interior mutable container (such as RefCell or Mutex) would normally
+    /// type with an interior mutable container (such as `RefCell` or `Mutex`) would normally
     /// be used.
     ///
-    /// **Known problems:** None.
+    /// **Known problems:** This pattern can be desirable to avoid the overhead of a `RefCell` or `Mutex` for
+    /// cases where mutation only happens before there are any additional references.
     ///
     /// **Example:**
     /// ```rust,ignore
@@ -241,7 +242,7 @@ declare_clippy_lint! {
     /// fn foo(interned: Rc<str>) { ... }
     /// ```
     pub RC_BUFFER,
-    perf,
+    restriction,
     "shared ownership of a buffer type"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index d8c57f0e7ae..93d59cc7fcd 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -8,18 +8,18 @@ use rustc_span::source_map::Span;
 use unicode_normalization::UnicodeNormalization;
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for the Unicode zero-width space in the code.
+    /// **What it does:** Checks for invisible Unicode characters in the code.
     ///
     /// **Why is this bad?** Having an invisible character in the code makes for all
     /// sorts of April fools, but otherwise is very much frowned upon.
     ///
     /// **Known problems:** None.
     ///
-    /// **Example:** You don't see it, but there may be a zero-width space
-    /// somewhere in this text.
-    pub ZERO_WIDTH_SPACE,
+    /// **Example:** You don't see it, but there may be a zero-width space or soft hyphen
+    /// some­where in this text.
+    pub INVISIBLE_CHARACTERS,
     correctness,
-    "using a zero-width space in a string literal, which is confusing"
+    "using an invisible character in a string literal, which is confusing"
 }
 
 declare_clippy_lint! {
@@ -63,7 +63,7 @@ declare_clippy_lint! {
     "using a Unicode literal not in NFC normal form (see [Unicode tr15](http://www.unicode.org/reports/tr15/) for further information)"
 }
 
-declare_lint_pass!(Unicode => [ZERO_WIDTH_SPACE, NON_ASCII_LITERAL, UNICODE_NOT_NFC]);
+declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_NOT_NFC]);
 
 impl LateLintPass<'_> for Unicode {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
@@ -91,14 +91,17 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String {
 
 fn check_str(cx: &LateContext<'_>, span: Span, id: HirId) {
     let string = snippet(cx, span, "");
-    if string.contains('\u{200B}') {
+    if string.chars().any(|c| ['\u{200B}', '\u{ad}', '\u{2060}'].contains(&c)) {
         span_lint_and_sugg(
             cx,
-            ZERO_WIDTH_SPACE,
+            INVISIBLE_CHARACTERS,
             span,
-            "zero-width space detected",
+            "invisible character detected",
             "consider replacing the string with",
-            string.replace("\u{200B}", "\\u{200B}"),
+            string
+                .replace("\u{200B}", "\\u{200B}")
+                .replace("\u{ad}", "\\u{AD}")
+                .replace("\u{2060}", "\\u{2060}"),
             Applicability::MachineApplicable,
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
index 9b6a9075a29..1307237dbc7 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
@@ -170,22 +170,12 @@ fn mirrored_exprs(
 }
 
 fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
-    // NOTE: Vectors of references are not supported. In order to avoid hitting https://github.com/rust-lang/rust/issues/34162,
-    // (different unnamed lifetimes for closure arg and return type) we need to make sure the suggested
-    // closure parameter is not a reference in case we suggest `Reverse`. Trying to destructure more
-    // than one level of references would add some extra complexity as we would have to compensate
-    // in the closure body.
-
     if_chain! {
         if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
         if let name = name_ident.ident.name.to_ident_string();
         if name == "sort_by" || name == "sort_unstable_by";
         if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args;
-        let vec_ty = cx.typeck_results().expr_ty(vec);
-        if utils::is_type_diagnostic_item(cx, vec_ty, sym!(vec_type));
-        let ty = vec_ty.walk().nth(1).unwrap().expect_ty(); // T in Vec<T>
-        if !matches!(&ty.kind(), ty::Ref(..));
-        if utils::is_copy(cx, ty);
+        if utils::is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym!(vec_type));
         if let closure_body = cx.tcx.hir().body(*closure_body_id);
         if let &[
             Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..},
@@ -210,40 +200,32 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
             let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
             let unstable = name == "sort_unstable_by";
 
-            if_chain! {
-                if let ExprKind::Path(QPath::Resolved(_, Path {
-                    segments: [PathSegment { ident: left_name, .. }], ..
-                })) = &left_expr.kind;
-                if left_name == left_ident;
-                then {
-                    return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }))
-                } else {
-                    if !key_returns_borrow(cx, left_expr) {
-                        return Some(LintTrigger::SortByKey(SortByKeyDetection {
-                            vec_name,
-                            unstable,
-                            closure_arg,
-                            closure_body,
-                            reverse
-                        }))
-                    }
+            if let ExprKind::Path(QPath::Resolved(_, Path {
+                segments: [PathSegment { ident: left_name, .. }], ..
+            })) = &left_expr.kind {
+                if left_name == left_ident {
+                    return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }));
                 }
             }
+
+            if !expr_borrows(cx, left_expr) {
+                return Some(LintTrigger::SortByKey(SortByKeyDetection {
+                    vec_name,
+                    unstable,
+                    closure_arg,
+                    closure_body,
+                    reverse
+                }));
+            }
         }
     }
 
     None
 }
 
-fn key_returns_borrow(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    if let Some(def_id) = utils::fn_def_id(cx, expr) {
-        let output = cx.tcx.fn_sig(def_id).output();
-        let ty = output.skip_binder();
-        return matches!(ty.kind(), ty::Ref(..))
-            || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
-    }
-
-    false
+fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.typeck_results().expr_ty(expr);
+    matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
 }
 
 impl LateLintPass<'_> for UnnecessarySortBy {
@@ -256,7 +238,7 @@ impl LateLintPass<'_> for UnnecessarySortBy {
                 "use Vec::sort_by_key here instead",
                 "try",
                 format!(
-                    "{}.sort{}_by_key(|&{}| {})",
+                    "{}.sort{}_by_key(|{}| {})",
                     trigger.vec_name,
                     if trigger.unstable { "_unstable" } else { "" },
                     trigger.closure_arg,
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 9c5a12ea9c8..dd2fd0bb445 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -2,10 +2,10 @@
 
 #![deny(clippy::missing_docs_in_private_items)]
 
-use lazy_static::lazy_static;
 use rustc_ast::ast::{LitKind, MetaItemKind, NestedMetaItem};
 use rustc_span::source_map;
 use source_map::Span;
+use std::lazy::SyncLazy;
 use std::path::{Path, PathBuf};
 use std::sync::Mutex;
 use std::{env, fmt, fs, io};
@@ -54,9 +54,8 @@ impl From<io::Error> for Error {
     }
 }
 
-lazy_static! {
-    static ref ERRORS: Mutex<Vec<Error>> = Mutex::new(Vec::new());
-}
+/// Vec of errors that might be collected during config toml parsing
+static ERRORS: SyncLazy<Mutex<Vec<Error>>> = SyncLazy::new(|| Mutex::new(Vec::new()));
 
 macro_rules! define_Conf {
     ($(#[$doc:meta] ($config:ident, $config_str:literal: $Ty:ty, $default:expr),)+) => {
@@ -82,6 +81,7 @@ macro_rules! define_Conf {
                     use serde::Deserialize;
                     pub fn deserialize<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<$Ty, D::Error> {
                         use super::super::{ERRORS, Error};
+
                         Ok(
                             <$Ty>::deserialize(deserializer).unwrap_or_else(|e| {
                                 ERRORS
@@ -164,6 +164,8 @@ define_Conf! {
     (max_fn_params_bools, "max_fn_params_bools": u64, 3),
     /// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
     (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false),
+    /// Lint: DISALLOWED_METHOD. The list of blacklisted methods to lint about. NB: `bar` is not here since it has legitimate uses
+    (disallowed_methods, "disallowed_methods": Vec<String>, Vec::<String>::new()),
 }
 
 impl Default for Conf {
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 247effde19b..790ac4f7dd8 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -18,9 +18,9 @@ pub mod internal_lints;
 pub mod numeric_literal;
 pub mod paths;
 pub mod ptr;
+pub mod qualify_min_const_fn;
 pub mod sugg;
 pub mod usage;
-pub mod qualify_min_const_fn;
 
 pub use self::attrs::*;
 pub use self::diagnostics::*;
@@ -47,7 +47,6 @@ use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable};
-use rustc_mir::const_eval;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::symbol::{self, kw, Symbol};
@@ -884,19 +883,11 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 
 /// Checks if an expression is constructing a tuple-like enum variant or struct
 pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    fn has_no_arguments(cx: &LateContext<'_>, def_id: DefId) -> bool {
-        cx.tcx.fn_sig(def_id).skip_binder().inputs().is_empty()
-    }
-
     if let ExprKind::Call(ref fun, _) = expr.kind {
         if let ExprKind::Path(ref qp) = fun.kind {
             let res = cx.qpath_res(qp, fun.hir_id);
             return match res {
                 def::Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
-                // FIXME: check the constness of the arguments, see https://github.com/rust-lang/rust-clippy/pull/5682#issuecomment-638681210
-                def::Res::Def(DefKind::Fn | DefKind::AssocFn, def_id) if has_no_arguments(cx, def_id) => {
-                    const_eval::is_const_fn(cx.tcx, def_id)
-                },
                 def::Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
                 _ => false,
             };
@@ -1287,8 +1278,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::Opaque(ref def_id, _) => {
             for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
                 if let ty::PredicateAtom::Trait(trait_predicate, _) = predicate.skip_binders() {
-                    if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some()
-                    {
+                    if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
                         return true;
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs b/src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs
index 5e8800d38eb..52d3c2c1daf 100644
--- a/src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/numeric_literal.rs
@@ -36,8 +36,9 @@ pub struct NumericLiteral<'a> {
     pub integer: &'a str,
     /// The fraction part of the number.
     pub fraction: Option<&'a str>,
-    /// The character used as exponent separator (b'e' or b'E') and the exponent part.
-    pub exponent: Option<(char, &'a str)>,
+    /// The exponent separator (b'e' or b'E') including preceding underscore if present
+    /// and the exponent part.
+    pub exponent: Option<(&'a str, &'a str)>,
 
     /// The type suffix, including preceding underscore if present.
     pub suffix: Option<&'a str>,
@@ -100,7 +101,7 @@ impl<'a> NumericLiteral<'a> {
         self.radix == Radix::Decimal
     }
 
-    pub fn split_digit_parts(digits: &str, float: bool) -> (&str, Option<&str>, Option<(char, &str)>) {
+    pub fn split_digit_parts(digits: &str, float: bool) -> (&str, Option<&str>, Option<(&str, &str)>) {
         let mut integer = digits;
         let mut fraction = None;
         let mut exponent = None;
@@ -113,12 +114,14 @@ impl<'a> NumericLiteral<'a> {
                         fraction = Some(&digits[i + 1..]);
                     },
                     'e' | 'E' => {
-                        if integer.len() > i {
-                            integer = &digits[..i];
+                        let exp_start = if digits[..i].ends_with('_') { i - 1 } else { i };
+
+                        if integer.len() > exp_start {
+                            integer = &digits[..exp_start];
                         } else {
-                            fraction = Some(&digits[integer.len() + 1..i]);
+                            fraction = Some(&digits[integer.len() + 1..exp_start]);
                         };
-                        exponent = Some((c, &digits[i + 1..]));
+                        exponent = Some((&digits[exp_start..=i], &digits[i + 1..]));
                         break;
                     },
                     _ => {},
@@ -153,7 +156,7 @@ impl<'a> NumericLiteral<'a> {
         }
 
         if let Some((separator, exponent)) = self.exponent {
-            output.push(separator);
+            output.push_str(separator);
             Self::group_digits(&mut output, exponent, group_size, true, false);
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/paths.rs b/src/tools/clippy/clippy_lints/src/utils/paths.rs
index be837a61dc0..277da9d3f3a 100644
--- a/src/tools/clippy/clippy_lints/src/utils/paths.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/paths.rs
@@ -41,6 +41,9 @@ pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
 pub const FMT_ARGUMENTS_NEW_V1: [&str; 4] = ["core", "fmt", "Arguments", "new_v1"];
 pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments", "new_v1_formatted"];
 pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
+pub const FN: [&str; 3] = ["core", "ops", "Fn"];
+pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"];
+pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"];
 pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
 pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
 pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
diff --git a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs
index 19d890b4554..7cb7d0a26b6 100644
--- a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs
@@ -1,9 +1,12 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_middle::mir::*;
+use rustc_middle::mir::{
+    Body, CastKind, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
+    TerminatorKind,
+};
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
-use rustc_span::symbol::{sym};
+use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi::RustIntrinsic;
 use std::borrow::Cow;
@@ -24,15 +27,9 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>) -> McfResult {
                 | ty::PredicateAtom::ConstEvaluatable(..)
                 | ty::PredicateAtom::ConstEquate(..)
                 | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue,
-                ty::PredicateAtom::ObjectSafe(_) => {
-                    panic!("object safe predicate on function: {:#?}", predicate)
-                }
-                ty::PredicateAtom::ClosureKind(..) => {
-                    panic!("closure kind predicate on function: {:#?}", predicate)
-                }
-                ty::PredicateAtom::Subtype(_) => {
-                    panic!("subtype predicate on function: {:#?}", predicate)
-                }
+                ty::PredicateAtom::ObjectSafe(_) => panic!("object safe predicate on function: {:#?}", predicate),
+                ty::PredicateAtom::ClosureKind(..) => panic!("closure kind predicate on function: {:#?}", predicate),
+                ty::PredicateAtom::Subtype(_) => panic!("subtype predicate on function: {:#?}", predicate),
                 ty::PredicateAtom::Trait(pred, _) => {
                     if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                         continue;
@@ -48,12 +45,12 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>) -> McfResult {
                                  on const fn parameters are unstable"
                                     .into(),
                             ));
-                        }
+                        },
                         // other kinds of bounds are either tautologies
                         // or cause errors in other passes
                         _ => continue,
                     }
-                }
+                },
             }
         }
         match predicates.parent {
@@ -93,24 +90,23 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
 
         match ty.kind() {
             ty::Ref(_, _, hir::Mutability::Mut) => {
-                    return Err((span, "mutable references in const fn are unstable".into()));
-            }
+                return Err((span, "mutable references in const fn are unstable".into()));
+            },
             ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
             ty::FnPtr(..) => {
-                    return Err((span, "function pointers in const fn are unstable".into()));
-            }
+                return Err((span, "function pointers in const fn are unstable".into()));
+            },
             ty::Dynamic(preds, _) => {
                 for pred in preds.iter() {
                     match pred.skip_binder() {
-                        ty::ExistentialPredicate::AutoTrait(_)
-                        | ty::ExistentialPredicate::Projection(_) => {
+                        ty::ExistentialPredicate::AutoTrait(_) | ty::ExistentialPredicate::Projection(_) => {
                             return Err((
                                 span,
                                 "trait bounds other than `Sized` \
                                  on const fn parameters are unstable"
                                     .into(),
                             ));
-                        }
+                        },
                         ty::ExistentialPredicate::Trait(trait_ref) => {
                             if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
                                 return Err((
@@ -120,34 +116,23 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
                                         .into(),
                                 ));
                             }
-                        }
+                        },
                     }
                 }
-            }
-            _ => {}
+            },
+            _ => {},
         }
     }
     Ok(())
 }
 
-fn check_rvalue(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    def_id: DefId,
-    rvalue: &Rvalue<'tcx>,
-    span: Span,
-) -> McfResult {
+fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rvalue<'tcx>, span: Span) -> McfResult {
     match rvalue {
-        Rvalue::ThreadLocalRef(_) => {
-            Err((span, "cannot access thread local storage in const fn".into()))
-        }
-        Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
-            check_operand(tcx, operand, span, body)
-        }
-        Rvalue::Len(place)
-        | Rvalue::Discriminant(place)
-        | Rvalue::Ref(_, _, place)
-        | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span,  body),
+        Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
+        Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => check_operand(tcx, operand, span, body),
+        Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
+            check_place(tcx, *place, span, body)
+        },
         Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
             use rustc_middle::ty::cast::CastTy;
             let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast");
@@ -155,20 +140,16 @@ fn check_rvalue(
             match (cast_in, cast_out) {
                 (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
                     Err((span, "casting pointers to ints is unstable in const fn".into()))
-                }
+                },
                 _ => check_operand(tcx, operand, span, body),
             }
-        }
-        Rvalue::Cast(
-            CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer),
-            operand,
-            _,
-        ) => check_operand(tcx, operand, span, body),
+        },
+        Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), operand, _) => {
+            check_operand(tcx, operand, span, body)
+        },
         Rvalue::Cast(
             CastKind::Pointer(
-                PointerCast::UnsafeFnPointer
-                | PointerCast::ClosureFnPointer(_)
-                | PointerCast::ReifyFnPointer,
+                PointerCast::UnsafeFnPointer | PointerCast::ClosureFnPointer(_) | PointerCast::ReifyFnPointer,
             ),
             _,
             _,
@@ -178,10 +159,7 @@ fn check_rvalue(
                 deref_ty.ty
             } else {
                 // We cannot allow this for now.
-                return Err((
-                    span,
-                    "unsizing casts are only allowed for references right now".into(),
-                ));
+                return Err((span, "unsizing casts are only allowed for references right now".into()));
             };
             let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id));
             if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
@@ -192,7 +170,7 @@ fn check_rvalue(
                 // We just can't allow trait objects until we have figured out trait method calls.
                 Err((span, "unsizing casts are not allowed in const fn".into()))
             }
-        }
+        },
         // binops are fine on integers
         Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
             check_operand(tcx, lhs, span, body)?;
@@ -201,13 +179,14 @@ fn check_rvalue(
             if ty.is_integral() || ty.is_bool() || ty.is_char() {
                 Ok(())
             } else {
-                Err((span, "only int, `bool` and `char` operations are stable in const fn".into()))
+                Err((
+                    span,
+                    "only int, `bool` and `char` operations are stable in const fn".into(),
+                ))
             }
-        }
+        },
         Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()),
-        Rvalue::NullaryOp(NullOp::Box, _) => {
-            Err((span, "heap allocations are not allowed in const fn".into()))
-        }
+        Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())),
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
             if ty.is_integral() || ty.is_bool() {
@@ -215,39 +194,29 @@ fn check_rvalue(
             } else {
                 Err((span, "only int and `bool` operations are stable in const fn".into()))
             }
-        }
+        },
         Rvalue::Aggregate(_, operands) => {
             for operand in operands {
                 check_operand(tcx, operand, span, body)?;
             }
             Ok(())
-        }
+        },
     }
 }
 
-fn check_statement(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    def_id: DefId,
-    statement: &Statement<'tcx>,
-) -> McfResult {
+fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statement: &Statement<'tcx>) -> McfResult {
     let span = statement.source_info.span;
     match &statement.kind {
         StatementKind::Assign(box (place, rval)) => {
-            check_place(tcx, *place, span,  body)?;
+            check_place(tcx, *place, span, body)?;
             check_rvalue(tcx, body, def_id, rval, span)
-        }
-
-        StatementKind::FakeRead(_, place) => check_place(tcx, **place, span, body),
+        },
 
+        StatementKind::FakeRead(_, place) |
         // just an assignment
-        StatementKind::SetDiscriminant { place, .. } => {
-            check_place(tcx, **place, span,  body)
-        }
+        StatementKind::SetDiscriminant { place, .. } => check_place(tcx, **place, span, body),
 
-        StatementKind::LlvmInlineAsm { .. } => {
-            Err((span, "cannot use inline assembly in const fn".into()))
-        }
+        StatementKind::LlvmInlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
 
         // These are all NOPs
         StatementKind::StorageLive(_)
@@ -259,12 +228,7 @@ fn check_statement(
     }
 }
 
-fn check_operand(
-    tcx: TyCtxt<'tcx>,
-    operand: &Operand<'tcx>,
-    span: Span,
-    body: &Body<'tcx>,
-) -> McfResult {
+fn check_operand(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
     match operand {
         Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body),
         Operand::Constant(c) => match c.check_static_ptr(tcx) {
@@ -274,14 +238,9 @@ fn check_operand(
     }
 }
 
-fn check_place(
-    tcx: TyCtxt<'tcx>,
-    place: Place<'tcx>,
-    span: Span,
-    body: &Body<'tcx>,
-) -> McfResult {
+fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
     let mut cursor = place.projection.as_ref();
-    while let &[ref proj_base @ .., elem] = cursor {
+    while let [ref proj_base @ .., elem] = *cursor {
         cursor = proj_base;
         match elem {
             ProjectionElem::Field(..) => {
@@ -289,26 +248,22 @@ fn check_place(
                 if let Some(def) = base_ty.ty_adt_def() {
                     // No union field accesses in `const fn`
                     if def.is_union() {
-                            return Err((span, "accessing union fields is unstable".into()));
+                        return Err((span, "accessing union fields is unstable".into()));
                     }
                 }
-            }
+            },
             ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::Downcast(..)
             | ProjectionElem::Subslice { .. }
             | ProjectionElem::Deref
-            | ProjectionElem::Index(_) => {}
+            | ProjectionElem::Index(_) => {},
         }
     }
 
     Ok(())
 }
 
-fn check_terminator(
-    tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
-    terminator: &Terminator<'tcx>,
-) -> McfResult {
+fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Terminator<'tcx>) -> McfResult {
     let span = terminator.source_info.span;
     match &terminator.kind {
         TerminatorKind::FalseEdge { .. }
@@ -318,20 +273,22 @@ fn check_terminator(
         | TerminatorKind::Resume
         | TerminatorKind::Unreachable => Ok(()),
 
-        TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span,  body),
+        TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, body),
         TerminatorKind::DropAndReplace { place, value, .. } => {
-            check_place(tcx, *place, span,  body)?;
+            check_place(tcx, *place, span, body)?;
             check_operand(tcx, value, span, body)
-        }
+        },
 
-        TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => {
-            check_operand(tcx, discr, span, body)
-        }
+        TerminatorKind::SwitchInt {
+            discr,
+            switch_ty: _,
+            targets: _,
+        } => check_operand(tcx, discr, span, body),
 
         TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())),
         TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
             Err((span, "const fn generators are unstable".into()))
-        }
+        },
 
         TerminatorKind::Call {
             func,
@@ -343,8 +300,7 @@ fn check_terminator(
         } => {
             let fn_ty = func.ty(body, tcx);
             if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
-                if !rustc_mir::const_eval::is_min_const_fn(tcx, fn_def_id)
-                {
+                if !rustc_mir::const_eval::is_min_const_fn(tcx, fn_def_id) {
                     return Err((
                         span,
                         format!(
@@ -360,9 +316,7 @@ fn check_terminator(
                 // within const fns. `transmute` is allowed in all other const contexts.
                 // This won't really scale to more intrinsics or functions. Let's allow const
                 // transmutes in const fn before we add more hacks to this.
-                if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic
-                    && tcx.item_name(fn_def_id) == sym::transmute
-                {
+                if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic && tcx.item_name(fn_def_id) == sym::transmute {
                     return Err((
                         span,
                         "can only call `transmute` from const items, not `const fn`".into(),
@@ -378,14 +332,16 @@ fn check_terminator(
             } else {
                 Err((span, "can only call other const fns within const fn".into()))
             }
-        }
+        },
 
-        TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => {
-            check_operand(tcx, cond, span, body)
-        }
+        TerminatorKind::Assert {
+            cond,
+            expected: _,
+            msg: _,
+            target: _,
+            cleanup: _,
+        } => check_operand(tcx, cond, span, body),
 
-        TerminatorKind::InlineAsm { .. } => {
-            Err((span, "cannot use inline assembly in const fn".into()))
-        }
+        TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index fac63bcb993..d9d60fffcd7 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -235,8 +235,19 @@ impl EarlyLintPass for Write {
     }
 
     fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
+        fn is_build_script(cx: &EarlyContext<'_>) -> bool {
+            // Cargo sets the crate name for build scripts to `build_script_build`
+            cx.sess
+                .opts
+                .crate_name
+                .as_ref()
+                .map_or(false, |crate_name| crate_name == "build_script_build")
+        }
+
         if mac.path == sym!(println) {
-            span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
+            if !is_build_script(cx) {
+                span_lint(cx, PRINT_STDOUT, mac.span(), "use of `println!`");
+            }
             if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
                 if fmt_str.symbol == Symbol::intern("") {
                     span_lint_and_sugg(
@@ -251,7 +262,9 @@ impl EarlyLintPass for Write {
                 }
             }
         } else if mac.path == sym!(print) {
-            span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
+            if !is_build_script(cx) {
+                span_lint(cx, PRINT_STDOUT, mac.span(), "use of `print!`");
+            }
             if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), false) {
                 if check_newlines(&fmt_str) {
                     span_lint_and_then(
diff --git a/src/tools/clippy/clippy_workspace_tests/build.rs b/src/tools/clippy/clippy_workspace_tests/build.rs
new file mode 100644
index 00000000000..3507168a3a9
--- /dev/null
+++ b/src/tools/clippy/clippy_workspace_tests/build.rs
@@ -0,0 +1,7 @@
+#![deny(clippy::print_stdout)]
+
+fn main() {
+    // Test for #6041
+    println!("Hello");
+    print!("Hello");
+}
diff --git a/src/tools/clippy/doc/adding_lints.md b/src/tools/clippy/doc/adding_lints.md
index 21e0f6f4fc7..2869c3bf7d4 100644
--- a/src/tools/clippy/doc/adding_lints.md
+++ b/src/tools/clippy/doc/adding_lints.md
@@ -189,7 +189,8 @@ declare_clippy_lint! {
 
 * The section of lines prefixed with `///` constitutes the lint documentation
   section. This is the default documentation style and will be displayed
-  [like this][example_lint_page].
+  [like this][example_lint_page]. To render and open this documentation locally
+  in a browser, run `cargo dev serve`.
 * `FOO_FUNCTIONS` is the name of our lint. Be sure to follow the
   [lint naming guidelines][lint_naming] here when naming your lint.
   In short, the name should state the thing that is being checked for and
diff --git a/src/tools/clippy/doc/basics.md b/src/tools/clippy/doc/basics.md
index c81e7f6e069..38959e2331b 100644
--- a/src/tools/clippy/doc/basics.md
+++ b/src/tools/clippy/doc/basics.md
@@ -13,6 +13,7 @@ Lints] or [Common Tools].
   - [Setup](#setup)
   - [Building and Testing](#building-and-testing)
   - [`cargo dev`](#cargo-dev)
+  - [PR](#pr)
 
 ## Get the Code
 
@@ -110,3 +111,8 @@ cargo dev new_lint
 # (experimental) Setup Clippy to work with rust-analyzer
 cargo dev ra-setup
 ```
+
+## PR
+
+We follow a rustc no merge-commit policy.
+See <https://rustc-dev-guide.rust-lang.org/contributing.html#opening-a-pr>.
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index f4f2259cefd..805828eece1 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -277,9 +277,9 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
     // If backtraces are enabled, also print the query stack
     let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
 
-    if backtrace {
-        TyCtxt::try_print_query_stack(&handler);
-    }
+    let num_frames = if backtrace { None } else { Some(2) };
+
+    TyCtxt::try_print_query_stack(&handler, num_frames);
 }
 
 fn toolchain_path(home: Option<String>, toolchain: Option<String>) -> Option<PathBuf> {
@@ -357,7 +357,7 @@ pub fn main() {
                 args.extend(vec!["--sysroot".into(), sys_root]);
             };
 
-            return rustc_driver::run_compiler(&args, &mut DefaultCallbacks, None, None, None);
+            return rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run();
         }
 
         if orig_args.iter().any(|a| a == "--version" || a == "-V") {
@@ -420,6 +420,6 @@ pub fn main() {
         let mut default = DefaultCallbacks;
         let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
             if clippy_enabled { &mut clippy } else { &mut default };
-        rustc_driver::run_compiler(&args, callbacks, None, None, None)
+        rustc_driver::RunCompiler::new(&args, callbacks).run()
     }))
 }
diff --git a/src/tools/clippy/src/lintlist/mod.rs b/src/tools/clippy/src/lintlist/mod.rs
index f6d529de9a3..ce3d0efab3a 100644
--- a/src/tools/clippy/src/lintlist/mod.rs
+++ b/src/tools/clippy/src/lintlist/mod.rs
@@ -110,7 +110,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
     },
     Lint {
         name: "borrow_interior_mutable_const",
-        group: "correctness",
+        group: "style",
         desc: "referencing `const` with interior mutability",
         deprecation: None,
         module: "non_copy_const",
@@ -334,7 +334,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
     },
     Lint {
         name: "declare_interior_mutable_const",
-        group: "correctness",
+        group: "style",
         desc: "declaring `const` with interior mutability",
         deprecation: None,
         module: "non_copy_const",
@@ -382,6 +382,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "derive",
     },
     Lint {
+        name: "disallowed_method",
+        group: "nursery",
+        desc: "use of a disallowed method call",
+        deprecation: None,
+        module: "disallowed_method",
+    },
+    Lint {
         name: "diverging_sub_expression",
         group: "complexity",
         desc: "whether an expression contains a diverging sub expression",
@@ -886,6 +893,20 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "attrs",
     },
     Lint {
+        name: "inline_asm_x86_att_syntax",
+        group: "restriction",
+        desc: "prefer Intel x86 assembly syntax",
+        deprecation: None,
+        module: "asm_syntax",
+    },
+    Lint {
+        name: "inline_asm_x86_intel_syntax",
+        group: "restriction",
+        desc: "prefer AT&T x86 assembly syntax",
+        deprecation: None,
+        module: "asm_syntax",
+    },
+    Lint {
         name: "inline_fn_without_body",
         group: "correctness",
         desc: "use of `#[inline]` on trait methods without bodies",
@@ -942,6 +963,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "types",
     },
     Lint {
+        name: "invisible_characters",
+        group: "correctness",
+        desc: "using an invisible character in a string literal, which is confusing",
+        deprecation: None,
+        module: "unicode",
+    },
+    Lint {
         name: "items_after_statements",
         group: "pedantic",
         desc: "blocks where an item comes after a statement",
@@ -1860,7 +1888,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
     },
     Lint {
         name: "rc_buffer",
-        group: "perf",
+        group: "restriction",
         desc: "shared ownership of a buffer type",
         deprecation: None,
         module: "types",
@@ -2133,7 +2161,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
     },
     Lint {
         name: "string_lit_as_bytes",
-        group: "style",
+        group: "nursery",
         desc: "calling `as_bytes` on a string literal instead of using a byte string literal",
         deprecation: None,
         module: "strings",
@@ -2783,13 +2811,6 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "misc",
     },
     Lint {
-        name: "zero_width_space",
-        group: "correctness",
-        desc: "using a zero-width space in a string literal, which is confusing",
-        deprecation: None,
-        module: "unicode",
-    },
-    Lint {
         name: "zst_offset",
         group: "correctness",
         desc: "Check for offset calculations on raw pointers to zero-sized types",
diff --git a/src/tools/clippy/tests/cargo/mod.rs b/src/tools/clippy/tests/cargo/mod.rs
index 3c385343f70..a8f3e3145f6 100644
--- a/src/tools/clippy/tests/cargo/mod.rs
+++ b/src/tools/clippy/tests/cargo/mod.rs
@@ -1,27 +1,24 @@
-use lazy_static::lazy_static;
 use std::env;
+use std::lazy::SyncLazy;
 use std::path::PathBuf;
 
-lazy_static! {
-    pub static ref CARGO_TARGET_DIR: PathBuf = {
-        match env::var_os("CARGO_TARGET_DIR") {
-            Some(v) => v.into(),
-            None => env::current_dir().unwrap().join("target"),
-        }
-    };
-    pub static ref TARGET_LIB: PathBuf = {
-        if let Some(path) = option_env!("TARGET_LIBS") {
-            path.into()
-        } else {
-            let mut dir = CARGO_TARGET_DIR.clone();
-            if let Some(target) = env::var_os("CARGO_BUILD_TARGET") {
-                dir.push(target);
-            }
-            dir.push(env!("PROFILE"));
-            dir
+pub static CARGO_TARGET_DIR: SyncLazy<PathBuf> = SyncLazy::new(|| match env::var_os("CARGO_TARGET_DIR") {
+    Some(v) => v.into(),
+    None => env::current_dir().unwrap().join("target"),
+});
+
+pub static TARGET_LIB: SyncLazy<PathBuf> = SyncLazy::new(|| {
+    if let Some(path) = option_env!("TARGET_LIBS") {
+        path.into()
+    } else {
+        let mut dir = CARGO_TARGET_DIR.clone();
+        if let Some(target) = env::var_os("CARGO_BUILD_TARGET") {
+            dir.push(target);
         }
-    };
-}
+        dir.push(env!("PROFILE"));
+        dir
+    }
+});
 
 #[must_use]
 pub fn is_rustc_test_suite() -> bool {
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 697823712bf..0e8f7683103 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -1,4 +1,5 @@
 #![feature(test)] // compiletest_rs requires this attribute
+#![feature(once_cell)]
 
 use compiletest_rs as compiletest;
 use compiletest_rs::common::Mode as TestMode;
@@ -71,7 +72,7 @@ fn default_config() -> compiletest::Config {
     }
 
     config.target_rustcflags = Some(format!(
-        "-L {0} -L {1} -Dwarnings -Zui-testing {2}",
+        "--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}",
         host_lib().join("deps").display(),
         cargo::TARGET_LIB.join("deps").display(),
         third_party_crates(),
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 81af3d3033b..48e0478f169 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -1,15 +1,14 @@
 // Dogfood cannot run on Windows
 #![cfg(not(windows))]
+#![feature(once_cell)]
 
-use lazy_static::lazy_static;
+use std::lazy::SyncLazy;
 use std::path::PathBuf;
 use std::process::Command;
 
 mod cargo;
 
-lazy_static! {
-    static ref CLIPPY_PATH: PathBuf = cargo::TARGET_LIB.join("cargo-clippy");
-}
+static CLIPPY_PATH: SyncLazy<PathBuf> = SyncLazy::new(|| cargo::TARGET_LIB.join("cargo-clippy"));
 
 #[test]
 fn dogfood_clippy() {
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml
new file mode 100644
index 00000000000..a1f515e443d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/clippy.toml
@@ -0,0 +1 @@
+disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match"]
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs
new file mode 100644
index 00000000000..3d3f0729abd
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.rs
@@ -0,0 +1,13 @@
+#![warn(clippy::disallowed_method)]
+
+extern crate regex;
+use regex::Regex;
+
+fn main() {
+    let a = vec![1, 2, 3, 4];
+    let re = Regex::new(r"ab.*c").unwrap();
+
+    re.is_match("abc");
+
+    a.iter().sum::<i32>();
+}
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr
new file mode 100644
index 00000000000..ed91b5a6796
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_method/conf_disallowed_method.stderr
@@ -0,0 +1,16 @@
+error: use of a disallowed method `regex::re_unicode::Regex::is_match`
+  --> $DIR/conf_disallowed_method.rs:10:5
+   |
+LL |     re.is_match("abc");
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::disallowed-method` implied by `-D warnings`
+
+error: use of a disallowed method `core::iter::traits::iterator::Iterator::sum`
+  --> $DIR/conf_disallowed_method.rs:12:5
+   |
+LL |     a.iter().sum::<i32>();
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 6fbba01416a..103ec27e7d7 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `third-party` at line 5 column 1
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui/asm_syntax.rs b/src/tools/clippy/tests/ui/asm_syntax.rs
new file mode 100644
index 00000000000..658cae397e1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/asm_syntax.rs
@@ -0,0 +1,31 @@
+#![feature(asm)]
+// only-x86_64
+
+#[warn(clippy::inline_asm_x86_intel_syntax)]
+mod warn_intel {
+    pub(super) unsafe fn use_asm() {
+        asm!("");
+        asm!("", options());
+        asm!("", options(nostack));
+        asm!("", options(att_syntax));
+        asm!("", options(nostack, att_syntax));
+    }
+}
+
+#[warn(clippy::inline_asm_x86_att_syntax)]
+mod warn_att {
+    pub(super) unsafe fn use_asm() {
+        asm!("");
+        asm!("", options());
+        asm!("", options(nostack));
+        asm!("", options(att_syntax));
+        asm!("", options(nostack, att_syntax));
+    }
+}
+
+fn main() {
+    unsafe {
+        warn_att::use_asm();
+        warn_intel::use_asm();
+    }
+}
diff --git a/src/tools/clippy/tests/ui/asm_syntax.stderr b/src/tools/clippy/tests/ui/asm_syntax.stderr
new file mode 100644
index 00000000000..27b51166eac
--- /dev/null
+++ b/src/tools/clippy/tests/ui/asm_syntax.stderr
@@ -0,0 +1,44 @@
+error: Intel x86 assembly syntax used
+  --> $DIR/asm_syntax.rs:7:9
+   |
+LL |         asm!("");
+   |         ^^^^^^^^^
+   |
+   = note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings`
+   = help: use AT&T x86 assembly syntax
+
+error: Intel x86 assembly syntax used
+  --> $DIR/asm_syntax.rs:8:9
+   |
+LL |         asm!("", options());
+   |         ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use AT&T x86 assembly syntax
+
+error: Intel x86 assembly syntax used
+  --> $DIR/asm_syntax.rs:9:9
+   |
+LL |         asm!("", options(nostack));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use AT&T x86 assembly syntax
+
+error: AT&T x86 assembly syntax used
+  --> $DIR/asm_syntax.rs:21:9
+   |
+LL |         asm!("", options(att_syntax));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings`
+   = help: use Intel x86 assembly syntax
+
+error: AT&T x86 assembly syntax used
+  --> $DIR/asm_syntax.rs:22:9
+   |
+LL |         asm!("", options(nostack, att_syntax));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use Intel x86 assembly syntax
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/attrs.rs b/src/tools/clippy/tests/ui/attrs.rs
index 32685038067..8df6e19421e 100644
--- a/src/tools/clippy/tests/ui/attrs.rs
+++ b/src/tools/clippy/tests/ui/attrs.rs
@@ -1,8 +1,5 @@
 #![warn(clippy::inline_always, clippy::deprecated_semver)]
 #![allow(clippy::assertions_on_constants)]
-// Test that the whole restriction group is not enabled
-#![warn(clippy::restriction)]
-#![deny(clippy::restriction)]
 #![allow(clippy::missing_docs_in_private_items, clippy::panic, clippy::unreachable)]
 
 #[inline(always)]
diff --git a/src/tools/clippy/tests/ui/attrs.stderr b/src/tools/clippy/tests/ui/attrs.stderr
index 4324984dd60..df4e9e20b64 100644
--- a/src/tools/clippy/tests/ui/attrs.stderr
+++ b/src/tools/clippy/tests/ui/attrs.stderr
@@ -1,5 +1,5 @@
 error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea
-  --> $DIR/attrs.rs:8:1
+  --> $DIR/attrs.rs:5:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | #[inline(always)]
    = note: `-D clippy::inline-always` implied by `-D warnings`
 
 error: the since field must contain a semver-compliant version
-  --> $DIR/attrs.rs:28:14
+  --> $DIR/attrs.rs:25:14
    |
 LL | #[deprecated(since = "forever")]
    |              ^^^^^^^^^^^^^^^^^
@@ -15,27 +15,10 @@ LL | #[deprecated(since = "forever")]
    = note: `-D clippy::deprecated-semver` implied by `-D warnings`
 
 error: the since field must contain a semver-compliant version
-  --> $DIR/attrs.rs:31:14
+  --> $DIR/attrs.rs:28:14
    |
 LL | #[deprecated(since = "1")]
    |              ^^^^^^^^^^^
 
-error: restriction lints are not meant to be all enabled
-  --> $DIR/attrs.rs:4:9
-   |
-LL | #![warn(clippy::restriction)]
-   |         ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
-   = help: try enabling only the lints you really need
-
-error: restriction lints are not meant to be all enabled
-  --> $DIR/attrs.rs:5:9
-   |
-LL | #![deny(clippy::restriction)]
-   |         ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: try enabling only the lints you really need
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
index e6626d57a77..de670cdfc31 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs
@@ -1,7 +1,8 @@
+// compile-flags: --emit=link
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
-#![feature(repr128, proc_macro_hygiene, proc_macro_quote)]
+#![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)]
 #![allow(clippy::useless_conversion)]
 
 extern crate proc_macro;
@@ -11,7 +12,11 @@ extern crate syn;
 use proc_macro::TokenStream;
 use quote::{quote, quote_spanned};
 use syn::parse_macro_input;
-use syn::{parse_quote, ItemTrait, TraitItem};
+use syn::spanned::Spanned;
+use syn::token::Star;
+use syn::{
+    parse_quote, FnArg, ImplItem, ItemImpl, ItemTrait, Lifetime, Pat, PatIdent, PatType, Signature, TraitItem, Type,
+};
 
 #[proc_macro_attribute]
 pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream {
@@ -35,3 +40,56 @@ pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream {
     }
     TokenStream::from(quote!(#item))
 }
+
+#[proc_macro_attribute]
+pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStream {
+    fn make_name(count: usize) -> String {
+        format!("'life{}", count)
+    }
+
+    fn mut_receiver_of(sig: &mut Signature) -> Option<&mut FnArg> {
+        let arg = sig.inputs.first_mut()?;
+        if let FnArg::Typed(PatType { pat, .. }) = arg {
+            if let Pat::Ident(PatIdent { ident, .. }) = &**pat {
+                if ident == "self" {
+                    return Some(arg);
+                }
+            }
+        }
+        None
+    }
+
+    let mut elided = 0;
+    let mut item = parse_macro_input!(input as ItemImpl);
+
+    // Look for methods having arbitrary self type taken by &mut ref
+    for inner in &mut item.items {
+        if let ImplItem::Method(method) = inner {
+            if let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig) {
+                if let box Type::Reference(reference) = &mut pat_type.ty {
+                    // Target only unnamed lifetimes
+                    let name = match &reference.lifetime {
+                        Some(lt) if lt.ident == "_" => make_name(elided),
+                        None => make_name(elided),
+                        _ => continue,
+                    };
+                    elided += 1;
+
+                    // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it.
+                    // In order to avoid adding the dependency, get a default span from a non-existent token.
+                    // A default span is needed to mark the code as coming from expansion.
+                    let span = Star::default().span();
+
+                    // Replace old lifetime with the named one
+                    let lifetime = Lifetime::new(&name, span);
+                    reference.lifetime = Some(parse_quote!(#lifetime));
+
+                    // Add lifetime to the generics of the method
+                    method.sig.generics.params.push(parse_quote!(#lifetime));
+                }
+            }
+        }
+    }
+
+    TokenStream::from(quote!(#item))
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
index 05ffb55f620..3df8be6c232 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
@@ -1,3 +1,4 @@
+// compile-flags: --emit=link
 // no-prefer-dynamic
 
 #![crate_type = "proc-macro"]
diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs
new file mode 100644
index 00000000000..d055f17526b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs
@@ -0,0 +1,8 @@
+#![warn(clippy::blanket_clippy_restriction_lints)]
+
+//! Test that the whole restriction group is not enabled
+#![warn(clippy::restriction)]
+#![deny(clippy::restriction)]
+#![forbid(clippy::restriction)]
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
new file mode 100644
index 00000000000..537557f8b0a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr
@@ -0,0 +1,27 @@
+error: restriction lints are not meant to be all enabled
+  --> $DIR/blanket_clippy_restriction_lints.rs:4:9
+   |
+LL | #![warn(clippy::restriction)]
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
+   = help: try enabling only the lints you really need
+
+error: restriction lints are not meant to be all enabled
+  --> $DIR/blanket_clippy_restriction_lints.rs:5:9
+   |
+LL | #![deny(clippy::restriction)]
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try enabling only the lints you really need
+
+error: restriction lints are not meant to be all enabled
+  --> $DIR/blanket_clippy_restriction_lints.rs:6:11
+   |
+LL | #![forbid(clippy::restriction)]
+   |           ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try enabling only the lints you really need
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs b/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs
index 4bb833795bb..948deba3ea6 100644
--- a/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs
+++ b/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1698
 
 pub trait Trait {
diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
index 086548e58ed..619d11cefc4 100644
--- a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
+++ b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs
@@ -1,3 +1,4 @@
+// compile-flags: --emit=link
 // no-prefer-dynamic
 // ^ compiletest by default builds all aux files as dylibs, but we don't want that for proc-macro
 // crates. If we don't set this, compiletest will override the `crate_type` attribute below and
diff --git a/src/tools/clippy/tests/ui/crashes/cc_seme.rs b/src/tools/clippy/tests/ui/crashes/cc_seme.rs
index c48c7e9e6c6..98588be9cf8 100644
--- a/src/tools/clippy/tests/ui/crashes/cc_seme.rs
+++ b/src/tools/clippy/tests/ui/crashes/cc_seme.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #[allow(dead_code)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/478
diff --git a/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs b/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs
index db1fa871afe..dca32aa3b56 100644
--- a/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs
+++ b/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::all)]
 #![allow(unused_imports)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1588.rs b/src/tools/clippy/tests/ui/crashes/ice-1588.rs
index 15d0f705b36..b0a3d11bce4 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-1588.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-1588.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::all)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1588
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1782.rs b/src/tools/clippy/tests/ui/crashes/ice-1782.rs
index 1ca6b6976b3..81af88962a6 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-1782.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-1782.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(dead_code, unused_variables)]
 
 /// Should not trigger an ICE in `SpanlessEq` / `consts::constant`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1969.rs b/src/tools/clippy/tests/ui/crashes/ice-1969.rs
index 837ec9df31a..96a8fe6c24d 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-1969.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-1969.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::all)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1969
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2499.rs b/src/tools/clippy/tests/ui/crashes/ice-2499.rs
index ffef1631775..45b3b1869dd 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2499.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2499.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)]
 
 /// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2594.rs b/src/tools/clippy/tests/ui/crashes/ice-2594.rs
index ac19f1976e9..3f3986b6fc6 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2594.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2594.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(dead_code, unused_variables)]
 
 /// Should not trigger an ICE in `SpanlessHash` / `consts::constant`
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2727.rs b/src/tools/clippy/tests/ui/crashes/ice-2727.rs
index d832c286033..56024abc8f5 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2727.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2727.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2727
 
 pub fn f(new: fn()) {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2760.rs b/src/tools/clippy/tests/ui/crashes/ice-2760.rs
index 9e5e299c336..f1a229f3f4f 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2760.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2760.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(
     unused_variables,
     clippy::blacklisted_name,
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2774.rs b/src/tools/clippy/tests/ui/crashes/ice-2774.rs
index 47f8e3b18ee..d44b0fae820 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2774.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2774.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 use std::collections::HashSet;
 
 // See rust-lang/rust-clippy#2774.
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2774.stderr b/src/tools/clippy/tests/ui/crashes/ice-2774.stderr
new file mode 100644
index 00000000000..0c2d48f938f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-2774.stderr
@@ -0,0 +1,10 @@
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/ice-2774.rs:15:1
+   |
+LL | pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2862.rs b/src/tools/clippy/tests/ui/crashes/ice-2862.rs
index 47324ce1831..8326e3663b0 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2862.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2862.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2862
 
 pub trait FooMap {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2865.rs b/src/tools/clippy/tests/ui/crashes/ice-2865.rs
index c4f6c0fed68..6b1ceb50569 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2865.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2865.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #[allow(dead_code)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2865
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3151.rs b/src/tools/clippy/tests/ui/crashes/ice-3151.rs
index ffad2d06b56..fef4d7db84d 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3151.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-3151.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2865
 
 #[derive(Clone)]
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3462.rs b/src/tools/clippy/tests/ui/crashes/ice-3462.rs
index 95c7dff9be3..7d62e315da2 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3462.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-3462.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![warn(clippy::all)]
 #![allow(clippy::blacklisted_name)]
 #![allow(unused)]
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3741.rs b/src/tools/clippy/tests/ui/crashes/ice-3741.rs
index a548415da62..1253ddcfaeb 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3741.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-3741.rs
@@ -1,5 +1,4 @@
 // aux-build:proc_macro_crash.rs
-// run-pass
 
 #![warn(clippy::suspicious_else_formatting)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3747.rs b/src/tools/clippy/tests/ui/crashes/ice-3747.rs
index d0b44ebafee..cdf018cbc88 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3747.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-3747.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/3747
 
 macro_rules! a {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4727.rs b/src/tools/clippy/tests/ui/crashes/ice-4727.rs
index cdb59caec67..2a4bc83f58a 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-4727.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-4727.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![warn(clippy::use_self)]
 
 #[path = "auxiliary/ice-4727-aux.rs"]
diff --git a/src/tools/clippy/tests/ui/crashes/ice-4760.rs b/src/tools/clippy/tests/ui/crashes/ice-4760.rs
index ead67d5ed1b..08b06961760 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-4760.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-4760.rs
@@ -1,4 +1,3 @@
-// run-pass
 const COUNT: usize = 2;
 struct Thing;
 trait Dummy {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-700.rs b/src/tools/clippy/tests/ui/crashes/ice-700.rs
index b06df83d51a..0cbceedbd6b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-700.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-700.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::all)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/700
diff --git a/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs b/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs
index e02eb28ab86..30e4b11ec0b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::all)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1336
diff --git a/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs b/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs
index 4ef992b05e7..2f913292995 100644
--- a/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs
+++ b/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::comparison_chain)]
 #![deny(clippy::if_same_then_else)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/issue-825.rs b/src/tools/clippy/tests/ui/crashes/issue-825.rs
index 3d4a88ab3c4..05696e3d7d5 100644
--- a/src/tools/clippy/tests/ui/crashes/issue-825.rs
+++ b/src/tools/clippy/tests/ui/crashes/issue-825.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(warnings)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/825
diff --git a/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs b/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs
index c4acd5cda1b..bb238c81ebc 100644
--- a/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs
+++ b/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(dead_code)]
 
 /// Issue: https://github.com/rust-lang/rust-clippy/issues/2596
diff --git a/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs b/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs
index 848f0ea52ca..94c939665e6 100644
--- a/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs
+++ b/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::match_same_arms)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/2427
diff --git a/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs b/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs
index d8fbaa54146..a238e7896fc 100644
--- a/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs
+++ b/src/tools/clippy/tests/ui/crashes/mut_mut_macro.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::mut_mut, clippy::zero_ptr, clippy::cmp_nan)]
 #![allow(dead_code)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs b/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs
index 48507efe1e9..4f61c76828d 100644
--- a/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs
+++ b/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #[deny(clippy::all)]
 #[derive(Debug)]
 pub enum Error {
diff --git a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs
index bd1fa4a0b1e..676564b2445 100644
--- a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs
+++ b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![deny(clippy::needless_lifetimes)]
 #![allow(dead_code)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
new file mode 100644
index 00000000000..d68bbe78802
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
@@ -0,0 +1,14 @@
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes_impl_trait.rs:15:5
+   |
+LL |     fn baz<'a>(&'a self) -> impl Foo + 'a {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/needless_lifetimes_impl_trait.rs:1:9
+   |
+LL | #![deny(clippy::needless_lifetimes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs b/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
index f79d9ab6460..c7468493380 100644
--- a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
+++ b/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #[macro_use]
 extern crate clippy_mini_macro_test;
 
diff --git a/src/tools/clippy/tests/ui/crashes/regressions.rs b/src/tools/clippy/tests/ui/crashes/regressions.rs
index 3d5063d1a3a..a41bcb33b44 100644
--- a/src/tools/clippy/tests/ui/crashes/regressions.rs
+++ b/src/tools/clippy/tests/ui/crashes/regressions.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::blacklisted_name)]
 
 pub fn foo(bar: *const u8) {
diff --git a/src/tools/clippy/tests/ui/crashes/returns.rs b/src/tools/clippy/tests/ui/crashes/returns.rs
index f2153efc388..8021ed4607d 100644
--- a/src/tools/clippy/tests/ui/crashes/returns.rs
+++ b/src/tools/clippy/tests/ui/crashes/returns.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 /// Test for https://github.com/rust-lang/rust-clippy/issues/1346
 
 #[deny(warnings)]
diff --git a/src/tools/clippy/tests/ui/crashes/single-match-else.rs b/src/tools/clippy/tests/ui/crashes/single-match-else.rs
index 3a4bbe310cc..1ba7ac08213 100644
--- a/src/tools/clippy/tests/ui/crashes/single-match-else.rs
+++ b/src/tools/clippy/tests/ui/crashes/single-match-else.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![warn(clippy::single_match_else)]
 
 //! Test for https://github.com/rust-lang/rust-clippy/issues/1588
diff --git a/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs b/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs
index 2bb95c18a39..60105a8213f 100644
--- a/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs
+++ b/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![feature(trivial_bounds)]
 #![allow(unused, trivial_bounds)]
 
diff --git a/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs b/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs
index 265017c51d9..6d2124c12fe 100644
--- a/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs
+++ b/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs
@@ -1,5 +1,3 @@
-// run-pass
-
 #![allow(clippy::useless_attribute)] //issue #2910
 
 #[macro_use]
diff --git a/src/tools/clippy/tests/ui/custom_ice_message.stderr b/src/tools/clippy/tests/ui/custom_ice_message.stderr
index a9a65a38c10..a1b8e2ee162 100644
--- a/src/tools/clippy/tests/ui/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui/custom_ice_message.stderr
@@ -9,3 +9,5 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy
 
 note: Clippy version: foo
 
+query stack during panic:
+end of query stack
diff --git a/src/tools/clippy/tests/ui/escape_analysis.rs b/src/tools/clippy/tests/ui/escape_analysis.rs
index c0a52d832c0..07004489610 100644
--- a/src/tools/clippy/tests/ui/escape_analysis.rs
+++ b/src/tools/clippy/tests/ui/escape_analysis.rs
@@ -174,3 +174,11 @@ mod issue_3739 {
         };
     }
 }
+
+/// Issue #5542
+///
+/// This shouldn't warn for `boxed_local` as it is intended to called from non-Rust code.
+pub extern "C" fn do_not_warn_me(_c_pointer: Box<String>) -> () {}
+
+#[rustfmt::skip] // Forces rustfmt to not add ABI
+pub extern fn do_not_warn_me_no_abi(_c_pointer: Box<String>) -> () {}
diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.rs b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
index aa6ef162fe4..81d8221bd13 100644
--- a/src/tools/clippy/tests/ui/explicit_counter_loop.rs
+++ b/src/tools/clippy/tests/ui/explicit_counter_loop.rs
@@ -38,54 +38,54 @@ mod issue_1219 {
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             if ch == 'a' {
                 continue;
             }
             count += 1;
-            println!("{}", count);
         }
 
         // should not trigger the lint because the count is conditional
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             if ch == 'a' {
                 count += 1;
             }
-            println!("{}", count);
         }
 
         // should trigger the lint because the count is not conditional
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             count += 1;
             if ch == 'a' {
                 continue;
             }
-            println!("{}", count);
         }
 
         // should trigger the lint because the count is not conditional
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             count += 1;
             for i in 0..2 {
                 let _ = 123;
             }
-            println!("{}", count);
         }
 
         // should not trigger the lint because the count is incremented multiple times
         let text = "banana";
         let mut count = 0;
         for ch in text.chars() {
+            println!("{}", count);
             count += 1;
             for i in 0..2 {
                 count += 1;
             }
-            println!("{}", count);
         }
     }
 }
@@ -96,30 +96,30 @@ mod issue_3308 {
         let mut skips = 0;
         let erasures = vec![];
         for i in 0..10 {
+            println!("{}", skips);
             while erasures.contains(&(i + skips)) {
                 skips += 1;
             }
-            println!("{}", skips);
         }
 
         // should not trigger the lint because the count is incremented multiple times
         let mut skips = 0;
         for i in 0..10 {
+            println!("{}", skips);
             let mut j = 0;
             while j < 5 {
                 skips += 1;
                 j += 1;
             }
-            println!("{}", skips);
         }
 
         // should not trigger the lint because the count is incremented multiple times
         let mut skips = 0;
         for i in 0..10 {
+            println!("{}", skips);
             for j in 0..5 {
                 skips += 1;
             }
-            println!("{}", skips);
         }
     }
 }
@@ -145,3 +145,16 @@ mod issue_4732 {
         let _closure = || println!("index: {}", index);
     }
 }
+
+mod issue_4677 {
+    pub fn test() {
+        let slice = &[1, 2, 3];
+
+        // should not trigger the lint because the count is used after incremented
+        let mut count = 0;
+        for _i in slice {
+            count += 1;
+            println!("{}", count);
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed
index b75f10917df..dd683e7f746 100644
--- a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed
+++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed
@@ -40,4 +40,8 @@ fn main() {
     // Ignore literals in macros
     let _ = mac1!();
     let _ = mac2!();
+
+    // Issue #6096
+    // Allow separating exponent with '_'
+    let _ = 1.025_011_10_E0;
 }
diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs
index 79ce38be19b..d5d27c853c2 100644
--- a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs
+++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs
@@ -40,4 +40,8 @@ fn main() {
     // Ignore literals in macros
     let _ = mac1!();
     let _ = mac2!();
+
+    // Issue #6096
+    // Allow separating exponent with '_'
+    let _ = 1.025_011_10_E0;
 }
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
index baee7735730..70cdb067d91 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
@@ -1,6 +1,11 @@
 // run-rustfix
 
-#![allow(dead_code, unused_variables, clippy::excessive_precision)]
+#![allow(
+    dead_code,
+    unused_variables,
+    clippy::excessive_precision,
+    clippy::inconsistent_digit_grouping
+)]
 
 fn main() {
     let fail14 = 2_i32;
@@ -12,13 +17,13 @@ fn main() {
     let fail20 = 2_i8; //
     let fail21 = 4_i16; //
 
-    let fail24 = 12.34_f64;
+    let ok24 = 12.34_64;
     let fail25 = 1E2_f32;
     let fail26 = 43E7_f64;
     let fail27 = 243E17_f32;
     #[allow(overflowing_literals)]
     let fail28 = 241_251_235E723_f64;
-    let fail29 = 42_279.911_f32;
+    let ok29 = 42279.911_32;
 
     let _ = 1.123_45E1_f32;
 }
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
index 6de447f4021..729990af399 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
@@ -1,6 +1,11 @@
 // run-rustfix
 
-#![allow(dead_code, unused_variables, clippy::excessive_precision)]
+#![allow(
+    dead_code,
+    unused_variables,
+    clippy::excessive_precision,
+    clippy::inconsistent_digit_grouping
+)]
 
 fn main() {
     let fail14 = 2_32;
@@ -12,13 +17,13 @@ fn main() {
     let fail20 = 2__8; //
     let fail21 = 4___16; //
 
-    let fail24 = 12.34_64;
+    let ok24 = 12.34_64;
     let fail25 = 1E2_32;
     let fail26 = 43E7_64;
     let fail27 = 243E17_32;
     #[allow(overflowing_literals)]
     let fail28 = 241251235E723_64;
-    let fail29 = 42279.911_32;
+    let ok29 = 42279.911_32;
 
     let _ = 1.12345E1_32;
 }
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
index 48a7ae90494..b338b8aa622 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
@@ -1,5 +1,5 @@
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:6:18
+  --> $DIR/mistyped_literal_suffix.rs:11:18
    |
 LL |     let fail14 = 2_32;
    |                  ^^^^ help: did you mean to write: `2_i32`
@@ -7,76 +7,64 @@ LL |     let fail14 = 2_32;
    = note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:7:18
+  --> $DIR/mistyped_literal_suffix.rs:12:18
    |
 LL |     let fail15 = 4_64;
    |                  ^^^^ help: did you mean to write: `4_i64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:8:18
+  --> $DIR/mistyped_literal_suffix.rs:13:18
    |
 LL |     let fail16 = 7_8; //
    |                  ^^^ help: did you mean to write: `7_i8`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:9:18
+  --> $DIR/mistyped_literal_suffix.rs:14:18
    |
 LL |     let fail17 = 23_16; //
    |                  ^^^^^ help: did you mean to write: `23_i16`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:12:18
+  --> $DIR/mistyped_literal_suffix.rs:17:18
    |
 LL |     let fail20 = 2__8; //
    |                  ^^^^ help: did you mean to write: `2_i8`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:13:18
+  --> $DIR/mistyped_literal_suffix.rs:18:18
    |
 LL |     let fail21 = 4___16; //
    |                  ^^^^^^ help: did you mean to write: `4_i16`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:15:18
-   |
-LL |     let fail24 = 12.34_64;
-   |                  ^^^^^^^^ help: did you mean to write: `12.34_f64`
-
-error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:16:18
+  --> $DIR/mistyped_literal_suffix.rs:21:18
    |
 LL |     let fail25 = 1E2_32;
    |                  ^^^^^^ help: did you mean to write: `1E2_f32`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:17:18
+  --> $DIR/mistyped_literal_suffix.rs:22:18
    |
 LL |     let fail26 = 43E7_64;
    |                  ^^^^^^^ help: did you mean to write: `43E7_f64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:18:18
+  --> $DIR/mistyped_literal_suffix.rs:23:18
    |
 LL |     let fail27 = 243E17_32;
    |                  ^^^^^^^^^ help: did you mean to write: `243E17_f32`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:20:18
+  --> $DIR/mistyped_literal_suffix.rs:25:18
    |
 LL |     let fail28 = 241251235E723_64;
    |                  ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:21:18
-   |
-LL |     let fail29 = 42279.911_32;
-   |                  ^^^^^^^^^^^^ help: did you mean to write: `42_279.911_f32`
-
-error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:23:13
+  --> $DIR/mistyped_literal_suffix.rs:28:13
    |
 LL |     let _ = 1.12345E1_32;
    |             ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32`
 
-error: aborting due to 13 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs
new file mode 100644
index 00000000000..a39d96109f1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs
@@ -0,0 +1,45 @@
+// aux-build:proc_macro_attr.rs
+
+#![warn(clippy::needless_arbitrary_self_type)]
+
+#[macro_use]
+extern crate proc_macro_attr;
+
+mod issue_6089 {
+    // Check that we don't lint if the `self` parameter comes from expansion
+
+    macro_rules! test_from_expansion {
+        () => {
+            trait T1 {
+                fn test(self: &Self);
+            }
+
+            struct S1 {}
+
+            impl T1 for S1 {
+                fn test(self: &Self) {}
+            }
+        };
+    }
+
+    test_from_expansion!();
+
+    // If only the lifetime name comes from expansion we will lint, but the suggestion will have
+    // placeholders and will not be applied automatically, as we can't reliably know the original name.
+    // This specific case happened with async_trait.
+
+    trait T2 {
+        fn call_with_mut_self(&mut self);
+    }
+
+    struct S2 {}
+
+    // The method's signature will be expanded to:
+    //  fn call_with_mut_self<'life0>(self: &'life0 mut Self) {}
+    #[rename_my_lifetimes]
+    impl T2 for S2 {
+        fn call_with_mut_self(self: &mut Self) {}
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr
new file mode 100644
index 00000000000..44a0e6ddeac
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr
@@ -0,0 +1,10 @@
+error: the type of the `self` parameter does not need to be arbitrary
+  --> $DIR/needless_arbitrary_self_type_unfixable.rs:41:31
+   |
+LL |         fn call_with_mut_self(self: &mut Self) {}
+   |                               ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'_ mut self`
+   |
+   = note: `-D clippy::needless-arbitrary-self-type` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs
index 913cd004f19..d482d466e44 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs
@@ -259,4 +259,102 @@ mod issue4291 {
     }
 }
 
+mod issue2944 {
+    trait Foo {}
+    struct Bar {}
+    struct Baz<'a> {
+        bar: &'a Bar,
+    }
+
+    impl<'a> Foo for Baz<'a> {}
+    impl Bar {
+        fn baz<'a>(&'a self) -> impl Foo + 'a {
+            Baz { bar: self }
+        }
+    }
+}
+
+mod nested_elision_sites {
+    // issue #issue2944
+
+    // closure trait bounds subject to nested elision
+    // don't lint because they refer to outer lifetimes
+    fn trait_fn<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
+        move || i
+    }
+    fn trait_fn_mut<'a>(i: &'a i32) -> impl FnMut() -> &'a i32 {
+        move || i
+    }
+    fn trait_fn_once<'a>(i: &'a i32) -> impl FnOnce() -> &'a i32 {
+        move || i
+    }
+
+    // don't lint
+    fn impl_trait_in_input_position<'a>(f: impl Fn() -> &'a i32) -> &'a i32 {
+        f()
+    }
+    fn impl_trait_in_output_position<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
+        move || i
+    }
+    // lint
+    fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
+        f(i)
+    }
+    fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
+        f(i)
+    }
+
+    // don't lint
+    fn generics_not_elidable<'a, T: Fn() -> &'a i32>(f: T) -> &'a i32 {
+        f()
+    }
+    // lint
+    fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
+        f(i)
+    }
+
+    // don't lint
+    fn where_clause_not_elidable<'a, T>(f: T) -> &'a i32
+    where
+        T: Fn() -> &'a i32,
+    {
+        f()
+    }
+    // lint
+    fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
+    where
+        T: Fn(&i32) -> &i32,
+    {
+        f(i)
+    }
+
+    // don't lint
+    fn pointer_fn_in_input_position<'a>(f: fn(&'a i32) -> &'a i32, i: &'a i32) -> &'a i32 {
+        f(i)
+    }
+    fn pointer_fn_in_output_position<'a>(_: &'a i32) -> fn(&'a i32) -> &'a i32 {
+        |i| i
+    }
+    // lint
+    fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
+        f(i)
+    }
+
+    // don't lint
+    fn nested_fn_pointer_1<'a>(_: &'a i32) -> fn(fn(&'a i32) -> &'a i32) -> i32 {
+        |f| 42
+    }
+    fn nested_fn_pointer_2<'a>(_: &'a i32) -> impl Fn(fn(&'a i32)) {
+        |f| ()
+    }
+
+    // lint
+    fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
+        |f| 42
+    }
+    fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
+        |f| ()
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
index d3a360ed8b5..c8a2e8b81c0 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
@@ -102,5 +102,53 @@ error: explicit lifetimes given in parameter types where they could be elided (o
 LL |         fn needless_lt<'a>(_x: &'a u8) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 17 previous errors
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:271:9
+   |
+LL |         fn baz<'a>(&'a self) -> impl Foo + 'a {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:300:5
+   |
+LL |     fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:303:5
+   |
+LL |     fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:312:5
+   |
+LL |     fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:324:5
+   |
+LL |     fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:339:5
+   |
+LL |     fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:352:5
+   |
+LL |     fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:355:5
+   |
+LL |     fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 25 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_range_loop2.rs b/src/tools/clippy/tests/ui/needless_range_loop2.rs
index a82b1159161..7633316e0f8 100644
--- a/src/tools/clippy/tests/ui/needless_range_loop2.rs
+++ b/src/tools/clippy/tests/ui/needless_range_loop2.rs
@@ -82,6 +82,20 @@ fn main() {
     for i in 1..3 {
         println!("{}", arr[i]);
     }
+
+    // Fix #5945
+    let mut vec = vec![1, 2, 3, 4];
+    for i in 0..vec.len() - 1 {
+        vec[i] += 1;
+    }
+    let mut vec = vec![1, 2, 3, 4];
+    for i in vec.len() - 3..vec.len() {
+        vec[i] += 1;
+    }
+    let mut vec = vec![1, 2, 3, 4];
+    for i in vec.len() - 3..vec.len() - 1 {
+        vec[i] += 1;
+    }
 }
 
 mod issue2277 {
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 5fb568672d3..2045ffdb5f0 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -58,6 +58,12 @@ fn or_fun_call() {
     let without_default = Some(Foo);
     without_default.unwrap_or_else(Foo::new);
 
+    let mut map = HashMap::<u64, String>::new();
+    map.entry(42).or_insert_with(String::new);
+
+    let mut btree = BTreeMap::<u64, String>::new();
+    btree.entry(42).or_insert_with(String::new);
+
     let stringy = Some(String::from(""));
     let _ = stringy.unwrap_or_else(|| "".to_owned());
 
@@ -110,23 +116,4 @@ fn f() -> Option<()> {
     Some(())
 }
 
-// Issue 5886 - const fn (with no arguments)
-pub fn skip_const_fn_with_no_args() {
-    const fn foo() -> Option<i32> {
-        Some(42)
-    }
-    let _ = None.or(foo());
-
-    // See issue #5693.
-    let mut map = std::collections::HashMap::new();
-    map.insert(1, vec![1]);
-    map.entry(1).or_insert(vec![]);
-
-    let mut map = HashMap::<u64, String>::new();
-    map.entry(42).or_insert(String::new());
-
-    let mut btree = BTreeMap::<u64, String>::new();
-    btree.entry(42).or_insert(String::new());
-}
-
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index 737b0f7e55b..522f31b72d0 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -58,6 +58,12 @@ fn or_fun_call() {
     let without_default = Some(Foo);
     without_default.unwrap_or(Foo::new());
 
+    let mut map = HashMap::<u64, String>::new();
+    map.entry(42).or_insert(String::new());
+
+    let mut btree = BTreeMap::<u64, String>::new();
+    btree.entry(42).or_insert(String::new());
+
     let stringy = Some(String::from(""));
     let _ = stringy.unwrap_or("".to_owned());
 
@@ -110,23 +116,4 @@ fn f() -> Option<()> {
     Some(())
 }
 
-// Issue 5886 - const fn (with no arguments)
-pub fn skip_const_fn_with_no_args() {
-    const fn foo() -> Option<i32> {
-        Some(42)
-    }
-    let _ = None.or(foo());
-
-    // See issue #5693.
-    let mut map = std::collections::HashMap::new();
-    map.insert(1, vec![1]);
-    map.entry(1).or_insert(vec![]);
-
-    let mut map = HashMap::<u64, String>::new();
-    map.entry(42).or_insert(String::new());
-
-    let mut btree = BTreeMap::<u64, String>::new();
-    btree.entry(42).or_insert(String::new());
-}
-
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index b8a436993f3..bc5978b538f 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -60,23 +60,35 @@ error: use of `unwrap_or` followed by a function call
 LL |     without_default.unwrap_or(Foo::new());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)`
 
+error: use of `or_insert` followed by a function call
+  --> $DIR/or_fun_call.rs:62:19
+   |
+LL |     map.entry(42).or_insert(String::new());
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
+
+error: use of `or_insert` followed by a function call
+  --> $DIR/or_fun_call.rs:65:21
+   |
+LL |     btree.entry(42).or_insert(String::new());
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)`
+
 error: use of `unwrap_or` followed by a function call
-  --> $DIR/or_fun_call.rs:62:21
+  --> $DIR/or_fun_call.rs:68:21
    |
 LL |     let _ = stringy.unwrap_or("".to_owned());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())`
 
 error: use of `or` followed by a function call
-  --> $DIR/or_fun_call.rs:87:35
+  --> $DIR/or_fun_call.rs:93:35
    |
 LL |     let _ = Some("a".to_string()).or(Some("b".to_string()));
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))`
 
 error: use of `or` followed by a function call
-  --> $DIR/or_fun_call.rs:91:10
+  --> $DIR/or_fun_call.rs:97:10
    |
 LL |         .or(Some(Bar(b, Duration::from_secs(2))));
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))`
 
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/print_stdout_build_script.rs b/src/tools/clippy/tests/ui/print_stdout_build_script.rs
new file mode 100644
index 00000000000..997ebef8a69
--- /dev/null
+++ b/src/tools/clippy/tests/ui/print_stdout_build_script.rs
@@ -0,0 +1,12 @@
+// compile-flags: --crate-name=build_script_build
+
+#![warn(clippy::print_stdout)]
+
+fn main() {
+    // Fix #6041
+    //
+    // The `print_stdout` lint shouldn't emit in `build.rs`
+    // as these methods are used for the build script.
+    println!("Hello");
+    print!("Hello");
+}
diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs
index 9767e5bf76a..f7f3b195ccc 100644
--- a/src/tools/clippy/tests/ui/regex.rs
+++ b/src/tools/clippy/tests/ui/regex.rs
@@ -71,6 +71,9 @@ fn trivial_regex() {
     let non_trivial_ends_with = Regex::new("foo|bar");
     let non_trivial_binary = BRegex::new("foo|bar");
     let non_trivial_binary_builder = BRegexBuilder::new("foo|bar");
+
+    // #6005: unicode classes in bytes::Regex
+    let a_byte_of_unicode = BRegex::new(r"\p{C}");
 }
 
 fn main() {
diff --git a/src/tools/clippy/tests/ui/unicode.rs b/src/tools/clippy/tests/ui/unicode.rs
index 27db9594f3b..1f596c312fe 100644
--- a/src/tools/clippy/tests/ui/unicode.rs
+++ b/src/tools/clippy/tests/ui/unicode.rs
@@ -1,7 +1,11 @@
-#[warn(clippy::zero_width_space)]
+#[warn(clippy::invisible_characters)]
 fn zero() {
     print!("Here >​< is a ZWS, and ​another");
     print!("This\u{200B}is\u{200B}fine");
+    print!("Here >­< is a SHY, and ­another");
+    print!("This\u{ad}is\u{ad}fine");
+    print!("Here >⁠< is a WJ, and ⁠another");
+    print!("This\u{2060}is\u{2060}fine");
 }
 
 #[warn(clippy::unicode_not_nfc)]
diff --git a/src/tools/clippy/tests/ui/unicode.stderr b/src/tools/clippy/tests/ui/unicode.stderr
index 4575a132e5b..3fca463c620 100644
--- a/src/tools/clippy/tests/ui/unicode.stderr
+++ b/src/tools/clippy/tests/ui/unicode.stderr
@@ -1,13 +1,25 @@
-error: zero-width space detected
+error: invisible character detected
   --> $DIR/unicode.rs:3:12
    |
 LL |     print!("Here >​< is a ZWS, and ​another");
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{200B}< is a ZWS, and /u{200B}another"`
    |
-   = note: `-D clippy::zero-width-space` implied by `-D warnings`
+   = note: `-D clippy::invisible-characters` implied by `-D warnings`
+
+error: invisible character detected
+  --> $DIR/unicode.rs:5:12
+   |
+LL |     print!("Here >­< is a SHY, and ­another");
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{AD}< is a SHY, and /u{AD}another"`
+
+error: invisible character detected
+  --> $DIR/unicode.rs:7:12
+   |
+LL |     print!("Here >⁠< is a WJ, and ⁠another");
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >/u{2060}< is a WJ, and /u{2060}another"`
 
 error: non-NFC Unicode sequence detected
-  --> $DIR/unicode.rs:9:12
+  --> $DIR/unicode.rs:13:12
    |
 LL |     print!("̀àh?");
    |            ^^^^^ help: consider replacing the string with: `"̀àh?"`
@@ -15,12 +27,12 @@ LL |     print!("̀àh?");
    = note: `-D clippy::unicode-not-nfc` implied by `-D warnings`
 
 error: literal non-ASCII character detected
-  --> $DIR/unicode.rs:15:12
+  --> $DIR/unicode.rs:19:12
    |
 LL |     print!("Üben!");
    |            ^^^^^^^ help: consider replacing the string with: `"/u{dc}ben!"`
    |
    = note: `-D clippy::non-ascii-literal` implied by `-D warnings`
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
index ad0d0387db0..b45b27d8f23 100644
--- a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed
@@ -13,12 +13,12 @@ fn unnecessary_sort_by() {
     // Forward examples
     vec.sort();
     vec.sort_unstable();
-    vec.sort_by_key(|&a| (a + 5).abs());
-    vec.sort_unstable_by_key(|&a| id(-a));
+    vec.sort_by_key(|a| (a + 5).abs());
+    vec.sort_unstable_by_key(|a| id(-a));
     // Reverse examples
-    vec.sort_by_key(|&b| Reverse(b));
-    vec.sort_by_key(|&b| Reverse((b + 5).abs()));
-    vec.sort_unstable_by_key(|&b| Reverse(id(-b)));
+    vec.sort_by(|a, b| b.cmp(a)); // not linted to avoid suggesting `Reverse(b)` which would borrow
+    vec.sort_by_key(|b| Reverse((b + 5).abs()));
+    vec.sort_unstable_by_key(|b| Reverse(id(-b)));
     // Negative examples (shouldn't be changed)
     let c = &7;
     vec.sort_by(|a, b| (b - a).cmp(&(a - b)));
@@ -26,10 +26,11 @@ fn unnecessary_sort_by() {
     vec.sort_by(|_, b| b.cmp(c));
     vec.sort_unstable_by(|a, _| a.cmp(c));
 
-    // Ignore vectors of references
+    // Vectors of references are fine as long as the resulting key does not borrow
     let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5];
-    vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
-    vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+    vec.sort_by_key(|a| (***a).abs());
+    vec.sort_unstable_by_key(|a| (***a).abs());
+    // `Reverse(b)` would borrow in the following cases, don't lint
     vec.sort_by(|a, b| b.cmp(a));
     vec.sort_unstable_by(|a, b| b.cmp(a));
 }
@@ -68,10 +69,9 @@ mod issue_5754 {
     }
 }
 
-// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K`
-// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are
-// not linted.
+// The closure parameter is not dereferenced anymore, so non-Copy types can be linted
 mod issue_6001 {
+    use super::*;
     struct Test(String);
 
     impl Test {
@@ -85,11 +85,11 @@ mod issue_6001 {
         let mut args: Vec<Test> = vec![];
 
         // Forward
-        args.sort_by(|a, b| a.name().cmp(&b.name()));
-        args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
+        args.sort_by_key(|a| a.name());
+        args.sort_unstable_by_key(|a| a.name());
         // Reverse
-        args.sort_by(|a, b| b.name().cmp(&a.name()));
-        args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
+        args.sort_by_key(|b| Reverse(b.name()));
+        args.sort_unstable_by_key(|b| Reverse(b.name()));
     }
 }
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs
index 9746f6e6849..be2abe7f701 100644
--- a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs
@@ -16,7 +16,7 @@ fn unnecessary_sort_by() {
     vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs()));
     vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b)));
     // Reverse examples
-    vec.sort_by(|a, b| b.cmp(a));
+    vec.sort_by(|a, b| b.cmp(a)); // not linted to avoid suggesting `Reverse(b)` which would borrow
     vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
     vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a)));
     // Negative examples (shouldn't be changed)
@@ -26,10 +26,11 @@ fn unnecessary_sort_by() {
     vec.sort_by(|_, b| b.cmp(c));
     vec.sort_unstable_by(|a, _| a.cmp(c));
 
-    // Ignore vectors of references
+    // Vectors of references are fine as long as the resulting key does not borrow
     let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5];
     vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
     vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+    // `Reverse(b)` would borrow in the following cases, don't lint
     vec.sort_by(|a, b| b.cmp(a));
     vec.sort_unstable_by(|a, b| b.cmp(a));
 }
@@ -68,10 +69,9 @@ mod issue_5754 {
     }
 }
 
-// `Vec::sort_by_key` closure parameter is `F: FnMut(&T) -> K`
-// The suggestion is destructuring T and we know T is not a reference, so test that non-Copy T are
-// not linted.
+// The closure parameter is not dereferenced anymore, so non-Copy types can be linted
 mod issue_6001 {
+    use super::*;
     struct Test(String);
 
     impl Test {
diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr
index 70c6cf0a3b6..50607933e18 100644
--- a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr
@@ -16,31 +16,61 @@ error: use Vec::sort_by_key here instead
   --> $DIR/unnecessary_sort_by.rs:16:5
    |
 LL |     vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs()));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&a| (a + 5).abs())`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (a + 5).abs())`
 
 error: use Vec::sort_by_key here instead
   --> $DIR/unnecessary_sort_by.rs:17:5
    |
 LL |     vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b)));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&a| id(-a))`
-
-error: use Vec::sort_by_key here instead
-  --> $DIR/unnecessary_sort_by.rs:19:5
-   |
-LL |     vec.sort_by(|a, b| b.cmp(a));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse(b))`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| id(-a))`
 
 error: use Vec::sort_by_key here instead
   --> $DIR/unnecessary_sort_by.rs:20:5
    |
 LL |     vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|&b| Reverse((b + 5).abs()))`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| Reverse((b + 5).abs()))`
 
 error: use Vec::sort_by_key here instead
   --> $DIR/unnecessary_sort_by.rs:21:5
    |
 LL |     vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a)));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|&b| Reverse(id(-b)))`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|b| Reverse(id(-b)))`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:31:5
+   |
+LL |     vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (***a).abs())`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:32:5
+   |
+LL |     vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| (***a).abs())`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:88:9
+   |
+LL |         args.sort_by(|a, b| a.name().cmp(&b.name()));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|a| a.name())`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:89:9
+   |
+LL |         args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|a| a.name())`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:91:9
+   |
+LL |         args.sort_by(|a, b| b.name().cmp(&a.name()));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|b| Reverse(b.name()))`
+
+error: use Vec::sort_by_key here instead
+  --> $DIR/unnecessary_sort_by.rs:92:9
+   |
+LL |         args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|b| Reverse(b.name()))`
 
-error: aborting due to 7 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 3fafb835ea42e6e3af27f5dc8f26bda590cb49e
+Subproject 8beccc4bef598e95e31536f996ea5771d8126d0
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index 33613e2dc10..7586f5aa3b5 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -33,7 +33,7 @@ MAINTAINERS = {
     'rust-by-example': {'steveklabnik', 'marioidival'},
     'embedded-book': {'adamgreig', 'andre-richter', 'jamesmunns', 'therealprof'},
     'edition-guide': {'ehuss', 'steveklabnik'},
-    'rustc-dev-guide': {'mark-i-m', 'spastorino', 'amanjeev', 'JohnTitor'},
+    'rustc-dev-guide': {'spastorino', 'amanjeev', 'JohnTitor'},
 }
 
 LABELS = {
diff --git a/src/tools/rls b/src/tools/rls
-Subproject 9bfb47a79299d52f45304367762c9bfc96d9ed7
+Subproject 1f686d5f707269b1086f6afcdced36225c0c5ff
diff --git a/src/tools/rust-demangler/main.rs b/src/tools/rust-demangler/main.rs
index e1e49230ad1..fd031ccb252 100644
--- a/src/tools/rust-demangler/main.rs
+++ b/src/tools/rust-demangler/main.rs
@@ -21,6 +21,41 @@
 //! $ "${TARGET}"/llvm/bin/llvm-cov show --Xdemangler="${TARGET}"/stage0-tools-bin/rust-demangler \
 //!   --instr-profile=main.profdata ./main --show-line-counts-or-regions
 //! ```
+//!
+//! Note regarding crate disambiguators:
+//!
+//! Some demangled symbol paths can include "crate disambiguator" suffixes, represented as a large
+//! hexadecimal value enclosed in square braces, and appended to the name of the crate. a suffix to the
+//! original crate name. For example, the `core` crate, here, includes a disambiguator:
+//!
+//! ```rust
+//!     <generics::Firework<f64> as core[a7a74cee373f048]::ops::drop::Drop>::drop
+//! ```
+//!
+//! These disambiguators are known to vary depending on environmental circumstances. As a result,
+//! tests that compare results including demangled names can fail across development environments,
+//! particularly with cross-platform testing. Also, the resulting crate paths are not syntactically
+//! valid, and don't match the original source symbol paths, which can impact development tools.
+//!
+//! For these reasons, by default, `rust-demangler` uses a heuristic to remove crate disambiguators
+//! from their original demangled representation before printing them to standard output. If crate
+//! disambiguators are required, add the `-d` (or `--disambiguators`) flag, and the disambiguators
+//! will not be removed.
+//!
+//! Also note that the disambiguators are stripped by a Regex pattern that is tolerant to some
+//! variation in the number of hexadecimal digits. The disambiguators come from a hash value, which
+//! typically generates a 16-digit hex representation on a 64-bit architecture; however, leading
+//! zeros are not included, which can shorten the hex digit length, and a different hash algorithm
+//! that might also be dependent on the architecture, might shorten the length even further. A
+//! minimum length of 5 digits is assumed, which should be more than sufficient to support hex
+//! representations that generate only 8-digits of precision with an extremely rare (but not
+//! impossible) result with up to 3 leading zeros.
+//!
+//! Using a minimum number of digits less than 5 risks the possibility of stripping demangled name
+//! components with a similar pattern. For example, some closures instantiated multiple times
+//! include their own disambiguators, demangled as non-hashed zero-based indexes in square brackets.
+//! These disambiguators seem to have more analytical value (for instance, in coverage analysis), so
+//! they are not removed.
 
 use regex::Regex;
 use rustc_demangle::demangle;
@@ -29,7 +64,25 @@ use std::io::{self, Read, Write};
 const REPLACE_COLONS: &str = "::";
 
 fn main() -> io::Result<()> {
-    let mut strip_crate_disambiguators = Some(Regex::new(r"\[[a-f0-9]{16}\]::").unwrap());
+    // FIXME(richkadel): In Issue #77615 discussed updating the `rustc-demangle` library, to provide
+    // an option to generate demangled names without including crate disambiguators. If that
+    // happens, update this tool to use that option (if the `-d` flag is not set) instead stripping
+    // them via the Regex heuristic. The update the doc comments and help.
+
+    // Strip hashed hexadecimal crate disambiguators. Leading zeros are not enforced, and can be
+    // different across different platform/architecture types, so while 16 hex digits are common,
+    // they can also be shorter.
+    //
+    // Also note that a demangled symbol path may include the `[<digits>]` pattern, with zero-based
+    // indexes (such as for closures, and possibly for types defined in anonymous scopes). Preferably
+    // these should not be stripped.
+    //
+    // The minimum length of 5 digits supports the possibility that some target architecture (maybe
+    // a 32-bit or smaller architecture) could generate a hash value with a maximum of 8 digits,
+    // and more than three leading zeros should be extremely unlikely. Conversely, it should be
+    // sufficient to assume the zero-based indexes for closures and anonymous scopes will never
+    // exceed the value 9999.
+    let mut strip_crate_disambiguators = Some(Regex::new(r"\[[a-f0-9]{5,16}\]::").unwrap());
 
     let mut args = std::env::args();
     let progname = args.next().unwrap();
@@ -41,14 +94,19 @@ fn main() -> io::Result<()> {
             eprintln!("Usage: {} [-d|--disambiguators]", progname);
             eprintln!();
             eprintln!(
-                "This tool converts a list of Rust mangled symbols (one per line) into a\n
+                "This tool converts a list of Rust mangled symbols (one per line) into a\n\
                 corresponding list of demangled symbols."
             );
             eprintln!();
             eprintln!(
                 "With -d (--disambiguators), Rust symbols mangled with the v0 symbol mangler may\n\
-                include crate disambiguators (a 16 character hex value in square brackets).\n\
-                Crate disambiguators are removed by default."
+                include crate disambiguators (a hexadecimal hash value, typically up to 16 digits\n\
+                long, enclosed in square brackets)."
+            );
+            eprintln!();
+            eprintln!(
+                "By default, crate disambiguators are removed, using a heuristics-based regular\n\
+                expression. (See the `rust-demangler` doc comments for more information.)"
             );
             eprintln!();
             std::process::exit(1)
diff --git a/triagebot.toml b/triagebot.toml
index 8b7b536bcbf..fc733b9e45f 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -75,6 +75,7 @@ label = "I-prioritize"
 
 [autolabel."I-prioritize"]
 trigger_labels = [
+    "regression-untriaged",
     "regression-from-stable-to-stable",
     "regression-from-stable-to-beta",
     "regression-from-stable-to-nightly",