about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_apfloat/Cargo.toml2
-rw-r--r--compiler/rustc_arena/Cargo.toml2
-rw-r--r--compiler/rustc_arena/src/lib.rs15
-rw-r--r--compiler/rustc_ast/Cargo.toml2
-rw-r--r--compiler/rustc_ast/src/ast.rs50
-rw-r--r--compiler/rustc_ast/src/lib.rs1
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs33
-rw-r--r--compiler/rustc_ast/src/node_id.rs14
-rw-r--r--compiler/rustc_ast/src/visit.rs18
-rw-r--r--compiler/rustc_ast_lowering/Cargo.toml2
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs6
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs117
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs92
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs7
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs6
-rw-r--r--compiler/rustc_ast_passes/src/node_count.rs4
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs63
-rw-r--r--compiler/rustc_attr/src/builtin.rs2
-rw-r--r--compiler/rustc_builtin_macros/Cargo.toml3
-rw-r--r--compiler/rustc_builtin_macros/src/derive.rs132
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs199
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs21
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs47
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs57
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/standard_library_imports.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs15
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs7
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs11
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs80
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs124
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs24
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs143
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs4
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs28
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs30
-rw-r--r--compiler/rustc_codegen_ssa/src/mono_item.rs4
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_data_structures/src/graph/dominators/mod.rs4
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs27
-rw-r--r--compiler/rustc_data_structures/src/sharded.rs30
-rw-r--r--compiler/rustc_driver/src/args.rs16
-rw-r--r--compiler/rustc_driver/src/lib.rs19
-rw-r--r--compiler/rustc_driver/src/pretty.rs24
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs12
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0074.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0076.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0077.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0162.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0165.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0463.md21
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0542.md47
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0543.md35
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0545.md35
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0546.md11
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0547.md37
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0549.md37
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs24
-rw-r--r--compiler/rustc_errors/src/emitter.rs13
-rw-r--r--compiler/rustc_errors/src/json.rs67
-rw-r--r--compiler/rustc_errors/src/lib.rs43
-rw-r--r--compiler/rustc_expand/Cargo.toml2
-rw-r--r--compiler/rustc_expand/src/base.rs51
-rw-r--r--compiler/rustc_expand/src/config.rs2
-rw-r--r--compiler/rustc_expand/src/expand.rs479
-rw-r--r--compiler/rustc_expand/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/module.rs24
-rw-r--r--compiler/rustc_expand/src/mut_visit/tests.rs8
-rw-r--r--compiler/rustc_expand/src/parse/tests.rs4
-rw-r--r--compiler/rustc_expand/src/placeholders.rs8
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs94
-rw-r--r--compiler/rustc_feature/src/active.rs7
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs1
-rw-r--r--compiler/rustc_hir/Cargo.toml2
-rw-r--r--compiler/rustc_hir/src/hir.rs238
-rw-r--r--compiler/rustc_hir/src/hir_id.rs15
-rw-r--r--compiler/rustc_hir/src/intravisit.rs57
-rw-r--r--compiler/rustc_hir/src/lang_items.rs5
-rw-r--r--compiler/rustc_hir/src/lib.rs1
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs73
-rw-r--r--compiler/rustc_hir/src/target.rs2
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs17
-rw-r--r--compiler/rustc_incremental/src/assert_dep_graph.rs6
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs28
-rw-r--r--compiler/rustc_incremental/src/persist/file_format.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs4
-rw-r--r--compiler/rustc_incremental/src/persist/load.rs2
-rw-r--r--compiler/rustc_index/src/bit_set.rs12
-rw-r--r--compiler/rustc_index/src/bit_set/tests.rs34
-rw-r--r--compiler/rustc_index/src/lib.rs4
-rw-r--r--compiler/rustc_infer/Cargo.toml2
-rw-r--r--compiler/rustc_infer/src/infer/at.rs25
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs11
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs1
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs23
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs232
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs22
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/README.md1
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs8
-rw-r--r--compiler/rustc_infer/src/infer/undo_log.rs2
-rw-r--r--compiler/rustc_infer/src/traits/util.rs41
-rw-r--r--compiler/rustc_interface/Cargo.toml5
-rw-r--r--compiler/rustc_interface/src/interface.rs23
-rw-r--r--compiler/rustc_interface/src/passes.rs51
-rw-r--r--compiler/rustc_interface/src/proc_macro_decls.rs2
-rw-r--r--compiler/rustc_interface/src/queries.rs8
-rw-r--r--compiler/rustc_interface/src/util.rs32
-rw-r--r--compiler/rustc_lint/Cargo.toml1
-rw-r--r--compiler/rustc_lint/src/builtin.rs136
-rw-r--r--compiler/rustc_lint/src/context.rs49
-rw-r--r--compiler/rustc_lint/src/early.rs7
-rw-r--r--compiler/rustc_lint/src/late.rs20
-rw-r--r--compiler/rustc_lint/src/levels.rs111
-rw-r--r--compiler/rustc_lint/src/lib.rs6
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs197
-rw-r--r--compiler/rustc_lint/src/panic_fmt.rs155
-rw-r--r--compiler/rustc_lint/src/passes.rs2
-rw-r--r--compiler/rustc_lint/src/traits.rs3
-rw-r--r--compiler/rustc_lint/src/types.rs54
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs101
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs10
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h1
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp26
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp2
-rw-r--r--compiler/rustc_macros/src/query.rs27
-rw-r--r--compiler/rustc_metadata/Cargo.toml2
-rw-r--r--compiler/rustc_metadata/src/creader.rs27
-rw-r--r--compiler/rustc_metadata/src/foreign_modules.rs15
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs398
-rw-r--r--compiler/rustc_middle/Cargo.toml2
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs119
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs104
-rw-r--r--compiler/rustc_middle/src/hir/map/blocks.rs6
-rw-r--r--compiler/rustc_middle/src/hir/map/collector.rs81
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs87
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ich/impls_hir.rs3
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/lint.rs12
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs28
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs1
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs17
-rw-r--r--compiler/rustc_middle/src/query/mod.rs51
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs20
-rw-r--r--compiler/rustc_middle/src/traits/select.rs3
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs3
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs8
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs64
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs32
-rw-r--r--compiler/rustc_middle/src/ty/error.rs63
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs1
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs19
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs18
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs34
-rw-r--r--compiler/rustc_middle/src/ty/query/job.rs26
-rw-r--r--compiler/rustc_middle/src/ty/query/mod.rs225
-rw-r--r--compiler/rustc_middle/src/ty/query/on_disk_cache.rs54
-rw-r--r--compiler/rustc_middle/src/ty/query/plumbing.rs576
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs4
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs117
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs9
-rw-r--r--compiler/rustc_middle/src/util/bug.rs4
-rw-r--r--compiler/rustc_mir/Cargo.toml2
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs106
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs13
-rw-r--r--compiler/rustc_mir/src/borrow_check/mod.rs13
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/mod.rs53
-rw-r--r--compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs12
-rw-r--r--compiler/rustc_mir/src/const_eval/error.rs13
-rw-r--r--compiler/rustc_mir/src/const_eval/eval_queries.rs20
-rw-r--r--compiler/rustc_mir/src/const_eval/machine.rs30
-rw-r--r--compiler/rustc_mir/src/const_eval/mod.rs14
-rw-r--r--compiler/rustc_mir/src/dataflow/impls/borrows.rs179
-rw-r--r--compiler/rustc_mir/src/interpret/cast.rs24
-rw-r--r--compiler/rustc_mir/src/interpret/eval_context.rs53
-rw-r--r--compiler/rustc_mir/src/interpret/intern.rs22
-rw-r--r--compiler/rustc_mir/src/interpret/intrinsics.rs95
-rw-r--r--compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs6
-rw-r--r--compiler/rustc_mir/src/interpret/machine.rs16
-rw-r--r--compiler/rustc_mir/src/interpret/operand.rs64
-rw-r--r--compiler/rustc_mir/src/interpret/operator.rs26
-rw-r--r--compiler/rustc_mir/src/interpret/place.rs149
-rw-r--r--compiler/rustc_mir/src/interpret/step.rs60
-rw-r--r--compiler/rustc_mir/src/interpret/terminator.rs40
-rw-r--r--compiler/rustc_mir/src/interpret/traits.rs2
-rw-r--r--compiler/rustc_mir/src/interpret/validity.rs106
-rw-r--r--compiler/rustc_mir/src/interpret/visitor.rs60
-rw-r--r--compiler/rustc_mir/src/monomorphize/collector.rs33
-rw-r--r--compiler/rustc_mir/src/monomorphize/partitioning/default.rs9
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/validation.rs2
-rw-r--r--compiler/rustc_mir/src/transform/const_prop.rs58
-rw-r--r--compiler/rustc_mir/src/transform/coverage/tests.rs6
-rw-r--r--compiler/rustc_mir/src/transform/inline.rs9
-rw-r--r--compiler/rustc_mir/src/transform/inline/cycle.rs7
-rw-r--r--compiler/rustc_mir/src/transform/promote_consts.rs35
-rw-r--r--compiler/rustc_mir/src/util/generic_graphviz.rs8
-rw-r--r--compiler/rustc_mir/src/util/pretty.rs26
-rw-r--r--compiler/rustc_mir_build/Cargo.toml2
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs10
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs20
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs6
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs90
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/into.rs11
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs78
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs20
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs216
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs6
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs49
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs578
-rw-r--r--compiler/rustc_parse/Cargo.toml2
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs30
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs186
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs18
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs185
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs2
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs389
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs139
-rw-r--r--compiler/rustc_parse/src/parser/item.rs325
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs171
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs48
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs213
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs70
-rw-r--r--compiler/rustc_parse_format/src/lib.rs2
-rw-r--r--compiler/rustc_passes/src/check_attr.rs44
-rw-r--r--compiler/rustc_passes/src/check_const.rs2
-rw-r--r--compiler/rustc_passes/src/dead.rs48
-rw-r--r--compiler/rustc_passes/src/diagnostic_items.rs15
-rw-r--r--compiler/rustc_passes/src/entry.rs11
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs17
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs34
-rw-r--r--compiler/rustc_passes/src/lang_items.rs6
-rw-r--r--compiler/rustc_passes/src/layout_test.rs6
-rw-r--r--compiler/rustc_passes/src/reachable.rs27
-rw-r--r--compiler/rustc_passes/src/region.rs2
-rw-r--r--compiler/rustc_passes/src/stability.rs36
-rw-r--r--compiler/rustc_plugin_impl/src/build.rs10
-rw-r--r--compiler/rustc_privacy/src/lib.rs201
-rw-r--r--compiler/rustc_query_impl/Cargo.toml27
-rw-r--r--compiler/rustc_query_impl/src/README.md (renamed from compiler/rustc_middle/src/ty/query/README.md)0
-rw-r--r--compiler/rustc_query_impl/src/keys.rs (renamed from compiler/rustc_middle/src/ty/query/keys.rs)95
-rw-r--r--compiler/rustc_query_impl/src/lib.rs65
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs728
-rw-r--r--compiler/rustc_query_impl/src/profiling_support.rs (renamed from compiler/rustc_middle/src/ty/query/profiling_support.rs)57
-rw-r--r--compiler/rustc_query_impl/src/stats.rs (renamed from compiler/rustc_middle/src/ty/query/stats.rs)39
-rw-r--r--compiler/rustc_query_impl/src/values.rs (renamed from compiler/rustc_middle/src/ty/query/values.rs)15
-rw-r--r--compiler/rustc_query_system/Cargo.toml2
-rw-r--r--compiler/rustc_query_system/src/cache.rs7
-rw-r--r--compiler/rustc_query_system/src/dep_graph/dep_node.rs2
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs55
-rw-r--r--compiler/rustc_query_system/src/dep_graph/mod.rs45
-rw-r--r--compiler/rustc_query_system/src/query/caches.rs58
-rw-r--r--compiler/rustc_query_system/src/query/config.rs19
-rw-r--r--compiler/rustc_query_system/src/query/job.rs5
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs34
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs422
-rw-r--r--compiler/rustc_resolve/Cargo.toml2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs102
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs11
-rw-r--r--compiler/rustc_resolve/src/imports.rs81
-rw-r--r--compiler/rustc_resolve/src/late.rs25
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs6
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs40
-rw-r--r--compiler/rustc_resolve/src/lib.rs111
-rw-r--r--compiler/rustc_resolve/src/macros.rs186
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs144
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs14
-rw-r--r--compiler/rustc_save_analysis/src/sig.rs34
-rw-r--r--compiler/rustc_serialize/Cargo.toml2
-rw-r--r--compiler/rustc_serialize/src/lib.rs1
-rw-r--r--compiler/rustc_serialize/tests/leb128.rs1
-rw-r--r--compiler/rustc_session/src/config.rs138
-rw-r--r--compiler/rustc_session/src/filesearch.rs52
-rw-r--r--compiler/rustc_session/src/options.rs4
-rw-r--r--compiler/rustc_session/src/session.rs14
-rw-r--r--compiler/rustc_span/src/def_id.rs4
-rw-r--r--compiler/rustc_span/src/hygiene.rs4
-rw-r--r--compiler/rustc_span/src/lib.rs10
-rw-r--r--compiler/rustc_span/src/source_map.rs59
-rw-r--r--compiler/rustc_span/src/source_map/tests.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs8
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs12
-rw-r--r--compiler/rustc_target/src/spec/mod.rs6
-rw-r--r--compiler/rustc_target/src/spec/riscv32gc_unknown_linux_musl.rs19
-rw-r--r--compiler/rustc_target/src/spec/riscv64gc_unknown_linux_musl.rs19
-rw-r--r--compiler/rustc_trait_selection/Cargo.toml2
-rw-r--r--compiler/rustc_trait_selection/src/autoderef.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs40
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs25
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs46
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs22
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs113
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs67
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs38
-rw-r--r--compiler/rustc_traits/Cargo.toml2
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs7
-rw-r--r--compiler/rustc_traits/src/dropck_outlives.rs2
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs8
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs23
-rw-r--r--compiler/rustc_typeck/Cargo.toml2
-rw-r--r--compiler/rustc_typeck/src/astconv/errors.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs65
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs293
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs5
-rw-r--r--compiler/rustc_typeck/src/check/check.rs157
-rw-r--r--compiler/rustc_typeck/src/check/closure.rs14
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs12
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs2
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs115
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs26
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/mod.rs8
-rw-r--r--compiler/rustc_typeck/src/check/intrinsic.rs16
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs56
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs3
-rw-r--r--compiler/rustc_typeck/src/check/op.rs12
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs2
-rw-r--r--compiler/rustc_typeck/src/check/place_op.rs6
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs404
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs69
-rw-r--r--compiler/rustc_typeck/src/check/writeback.rs2
-rw-r--r--compiler/rustc_typeck/src/check_unused.rs39
-rw-r--r--compiler/rustc_typeck/src/coherence/builtin.rs3
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls.rs54
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs3
-rw-r--r--compiler/rustc_typeck/src/coherence/mod.rs18
-rw-r--r--compiler/rustc_typeck/src/coherence/orphan.rs7
-rw-r--r--compiler/rustc_typeck/src/coherence/unsafety.rs3
-rw-r--r--compiler/rustc_typeck/src/collect.rs315
-rw-r--r--compiler/rustc_typeck/src/collect/item_bounds.rs4
-rw-r--r--compiler/rustc_typeck/src/collect/type_of.rs80
-rw-r--r--compiler/rustc_typeck/src/constrained_generic_params.rs2
-rw-r--r--compiler/rustc_typeck/src/expr_use_visitor.rs2
-rw-r--r--compiler/rustc_typeck/src/impl_wf_check.rs9
-rw-r--r--compiler/rustc_typeck/src/lib.rs8
-rw-r--r--compiler/rustc_typeck/src/mem_categorization.rs2
-rw-r--r--compiler/rustc_typeck/src/outlives/implicit_infer.rs9
-rw-r--r--compiler/rustc_typeck/src/outlives/test.rs6
-rw-r--r--compiler/rustc_typeck/src/variance/constraints.rs14
-rw-r--r--compiler/rustc_typeck/src/variance/terms.rs14
-rw-r--r--compiler/rustc_typeck/src/variance/test.rs6
370 files changed, 9552 insertions, 7065 deletions
diff --git a/compiler/rustc_apfloat/Cargo.toml b/compiler/rustc_apfloat/Cargo.toml
index 306513f1a7e..103e64be5ac 100644
--- a/compiler/rustc_apfloat/Cargo.toml
+++ b/compiler/rustc_apfloat/Cargo.toml
@@ -6,4 +6,4 @@ edition = "2018"
 
 [dependencies]
 bitflags = "1.2.1"
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml
index 29caa852ed4..f2d039c82ab 100644
--- a/compiler/rustc_arena/Cargo.toml
+++ b/compiler/rustc_arena/Cargo.toml
@@ -5,4 +5,4 @@ version = "0.0.0"
 edition = "2018"
 
 [dependencies]
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 651f4c6fabd..f17c43ceaff 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -568,10 +568,13 @@ impl Drop for DropType {
 }
 
 /// An arena which can be used to allocate any type.
+///
+/// # Safety
+///
 /// Allocating in this arena is unsafe since the type system
 /// doesn't know which types it contains. In order to
-/// allocate safely, you must store a PhantomData<T>
-/// alongside this arena for each type T you allocate.
+/// allocate safely, you must store a `PhantomData<T>`
+/// alongside this arena for each type `T` you allocate.
 #[derive(Default)]
 pub struct DropArena {
     /// A list of destructors to run when the arena drops.
@@ -589,7 +592,7 @@ impl DropArena {
         ptr::write(mem, object);
         let result = &mut *mem;
         // Record the destructor after doing the allocation as that may panic
-        // and would cause `object`'s destructor to run twice if it was recorded before
+        // and would cause `object`'s destructor to run twice if it was recorded before.
         self.destructors
             .borrow_mut()
             .push(DropType { drop_fn: drop_for_type::<T>, obj: result as *mut T as *mut u8 });
@@ -607,16 +610,16 @@ impl DropArena {
         let start_ptr = self.arena.alloc_raw(Layout::array::<T>(len).unwrap()) as *mut T;
 
         let mut destructors = self.destructors.borrow_mut();
-        // Reserve space for the destructors so we can't panic while adding them
+        // Reserve space for the destructors so we can't panic while adding them.
         destructors.reserve(len);
 
         // Move the content to the arena by copying it and then forgetting
-        // the content of the SmallVec
+        // the content of the SmallVec.
         vec.as_ptr().copy_to_nonoverlapping(start_ptr, len);
         mem::forget(vec.drain(..));
 
         // Record the destructors after doing the allocation as that may panic
-        // and would cause `object`'s destructor to run twice if it was recorded before
+        // and would cause `object`'s destructor to run twice if it was recorded before.
         for i in 0..len {
             destructors
                 .push(DropType { drop_fn: drop_for_type::<T>, obj: start_ptr.add(i) as *mut u8 });
diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml
index 13e17a807c4..6b9b9e8155e 100644
--- a/compiler/rustc_ast/Cargo.toml
+++ b/compiler/rustc_ast/Cargo.toml
@@ -15,5 +15,5 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_index = { path = "../rustc_index" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_macros = { path = "../rustc_macros" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 bitflags = "1.2.1"
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 2ddcb9ef844..3550055ac10 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -486,8 +486,8 @@ pub struct WhereEqPredicate {
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Crate {
-    pub module: Mod,
     pub attrs: Vec<Attribute>,
+    pub items: Vec<P<Item>>,
     pub span: Span,
     /// The order of items in the HIR is unrelated to the order of
     /// items in the AST. However, we generate proc macro harnesses
@@ -2299,21 +2299,22 @@ impl FnRetTy {
     }
 }
 
-/// Module declaration.
-///
-/// E.g., `mod foo;` or `mod foo { .. }`.
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug)]
+pub enum Inline {
+    Yes,
+    No,
+}
+
+/// Module item kind.
 #[derive(Clone, Encodable, Decodable, Debug)]
-pub struct Mod {
-    /// A span from the first token past `{` to the last token until `}`.
-    /// For `mod foo;`, the inner span ranges from the first token
-    /// to the last token in the external file.
-    pub inner: Span,
-    /// `unsafe` keyword accepted syntactically for macro DSLs, but not
-    /// semantically by Rust.
-    pub unsafety: Unsafe,
-    pub items: Vec<P<Item>>,
-    /// `true` for `mod foo { .. }`; `false` for `mod foo;`.
-    pub inline: bool,
+pub enum ModKind {
+    /// Module with inlined definition `mod foo { ... }`,
+    /// or with definition outlined to a separate file `mod foo;` and already loaded from it.
+    /// The inner span is from the first token past `{` to the last token until `}`,
+    /// or from the first to the last token in the loaded file.
+    Loaded(Vec<P<Item>>, Inline, Span),
+    /// Module with definition outlined to a separate file `mod foo;` but not yet loaded from it.
+    Unloaded,
 }
 
 /// Foreign module declaration.
@@ -2710,7 +2711,9 @@ pub enum ItemKind {
     /// A module declaration (`mod`).
     ///
     /// E.g., `mod foo;` or `mod foo { .. }`.
-    Mod(Mod),
+    /// `unsafe` keyword on modules is accepted syntactically for macro DSLs, but not
+    /// semantically by Rust.
+    Mod(Unsafe, ModKind),
     /// An external module (`extern`).
     ///
     /// E.g., `extern {}` or `extern "C" {}`.
@@ -2975,3 +2978,18 @@ macro_rules! derive_has_tokens {
 derive_has_tokens! {
     Item, Expr, Ty, AttrItem, Visibility, Path, Block, Pat
 }
+
+macro_rules! derive_has_attrs_no_tokens {
+    ($($ty:path),*) => { $(
+        impl HasTokens for $ty {
+            fn finalize_tokens(&mut self, _tokens: LazyTokenStream) {}
+        }
+    )* }
+}
+
+// These ast nodes only support inert attributes, so they don't
+// store tokens (since nothing can observe them)
+derive_has_attrs_no_tokens! {
+    StructField, Arm,
+    Field, FieldPat, Variant, Param, GenericParam
+}
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 0f411eda49d..ddf52caed08 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -14,7 +14,6 @@
 #![feature(const_fn_transmute)]
 #![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
-#![feature(iterator_fold_self)]
 #![feature(label_break_value)]
 #![feature(nll)]
 #![feature(or_patterns)]
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 90d31d4801f..c286738811c 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -28,7 +28,7 @@ pub trait ExpectOne<A: Array> {
 
 impl<A: Array> ExpectOne<A> for SmallVec<A> {
     fn expect_one(self, err: &'static str) -> A::Item {
-        assert!(self.len() == 1, err);
+        assert!(self.len() == 1, "{}", err);
         self.into_iter().next().unwrap()
     }
 }
@@ -170,10 +170,6 @@ pub trait MutVisitor: Sized {
         noop_visit_ty_constraint(t, self);
     }
 
-    fn visit_mod(&mut self, m: &mut Mod) {
-        noop_visit_mod(m, self);
-    }
-
     fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
         noop_visit_foreign_mod(nm, self);
     }
@@ -917,7 +913,13 @@ pub fn noop_visit_item_kind<T: MutVisitor>(kind: &mut ItemKind, vis: &mut T) {
             vis.visit_generics(generics);
             visit_opt(body, |body| vis.visit_block(body));
         }
-        ItemKind::Mod(m) => vis.visit_mod(m),
+        ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
+            ModKind::Loaded(items, _inline, inner_span) => {
+                vis.visit_span(inner_span);
+                items.flat_map_in_place(|item| vis.flat_map_item(item));
+            }
+            ModKind::Unloaded => {}
+        },
         ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
         ItemKind::GlobalAsm(_ga) => {}
         ItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
@@ -998,14 +1000,10 @@ pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
     vis.visit_asyncness(asyncness);
 }
 
-pub fn noop_visit_mod<T: MutVisitor>(module: &mut Mod, vis: &mut T) {
-    let Mod { inner, unsafety: _, items, inline: _ } = module;
-    vis.visit_span(inner);
-    items.flat_map_in_place(|item| vis.flat_map_item(item));
-}
-
+// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible,
+// or make crate visiting first class if necessary.
 pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
-    visit_clobber(krate, |Crate { module, attrs, span, proc_macros }| {
+    visit_clobber(krate, |Crate { attrs, items, span, proc_macros }| {
         let item_vis =
             Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None };
         let item = P(Item {
@@ -1014,19 +1012,20 @@ pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
             id: DUMMY_NODE_ID,
             vis: item_vis,
             span,
-            kind: ItemKind::Mod(module),
+            kind: ItemKind::Mod(Unsafe::No, ModKind::Loaded(items, Inline::Yes, span)),
             tokens: None,
         });
         let items = vis.flat_map_item(item);
 
         let len = items.len();
         if len == 0 {
-            let module = Mod { inner: span, unsafety: Unsafe::No, items: vec![], inline: true };
-            Crate { module, attrs: vec![], span, proc_macros }
+            Crate { attrs: vec![], items: vec![], span, proc_macros }
         } else if len == 1 {
             let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner();
             match kind {
-                ItemKind::Mod(module) => Crate { module, attrs, span, proc_macros },
+                ItemKind::Mod(_, ModKind::Loaded(items, ..)) => {
+                    Crate { attrs, items, span, proc_macros }
+                }
                 _ => panic!("visitor converted a module to not a module"),
             }
         } else {
diff --git a/compiler/rustc_ast/src/node_id.rs b/compiler/rustc_ast/src/node_id.rs
index 6e7d2bab287..d20bace6088 100644
--- a/compiler/rustc_ast/src/node_id.rs
+++ b/compiler/rustc_ast/src/node_id.rs
@@ -2,6 +2,12 @@ use rustc_span::ExpnId;
 use std::fmt;
 
 rustc_index::newtype_index! {
+    /// Identifies an AST node.
+    ///
+    /// This identifies top-level definitions, expressions, and everything in between.
+    /// This is later turned into [`DefId`] and `HirId` for the HIR.
+    ///
+    /// [`DefId`]: rustc_span::def_id::DefId
     pub struct NodeId {
         DEBUG_FORMAT = "NodeId({})"
     }
@@ -9,12 +15,12 @@ rustc_index::newtype_index! {
 
 rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeId);
 
-/// `NodeId` used to represent the root of the crate.
+/// The [`NodeId`] used to represent the root of the crate.
 pub const CRATE_NODE_ID: NodeId = NodeId::from_u32(0);
 
-/// When parsing and doing expansions, we initially give all AST nodes this AST
-/// node value. Then later, during expansion, we renumber them to have small,
-/// positive ids.
+/// When parsing and at the beginning of doing expansions, we initially give all AST nodes
+/// this dummy AST [`NodeId`]. Then, during a later phase of expansion, we renumber them
+/// to have small, positive IDs.
 pub const DUMMY_NODE_ID: NodeId = NodeId::MAX;
 
 impl NodeId {
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index c37d4cd9f79..32b9dd46bae 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -74,7 +74,7 @@ impl<'a> FnKind<'a> {
 /// Each method of the `Visitor` trait is a hook to be potentially
 /// overridden. Each method's default implementation recursively visits
 /// the substructure of the input via the corresponding `walk` method;
-/// e.g., the `visit_mod` method by default calls `visit::walk_mod`.
+/// e.g., the `visit_item` method by default calls `visit::walk_item`.
 ///
 /// If you want to ensure that your code handles every variant
 /// explicitly, you need to override each method. (And you also need
@@ -87,9 +87,6 @@ pub trait Visitor<'ast>: Sized {
     fn visit_ident(&mut self, ident: Ident) {
         walk_ident(self, ident);
     }
-    fn visit_mod(&mut self, m: &'ast Mod, _s: Span, _attrs: &[Attribute], _n: NodeId) {
-        walk_mod(self, m);
-    }
     fn visit_foreign_item(&mut self, i: &'ast ForeignItem) {
         walk_foreign_item(self, i)
     }
@@ -238,14 +235,10 @@ pub fn walk_ident<'a, V: Visitor<'a>>(visitor: &mut V, ident: Ident) {
 }
 
 pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) {
-    visitor.visit_mod(&krate.module, krate.span, &krate.attrs, CRATE_NODE_ID);
+    walk_list!(visitor, visit_item, &krate.items);
     walk_list!(visitor, visit_attribute, &krate.attrs);
 }
 
-pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, module: &'a Mod) {
-    walk_list!(visitor, visit_item, &module.items);
-}
-
 pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) {
     for attr in local.attrs.iter() {
         visitor.visit_attribute(attr);
@@ -297,7 +290,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
             let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
             visitor.visit_fn(kind, item.span, item.id)
         }
-        ItemKind::Mod(ref module) => visitor.visit_mod(module, item.span, &item.attrs, item.id),
+        ItemKind::Mod(_unsafety, ref mod_kind) => match mod_kind {
+            ModKind::Loaded(items, _inline, _inner_span) => {
+                walk_list!(visitor, visit_item, items)
+            }
+            ModKind::Unloaded => {}
+        },
         ItemKind::ForeignMod(ref foreign_module) => {
             walk_list!(visitor, visit_foreign_item, &foreign_module.items);
         }
diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml
index 177a9066edf..0cced00189e 100644
--- a/compiler/rustc_ast_lowering/Cargo.toml
+++ b/compiler/rustc_ast_lowering/Cargo.toml
@@ -19,4 +19,4 @@ rustc_span = { path = "../rustc_span" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_session = { path = "../rustc_session" }
 rustc_ast = { path = "../rustc_ast" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 4d6afd2fe0d..b118c0eaed4 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -260,9 +260,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
         match u {
-            UnOp::Deref => hir::UnOp::UnDeref,
-            UnOp::Not => hir::UnOp::UnNot,
-            UnOp::Neg => hir::UnOp::UnNeg,
+            UnOp::Deref => hir::UnOp::Deref,
+            UnOp::Not => hir::UnOp::Not,
+            UnOp::Neg => hir::UnOp::Neg,
         }
     }
 
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 1efe83cacea..8b740b77740 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -15,11 +15,11 @@ use rustc_span::source_map::{respan, DesugaringKind};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use rustc_target::spec::abi;
-
 use smallvec::{smallvec, SmallVec};
-use std::collections::BTreeSet;
 use tracing::debug;
 
+use std::mem;
+
 pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
     pub(super) lctx: &'a mut LoweringContext<'lowering, 'hir>,
 }
@@ -34,32 +34,13 @@ impl ItemLowerer<'_, '_, '_> {
 }
 
 impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
-    fn visit_mod(&mut self, m: &'a Mod, _s: Span, _attrs: &[Attribute], n: NodeId) {
-        let hir_id = self.lctx.lower_node_id(n);
-
-        self.lctx.modules.insert(
-            hir_id,
-            hir::ModuleItems {
-                items: BTreeSet::new(),
-                trait_items: BTreeSet::new(),
-                impl_items: BTreeSet::new(),
-                foreign_items: BTreeSet::new(),
-            },
-        );
-
-        let old = self.lctx.current_module;
-        self.lctx.current_module = hir_id;
-        visit::walk_mod(self, m);
-        self.lctx.current_module = old;
-    }
-
     fn visit_item(&mut self, item: &'a Item) {
         let mut item_hir_id = None;
         self.lctx.with_hir_id_owner(item.id, |lctx| {
             lctx.without_in_scope_lifetime_defs(|lctx| {
                 if let Some(hir_item) = lctx.lower_item(item) {
-                    item_hir_id = Some(hir_item.hir_id);
-                    lctx.insert_item(hir_item);
+                    let id = lctx.insert_item(hir_item);
+                    item_hir_id = Some(id);
                 }
             })
         });
@@ -67,10 +48,18 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
         if let Some(hir_id) = item_hir_id {
             self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
                 let this = &mut ItemLowerer { lctx: this };
-                if let ItemKind::Impl(box ImplKind { ref of_trait, .. }) = item.kind {
-                    this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
-                } else {
-                    visit::walk_item(this, item);
+                match item.kind {
+                    ItemKind::Mod(..) => {
+                        let def_id = this.lctx.lower_node_id(item.id).expect_owner();
+                        let old_current_module =
+                            mem::replace(&mut this.lctx.current_module, def_id);
+                        visit::walk_item(this, item);
+                        this.lctx.current_module = old_current_module;
+                    }
+                    ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
+                        this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
+                    }
+                    _ => visit::walk_item(this, item),
                 }
             });
         }
@@ -92,15 +81,15 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
         self.lctx.with_hir_id_owner(item.id, |lctx| match ctxt {
             AssocCtxt::Trait => {
                 let hir_item = lctx.lower_trait_item(item);
-                let id = hir::TraitItemId { hir_id: hir_item.hir_id };
+                let id = hir_item.trait_item_id();
                 lctx.trait_items.insert(id, hir_item);
-                lctx.modules.get_mut(&lctx.current_module).unwrap().trait_items.insert(id);
+                lctx.modules.entry(lctx.current_module).or_default().trait_items.insert(id);
             }
             AssocCtxt::Impl => {
                 let hir_item = lctx.lower_impl_item(item);
-                let id = hir::ImplItemId { hir_id: hir_item.hir_id };
+                let id = hir_item.impl_item_id();
                 lctx.impl_items.insert(id, hir_item);
-                lctx.modules.get_mut(&lctx.current_module).unwrap().impl_items.insert(id);
+                lctx.modules.entry(lctx.current_module).or_default().impl_items.insert(id);
             }
         });
 
@@ -111,9 +100,9 @@ impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
         self.lctx.allocate_hir_id_counter(item.id);
         self.lctx.with_hir_id_owner(item.id, |lctx| {
             let hir_item = lctx.lower_foreign_item(item);
-            let id = hir::ForeignItemId { hir_id: hir_item.hir_id };
+            let id = hir_item.foreign_item_id();
             lctx.foreign_items.insert(id, hir_item);
-            lctx.modules.get_mut(&lctx.current_module).unwrap().foreign_items.insert(id);
+            lctx.modules.entry(lctx.current_module).or_default().foreign_items.insert(id);
         });
 
         visit::walk_foreign_item(self, item);
@@ -128,14 +117,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
     // only used when lowering a child item of a trait or impl.
     fn with_parent_item_lifetime_defs<T>(
         &mut self,
-        parent_hir_id: hir::HirId,
+        parent_hir_id: hir::ItemId,
         f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T,
     ) -> T {
         let old_len = self.in_scope_lifetimes.len();
 
         let parent_generics = match self.items.get(&parent_hir_id).unwrap().kind {
             hir::ItemKind::Impl(hir::Impl { ref generics, .. })
-            | hir::ItemKind::Trait(_, _, ref generics, ..) => &generics.params[..],
+            | hir::ItemKind::Trait(_, _, ref generics, ..) => generics.params,
             _ => &[],
         };
         let lt_def_names = parent_generics.iter().filter_map(|param| match param.kind {
@@ -157,7 +146,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         &mut self,
         f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T,
     ) -> T {
-        let old_in_scope_lifetimes = std::mem::replace(&mut self.in_scope_lifetimes, vec![]);
+        let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
 
         // this vector is only used when walking over impl headers,
         // input types, and the like, and should not be non-empty in
@@ -172,12 +161,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
         res
     }
 
-    pub(super) fn lower_mod(&mut self, m: &Mod) -> hir::Mod<'hir> {
+    pub(super) fn lower_mod(&mut self, items: &[P<Item>], inner: Span) -> hir::Mod<'hir> {
         hir::Mod {
-            inner: m.inner,
-            item_ids: self
-                .arena
-                .alloc_from_iter(m.items.iter().flat_map(|x| self.lower_item_id(x))),
+            inner,
+            item_ids: self.arena.alloc_from_iter(items.iter().flat_map(|x| self.lower_item_id(x))),
         }
     }
 
@@ -197,7 +184,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         node_ids
             .into_iter()
-            .map(|node_id| hir::ItemId { id: self.allocate_hir_id_counter(node_id) })
+            .map(|node_id| hir::ItemId {
+                def_id: self.allocate_hir_id_counter(node_id).expect_owner(),
+            })
             .collect()
     }
 
@@ -232,13 +221,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         if let ItemKind::MacroDef(MacroDef { ref body, macro_rules }) = i.kind {
             if !macro_rules || self.sess.contains_name(&i.attrs, sym::macro_export) {
-                let hir_id = self.lower_node_id(i.id);
+                let def_id = self.lower_node_id(i.id).expect_owner();
                 let body = P(self.lower_mac_args(body));
                 self.exported_macros.push(hir::MacroDef {
                     ident,
                     vis,
                     attrs,
-                    hir_id,
+                    def_id,
                     span: i.span,
                     ast: MacroDef { body, macro_rules },
                 });
@@ -250,7 +239,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
         let kind = self.lower_item_kind(i.span, i.id, &mut ident, attrs, &mut vis, &i.kind);
 
-        Some(hir::Item { hir_id: self.lower_node_id(i.id), ident, attrs, kind, vis, span: i.span })
+        Some(hir::Item {
+            def_id: self.lower_node_id(i.id).expect_owner(),
+            ident,
+            attrs,
+            kind,
+            vis,
+            span: i.span,
+        })
     }
 
     fn lower_item_kind(
@@ -318,7 +314,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     hir::ItemKind::Fn(sig, generics, body_id)
                 })
             }
-            ItemKind::Mod(ref m) => hir::ItemKind::Mod(self.lower_mod(m)),
+            ItemKind::Mod(_, ref mod_kind) => match mod_kind {
+                ModKind::Loaded(items, _, inner_span) => {
+                    hir::ItemKind::Mod(self.lower_mod(items, *inner_span))
+                }
+                ModKind::Unloaded => panic!("`mod` items should have been loaded by now"),
+            },
             ItemKind::ForeignMod(ref fm) => {
                 if fm.abi.is_none() {
                     self.maybe_lint_missing_abi(span, id, abi::Abi::C);
@@ -387,8 +388,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 self_ty: ref ty,
                 items: ref impl_items,
             }) => {
-                let def_id = self.resolver.local_def_id(id);
-
                 // Lower the "impl header" first. This ordering is important
                 // for in-band lifetimes! Consider `'a` here:
                 //
@@ -402,10 +401,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 // method, it will not be considered an in-band
                 // lifetime to be added, but rather a reference to a
                 // parent lifetime.
-                let lowered_trait_impl_id = self.lower_node_id(id);
+                let lowered_trait_def_id = self.lower_node_id(id).expect_owner();
                 let (generics, (trait_ref, lowered_ty)) = self.add_in_band_defs(
                     ast_generics,
-                    def_id,
+                    lowered_trait_def_id,
                     AnonymousLifetimeMode::CreateParameter,
                     |this, _| {
                         let trait_ref = trait_ref.as_ref().map(|trait_ref| {
@@ -417,7 +416,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                                 this.trait_impls
                                     .entry(def_id)
                                     .or_default()
-                                    .push(lowered_trait_impl_id);
+                                    .push(lowered_trait_def_id);
                             }
                         }
 
@@ -557,7 +556,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         let vis = this.rebuild_vis(&vis);
 
                         this.insert_item(hir::Item {
-                            hir_id: new_id,
+                            def_id: new_id.expect_owner(),
                             ident,
                             attrs,
                             kind,
@@ -629,7 +628,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                             this.lower_use_tree(use_tree, &prefix, id, &mut vis, &mut ident, attrs);
 
                         this.insert_item(hir::Item {
-                            hir_id: new_hir_id,
+                            def_id: new_hir_id.expect_owner(),
                             ident,
                             attrs,
                             kind,
@@ -702,7 +701,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem<'hir> {
         let def_id = self.resolver.local_def_id(i.id);
         hir::ForeignItem {
-            hir_id: self.lower_node_id(i.id),
+            def_id,
             ident: i.ident,
             attrs: self.lower_attrs(&i.attrs),
             kind: match i.kind {
@@ -737,7 +736,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef<'hir> {
         hir::ForeignItemRef {
-            id: hir::ForeignItemId { hir_id: self.lower_node_id(i.id) },
+            id: hir::ForeignItemId { def_id: self.lower_node_id(i.id).expect_owner() },
             ident: i.ident,
             span: i.span,
             vis: self.lower_visibility(&i.vis, Some(i.id)),
@@ -837,7 +836,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         };
 
         hir::TraitItem {
-            hir_id: self.lower_node_id(i.id),
+            def_id: trait_item_def_id,
             ident: i.ident,
             attrs: self.lower_attrs(&i.attrs),
             generics,
@@ -857,7 +856,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
             AssocItemKind::MacCall(..) => unimplemented!(),
         };
-        let id = hir::TraitItemId { hir_id: self.lower_node_id(i.id) };
+        let id = hir::TraitItemId { def_id: self.lower_node_id(i.id).expect_owner() };
         let defaultness = hir::Defaultness::Default { has_value: has_default };
         hir::TraitItemRef { id, ident: i.ident, span: i.span, defaultness, kind }
     }
@@ -922,7 +921,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let has_value = true;
         let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
         hir::ImplItem {
-            hir_id: self.lower_node_id(i.id),
+            def_id: self.lower_node_id(i.id).expect_owner(),
             ident: i.ident,
             attrs: self.lower_attrs(&i.attrs),
             generics,
@@ -938,7 +937,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let has_value = true;
         let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
         hir::ImplItemRef {
-            id: hir::ImplItemId { hir_id: self.lower_node_id(i.id) },
+            id: hir::ImplItemId { def_id: self.lower_node_id(i.id).expect_owner() },
             ident: i.ident,
             span: i.span,
             vis: self.lower_visibility(&i.vis, Some(i.id)),
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index b7f227da73e..05b417effd4 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -48,7 +48,7 @@ use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace, PartialRes, PerNS, Res};
-use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
 use rustc_hir::intravisit;
 use rustc_hir::{ConstArg, GenericArg, ParamName};
@@ -99,7 +99,7 @@ struct LoweringContext<'a, 'hir: 'a> {
     arena: &'hir Arena<'hir>,
 
     /// The items being lowered are collected here.
-    items: BTreeMap<hir::HirId, hir::Item<'hir>>,
+    items: BTreeMap<hir::ItemId, hir::Item<'hir>>,
 
     trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem<'hir>>,
     impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem<'hir>>,
@@ -108,9 +108,9 @@ struct LoweringContext<'a, 'hir: 'a> {
     exported_macros: Vec<hir::MacroDef<'hir>>,
     non_exported_macro_attrs: Vec<ast::Attribute>,
 
-    trait_impls: BTreeMap<DefId, Vec<hir::HirId>>,
+    trait_impls: BTreeMap<DefId, Vec<LocalDefId>>,
 
-    modules: BTreeMap<hir::HirId, hir::ModuleItems>,
+    modules: BTreeMap<LocalDefId, hir::ModuleItems>,
 
     generator_kind: Option<hir::GeneratorKind>,
 
@@ -158,7 +158,7 @@ struct LoweringContext<'a, 'hir: 'a> {
     /// vector.
     in_scope_lifetimes: Vec<ParamName>,
 
-    current_module: hir::HirId,
+    current_module: LocalDefId,
 
     type_def_lifetime_params: DefIdMap<usize>,
 
@@ -314,8 +314,8 @@ pub fn lower_crate<'a, 'hir>(
         is_in_dyn_type: false,
         anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
         type_def_lifetime_params: Default::default(),
-        current_module: hir::CRATE_HIR_ID,
-        current_hir_id_owner: vec![(LocalDefId { local_def_index: CRATE_DEF_INDEX }, 0)],
+        current_module: CRATE_DEF_ID,
+        current_hir_id_owner: vec![(CRATE_DEF_ID, 0)],
         item_local_id_counters: Default::default(),
         node_id_to_hir_id: IndexVec::new(),
         generator_kind: None,
@@ -560,7 +560,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         visit::walk_crate(&mut MiscCollector { lctx: &mut self }, c);
         visit::walk_crate(&mut item::ItemLowerer { lctx: &mut self }, c);
 
-        let module = self.lower_mod(&c.module);
+        let module = self.lower_mod(&c.items, c.span);
         let attrs = self.lower_attrs(&c.attrs);
         let body_ids = body_ids(&self.bodies);
         let proc_macros =
@@ -605,12 +605,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
     }
 
-    fn insert_item(&mut self, item: hir::Item<'hir>) {
-        let id = item.hir_id;
-        // FIXME: Use `debug_asset-rt`.
-        assert_eq!(id.local_id, hir::ItemLocalId::from_u32(0));
+    fn insert_item(&mut self, item: hir::Item<'hir>) -> hir::ItemId {
+        let id = hir::ItemId { def_id: item.def_id };
         self.items.insert(id, item);
-        self.modules.get_mut(&self.current_module).unwrap().items.insert(id);
+        self.modules.entry(self.current_module).or_default().items.insert(id);
+        id
     }
 
     fn allocate_hir_id_counter(&mut self, owner: NodeId) -> hir::HirId {
@@ -1076,16 +1075,40 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_assoc_ty_constraint(
         &mut self,
         constraint: &AssocTyConstraint,
-        itctx: ImplTraitContext<'_, 'hir>,
+        mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
 
-        if let Some(ref gen_args) = constraint.gen_args {
-            self.sess.span_fatal(
-                gen_args.span(),
-                "generic associated types in trait paths are currently not implemented",
-            );
-        }
+        // lower generic arguments of identifier in constraint
+        let gen_args = if let Some(ref gen_args) = constraint.gen_args {
+            let gen_args_ctor = match gen_args {
+                GenericArgs::AngleBracketed(ref data) => {
+                    self.lower_angle_bracketed_parameter_data(
+                        data,
+                        ParamMode::Explicit,
+                        itctx.reborrow(),
+                    )
+                    .0
+                }
+                GenericArgs::Parenthesized(ref data) => {
+                    let mut err = self.sess.struct_span_err(
+                        gen_args.span(),
+                        "parenthesized generic arguments cannot be used in associated type constraints"
+                    );
+                    // FIXME: try to write a suggestion here
+                    err.emit();
+                    self.lower_angle_bracketed_parameter_data(
+                        &data.as_angle_bracketed_args(),
+                        ParamMode::Explicit,
+                        itctx.reborrow(),
+                    )
+                    .0
+                }
+            };
+            self.arena.alloc(gen_args_ctor.into_generic_args(&self.arena))
+        } else {
+            self.arena.alloc(hir::GenericArgs::none())
+        };
 
         let kind = match constraint.kind {
             AssocTyConstraintKind::Equality { ref ty } => {
@@ -1182,6 +1205,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         hir::TypeBinding {
             hir_id: self.lower_node_id(constraint.id),
             ident: constraint.ident,
+            gen_args,
             kind,
             span: constraint.span,
         }
@@ -1522,11 +1546,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             };
 
             trace!("lower_opaque_impl_trait: {:#?}", opaque_ty_def_id);
-            let opaque_ty_id =
-                lctx.generate_opaque_type(opaque_ty_node_id, opaque_ty_item, span, opaque_ty_span);
+            lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span);
 
             // `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
-            hir::TyKind::OpaqueDef(hir::ItemId { id: opaque_ty_id }, lifetimes)
+            hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, lifetimes)
         })
     }
 
@@ -1534,17 +1557,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// returns the lowered node-ID for the opaque type.
     fn generate_opaque_type(
         &mut self,
-        opaque_ty_node_id: NodeId,
+        opaque_ty_id: LocalDefId,
         opaque_ty_item: hir::OpaqueTy<'hir>,
         span: Span,
         opaque_ty_span: Span,
-    ) -> hir::HirId {
+    ) {
         let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(opaque_ty_item);
-        let opaque_ty_id = self.lower_node_id(opaque_ty_node_id);
         // Generate an `type Foo = impl Trait;` declaration.
         trace!("registering opaque type with id {:#?}", opaque_ty_id);
         let opaque_ty_item = hir::Item {
-            hir_id: opaque_ty_id,
+            def_id: opaque_ty_id,
             ident: Ident::invalid(),
             attrs: Default::default(),
             kind: opaque_ty_item_kind,
@@ -1556,7 +1578,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // automatically for all AST items. But this opaque type item
         // does not actually exist in the AST.
         self.insert_item(opaque_ty_item);
-        opaque_ty_id
     }
 
     fn lifetimes_from_impl_trait_bounds(
@@ -1985,7 +2006,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // grow.
         let input_lifetimes_count = self.in_scope_lifetimes.len() + self.lifetimes_to_define.len();
 
-        let (opaque_ty_id, lifetime_params) = self.with_hir_id_owner(opaque_ty_node_id, |this| {
+        let lifetime_params = self.with_hir_id_owner(opaque_ty_node_id, |this| {
             // We have to be careful to get elision right here. The
             // idea is that we create a lifetime parameter for each
             // lifetime in the return type.  So, given a return type
@@ -2036,10 +2057,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             };
 
             trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
-            let opaque_ty_id =
-                this.generate_opaque_type(opaque_ty_node_id, opaque_ty_item, span, opaque_ty_span);
+            this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span);
 
-            (opaque_ty_id, lifetime_params)
+            lifetime_params
         });
 
         // As documented above on the variable
@@ -2082,7 +2102,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // Foo = impl Trait` is, internally, created as a child of the
         // async fn, so the *type parameters* are inherited.  It's
         // only the lifetime parameters that we must supply.
-        let opaque_ty_ref = hir::TyKind::OpaqueDef(hir::ItemId { id: opaque_ty_id }, generic_args);
+        let opaque_ty_ref =
+            hir::TyKind::OpaqueDef(hir::ItemId { def_id: opaque_ty_def_id }, generic_args);
         let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
         hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
     }
@@ -2407,7 +2428,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let mut ids: SmallVec<[hir::Stmt<'hir>; 1]> = item_ids
                     .into_iter()
                     .map(|item_id| {
-                        let item_id = hir::ItemId { id: self.lower_node_id(item_id) };
+                        let item_id = hir::ItemId {
+                            // All the items that `lower_local` finds are `impl Trait` types.
+                            def_id: self.lower_node_id(item_id).expect_owner(),
+                        };
                         self.stmt(s.span, hir::StmtKind::Item(item_id))
                     })
                     .collect();
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 9079e26eb50..cb4d5ea6ee6 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -362,7 +362,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
     }
 
-    fn lower_angle_bracketed_parameter_data(
+    pub(crate) fn lower_angle_bracketed_parameter_data(
         &mut self,
         data: &AngleBracketedArgs,
         param_mode: ParamMode,
@@ -426,6 +426,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     ) -> hir::TypeBinding<'hir> {
         let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
         let kind = hir::TypeBindingKind::Equality { ty };
-        hir::TypeBinding { hir_id: self.next_id(), span, ident, kind }
+        let args = arena_vec![self;];
+        let bindings = arena_vec![self;];
+        let gen_args = self.arena.alloc(hir::GenericArgs { args, bindings, parenthesized: false });
+        hir::TypeBinding { hir_id: self.next_id(), gen_args, span, ident, kind }
     }
 }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 8defd91c688..563bcda5190 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1054,12 +1054,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 walk_list!(self, visit_attribute, &item.attrs);
                 return;
             }
-            ItemKind::Mod(Mod { inline, unsafety, .. }) => {
+            ItemKind::Mod(unsafety, ref mod_kind) => {
                 if let Unsafe::Yes(span) = unsafety {
                     self.err_handler().span_err(span, "module cannot be declared unsafe");
                 }
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
-                if !inline && !self.session.contains_name(&item.attrs, sym::path) {
+                if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
+                    && !self.session.contains_name(&item.attrs, sym::path)
+                {
                     self.check_mod_file_item_asciionly(item.ident);
                 }
             }
diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs
index 2971fa435c8..fb7e0d3450f 100644
--- a/compiler/rustc_ast_passes/src/node_count.rs
+++ b/compiler/rustc_ast_passes/src/node_count.rs
@@ -20,10 +20,6 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_ident(self, ident);
     }
-    fn visit_mod(&mut self, m: &Mod, _s: Span, _a: &[Attribute], _n: NodeId) {
-        self.count += 1;
-        walk_mod(self, m)
-    }
     fn visit_foreign_item(&mut self, i: &ForeignItem) {
         self.count += 1;
         walk_foreign_item(self, i)
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 7f4775bf41a..82f6e936b76 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -9,7 +9,7 @@ use rustc_ast::util::classify;
 use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
 use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
-use rustc_ast::{GenericArg, MacArgs};
+use rustc_ast::{GenericArg, MacArgs, ModKind};
 use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
 use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@@ -87,7 +87,6 @@ pub struct State<'a> {
     pub s: pp::Printer,
     comments: Option<Comments<'a>>,
     ann: &'a (dyn PpAnn + 'a),
-    is_expanded: bool,
 }
 
 crate const INDENT_UNIT: usize = 4;
@@ -103,12 +102,8 @@ pub fn print_crate<'a>(
     is_expanded: bool,
     edition: Edition,
 ) -> String {
-    let mut s = State {
-        s: pp::mk_printer(),
-        comments: Some(Comments::new(sm, filename, input)),
-        ann,
-        is_expanded,
-    };
+    let mut s =
+        State { s: pp::mk_printer(), comments: Some(Comments::new(sm, filename, input)), ann };
 
     if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
         // We need to print `#![no_std]` (and its feature gate) so that
@@ -132,7 +127,10 @@ pub fn print_crate<'a>(
         }
     }
 
-    s.print_mod(&krate.module, &krate.attrs);
+    s.print_inner_attributes(&krate.attrs);
+    for item in &krate.items {
+        s.print_item(item);
+    }
     s.print_remaining_comments();
     s.ann.post(&mut s, AnnNode::Crate(krate));
     s.s.eof()
@@ -853,7 +851,7 @@ 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 }
+        State { s: pp::mk_printer(), comments: None, ann: &NoAnn }
     }
 
     // Synthesizes a comment that was not textually present in the original source
@@ -891,13 +889,6 @@ impl<'a> State<'a> {
         self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
     }
 
-    pub fn print_mod(&mut self, _mod: &ast::Mod, attrs: &[ast::Attribute]) {
-        self.print_inner_attributes(attrs);
-        for item in &_mod.items {
-            self.print_item(item);
-        }
-    }
-
     crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
         self.print_inner_attributes(attrs);
         for item in &nmod.items {
@@ -914,6 +905,7 @@ impl<'a> State<'a> {
 
     pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
         self.print_ident(constraint.ident);
+        constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
         self.s.space();
         match &constraint.kind {
             ast::AssocTyConstraintKind::Equality { ty } => {
@@ -1138,23 +1130,29 @@ impl<'a> State<'a> {
                 let body = body.as_deref();
                 self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
             }
-            ast::ItemKind::Mod(ref _mod) => {
+            ast::ItemKind::Mod(unsafety, ref mod_kind) => {
                 self.head(self.to_string(|s| {
                     s.print_visibility(&item.vis);
-                    s.print_unsafety(_mod.unsafety);
+                    s.print_unsafety(unsafety);
                     s.word("mod");
                 }));
                 self.print_ident(item.ident);
 
-                if _mod.inline || self.is_expanded {
-                    self.nbsp();
-                    self.bopen();
-                    self.print_mod(_mod, &item.attrs);
-                    self.bclose(item.span);
-                } else {
-                    self.s.word(";");
-                    self.end(); // end inner head-block
-                    self.end(); // end outer head-block
+                match mod_kind {
+                    ModKind::Loaded(items, ..) => {
+                        self.nbsp();
+                        self.bopen();
+                        self.print_inner_attributes(&item.attrs);
+                        for item in items {
+                            self.print_item(item);
+                        }
+                        self.bclose(item.span);
+                    }
+                    ModKind::Unloaded => {
+                        self.s.word(";");
+                        self.end(); // end inner head-block
+                        self.end(); // end outer head-block
+                    }
                 }
             }
             ast::ItemKind::ForeignMod(ref nmod) => {
@@ -1311,6 +1309,9 @@ impl<'a> State<'a> {
                     true,
                     item.span,
                 );
+                if macro_def.body.need_semicolon() {
+                    self.word(";");
+                }
             }
         }
         self.ann.post(self, AnnNode::Item(item))
@@ -1678,7 +1679,7 @@ impl<'a> State<'a> {
         self.ibox(INDENT_UNIT);
         self.s.word("[");
         self.print_inner_attributes_inline(attrs);
-        self.commasep_exprs(Inconsistent, &exprs[..]);
+        self.commasep_exprs(Inconsistent, exprs);
         self.s.word("]");
         self.end();
     }
@@ -1719,7 +1720,7 @@ impl<'a> State<'a> {
         self.print_inner_attributes_inline(attrs);
         self.commasep_cmnt(
             Consistent,
-            &fields[..],
+            fields,
             |s, field| {
                 s.print_outer_attributes(&field.attrs);
                 s.ibox(INDENT_UNIT);
@@ -1754,7 +1755,7 @@ impl<'a> State<'a> {
     fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>], attrs: &[ast::Attribute]) {
         self.popen();
         self.print_inner_attributes_inline(attrs);
-        self.commasep_exprs(Inconsistent, &exprs[..]);
+        self.commasep_exprs(Inconsistent, exprs);
         if exprs.len() == 1 {
             self.s.word(",");
         }
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 696d5fdd6cd..aca3fbbca13 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -74,7 +74,7 @@ pub enum InlineAttr {
     Never,
 }
 
-#[derive(Clone, Encodable, Decodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
 pub enum InstructionSetAttr {
     ArmA32,
     ArmT32,
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index c397a854126..962dfbac934 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -15,10 +15,11 @@ rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
+rustc_lexer = { path = "../rustc_lexer" }
 rustc_parse = { path = "../rustc_parse" }
 rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_ast = { path = "../rustc_ast" }
 rustc_expand = { path = "../rustc_expand" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
new file mode 100644
index 00000000000..fad64858ce3
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -0,0 +1,132 @@
+use rustc_ast::{self as ast, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
+use rustc_errors::{struct_span_err, Applicability};
+use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
+use rustc_expand::config::StripUnconfigured;
+use rustc_feature::AttributeTemplate;
+use rustc_parse::validate_attr;
+use rustc_session::Session;
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+
+crate struct Expander;
+
+impl MultiItemModifier for Expander {
+    fn expand(
+        &self,
+        ecx: &mut ExtCtxt<'_>,
+        span: Span,
+        meta_item: &ast::MetaItem,
+        item: Annotatable,
+    ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
+        let sess = ecx.sess;
+        if report_bad_target(sess, &item, span) {
+            // We don't want to pass inappropriate targets to derive macros to avoid
+            // follow up errors, all other errors below are recoverable.
+            return ExpandResult::Ready(vec![item]);
+        }
+
+        let template =
+            AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() };
+        let attr = ecx.attribute(meta_item.clone());
+        validate_attr::check_builtin_attribute(&sess.parse_sess, &attr, sym::derive, template);
+
+        let derives: Vec<_> = attr
+            .meta_item_list()
+            .unwrap_or_default()
+            .into_iter()
+            .filter_map(|nested_meta| match nested_meta {
+                NestedMetaItem::MetaItem(meta) => Some(meta),
+                NestedMetaItem::Literal(lit) => {
+                    // Reject `#[derive("Debug")]`.
+                    report_unexpected_literal(sess, &lit);
+                    None
+                }
+            })
+            .map(|meta| {
+                // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the paths.
+                report_path_args(sess, &meta);
+                meta.path
+            })
+            .collect();
+
+        // FIXME: Try to cache intermediate results to avoid collecting same paths multiple times.
+        match ecx.resolver.resolve_derives(ecx.current_expansion.id, derives, ecx.force_mode) {
+            Ok(()) => {
+                let mut visitor =
+                    StripUnconfigured { sess, features: ecx.ecfg.features, modified: false };
+                let mut item = visitor.fully_configure(item);
+                if visitor.modified {
+                    // Erase the tokens if cfg-stripping modified the item
+                    // This will cause us to synthesize fake tokens
+                    // when `nt_to_tokenstream` is called on this item.
+                    match &mut item {
+                        Annotatable::Item(item) => item,
+                        Annotatable::Stmt(stmt) => match &mut stmt.kind {
+                            StmtKind::Item(item) => item,
+                            _ => unreachable!(),
+                        },
+                        _ => unreachable!(),
+                    }
+                    .tokens = None;
+                }
+                ExpandResult::Ready(vec![item])
+            }
+            Err(Indeterminate) => ExpandResult::Retry(item),
+        }
+    }
+}
+
+fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
+    let item_kind = match item {
+        Annotatable::Item(item) => Some(&item.kind),
+        Annotatable::Stmt(stmt) => match &stmt.kind {
+            StmtKind::Item(item) => Some(&item.kind),
+            _ => None,
+        },
+        _ => None,
+    };
+
+    let bad_target =
+        !matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..)));
+    if bad_target {
+        struct_span_err!(
+            sess,
+            span,
+            E0774,
+            "`derive` may only be applied to structs, enums and unions",
+        )
+        .emit();
+    }
+    bad_target
+}
+
+fn report_unexpected_literal(sess: &Session, lit: &ast::Lit) {
+    let help_msg = match lit.token.kind {
+        token::Str if rustc_lexer::is_ident(&lit.token.symbol.as_str()) => {
+            format!("try using `#[derive({})]`", lit.token.symbol)
+        }
+        _ => "for example, write `#[derive(Debug)]` for `Debug`".to_string(),
+    };
+    struct_span_err!(sess, lit.span, E0777, "expected path to a trait, found literal",)
+        .help(&help_msg)
+        .emit();
+}
+
+fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
+    let report_error = |title, action| {
+        let span = meta.span.with_lo(meta.path.span.hi());
+        sess.struct_span_err(span, title)
+            .span_suggestion(span, action, String::new(), Applicability::MachineApplicable)
+            .emit();
+    };
+    match meta.kind {
+        MetaItemKind::Word => {}
+        MetaItemKind::List(..) => report_error(
+            "traits in `#[derive(...)]` don't accept arguments",
+            "remove the arguments",
+        ),
+        MetaItemKind::NameValue(..) => {
+            report_error("traits in `#[derive(...)]` don't accept values", "remove the value")
+        }
+    }
+}
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index c1473e24093..f84e6e07620 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -47,9 +47,10 @@ pub fn ordering_collapsed(
     span: Span,
     self_arg_tags: &[Ident],
 ) -> P<ast::Expr> {
-    let lft = cx.expr_ident(span, self_arg_tags[0]);
+    let lft = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[0]));
     let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
-    cx.expr_method_call(span, lft, Ident::new(sym::cmp, span), vec![rgt])
+    let fn_cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);
+    cx.expr_call_global(span, fn_cmp_path, vec![lft, rgt])
 }
 
 pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 21174ca4c8b..151a919e029 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -1,13 +1,11 @@
-pub use OrderingOp::*;
-
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
-use crate::deriving::{path_local, path_std, pathvec_std};
+use crate::deriving::{path_std, pathvec_std};
 
 use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, BinOpKind, Expr, MetaItem};
+use rustc_ast::{Expr, MetaItem};
 use rustc_expand::base::{Annotatable, ExtCtxt};
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 
 pub fn expand_deriving_partial_ord(
@@ -17,26 +15,6 @@ pub fn expand_deriving_partial_ord(
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
 ) {
-    macro_rules! md {
-        ($name:expr, $op:expr, $equal:expr) => {{
-            let inline = cx.meta_word(span, sym::inline);
-            let attrs = vec![cx.attribute(inline)];
-            MethodDef {
-                name: $name,
-                generics: Bounds::empty(),
-                explicit_self: borrowed_explicit_self(),
-                args: vec![(borrowed_self(), sym::other)],
-                ret_ty: Literal(path_local!(bool)),
-                attributes: attrs,
-                is_unsafe: false,
-                unify_fieldless_variants: true,
-                combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
-                    cs_op($op, $equal, cx, span, substr)
-                })),
-            }
-        }};
-    }
-
     let ordering_ty = Literal(path_std!(cmp::Ordering));
     let ret_ty = Literal(Path::new_(
         pathvec_std!(option::Option),
@@ -62,21 +40,6 @@ pub fn expand_deriving_partial_ord(
         })),
     };
 
-    // avoid defining extra methods if we can
-    // c-like enums, enums without any fields and structs without fields
-    // can safely define only `partial_cmp`.
-    let methods = if is_type_without_fields(item) {
-        vec![partial_cmp_def]
-    } else {
-        vec![
-            partial_cmp_def,
-            md!(sym::lt, true, false),
-            md!(sym::le, true, true),
-            md!(sym::gt, false, false),
-            md!(sym::ge, false, true),
-        ]
-    };
-
     let trait_def = TraitDef {
         span,
         attributes: vec![],
@@ -85,39 +48,12 @@ pub fn expand_deriving_partial_ord(
         generics: Bounds::empty(),
         is_unsafe: false,
         supports_unions: false,
-        methods,
+        methods: vec![partial_cmp_def],
         associated_types: Vec::new(),
     };
     trait_def.expand(cx, mitem, item, push)
 }
 
-#[derive(Copy, Clone)]
-pub enum OrderingOp {
-    PartialCmpOp,
-    LtOp,
-    LeOp,
-    GtOp,
-    GeOp,
-}
-
-pub fn some_ordering_collapsed(
-    cx: &mut ExtCtxt<'_>,
-    span: Span,
-    op: OrderingOp,
-    self_arg_tags: &[Ident],
-) -> P<ast::Expr> {
-    let lft = cx.expr_ident(span, self_arg_tags[0]);
-    let rgt = cx.expr_addr_of(span, cx.expr_ident(span, self_arg_tags[1]));
-    let op_sym = match op {
-        PartialCmpOp => sym::partial_cmp,
-        LtOp => sym::lt,
-        LeOp => sym::le,
-        GtOp => sym::gt,
-        GeOp => sym::ge,
-    };
-    cx.expr_method_call(span, lft, Ident::new(op_sym, span), vec![rgt])
-}
-
 pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
     let test_id = Ident::new(sym::cmp, span);
     let ordering = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
@@ -171,7 +107,11 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
             if self_args.len() != 2 {
                 cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
             } else {
-                some_ordering_collapsed(cx, span, PartialCmpOp, tag_tuple)
+                let lft = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[0]));
+                let rgt = cx.expr_addr_of(span, cx.expr_ident(span, tag_tuple[1]));
+                let fn_partial_cmp_path =
+                    cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp]);
+                cx.expr_call_global(span, fn_partial_cmp_path, vec![lft, rgt])
             }
         }),
         cx,
@@ -179,124 +119,3 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_
         substr,
     )
 }
-
-/// Strict inequality.
-fn cs_op(
-    less: bool,
-    inclusive: bool,
-    cx: &mut ExtCtxt<'_>,
-    span: Span,
-    substr: &Substructure<'_>,
-) -> P<Expr> {
-    let ordering_path = |cx: &mut ExtCtxt<'_>, name: &str| {
-        cx.expr_path(
-            cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, Symbol::intern(name)])),
-        )
-    };
-
-    let par_cmp = |cx: &mut ExtCtxt<'_>, span, self_f: P<Expr>, other_fs: &[P<Expr>], default| {
-        let other_f = match other_fs {
-            [o_f] => o_f,
-            _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
-        };
-
-        // `PartialOrd::partial_cmp(self.fi, other.fi)`
-        let cmp_path = cx.expr_path(
-            cx.path_global(span, cx.std_path(&[sym::cmp, sym::PartialOrd, sym::partial_cmp])),
-        );
-        let cmp = cx.expr_call(
-            span,
-            cmp_path,
-            vec![cx.expr_addr_of(span, self_f), cx.expr_addr_of(span, other_f.clone())],
-        );
-
-        let default = ordering_path(cx, default);
-        // `Option::unwrap_or(_, Ordering::Equal)`
-        let unwrap_path = cx.expr_path(
-            cx.path_global(span, cx.std_path(&[sym::option, sym::Option, sym::unwrap_or])),
-        );
-        cx.expr_call(span, unwrap_path, vec![cmp, default])
-    };
-
-    let fold = cs_fold1(
-        false, // need foldr
-        |cx, span, subexpr, self_f, other_fs| {
-            // build up a series of `partial_cmp`s from the inside
-            // out (hence foldr) to get lexical ordering, i.e., for op ==
-            // `ast::lt`
-            //
-            // ```
-            // Ordering::then_with(
-            //    Option::unwrap_or(
-            //        PartialOrd::partial_cmp(self.f1, other.f1), Ordering::Equal)
-            //    ),
-            //    Option::unwrap_or(
-            //        PartialOrd::partial_cmp(self.f2, other.f2), Ordering::Greater)
-            //    )
-            // )
-            // == Ordering::Less
-            // ```
-            //
-            // and for op ==
-            // `ast::le`
-            //
-            // ```
-            // Ordering::then_with(
-            //    Option::unwrap_or(
-            //        PartialOrd::partial_cmp(self.f1, other.f1), Ordering::Equal)
-            //    ),
-            //    Option::unwrap_or(
-            //        PartialOrd::partial_cmp(self.f2, other.f2), Ordering::Greater)
-            //    )
-            // )
-            // != Ordering::Greater
-            // ```
-            //
-            // The optimiser should remove the redundancy. We explicitly
-            // get use the binops to avoid auto-deref dereferencing too many
-            // layers of pointers, if the type includes pointers.
-
-            // `Option::unwrap_or(PartialOrd::partial_cmp(self.fi, other.fi), Ordering::Equal)`
-            let par_cmp = par_cmp(cx, span, self_f, other_fs, "Equal");
-
-            // `Ordering::then_with(Option::unwrap_or(..), ..)`
-            let then_with_path = cx.expr_path(
-                cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::then_with])),
-            );
-            cx.expr_call(span, then_with_path, vec![par_cmp, cx.lambda0(span, subexpr)])
-        },
-        |cx, args| match args {
-            Some((span, self_f, other_fs)) => {
-                let opposite = if less { "Greater" } else { "Less" };
-                par_cmp(cx, span, self_f, other_fs, opposite)
-            }
-            None => cx.expr_bool(span, inclusive),
-        },
-        Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
-            if self_args.len() != 2 {
-                cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
-            } else {
-                let op = match (less, inclusive) {
-                    (false, false) => GtOp,
-                    (false, true) => GeOp,
-                    (true, false) => LtOp,
-                    (true, true) => LeOp,
-                };
-                some_ordering_collapsed(cx, span, op, tag_tuple)
-            }
-        }),
-        cx,
-        span,
-        substr,
-    );
-
-    match *substr.fields {
-        EnumMatching(.., ref all_fields) | Struct(.., ref all_fields) if !all_fields.is_empty() => {
-            let ordering = ordering_path(cx, if less ^ inclusive { "Less" } else { "Greater" });
-            let comp_op = if inclusive { BinOpKind::Ne } else { BinOpKind::Eq };
-
-            cx.expr_binary(span, comp_op, fold, ordering)
-        }
-        _ => fold,
-    }
-}
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index ba43be6ae9a..cc6dac52d76 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -77,7 +77,8 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
             // tuple struct/"normal" variant
             let fn_path_debug_tuple = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_tuple]);
             let expr = cx.expr_call_global(span, fn_path_debug_tuple, vec![fmt, name]);
-            stmts.push(cx.stmt_let(span, true, builder, expr));
+            let expr = make_mut_borrow(cx, span, expr);
+            stmts.push(cx.stmt_let(span, false, builder, expr));
 
             for field in fields {
                 // Use double indirection to make sure this works for unsized types
@@ -85,8 +86,8 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
                 let field = cx.expr_addr_of(field.span, field);
 
                 let fn_path_field = cx.std_path(&[sym::fmt, sym::DebugTuple, sym::field]);
-                let builder_recv = make_mut_borrow(cx, span, builder_expr.clone());
-                let expr = cx.expr_call_global(span, fn_path_field, vec![builder_recv, field]);
+                let expr =
+                    cx.expr_call_global(span, fn_path_field, vec![builder_expr.clone(), field]);
 
                 // Use `let _ = expr;` to avoid triggering the
                 // unused_results lint.
@@ -99,7 +100,8 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
             // normal struct/struct variant
             let fn_path_debug_struct = cx.std_path(&[sym::fmt, sym::Formatter, sym::debug_struct]);
             let expr = cx.expr_call_global(span, fn_path_debug_struct, vec![fmt, name]);
-            stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));
+            let expr = make_mut_borrow(cx, span, expr);
+            stmts.push(cx.stmt_let(DUMMY_SP, false, builder, expr));
 
             for field in fields {
                 let name = cx.expr_lit(
@@ -111,17 +113,18 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
                 let fn_path_field = cx.std_path(&[sym::fmt, sym::DebugStruct, sym::field]);
                 let field = cx.expr_addr_of(field.span, field.self_.clone());
                 let field = cx.expr_addr_of(field.span, field);
-                let builder_recv = make_mut_borrow(cx, span, builder_expr.clone());
-                let expr =
-                    cx.expr_call_global(span, fn_path_field, vec![builder_recv, name, field]);
+                let expr = cx.expr_call_global(
+                    span,
+                    fn_path_field,
+                    vec![builder_expr.clone(), name, field],
+                );
                 stmts.push(stmt_let_underscore(cx, span, expr));
             }
             fn_path_finish = cx.std_path(&[sym::fmt, sym::DebugStruct, sym::finish]);
         }
     }
 
-    let builder_recv = make_mut_borrow(cx, span, builder_expr);
-    let expr = cx.expr_call_global(span, fn_path_finish, vec![builder_recv]);
+    let expr = cx.expr_call_global(span, fn_path_finish, vec![builder_expr]);
 
     stmts.push(cx.stmt_expr(expr));
     let block = cx.block(span, stmts);
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index df69f6c90d8..1d892b20729 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -91,18 +91,19 @@ fn decodable_substructure(
                 Unnamed(ref fields, _) => fields.len(),
                 Named(ref fields) => fields.len(),
             };
-            let read_struct_field = Ident::new(sym::read_struct_field, trait_span);
+            let fn_read_struct_field_path: Vec<_> =
+                cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct_field]);
 
             let path = cx.path_ident(trait_span, substr.type_ident);
             let result =
                 decode_static_fields(cx, trait_span, path, summary, |cx, span, name, field| {
                     cx.expr_try(
                         span,
-                        cx.expr_method_call(
+                        cx.expr_call_global(
                             span,
-                            blkdecoder.clone(),
-                            read_struct_field,
+                            fn_read_struct_field_path.clone(),
                             vec![
+                                blkdecoder.clone(),
                                 cx.expr_str(span, name),
                                 cx.expr_usize(span, field),
                                 exprdecode.clone(),
@@ -111,11 +112,14 @@ fn decodable_substructure(
                     )
                 });
             let result = cx.expr_ok(trait_span, result);
-            cx.expr_method_call(
+            let fn_read_struct_path: Vec<_> =
+                cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_struct]);
+
+            cx.expr_call_global(
                 trait_span,
-                decoder,
-                Ident::new(sym::read_struct, trait_span),
+                fn_read_struct_path,
                 vec![
+                    decoder,
                     cx.expr_str(trait_span, substr.type_ident.name),
                     cx.expr_usize(trait_span, nfields),
                     cx.lambda1(trait_span, result, blkarg),
@@ -127,7 +131,9 @@ fn decodable_substructure(
 
             let mut arms = Vec::with_capacity(fields.len() + 1);
             let mut variants = Vec::with_capacity(fields.len());
-            let rvariant_arg = Ident::new(sym::read_enum_variant_arg, trait_span);
+
+            let fn_read_enum_variant_arg_path: Vec<_> =
+                cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant_arg]);
 
             for (i, &(ident, v_span, ref parts)) in fields.iter().enumerate() {
                 variants.push(cx.expr_str(v_span, ident.name));
@@ -138,11 +144,10 @@ fn decodable_substructure(
                         let idx = cx.expr_usize(span, field);
                         cx.expr_try(
                             span,
-                            cx.expr_method_call(
+                            cx.expr_call_global(
                                 span,
-                                blkdecoder.clone(),
-                                rvariant_arg,
-                                vec![idx, exprdecode.clone()],
+                                fn_read_enum_variant_arg_path.clone(),
+                                vec![blkdecoder.clone(), idx, exprdecode.clone()],
                             ),
                         )
                     });
@@ -159,17 +164,21 @@ fn decodable_substructure(
             let lambda = cx.lambda(trait_span, vec![blkarg, variant], result);
             let variant_vec = cx.expr_vec(trait_span, variants);
             let variant_vec = cx.expr_addr_of(trait_span, variant_vec);
-            let result = cx.expr_method_call(
+            let fn_read_enum_variant_path: Vec<_> =
+                cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum_variant]);
+            let result = cx.expr_call_global(
                 trait_span,
-                blkdecoder,
-                Ident::new(sym::read_enum_variant, trait_span),
-                vec![variant_vec, lambda],
+                fn_read_enum_variant_path,
+                vec![blkdecoder, variant_vec, lambda],
             );
-            cx.expr_method_call(
+            let fn_read_enum_path: Vec<_> =
+                cx.def_site_path(&[sym::rustc_serialize, sym::Decoder, sym::read_enum]);
+
+            cx.expr_call_global(
                 trait_span,
-                decoder,
-                Ident::new(sym::read_enum, trait_span),
+                fn_read_enum_path,
                 vec![
+                    decoder,
                     cx.expr_str(trait_span, substr.type_ident.name),
                     cx.lambda1(trait_span, result, blkarg),
                 ],
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index 62aa1cbfbf2..01a57bea14e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -179,7 +179,8 @@ fn encodable_substructure(
 
     match *substr.fields {
         Struct(_, ref fields) => {
-            let emit_struct_field = Ident::new(sym::emit_struct_field, trait_span);
+            let fn_emit_struct_field_path =
+                cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct_field]);
             let mut stmts = Vec::new();
             for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
                 let name = match name {
@@ -189,11 +190,15 @@ fn encodable_substructure(
                 let self_ref = cx.expr_addr_of(span, self_.clone());
                 let enc = cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]);
                 let lambda = cx.lambda1(span, enc, blkarg);
-                let call = cx.expr_method_call(
+                let call = cx.expr_call_global(
                     span,
-                    blkencoder.clone(),
-                    emit_struct_field,
-                    vec![cx.expr_str(span, name), cx.expr_usize(span, i), lambda],
+                    fn_emit_struct_field_path.clone(),
+                    vec![
+                        blkencoder.clone(),
+                        cx.expr_str(span, name),
+                        cx.expr_usize(span, i),
+                        lambda,
+                    ],
                 );
 
                 // last call doesn't need a try!
@@ -216,11 +221,14 @@ fn encodable_substructure(
                 cx.lambda_stmts_1(trait_span, stmts, blkarg)
             };
 
-            cx.expr_method_call(
+            let fn_emit_struct_path =
+                cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_struct]);
+
+            cx.expr_call_global(
                 trait_span,
-                encoder,
-                Ident::new(sym::emit_struct, trait_span),
+                fn_emit_struct_path,
                 vec![
+                    encoder,
                     cx.expr_str(trait_span, substr.type_ident.name),
                     cx.expr_usize(trait_span, fields.len()),
                     blk,
@@ -235,7 +243,10 @@ fn encodable_substructure(
             // actually exist.
             let me = cx.stmt_let(trait_span, false, blkarg, encoder);
             let encoder = cx.expr_ident(trait_span, blkarg);
-            let emit_variant_arg = Ident::new(sym::emit_enum_variant_arg, trait_span);
+
+            let fn_emit_enum_variant_arg_path: Vec<_> =
+                cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant_arg]);
+
             let mut stmts = Vec::new();
             if !fields.is_empty() {
                 let last = fields.len() - 1;
@@ -244,11 +255,11 @@ fn encodable_substructure(
                     let enc =
                         cx.expr_call(span, fn_path.clone(), vec![self_ref, blkencoder.clone()]);
                     let lambda = cx.lambda1(span, enc, blkarg);
-                    let call = cx.expr_method_call(
+
+                    let call = cx.expr_call_global(
                         span,
-                        blkencoder.clone(),
-                        emit_variant_arg,
-                        vec![cx.expr_usize(span, i), lambda],
+                        fn_emit_enum_variant_arg_path.clone(),
+                        vec![blkencoder.clone(), cx.expr_usize(span, i), lambda],
                     );
                     let call = if i != last {
                         cx.expr_try(span, call)
@@ -265,23 +276,29 @@ fn encodable_substructure(
 
             let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
             let name = cx.expr_str(trait_span, variant.ident.name);
-            let call = cx.expr_method_call(
+
+            let fn_emit_enum_variant_path: Vec<_> =
+                cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum_variant]);
+
+            let call = cx.expr_call_global(
                 trait_span,
-                blkencoder,
-                Ident::new(sym::emit_enum_variant, trait_span),
+                fn_emit_enum_variant_path,
                 vec![
+                    blkencoder,
                     name,
                     cx.expr_usize(trait_span, idx),
                     cx.expr_usize(trait_span, fields.len()),
                     blk,
                 ],
             );
+
             let blk = cx.lambda1(trait_span, call, blkarg);
-            let ret = cx.expr_method_call(
+            let fn_emit_enum_path: Vec<_> =
+                cx.def_site_path(&[sym::rustc_serialize, sym::Encoder, sym::emit_enum]);
+            let ret = cx.expr_call_global(
                 trait_span,
-                encoder,
-                Ident::new(sym::emit_enum, trait_span),
-                vec![cx.expr_str(trait_span, substr.type_ident.name), blk],
+                fn_emit_enum_path,
+                vec![encoder, cx.expr_str(trait_span, substr.type_ident.name), blk],
             );
             cx.expr_block(cx.block(trait_span, vec![me, cx.stmt_expr(ret)]))
         }
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 85ca1da6f1d..7e88b58c0e2 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -270,7 +270,7 @@ impl<'a, 'b> Context<'a, 'b> {
                     parse::ArgumentNamed(s) => Named(s),
                 };
 
-                let ty = Placeholder(match &arg.format.ty[..] {
+                let ty = Placeholder(match arg.format.ty {
                     "" => "Display",
                     "?" => "Debug",
                     "e" => "LowerExp",
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index 0496c72cb00..0cc520e5bd1 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -312,7 +312,7 @@ pub mod printf {
                 return Some((Substitution::Escape, &s[start + 2..]));
             }
 
-            Cur::new_at(&s[..], start)
+            Cur::new_at(s, start)
         };
 
         // This is meant to be a translation of the following regex:
@@ -673,7 +673,7 @@ pub mod shell {
                 _ => { /* fall-through */ }
             }
 
-            Cur::new_at(&s[..], start)
+            Cur::new_at(s, start)
         };
 
         let at = at.at_next_cp()?;
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 59844b6c692..9a3c914337c 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -27,6 +27,7 @@ mod cfg_accessible;
 mod compile_error;
 mod concat;
 mod concat_idents;
+mod derive;
 mod deriving;
 mod env;
 mod format;
@@ -88,6 +89,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
     register_attr! {
         bench: test::expand_bench,
         cfg_accessible: cfg_accessible::Expander,
+        derive: derive::Expander,
         global_allocator: global_allocator::expand,
         test: test::expand_test,
         test_case: test::expand_test_case,
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 7582d980539..71bbae1161b 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -91,7 +91,7 @@ pub fn inject(
     }
 
     let decls = mk_decls(&mut krate, &mut cx, &macros);
-    krate.module.items.push(decls);
+    krate.items.push(decls);
 
     krate
 }
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index 91566ec1ef2..3a81d076dc5 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -44,7 +44,7 @@ pub fn inject(
     // .rev() to preserve ordering above in combination with insert(0, ...)
     for &name in names.iter().rev() {
         let ident = if rust_2018 { Ident::new(name, span) } else { Ident::new(name, call_site) };
-        krate.module.items.insert(
+        krate.items.insert(
             0,
             cx.item(
                 span,
@@ -79,7 +79,7 @@ pub fn inject(
         })),
     );
 
-    krate.module.items.insert(0, use_item);
+    krate.items.insert(0, use_item);
 
     krate
 }
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 4ac22be3c27..28e82597843 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -1,10 +1,10 @@
 // Code that generates a test runner to run all the tests in a crate
 
 use rustc_ast as ast;
-use rustc_ast::attr;
 use rustc_ast::entry::EntryPointType;
 use rustc_ast::mut_visit::{ExpectOne, *};
 use rustc_ast::ptr::P;
+use rustc_ast::{attr, ModKind};
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
 use rustc_feature::Features;
@@ -89,7 +89,7 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
         noop_visit_crate(c, self);
 
         // Create a main function to run our tests
-        c.module.items.push(mk_main(&mut self.cx));
+        c.items.push(mk_main(&mut self.cx));
     }
 
     fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
@@ -103,9 +103,9 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
 
         // We don't want to recurse into anything other than mods, since
         // mods or tests inside of functions will break things
-        if let ast::ItemKind::Mod(mut module) = item.kind {
+        if let ast::ItemKind::Mod(..) = item.kind {
             let tests = mem::take(&mut self.tests);
-            noop_visit_mod(&mut module, self);
+            noop_visit_item_kind(&mut item.kind, self);
             let mut tests = mem::replace(&mut self.tests, tests);
 
             if !tests.is_empty() {
@@ -113,8 +113,12 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
                     if item.id == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { item.id };
                 // Create an identifier that will hygienically resolve the test
                 // case name, even in another module.
+                let inner_span = match item.kind {
+                    ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) => span,
+                    _ => unreachable!(),
+                };
                 let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass(
-                    module.inner,
+                    inner_span,
                     AstPass::TestHarness,
                     &[],
                     Some(parent),
@@ -126,7 +130,6 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> {
                 }
                 self.cx.test_cases.extend(tests);
             }
-            item.kind = ast::ItemKind::Mod(module);
         }
         smallvec![P(item)]
     }
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index df89883f0bb..39781e2482a 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -164,8 +164,8 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: rustc_span::Symbol) -> ModuleCodege
             MonoItem::Static(def_id) => {
                 crate::constant::codegen_static(&mut cx.constants_cx, def_id)
             }
-            MonoItem::GlobalAsm(hir_id) => {
-                let item = cx.tcx.hir().expect_item(hir_id);
+            MonoItem::GlobalAsm(item_id) => {
+                let item = cx.tcx.hir().item(item_id);
                 if let rustc_hir::ItemKind::GlobalAsm(rustc_hir::GlobalAsm { asm }) = item.kind {
                     cx.global_asm.push_str(&*asm.as_str());
                     cx.global_asm.push_str("\n\n");
@@ -465,9 +465,5 @@ fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguR
         cgu.name()
     );
 
-    if tcx.dep_graph.try_mark_green(tcx, &dep_node).is_some() {
-        CguReuse::PreLto
-    } else {
-        CguReuse::No
-    }
+    if tcx.try_mark_green(&dep_node) { CguReuse::PreLto } else { CguReuse::No }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index 2d14ff2c022..f784d8d27cc 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -93,10 +93,9 @@ pub(super) fn run_jit(tcx: TyCtxt<'_>, codegen_mode: CodegenMode) -> ! {
                 MonoItem::Static(def_id) => {
                     crate::constant::codegen_static(&mut cx.constants_cx, def_id);
                 }
-                MonoItem::GlobalAsm(hir_id) => {
-                    let item = cx.tcx.hir().expect_item(hir_id);
-                    tcx.sess
-                        .span_fatal(item.span, "Global asm is not supported in JIT mode");
+                MonoItem::GlobalAsm(item_id) => {
+                    let item = cx.tcx.hir().item(item_id);
+                    tcx.sess.span_fatal(item.span, "Global asm is not supported in JIT mode");
                 }
             }
         }
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index f9373640dce..ebbb852f21c 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -29,6 +29,6 @@ rustc_llvm = { path = "../rustc_llvm" }
 rustc_session = { path = "../rustc_session" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_target = { path = "../rustc_target" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 8801211d51b..4aa25aae747 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -487,6 +487,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
             } else if reg == InlineAsmReg::AArch64(AArch64InlineAsmReg::x30) {
                 // LLVM doesn't recognize x30
                 "{lr}".to_string()
+            } else if reg == InlineAsmReg::Arm(ArmInlineAsmReg::r14) {
+                // LLVM doesn't recognize r14
+                "{lr}".to_string()
             } else {
                 format!("{{{}}}", reg.name())
             }
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index a78d692aaa7..26111729ba5 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -53,6 +53,9 @@ pub fn sanitize(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &'ll V
     if enabled.contains(SanitizerSet::THREAD) {
         llvm::Attribute::SanitizeThread.apply_llfn(Function, llfn);
     }
+    if enabled.contains(SanitizerSet::HWADDRESS) {
+        llvm::Attribute::SanitizeHWAddress.apply_llfn(Function, llfn);
+    }
 }
 
 /// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 326ae354ccf..5f8a11ab94e 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -11,6 +11,7 @@ use crate::llvm_util;
 use crate::type_::Type;
 use crate::LlvmCodegenBackend;
 use crate::ModuleLlvm;
+use rustc_codegen_ssa::back::link::ensure_removed;
 use rustc_codegen_ssa::back::write::{
     BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
     TargetMachineFactoryFn,
@@ -440,6 +441,8 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
             sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),
             sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
             sanitize_thread: config.sanitizer.contains(SanitizerSet::THREAD),
+            sanitize_hwaddress: config.sanitizer.contains(SanitizerSet::HWADDRESS),
+            sanitize_hwaddress_recover: config.sanitizer_recover.contains(SanitizerSet::HWADDRESS),
         })
     } else {
         None
@@ -652,6 +655,10 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static
     if config.sanitizer.contains(SanitizerSet::THREAD) {
         passes.push(llvm::LLVMRustCreateThreadSanitizerPass());
     }
+    if config.sanitizer.contains(SanitizerSet::HWADDRESS) {
+        let recover = config.sanitizer_recover.contains(SanitizerSet::HWADDRESS);
+        passes.push(llvm::LLVMRustCreateHWAddressSanitizerPass(recover));
+    }
 }
 
 pub(crate) fn link(
@@ -873,9 +880,7 @@ pub(crate) unsafe fn codegen(
 
                 if !config.emit_bc {
                     debug!("removing_bitcode {:?}", bc_out);
-                    if let Err(e) = fs::remove_file(&bc_out) {
-                        diag_handler.err(&format!("failed to remove bitcode: {}", e));
-                    }
+                    ensure_removed(diag_handler, &bc_out);
                 }
             }
 
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 14dd245625d..16e1a8a1242 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -8,9 +8,7 @@ use crate::value::Value;
 use libc::c_uint;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::const_cstr;
-use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::Node;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::interpret::{
     read_target_uint, Allocation, ErrorHandled, GlobalAlloc, Pointer,
@@ -18,7 +16,6 @@ use rustc_middle::mir::interpret::{
 use rustc_middle::mir::mono::MonoItem;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, span_bug};
-use rustc_span::symbol::sym;
 use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
 use tracing::debug;
 
@@ -209,70 +206,42 @@ impl CodegenCx<'ll, 'tcx> {
 
         let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
         let sym = self.tcx.symbol_name(instance).name;
+        let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
 
-        debug!("get_static: sym={} instance={:?}", sym, instance);
+        debug!("get_static: sym={} instance={:?} fn_attrs={:?}", sym, instance, fn_attrs);
 
-        let g = if let Some(local_def_id) = def_id.as_local() {
-            let id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
+        let g = if def_id.is_local() && !self.tcx.is_foreign_item(def_id) {
             let llty = self.layout_of(ty).llvm_type(self);
-            // FIXME: refactor this to work without accessing the HIR
-            let (g, attrs) = match self.tcx.hir().get(id) {
-                Node::Item(&hir::Item { attrs, kind: hir::ItemKind::Static(..), .. }) => {
-                    if let Some(g) = self.get_declared_value(sym) {
-                        if self.val_ty(g) != self.type_ptr_to(llty) {
-                            span_bug!(self.tcx.def_span(def_id), "Conflicting types for static");
-                        }
-                    }
-
-                    let g = self.declare_global(sym, llty);
-
-                    if !self.tcx.is_reachable_non_generic(local_def_id) {
-                        unsafe {
-                            llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden);
-                        }
-                    }
-
-                    (g, attrs)
+            if let Some(g) = self.get_declared_value(sym) {
+                if self.val_ty(g) != self.type_ptr_to(llty) {
+                    span_bug!(self.tcx.def_span(def_id), "Conflicting types for static");
                 }
+            }
 
-                Node::ForeignItem(&hir::ForeignItem {
-                    ref attrs,
-                    kind: hir::ForeignItemKind::Static(..),
-                    ..
-                }) => {
-                    let fn_attrs = self.tcx.codegen_fn_attrs(local_def_id);
-                    (check_and_apply_linkage(&self, &fn_attrs, ty, sym, def_id), &**attrs)
-                }
-
-                item => bug!("get_static: expected static, found {:?}", item),
-            };
-
-            debug!("get_static: sym={} attrs={:?}", sym, attrs);
+            let g = self.declare_global(sym, llty);
 
-            for attr in attrs {
-                if self.tcx.sess.check_name(attr, sym::thread_local) {
-                    llvm::set_thread_local_mode(g, self.tls_model);
+            if !self.tcx.is_reachable_non_generic(def_id) {
+                unsafe {
+                    llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden);
                 }
             }
 
             g
         } else {
-            // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
-            debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id));
+            check_and_apply_linkage(&self, &fn_attrs, ty, sym, def_id)
+        };
 
-            let attrs = self.tcx.codegen_fn_attrs(def_id);
-            let g = check_and_apply_linkage(&self, &attrs, ty, sym, def_id);
-
-            // Thread-local statics in some other crate need to *always* be linked
-            // against in a thread-local fashion, so we need to be sure to apply the
-            // thread-local attribute locally if it was present remotely. If we
-            // don't do this then linker errors can be generated where the linker
-            // complains that one object files has a thread local version of the
-            // symbol and another one doesn't.
-            if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
-                llvm::set_thread_local_mode(g, self.tls_model);
-            }
+        // Thread-local statics in some other crate need to *always* be linked
+        // against in a thread-local fashion, so we need to be sure to apply the
+        // thread-local attribute locally if it was present remotely. If we
+        // don't do this then linker errors can be generated where the linker
+        // complains that one object files has a thread local version of the
+        // symbol and another one doesn't.
+        if fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
+            llvm::set_thread_local_mode(g, self.tls_model);
+        }
 
+        if !def_id.is_local() {
             let needs_dll_storage_attr = self.use_dll_storage_attrs && !self.tcx.is_foreign_item(def_id) &&
                 // ThinLTO can't handle this workaround in all cases, so we don't
                 // emit the attrs. Instead we make them unnecessary by disallowing
@@ -304,8 +273,7 @@ impl CodegenCx<'ll, 'tcx> {
                     }
                 }
             }
-            g
-        };
+        }
 
         if self.use_dll_storage_attrs && self.tcx.is_dllimport_foreign_item(def_id) {
             // For foreign (native) libs we know the exact storage type to use.
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 6acd26bd415..ee099f93258 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -380,7 +380,7 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                     "rust_eh_personality"
                 };
                 let fty = self.type_variadic_func(&[], self.type_i32());
-                self.declare_cfn(name, fty)
+                self.declare_cfn(name, llvm::UnnamedAddr::Global, fty)
             }
         };
         attributes::apply_target_cpu_attr(self, llfn);
@@ -429,7 +429,7 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 
     fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
         if self.get_declared_value("main").is_none() {
-            Some(self.declare_cfn("main", fn_type))
+            Some(self.declare_cfn("main", llvm::UnnamedAddr::Global, fn_type))
         } else {
             // If the symbol already exists, it is an error: for example, the user wrote
             // #[no_mangle] extern "C" fn main(..) {..}
@@ -459,8 +459,7 @@ impl CodegenCx<'b, 'tcx> {
         } else {
             self.type_variadic_func(&[], ret)
         };
-        let f = self.declare_cfn(name, fn_ty);
-        llvm::SetUnnamedAddress(f, llvm::UnnamedAddr::No);
+        let f = self.declare_cfn(name, llvm::UnnamedAddr::No, fn_ty);
         self.intrinsics.borrow_mut().insert(name, f);
         f
     }
@@ -498,25 +497,6 @@ impl CodegenCx<'b, 'tcx> {
         let t_f32 = self.type_f32();
         let t_f64 = self.type_f64();
 
-        macro_rules! vector_types {
-            ($id_out:ident: $elem_ty:ident, $len:expr) => {
-                let $id_out = self.type_vector($elem_ty, $len);
-            };
-            ($($id_out:ident: $elem_ty:ident, $len:expr;)*) => {
-                $(vector_types!($id_out: $elem_ty, $len);)*
-            }
-        }
-        vector_types! {
-            t_v2f32: t_f32, 2;
-            t_v4f32: t_f32, 4;
-            t_v8f32: t_f32, 8;
-            t_v16f32: t_f32, 16;
-
-            t_v2f64: t_f64, 2;
-            t_v4f64: t_f64, 4;
-            t_v8f64: t_f64, 8;
-        }
-
         ifn!("llvm.wasm.trunc.saturate.unsigned.i32.f32", fn(t_f32) -> t_i32);
         ifn!("llvm.wasm.trunc.saturate.unsigned.i32.f64", fn(t_f64) -> t_i32);
         ifn!("llvm.wasm.trunc.saturate.unsigned.i64.f32", fn(t_f32) -> t_i64);
@@ -540,124 +520,40 @@ impl CodegenCx<'b, 'tcx> {
         ifn!("llvm.sideeffect", fn() -> void);
 
         ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
-        ifn!("llvm.powi.v2f32", fn(t_v2f32, t_i32) -> t_v2f32);
-        ifn!("llvm.powi.v4f32", fn(t_v4f32, t_i32) -> t_v4f32);
-        ifn!("llvm.powi.v8f32", fn(t_v8f32, t_i32) -> t_v8f32);
-        ifn!("llvm.powi.v16f32", fn(t_v16f32, t_i32) -> t_v16f32);
         ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
-        ifn!("llvm.powi.v2f64", fn(t_v2f64, t_i32) -> t_v2f64);
-        ifn!("llvm.powi.v4f64", fn(t_v4f64, t_i32) -> t_v4f64);
-        ifn!("llvm.powi.v8f64", fn(t_v8f64, t_i32) -> t_v8f64);
 
         ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32);
-        ifn!("llvm.pow.v2f32", fn(t_v2f32, t_v2f32) -> t_v2f32);
-        ifn!("llvm.pow.v4f32", fn(t_v4f32, t_v4f32) -> t_v4f32);
-        ifn!("llvm.pow.v8f32", fn(t_v8f32, t_v8f32) -> t_v8f32);
-        ifn!("llvm.pow.v16f32", fn(t_v16f32, t_v16f32) -> t_v16f32);
         ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64);
-        ifn!("llvm.pow.v2f64", fn(t_v2f64, t_v2f64) -> t_v2f64);
-        ifn!("llvm.pow.v4f64", fn(t_v4f64, t_v4f64) -> t_v4f64);
-        ifn!("llvm.pow.v8f64", fn(t_v8f64, t_v8f64) -> t_v8f64);
 
         ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32);
-        ifn!("llvm.sqrt.v2f32", fn(t_v2f32) -> t_v2f32);
-        ifn!("llvm.sqrt.v4f32", fn(t_v4f32) -> t_v4f32);
-        ifn!("llvm.sqrt.v8f32", fn(t_v8f32) -> t_v8f32);
-        ifn!("llvm.sqrt.v16f32", fn(t_v16f32) -> t_v16f32);
         ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64);
-        ifn!("llvm.sqrt.v2f64", fn(t_v2f64) -> t_v2f64);
-        ifn!("llvm.sqrt.v4f64", fn(t_v4f64) -> t_v4f64);
-        ifn!("llvm.sqrt.v8f64", fn(t_v8f64) -> t_v8f64);
 
         ifn!("llvm.sin.f32", fn(t_f32) -> t_f32);
-        ifn!("llvm.sin.v2f32", fn(t_v2f32) -> t_v2f32);
-        ifn!("llvm.sin.v4f32", fn(t_v4f32) -> t_v4f32);
-        ifn!("llvm.sin.v8f32", fn(t_v8f32) -> t_v8f32);
-        ifn!("llvm.sin.v16f32", fn(t_v16f32) -> t_v16f32);
         ifn!("llvm.sin.f64", fn(t_f64) -> t_f64);
-        ifn!("llvm.sin.v2f64", fn(t_v2f64) -> t_v2f64);
-        ifn!("llvm.sin.v4f64", fn(t_v4f64) -> t_v4f64);
-        ifn!("llvm.sin.v8f64", fn(t_v8f64) -> t_v8f64);
 
         ifn!("llvm.cos.f32", fn(t_f32) -> t_f32);
-        ifn!("llvm.cos.v2f32", fn(t_v2f32) -> t_v2f32);
-        ifn!("llvm.cos.v4f32", fn(t_v4f32) -> t_v4f32);
-        ifn!("llvm.cos.v8f32", fn(t_v8f32) -> t_v8f32);
-        ifn!("llvm.cos.v16f32", fn(t_v16f32) -> t_v16f32);
         ifn!("llvm.cos.f64", fn(t_f64) -> t_f64);
-        ifn!("llvm.cos.v2f64", fn(t_v2f64) -> t_v2f64);
-        ifn!("llvm.cos.v4f64", fn(t_v4f64) -> t_v4f64);
-        ifn!("llvm.cos.v8f64", fn(t_v8f64) -> t_v8f64);
 
         ifn!("llvm.exp.f32", fn(t_f32) -> t_f32);
-        ifn!("llvm.exp.v2f32", fn(t_v2f32) -> t_v2f32);
-        ifn!("llvm.exp.v4f32", fn(t_v4f32) -> t_v4f32);
-        ifn!("llvm.exp.v8f32", fn(t_v8f32) -> t_v8f32);
-        ifn!("llvm.exp.v16f32", fn(t_v16f32) -> t_v16f32);
         ifn!("llvm.exp.f64", fn(t_f64) -> t_f64);
-        ifn!("llvm.exp.v2f64", fn(t_v2f64) -> t_v2f64);
-        ifn!("llvm.exp.v4f64", fn(t_v4f64) -> t_v4f64);
-        ifn!("llvm.exp.v8f64", fn(t_v8f64) -> t_v8f64);
 
         ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32);
-        ifn!("llvm.exp2.v2f32", fn(t_v2f32) -> t_v2f32);
-        ifn!("llvm.exp2.v4f32", fn(t_v4f32) -> t_v4f32);
-        ifn!("llvm.exp2.v8f32", fn(t_v8f32) -> t_v8f32);
-        ifn!("llvm.exp2.v16f32", fn(t_v16f32) -> t_v16f32);
         ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64);
-        ifn!("llvm.exp2.v2f64", fn(t_v2f64) -> t_v2f64);
-        ifn!("llvm.exp2.v4f64", fn(t_v4f64) -> t_v4f64);
-        ifn!("llvm.exp2.v8f64", fn(t_v8f64) -> t_v8f64);
 
         ifn!("llvm.log.f32", fn(t_f32) -> t_f32);
-        ifn!("llvm.log.v2f32", fn(t_v2f32) -> t_v2f32);
-        ifn!("llvm.log.v4f32", fn(t_v4f32) -> t_v4f32);
-        ifn!("llvm.log.v8f32", fn(t_v8f32) -> t_v8f32);
-        ifn!("llvm.log.v16f32", fn(t_v16f32) -> t_v16f32);
         ifn!("llvm.log.f64", fn(t_f64) -> t_f64);
-        ifn!("llvm.log.v2f64", fn(t_v2f64) -> t_v2f64);
-        ifn!("llvm.log.v4f64", fn(t_v4f64) -> t_v4f64);
-        ifn!("llvm.log.v8f64", fn(t_v8f64) -> t_v8f64);
 
         ifn!("llvm.log10.f32", fn(t_f32) -> t_f32);
-        ifn!("llvm.log10.v2f32", fn(t_v2f32) -> t_v2f32);
-        ifn!("llvm.log10.v4f32", fn(t_v4f32) -> t_v4f32);
-        ifn!("llvm.log10.v8f32", fn(t_v8f32) -> t_v8f32);
-        ifn!("llvm.log10.v16f32", fn(t_v16f32) -> t_v16f32);
         ifn!("llvm.log10.f64", fn(t_f64) -> t_f64);
-        ifn!("llvm.log10.v2f64", fn(t_v2f64) -> t_v2f64);
-        ifn!("llvm.log10.v4f64", fn(t_v4f64) -> t_v4f64);
-        ifn!("llvm.log10.v8f64", fn(t_v8f64) -> t_v8f64);
 
         ifn!("llvm.log2.f32", fn(t_f32) -> t_f32);
-        ifn!("llvm.log2.v2f32", fn(t_v2f32) -> t_v2f32);
-        ifn!("llvm.log2.v4f32", fn(t_v4f32) -> t_v4f32);
-        ifn!("llvm.log2.v8f32", fn(t_v8f32) -> t_v8f32);
-        ifn!("llvm.log2.v16f32", fn(t_v16f32) -> t_v16f32);
         ifn!("llvm.log2.f64", fn(t_f64) -> t_f64);
-        ifn!("llvm.log2.v2f64", fn(t_v2f64) -> t_v2f64);
-        ifn!("llvm.log2.v4f64", fn(t_v4f64) -> t_v4f64);
-        ifn!("llvm.log2.v8f64", fn(t_v8f64) -> t_v8f64);
 
         ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32);
-        ifn!("llvm.fma.v2f32", fn(t_v2f32, t_v2f32, t_v2f32) -> t_v2f32);
-        ifn!("llvm.fma.v4f32", fn(t_v4f32, t_v4f32, t_v4f32) -> t_v4f32);
-        ifn!("llvm.fma.v8f32", fn(t_v8f32, t_v8f32, t_v8f32) -> t_v8f32);
-        ifn!("llvm.fma.v16f32", fn(t_v16f32, t_v16f32, t_v16f32) -> t_v16f32);
         ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64);
-        ifn!("llvm.fma.v2f64", fn(t_v2f64, t_v2f64, t_v2f64) -> t_v2f64);
-        ifn!("llvm.fma.v4f64", fn(t_v4f64, t_v4f64, t_v4f64) -> t_v4f64);
-        ifn!("llvm.fma.v8f64", fn(t_v8f64, t_v8f64, t_v8f64) -> t_v8f64);
 
         ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32);
-        ifn!("llvm.fabs.v2f32", fn(t_v2f32) -> t_v2f32);
-        ifn!("llvm.fabs.v4f32", fn(t_v4f32) -> t_v4f32);
-        ifn!("llvm.fabs.v8f32", fn(t_v8f32) -> t_v8f32);
-        ifn!("llvm.fabs.v16f32", fn(t_v16f32) -> t_v16f32);
         ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64);
-        ifn!("llvm.fabs.v2f64", fn(t_v2f64) -> t_v2f64);
-        ifn!("llvm.fabs.v4f64", fn(t_v4f64) -> t_v4f64);
-        ifn!("llvm.fabs.v8f64", fn(t_v8f64) -> t_v8f64);
 
         ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32);
         ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64);
@@ -665,24 +561,10 @@ impl CodegenCx<'b, 'tcx> {
         ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64);
 
         ifn!("llvm.floor.f32", fn(t_f32) -> t_f32);
-        ifn!("llvm.floor.v2f32", fn(t_v2f32) -> t_v2f32);
-        ifn!("llvm.floor.v4f32", fn(t_v4f32) -> t_v4f32);
-        ifn!("llvm.floor.v8f32", fn(t_v8f32) -> t_v8f32);
-        ifn!("llvm.floor.v16f32", fn(t_v16f32) -> t_v16f32);
         ifn!("llvm.floor.f64", fn(t_f64) -> t_f64);
-        ifn!("llvm.floor.v2f64", fn(t_v2f64) -> t_v2f64);
-        ifn!("llvm.floor.v4f64", fn(t_v4f64) -> t_v4f64);
-        ifn!("llvm.floor.v8f64", fn(t_v8f64) -> t_v8f64);
 
         ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32);
-        ifn!("llvm.ceil.v2f32", fn(t_v2f32) -> t_v2f32);
-        ifn!("llvm.ceil.v4f32", fn(t_v4f32) -> t_v4f32);
-        ifn!("llvm.ceil.v8f32", fn(t_v8f32) -> t_v8f32);
-        ifn!("llvm.ceil.v16f32", fn(t_v16f32) -> t_v16f32);
         ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64);
-        ifn!("llvm.ceil.v2f64", fn(t_v2f64) -> t_v2f64);
-        ifn!("llvm.ceil.v4f64", fn(t_v4f64) -> t_v4f64);
-        ifn!("llvm.ceil.v8f64", fn(t_v8f64) -> t_v8f64);
 
         ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64);
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 0591e0a5c12..8977fa085b9 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -30,6 +30,7 @@ fn declare_raw_fn(
     cx: &CodegenCx<'ll, '_>,
     name: &str,
     callconv: llvm::CallConv,
+    unnamed: llvm::UnnamedAddr,
     ty: &'ll Type,
 ) -> &'ll Value {
     debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty);
@@ -38,9 +39,7 @@ fn declare_raw_fn(
     };
 
     llvm::SetFunctionCallConv(llfn, callconv);
-    // Function addresses in Rust are never significant, allowing functions to
-    // be merged.
-    llvm::SetUnnamedAddress(llfn, llvm::UnnamedAddr::Global);
+    llvm::SetUnnamedAddress(llfn, unnamed);
 
     if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.disable_redzone) {
         llvm::Attribute::NoRedZone.apply_llfn(Function, llfn);
@@ -68,8 +67,13 @@ impl CodegenCx<'ll, 'tcx> {
     ///
     /// If there’s a value with the same name already declared, the function will
     /// update the declaration and return existing Value instead.
-    pub fn declare_cfn(&self, name: &str, fn_type: &'ll Type) -> &'ll Value {
-        declare_raw_fn(self, name, llvm::CCallConv, fn_type)
+    pub fn declare_cfn(
+        &self,
+        name: &str,
+        unnamed: llvm::UnnamedAddr,
+        fn_type: &'ll Type,
+    ) -> &'ll Value {
+        declare_raw_fn(self, name, llvm::CCallConv, unnamed, fn_type)
     }
 
     /// Declare a Rust function.
@@ -79,7 +83,15 @@ impl CodegenCx<'ll, 'tcx> {
     pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value {
         debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
 
-        let llfn = declare_raw_fn(self, name, fn_abi.llvm_cconv(), fn_abi.llvm_type(self));
+        // Function addresses in Rust are never significant, allowing functions to
+        // be merged.
+        let llfn = declare_raw_fn(
+            self,
+            name,
+            fn_abi.llvm_cconv(),
+            llvm::UnnamedAddr::Global,
+            fn_abi.llvm_type(self),
+        );
         fn_abi.apply_attrs_llfn(self, llfn);
         llfn
     }
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index bf0d499e6c4..668daa52ed2 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1009,7 +1009,7 @@ fn generic_simd_intrinsic(
     }
 
     fn simd_simple_float_intrinsic(
-        name: &str,
+        name: Symbol,
         in_elem: &::rustc_middle::ty::TyS<'_>,
         in_ty: &::rustc_middle::ty::TyS<'_>,
         in_len: u64,
@@ -1036,93 +1036,69 @@ fn generic_simd_intrinsic(
                 }
             }
         }
-        let ety = match in_elem.kind() {
-            ty::Float(f) if f.bit_width() == 32 => {
-                if in_len < 2 || in_len > 16 {
-                    return_error!(
-                        "unsupported floating-point vector `{}` with length `{}` \
-                         out-of-range [2, 16]",
-                        in_ty,
-                        in_len
-                    );
-                }
-                "f32"
-            }
-            ty::Float(f) if f.bit_width() == 64 => {
-                if in_len < 2 || in_len > 8 {
+
+        let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() {
+            let elem_ty = bx.cx.type_float_from_ty(*f);
+            match f.bit_width() {
+                32 => ("f32", elem_ty),
+                64 => ("f64", elem_ty),
+                _ => {
                     return_error!(
-                        "unsupported floating-point vector `{}` with length `{}` \
-                                   out-of-range [2, 8]",
-                        in_ty,
-                        in_len
+                        "unsupported element type `{}` of floating-point vector `{}`",
+                        f.name_str(),
+                        in_ty
                     );
                 }
-                "f64"
-            }
-            ty::Float(f) => {
-                return_error!(
-                    "unsupported element type `{}` of floating-point vector `{}`",
-                    f.name_str(),
-                    in_ty
-                );
-            }
-            _ => {
-                return_error!("`{}` is not a floating-point type", in_ty);
             }
+        } else {
+            return_error!("`{}` is not a floating-point type", in_ty);
         };
 
-        let llvm_name = &format!("llvm.{0}.v{1}{2}", name, in_len, ety);
-        let intrinsic = bx.get_intrinsic(&llvm_name);
-        let c =
-            bx.call(intrinsic, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
+        let vec_ty = bx.type_vector(elem_ty, in_len);
+
+        let (intr_name, fn_ty) = match name {
+            sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
+            sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)),
+            sym::simd_fcos => ("cos", bx.type_func(&[vec_ty], vec_ty)),
+            sym::simd_fabs => ("fabs", bx.type_func(&[vec_ty], vec_ty)),
+            sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)),
+            sym::simd_ceil => ("ceil", bx.type_func(&[vec_ty], vec_ty)),
+            sym::simd_fexp => ("exp", bx.type_func(&[vec_ty], vec_ty)),
+            sym::simd_fexp2 => ("exp2", bx.type_func(&[vec_ty], vec_ty)),
+            sym::simd_flog10 => ("log10", bx.type_func(&[vec_ty], vec_ty)),
+            sym::simd_flog2 => ("log2", bx.type_func(&[vec_ty], vec_ty)),
+            sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)),
+            sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)),
+            sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)),
+            sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)),
+            _ => return_error!("unrecognized intrinsic `{}`", name),
+        };
+
+        let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
+        let f = bx.declare_cfn(&llvm_name, llvm::UnnamedAddr::No, fn_ty);
+        let c = bx.call(f, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None);
         unsafe { llvm::LLVMRustSetHasUnsafeAlgebra(c) };
         Ok(c)
     }
 
-    match name {
-        sym::simd_fsqrt => {
-            return simd_simple_float_intrinsic("sqrt", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_fsin => {
-            return simd_simple_float_intrinsic("sin", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_fcos => {
-            return simd_simple_float_intrinsic("cos", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_fabs => {
-            return simd_simple_float_intrinsic("fabs", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_floor => {
-            return simd_simple_float_intrinsic("floor", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_ceil => {
-            return simd_simple_float_intrinsic("ceil", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_fexp => {
-            return simd_simple_float_intrinsic("exp", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_fexp2 => {
-            return simd_simple_float_intrinsic("exp2", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_flog10 => {
-            return simd_simple_float_intrinsic("log10", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_flog2 => {
-            return simd_simple_float_intrinsic("log2", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_flog => {
-            return simd_simple_float_intrinsic("log", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_fpowi => {
-            return simd_simple_float_intrinsic("powi", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_fpow => {
-            return simd_simple_float_intrinsic("pow", in_elem, in_ty, in_len, bx, span, args);
-        }
-        sym::simd_fma => {
-            return simd_simple_float_intrinsic("fma", in_elem, in_ty, in_len, bx, span, args);
-        }
-        _ => { /* fallthrough */ }
+    if std::matches!(
+        name,
+        sym::simd_fsqrt
+            | sym::simd_fsin
+            | sym::simd_fcos
+            | sym::simd_fabs
+            | sym::simd_floor
+            | sym::simd_ceil
+            | sym::simd_fexp
+            | sym::simd_fexp2
+            | sym::simd_flog10
+            | sym::simd_flog2
+            | sym::simd_flog
+            | sym::simd_fpowi
+            | sym::simd_fpow
+            | sym::simd_fma
+    ) {
+        return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
     }
 
     // FIXME: use:
@@ -1278,12 +1254,12 @@ fn generic_simd_intrinsic(
             format!("llvm.masked.gather.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
         let f = bx.declare_cfn(
             &llvm_intrinsic,
+            llvm::UnnamedAddr::No,
             bx.type_func(
                 &[llvm_pointer_vec_ty, alignment_ty, mask_ty, llvm_elem_vec_ty],
                 llvm_elem_vec_ty,
             ),
         );
-        llvm::SetUnnamedAddress(f, llvm::UnnamedAddr::No);
         let v = bx.call(f, &[args[1].immediate(), alignment, mask, args[0].immediate()], None);
         return Ok(v);
     }
@@ -1408,9 +1384,9 @@ fn generic_simd_intrinsic(
             format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
         let f = bx.declare_cfn(
             &llvm_intrinsic,
+            llvm::UnnamedAddr::No,
             bx.type_func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], ret_t),
         );
-        llvm::SetUnnamedAddress(f, llvm::UnnamedAddr::No);
         let v = bx.call(f, &[args[0].immediate(), args[1].immediate(), alignment, mask], None);
         return Ok(v);
     }
@@ -1714,8 +1690,11 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#,
         );
         let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
 
-        let f = bx.declare_cfn(&llvm_intrinsic, bx.type_func(&[vec_ty, vec_ty], vec_ty));
-        llvm::SetUnnamedAddress(f, llvm::UnnamedAddr::No);
+        let f = bx.declare_cfn(
+            &llvm_intrinsic,
+            llvm::UnnamedAddr::No,
+            bx.type_func(&[vec_ty, vec_ty], vec_ty),
+        );
         let v = bx.call(f, &[lhs, rhs], None);
         return Ok(v);
     }
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index e82198f8f0c..8c1740d8f25 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -131,6 +131,7 @@ pub enum Attribute {
     ReturnsTwice = 25,
     ReadNone = 26,
     InaccessibleMemOnly = 27,
+    SanitizeHWAddress = 28,
 }
 
 /// LLVMIntPredicate
@@ -439,6 +440,8 @@ pub struct SanitizerOptions {
     pub sanitize_memory_recover: bool,
     pub sanitize_memory_track_origins: c_int,
     pub sanitize_thread: bool,
+    pub sanitize_hwaddress: bool,
+    pub sanitize_hwaddress_recover: bool,
 }
 
 /// LLVMRelocMode
@@ -2128,6 +2131,7 @@ extern "C" {
         Recover: bool,
     ) -> &'static mut Pass;
     pub fn LLVMRustCreateThreadSanitizerPass() -> &'static mut Pass;
+    pub fn LLVMRustCreateHWAddressSanitizerPass(Recover: bool) -> &'static mut Pass;
     pub fn LLVMRustAddPass(PM: &PassManager<'_>, Pass: &'static mut Pass);
     pub fn LLVMRustAddLastExtensionPasses(
         PMB: &PassManagerBuilder,
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index e5df0f60941..835f9062399 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -10,6 +10,7 @@ test = false
 [dependencies]
 bitflags = "1.2.1"
 cc = "1.0.1"
+itertools = "0.9"
 num_cpus = "1.0"
 memmap = "0.7"
 tracing = "0.1"
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index b5339b455ac..b93a579df15 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_errors::Handler;
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use rustc_hir::def_id::CrateNum;
 use rustc_middle::middle::cstore::{EncodedMetadata, LibSource};
@@ -34,9 +35,11 @@ use std::path::{Path, PathBuf};
 use std::process::{ExitStatus, Output, Stdio};
 use std::{ascii, char, env, fmt, fs, io, mem, str};
 
-pub fn remove(sess: &Session, path: &Path) {
+pub fn ensure_removed(diag_handler: &Handler, path: &Path) {
     if let Err(e) = fs::remove_file(path) {
-        sess.err(&format!("failed to remove {}: {}", path.display(), e));
+        if e.kind() != io::ErrorKind::NotFound {
+            diag_handler.err(&format!("failed to remove {}: {}", path.display(), e));
+        }
     }
 }
 
@@ -112,11 +115,11 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
         if !sess.opts.cg.save_temps {
             let remove_temps_from_module = |module: &CompiledModule| {
                 if let Some(ref obj) = module.object {
-                    remove(sess, obj);
+                    ensure_removed(sess.diagnostic(), obj);
                 }
 
                 if let Some(ref obj) = module.dwarf_object {
-                    remove(sess, obj);
+                    ensure_removed(sess.diagnostic(), obj);
                 }
             };
 
@@ -893,6 +896,9 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke
     if sanitizer.contains(SanitizerSet::THREAD) {
         link_sanitizer_runtime(sess, linker, "tsan");
     }
+    if sanitizer.contains(SanitizerSet::HWADDRESS) {
+        link_sanitizer_runtime(sess, linker, "hwasan");
+    }
 }
 
 fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 6aef5cb535a..b0aed812460 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -1,4 +1,4 @@
-use super::link::{self, remove};
+use super::link::{self, ensure_removed};
 use super::linker::LinkerInfo;
 use super::lto::{self, SerializedModule};
 use super::symbol_export::symbol_name_for_instance_in_crate;
@@ -543,7 +543,7 @@ fn produce_final_output_artifacts(
             copy_gracefully(&path, &crate_output.path(output_type));
             if !sess.opts.cg.save_temps && !keep_numbered {
                 // The user just wants `foo.x`, not `foo.#module-name#.x`.
-                remove(sess, &path);
+                ensure_removed(sess.diagnostic(), &path);
             }
         } else {
             let ext = crate_output
@@ -642,19 +642,19 @@ fn produce_final_output_artifacts(
         for module in compiled_modules.modules.iter() {
             if let Some(ref path) = module.object {
                 if !keep_numbered_objects {
-                    remove(sess, path);
+                    ensure_removed(sess.diagnostic(), path);
                 }
             }
 
             if let Some(ref path) = module.dwarf_object {
                 if !keep_numbered_objects {
-                    remove(sess, path);
+                    ensure_removed(sess.diagnostic(), path);
                 }
             }
 
             if let Some(ref path) = module.bytecode {
                 if !keep_numbered_bitcode {
-                    remove(sess, path);
+                    ensure_removed(sess.diagnostic(), path);
                 }
             }
         }
@@ -662,13 +662,13 @@ fn produce_final_output_artifacts(
         if !user_wants_bitcode {
             if let Some(ref metadata_module) = compiled_modules.metadata_module {
                 if let Some(ref path) = metadata_module.bytecode {
-                    remove(sess, &path);
+                    ensure_removed(sess.diagnostic(), &path);
                 }
             }
 
             if let Some(ref allocator_module) = compiled_modules.allocator_module {
                 if let Some(ref path) = allocator_module.bytecode {
-                    remove(sess, path);
+                    ensure_removed(sess.diagnostic(), path);
                 }
             }
         }
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 0fc11c286f8..08e31c3b37f 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -32,10 +32,11 @@ use rustc_session::config::{self, EntryFnType};
 use rustc_session::Session;
 use rustc_target::abi::{Align, LayoutOf, VariantIdx};
 
-use std::cmp;
 use std::ops::{Deref, DerefMut};
 use std::time::{Duration, Instant};
 
+use itertools::Itertools;
+
 pub fn bin_op_to_icmp_predicate(op: hir::BinOpKind, signed: bool) -> IntPredicate {
     match op {
         hir::BinOpKind::Eq => IntPredicate::IntEQ,
@@ -546,12 +547,23 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
         ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module);
     }
 
-    // We sort the codegen units by size. This way we can schedule work for LLVM
-    // a bit more efficiently.
-    let codegen_units = {
-        let mut codegen_units = codegen_units.iter().collect::<Vec<_>>();
-        codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate()));
-        codegen_units
+    // For better throughput during parallel processing by LLVM, we used to sort
+    // CGUs largest to smallest. This would lead to better thread utilization
+    // by, for example, preventing a large CGU from being processed last and
+    // having only one LLVM thread working while the rest remained idle.
+    //
+    // However, this strategy would lead to high memory usage, as it meant the
+    // LLVM-IR for all of the largest CGUs would be resident in memory at once.
+    //
+    // Instead, we can compromise by ordering CGUs such that the largest and
+    // smallest are first, second largest and smallest are next, etc. If there
+    // are large size variations, this can reduce memory usage significantly.
+    let codegen_units: Vec<_> = {
+        let mut sorted_cgus = codegen_units.iter().collect::<Vec<_>>();
+        sorted_cgus.sort_by_cached_key(|cgu| cgu.size_estimate());
+
+        let (first_half, second_half) = sorted_cgus.split_at(sorted_cgus.len() / 2);
+        second_half.iter().rev().interleave(first_half).copied().collect()
     };
 
     // The non-parallel compiler can only translate codegen units to LLVM IR
@@ -855,7 +867,7 @@ fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguR
         cgu.name()
     );
 
-    if tcx.dep_graph.try_mark_green(tcx, &dep_node).is_some() {
+    if tcx.try_mark_green(&dep_node) {
         // We can re-use either the pre- or the post-thinlto state. If no LTO is
         // being performed then we can use post-LTO artifacts, otherwise we must
         // reuse pre-LTO artifacts
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index c8219081678..9ce90669800 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -709,7 +709,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             let (tup, args) = args.split_last().unwrap();
             (args, Some(tup))
         } else {
-            (&args[..], None)
+            (args, None)
         };
 
         'make_args: for (i, arg) in first_args.iter().enumerate() {
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index f1eae605da0..ea59e183118 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -320,6 +320,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     ) -> Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>> {
         let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full;
 
+        let target_is_msvc = self.cx.sess().target.is_like_msvc;
+
         if !full_debug_info && self.cx.sess().fewer_names() {
             return None;
         }
@@ -341,11 +343,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             && var.source_info.scope == mir::OUTERMOST_SOURCE_SCOPE
                         {
                             let arg_index = place.local.index() - 1;
-
-                            // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
-                            // offset in closures to account for the hidden environment?
-                            // Also, is this `+ 1` needed at all?
-                            VariableKind::ArgumentVariable(arg_index + 1)
+                            if target_is_msvc {
+                                // Rust compiler decomposes every &str or slice argument into two components:
+                                // a pointer to the memory address where the data is stored and a usize representing
+                                // the length of the str (or slice). These components will later be used to reconstruct
+                                // the original argument inside the body of the function that owns it (see the
+                                // definition of debug_introduce_local for more details).
+                                //
+                                // Since the original argument is declared inside a function rather than being passed
+                                // in as an argument, it must be marked as a LocalVariable for MSVC debuggers to visualize
+                                // its data correctly. (See issue #81894 for an in-depth description of the problem).
+                                match *var_ty.kind() {
+                                    ty::Ref(_, inner_type, _) => match *inner_type.kind() {
+                                        ty::Slice(_) | ty::Str => VariableKind::LocalVariable,
+                                        _ => VariableKind::ArgumentVariable(arg_index + 1),
+                                    },
+                                    _ => VariableKind::ArgumentVariable(arg_index + 1),
+                                }
+                            } else {
+                                // FIXME(eddyb) shouldn't `ArgumentVariable` indices be
+                                // offset in closures to account for the hidden environment?
+                                // Also, is this `+ 1` needed at all?
+                                VariableKind::ArgumentVariable(arg_index + 1)
+                            }
                         } else {
                             VariableKind::LocalVariable
                         };
diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs
index 607b5459673..8e79193759e 100644
--- a/compiler/rustc_codegen_ssa/src/mono_item.rs
+++ b/compiler/rustc_codegen_ssa/src/mono_item.rs
@@ -30,8 +30,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
             MonoItem::Static(def_id) => {
                 cx.codegen_static(def_id, cx.tcx().is_mutable_static(def_id));
             }
-            MonoItem::GlobalAsm(hir_id) => {
-                let item = cx.tcx().hir().expect_item(hir_id);
+            MonoItem::GlobalAsm(item_id) => {
+                let item = cx.tcx().hir().item(item_id);
                 if let hir::ItemKind::GlobalAsm(ref ga) = item.kind {
                     cx.codegen_global_asm(ga);
                 } else {
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 23e689fcae7..e3476517de5 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -22,7 +22,7 @@ stable_deref_trait = "1.0.0"
 rayon = { version = "0.3.0", package = "rustc-rayon" }
 rayon-core = { version = "0.3.0", package = "rustc-rayon-core" }
 rustc-hash = "1.1.0"
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_index = { path = "../rustc_index", package = "rustc_index" }
 bitflags = "1.2.1"
 measureme = "9.0.0"
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index ad62e3c9fc8..1cd170599ba 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -85,6 +85,10 @@ pub struct Dominators<N: Idx> {
 }
 
 impl<Node: Idx> Dominators<Node> {
+    pub fn dummy() -> Self {
+        Self { post_order_rank: IndexVec::new(), immediate_dominators: IndexVec::new() }
+    }
+
     pub fn is_reachable(&self, node: Node) -> bool {
         self.immediate_dominators[node].is_some()
     }
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 36d261fb737..5880bbd3de4 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -13,6 +13,7 @@
 #![feature(unboxed_closures)]
 #![feature(generator_trait)]
 #![feature(fn_traits)]
+#![feature(int_bits_const)]
 #![feature(min_specialization)]
 #![feature(auto_traits)]
 #![feature(nll)]
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 9a85b9d02c9..51f851dc946 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -590,28 +590,25 @@ pub fn print_time_passes_entry(
     end_rss: Option<usize>,
 ) {
     let rss_to_mb = |rss| (rss as f64 / 1_000_000.0).round() as usize;
+    let rss_change_to_mb = |rss| (rss as f64 / 1_000_000.0).round() as i128;
 
     let mem_string = match (start_rss, end_rss) {
         (Some(start_rss), Some(end_rss)) => {
-            // It's tempting to add the change in RSS from start to end, but its somewhat confusing
-            // and misleading when looking at time-passes output. Consider two adjacent entries:
-            //
-            // time:  10.000; rss start:  1000MB, end:  1000MB, change:     0MB     pass1
-            // time:   5.000; rss start:  2000MB, end:  2000MB, change:     0MB     pass2
-            //
-            // If you're looking for jumps in RSS based on the change column, you miss the fact
-            // that a 1GB jump happened between pass1 and pass2 (supposing pass1 and pass2 actually
-            // occur sequentially and pass1 isn't just nested within pass2). It's easy to imagine
-            // someone missing this or being confused by the fact that the change is zero.
-
-            format!("; rss: {:>5}MB -> {:>5}MB", rss_to_mb(start_rss), rss_to_mb(end_rss))
+            let change_rss = end_rss as i128 - start_rss as i128;
+
+            format!(
+                "; rss: {:>4}MB -> {:>4}MB ({:>+5}MB)",
+                rss_to_mb(start_rss),
+                rss_to_mb(end_rss),
+                rss_change_to_mb(change_rss),
+            )
         }
-        (Some(start_rss), None) => format!("; rss start: {:>5}MB", rss_to_mb(start_rss)),
-        (None, Some(end_rss)) => format!("; rss end: {:5>}MB", rss_to_mb(end_rss)),
+        (Some(start_rss), None) => format!("; rss start: {:>4}MB", rss_to_mb(start_rss)),
+        (None, Some(end_rss)) => format!("; rss end: {:>4}MB", rss_to_mb(end_rss)),
         (None, None) => String::new(),
     };
 
-    println!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what);
+    eprintln!("time: {:>7}{}\t{}", duration_to_secs_str(dur), mem_string, what);
 }
 
 // Hack up our own formatting for the duration to make it easier for scripts
diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs
index 485719c5175..14db71cb8f0 100644
--- a/compiler/rustc_data_structures/src/sharded.rs
+++ b/compiler/rustc_data_structures/src/sharded.rs
@@ -63,23 +63,9 @@ impl<T> Sharded<T> {
         if SHARDS == 1 { &self.shards[0].0 } else { self.get_shard_by_hash(make_hash(val)) }
     }
 
-    /// Get a shard with a pre-computed hash value. If `get_shard_by_value` is
-    /// ever used in combination with `get_shard_by_hash` on a single `Sharded`
-    /// instance, then `hash` must be computed with `FxHasher`. Otherwise,
-    /// `hash` can be computed with any hasher, so long as that hasher is used
-    /// consistently for each `Sharded` instance.
-    #[inline]
-    pub fn get_shard_index_by_hash(&self, hash: u64) -> usize {
-        let hash_len = mem::size_of::<usize>();
-        // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits.
-        // hashbrown also uses the lowest bits, so we can't use those
-        let bits = (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize;
-        bits % SHARDS
-    }
-
     #[inline]
     pub fn get_shard_by_hash(&self, hash: u64) -> &Lock<T> {
-        &self.shards[self.get_shard_index_by_hash(hash)].0
+        &self.shards[get_shard_index_by_hash(hash)].0
     }
 
     #[inline]
@@ -166,3 +152,17 @@ fn make_hash<K: Hash + ?Sized>(val: &K) -> u64 {
     val.hash(&mut state);
     state.finish()
 }
+
+/// Get a shard with a pre-computed hash value. If `get_shard_by_value` is
+/// ever used in combination with `get_shard_by_hash` on a single `Sharded`
+/// instance, then `hash` must be computed with `FxHasher`. Otherwise,
+/// `hash` can be computed with any hasher, so long as that hasher is used
+/// consistently for each `Sharded` instance.
+#[inline]
+pub fn get_shard_index_by_hash(hash: u64) -> usize {
+    let hash_len = mem::size_of::<usize>();
+    // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits.
+    // hashbrown also uses the lowest bits, so we can't use those
+    let bits = (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize;
+    bits % SHARDS
+}
diff --git a/compiler/rustc_driver/src/args.rs b/compiler/rustc_driver/src/args.rs
index 4f2febf04b1..01338359f1a 100644
--- a/compiler/rustc_driver/src/args.rs
+++ b/compiler/rustc_driver/src/args.rs
@@ -3,7 +3,7 @@ use std::fmt;
 use std::fs;
 use std::io;
 
-pub fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
+fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
     if let Some(path) = arg.strip_prefix('@') {
         let file = match fs::read_to_string(path) {
             Ok(file) => file,
@@ -18,6 +18,20 @@ pub fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
     }
 }
 
+pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
+    let mut args = Vec::new();
+    for arg in at_args {
+        match arg_expand(arg.clone()) {
+            Ok(arg) => args.extend(arg),
+            Err(err) => rustc_session::early_error(
+                rustc_session::config::ErrorOutputType::default(),
+                &format!("Failed to load argument file: {}", err),
+            ),
+        }
+    }
+    args
+}
+
 #[derive(Debug)]
 pub enum Error {
     Utf8Error(Option<String>),
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 8295e88f75a..79bb21b29fc 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -27,7 +27,6 @@ use rustc_interface::{interface, Queries};
 use rustc_lint::LintStore;
 use rustc_metadata::locator;
 use rustc_middle::middle::cstore::MetadataLoader;
-use rustc_middle::ty::TyCtxt;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
 use rustc_serialize::json::{self, ToJson};
@@ -55,7 +54,7 @@ use std::process::{self, Command, Stdio};
 use std::str;
 use std::time::Instant;
 
-mod args;
+pub mod args;
 pub mod pretty;
 
 /// Exit status code used for successful compilation and help output.
@@ -188,16 +187,8 @@ fn run_compiler(
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
     >,
 ) -> interface::Result<()> {
-    let mut args = Vec::new();
-    for arg in at_args {
-        match args::arg_expand(arg.clone()) {
-            Ok(arg) => args.extend(arg),
-            Err(err) => early_error(
-                ErrorOutputType::default(),
-                &format!("Failed to load argument file: {}", err),
-            ),
-        }
-    }
+    let args = args::arg_expand_all(at_args);
+
     let diagnostic_output = emitter.map_or(DiagnosticOutput::Default, DiagnosticOutput::Raw);
     let matches = match handle_options(&args) {
         Some(matches) => matches,
@@ -821,7 +812,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
     } else {
         "\n    --help -v           Print the full set of options rustc accepts"
     };
-    let at_path = if verbose && nightly_build {
+    let at_path = if verbose {
         "    @path               Read newline separated options from `path`\n"
     } else {
         ""
@@ -1240,7 +1231,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
 
     let num_frames = if backtrace { None } else { Some(2) };
 
-    TyCtxt::try_print_query_stack(&handler, num_frames);
+    interface::try_print_query_stack(&handler, num_frames);
 
     #[cfg(windows)]
     unsafe {
diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
index b7edc24bc4a..17d2b3386f5 100644
--- a/compiler/rustc_driver/src/pretty.rs
+++ b/compiler/rustc_driver/src/pretty.rs
@@ -15,8 +15,6 @@ use rustc_span::symbol::Ident;
 use rustc_span::FileName;
 
 use std::cell::Cell;
-use std::fs::File;
-use std::io::Write;
 use std::path::Path;
 
 pub use self::PpMode::*;
@@ -237,7 +235,7 @@ impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
             pprust_hir::AnnNode::Name(_) => {}
             pprust_hir::AnnNode::Item(item) => {
                 s.s.space();
-                s.synth_comment(format!("hir_id: {}", item.hir_id));
+                s.synth_comment(format!("hir_id: {}", item.hir_id()));
             }
             pprust_hir::AnnNode::SubItem(id) => {
                 s.s.space();
@@ -375,13 +373,14 @@ fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
     (src, src_name)
 }
 
-fn write_output(out: Vec<u8>, ofile: Option<&Path>) {
+fn write_or_print(out: &str, ofile: Option<&Path>) {
     match ofile {
-        None => print!("{}", String::from_utf8(out).unwrap()),
-        Some(p) => match File::create(p) {
-            Ok(mut w) => w.write_all(&out).unwrap(),
-            Err(e) => panic!("print-print failed to open {} due to {}", p.display(), e),
-        },
+        None => print!("{}", out),
+        Some(p) => {
+            if let Err(e) = std::fs::write(p, out) {
+                panic!("print-print failed to write {} due to {}", p.display(), e);
+            }
+        }
     }
 }
 
@@ -417,7 +416,7 @@ pub fn print_after_parsing(
         unreachable!();
     };
 
-    write_output(out.into_bytes(), ofile);
+    write_or_print(&out, ofile);
 }
 
 pub fn print_after_hir_lowering<'tcx>(
@@ -477,7 +476,7 @@ pub fn print_after_hir_lowering<'tcx>(
         _ => unreachable!(),
     }
 
-    write_output(out.into_bytes(), ofile);
+    write_or_print(&out, ofile);
 }
 
 // In an ideal world, this would be a public function called by the driver after
@@ -503,7 +502,8 @@ fn print_with_analysis(
     }
     .unwrap();
 
-    write_output(out, ofile);
+    let out = std::str::from_utf8(&out).unwrap();
+    write_or_print(out, ofile);
 
     Ok(())
 }
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 1ed43669ad8..c4330694504 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -285,7 +285,12 @@ E0537: include_str!("./error_codes/E0537.md"),
 E0538: include_str!("./error_codes/E0538.md"),
 E0539: include_str!("./error_codes/E0539.md"),
 E0541: include_str!("./error_codes/E0541.md"),
+E0542: include_str!("./error_codes/E0542.md"),
+E0543: include_str!("./error_codes/E0543.md"),
+E0545: include_str!("./error_codes/E0545.md"),
 E0546: include_str!("./error_codes/E0546.md"),
+E0547: include_str!("./error_codes/E0547.md"),
+E0549: include_str!("./error_codes/E0549.md"),
 E0550: include_str!("./error_codes/E0550.md"),
 E0551: include_str!("./error_codes/E0551.md"),
 E0552: include_str!("./error_codes/E0552.md"),
@@ -602,15 +607,8 @@ E0781: include_str!("./error_codes/E0781.md"),
     E0523,
 //  E0526, // shuffle indices are not constant
 //  E0540, // multiple rustc_deprecated attributes
-    E0542, // missing 'since'
-    E0543, // missing 'reason'
     E0544, // multiple stability levels
-    E0545, // incorrect 'issue'
-    E0547, // missing 'issue'
 //  E0548, // replaced with a generic attribute input check
-    // rustc_deprecated attribute must be paired with either stable or unstable
-    // attribute
-    E0549,
     E0553, // multiple rustc_const_unstable attributes
 //  E0555, // replaced with a generic attribute input check
 //  E0558, // replaced with a generic attribute input check
diff --git a/compiler/rustc_error_codes/src/error_codes/E0074.md b/compiler/rustc_error_codes/src/error_codes/E0074.md
index e25dec7681b..785d6de226d 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0074.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0074.md
@@ -11,7 +11,7 @@ This will cause an error:
 #![feature(repr_simd)]
 
 #[repr(simd)]
-struct Bad<T>(T, T, T);
+struct Bad<T>(T, T, T, T);
 ```
 
 This will not:
@@ -20,5 +20,5 @@ This will not:
 #![feature(repr_simd)]
 
 #[repr(simd)]
-struct Good(u32, u32, u32);
+struct Good(u32, u32, u32, u32);
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0076.md b/compiler/rustc_error_codes/src/error_codes/E0076.md
index f293a2a5772..1da8caa9506 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0076.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0076.md
@@ -7,7 +7,7 @@ Erroneous code example:
 #![feature(repr_simd)]
 
 #[repr(simd)]
-struct Bad(u16, u32, u32); // error!
+struct Bad(u16, u32, u32 u32); // error!
 ```
 
 When using the `#[simd]` attribute to automatically use SIMD operations in tuple
@@ -20,5 +20,5 @@ Fixed example:
 #![feature(repr_simd)]
 
 #[repr(simd)]
-struct Good(u32, u32, u32); // ok!
+struct Good(u32, u32, u32, u32); // ok!
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0077.md b/compiler/rustc_error_codes/src/error_codes/E0077.md
index b14513c6ccf..91aa24d1f52 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0077.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0077.md
@@ -19,5 +19,5 @@ Fixed example:
 #![feature(repr_simd)]
 
 #[repr(simd)]
-struct Good(u32, u32, u32); // ok!
+struct Good(u32, u32, u32, u32); // ok!
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0162.md b/compiler/rustc_error_codes/src/error_codes/E0162.md
index 98146147f39..0161c9325c2 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0162.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0162.md
@@ -1,6 +1,6 @@
 #### Note: this error code is no longer emitted by the compiler.
 
-An if-let pattern attempts to match the pattern, and enters the body if the
+An `if let` pattern attempts to match the pattern, and enters the body if the
 match was successful. If the match is irrefutable (when it cannot fail to
 match), use a regular `let`-binding instead. For instance:
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0165.md b/compiler/rustc_error_codes/src/error_codes/E0165.md
index 92243db4550..7bcd6c0cbf3 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0165.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0165.md
@@ -1,6 +1,6 @@
 #### Note: this error code is no longer emitted by the compiler.
 
-A while-let pattern attempts to match the pattern, and enters the body if the
+A `while let` pattern attempts to match the pattern, and enters the body if the
 match was successful. If the match is irrefutable (when it cannot fail to
 match), use a regular `let`-binding inside a `loop` instead. For instance:
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0463.md b/compiler/rustc_error_codes/src/error_codes/E0463.md
index e46938c607d..d0cd1b1dcb7 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0463.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0463.md
@@ -11,3 +11,24 @@ extern crate cake_is_a_lie; // error: can't find crate for `cake_is_a_lie`
 You need to link your code to the relevant crate in order to be able to use it
 (through Cargo or the `-L` option of rustc example). Plugins are crates as
 well, and you link to them the same way.
+
+## Common causes
+
+- The crate is not present at all. If using Cargo, add it to `[dependencies]`
+  in Cargo.toml.
+- The crate is present, but under a different name. If using Cargo, look for
+  `package = ` under `[dependencies]` in Cargo.toml.
+
+## Common causes for missing `std` or `core`
+
+- You are cross-compiling for a target which doesn't have `std` prepackaged.
+  Consider one of the following:
+  + Adding a pre-compiled version of std with `rustup target add`
+  + Building std from source with `cargo build -Z build-std`
+  + Using `#![no_std]` at the crate root, so you won't need `std` in the first
+    place.
+- You are developing the compiler itself and haven't built libstd from source.
+  You can usually build it with `x.py build library/std`. More information
+  about x.py is available in the [rustc-dev-guide].
+
+[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#building-the-compiler
diff --git a/compiler/rustc_error_codes/src/error_codes/E0542.md b/compiler/rustc_error_codes/src/error_codes/E0542.md
new file mode 100644
index 00000000000..7cb58f9d0cb
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0542.md
@@ -0,0 +1,47 @@
+The `since` value is missing in a stability attribute.
+
+Erroneous code example:
+
+```compile_fail,E0542
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[stable(feature = "_stable_fn")] // invalid
+fn _stable_fn() {}
+
+#[rustc_const_stable(feature = "_stable_const_fn")] // invalid
+fn _stable_const_fn() {}
+
+#[stable(feature = "_deprecated_fn", since = "0.1.0")]
+#[rustc_deprecated(
+    reason = "explanation for deprecation"
+)] // invalid
+fn _deprecated_fn() {}
+```
+
+To fix this issue, you need to provide the `since` field. Example:
+
+```
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[stable(feature = "_stable_fn", since = "1.0.0")] // ok!
+fn _stable_fn() {}
+
+#[rustc_const_stable(feature = "_stable_const_fn", since = "1.0.0")] // ok!
+fn _stable_const_fn() {}
+
+#[stable(feature = "_deprecated_fn", since = "0.1.0")]
+#[rustc_deprecated(
+    since = "1.0.0",
+    reason = "explanation for deprecation"
+)] // ok!
+fn _deprecated_fn() {}
+```
+
+See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
+of the Book and the [Stability attributes][stability-attributes] section of the
+Rustc Dev Guide for more details.
+
+[how-rust-made-nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+[stability-attributes]: https://rustc-dev-guide.rust-lang.org/stability.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0543.md b/compiler/rustc_error_codes/src/error_codes/E0543.md
new file mode 100644
index 00000000000..ba26f92e89f
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0543.md
@@ -0,0 +1,35 @@
+The `reason` value is missing in a stability attribute.
+
+Erroneous code example:
+
+```compile_fail,E0543
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[stable(since = "0.1.0", feature = "_deprecated_fn")]
+#[rustc_deprecated(
+    since = "1.0.0"
+)] // invalid
+fn _deprecated_fn() {}
+```
+
+To fix this issue, you need to provide the `reason` field. Example:
+
+```
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[stable(since = "0.1.0", feature = "_deprecated_fn")]
+#[rustc_deprecated(
+    since = "1.0.0",
+    reason = "explanation for deprecation"
+)] // ok!
+fn _deprecated_fn() {}
+```
+
+See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
+of the Book and the [Stability attributes][stability-attributes] section of the
+Rustc Dev Guide for more details.
+
+[how-rust-made-nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+[stability-attributes]: https://rustc-dev-guide.rust-lang.org/stability.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0545.md b/compiler/rustc_error_codes/src/error_codes/E0545.md
new file mode 100644
index 00000000000..9fb935a3ab1
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0545.md
@@ -0,0 +1,35 @@
+The `issue` value is incorrect in a stability attribute.
+
+Erroneous code example:
+
+```compile_fail,E0545
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[unstable(feature = "_unstable_fn", issue = "0")] // invalid
+fn _unstable_fn() {}
+
+#[rustc_const_unstable(feature = "_unstable_const_fn", issue = "0")] // invalid
+fn _unstable_const_fn() {}
+```
+
+To fix this issue, you need to provide a correct value in the `issue` field.
+Example:
+
+```
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[unstable(feature = "_unstable_fn", issue = "none")] // ok!
+fn _unstable_fn() {}
+
+#[rustc_const_unstable(feature = "_unstable_const_fn", issue = "1")] // ok!
+fn _unstable_const_fn() {}
+```
+
+See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
+of the Book and the [Stability attributes][stability-attributes] section of the
+Rustc Dev Guide for more details.
+
+[how-rust-made-nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+[stability-attributes]: https://rustc-dev-guide.rust-lang.org/stability.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0546.md b/compiler/rustc_error_codes/src/error_codes/E0546.md
index b2df22c0f8f..a33dcb7a9ac 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0546.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0546.md
@@ -1,4 +1,4 @@
-A feature name is missing.
+The `feature` value is missing in a stability attribute.
 
 Erroneous code example:
 
@@ -13,7 +13,7 @@ fn unstable_fn() {}
 fn stable_fn() {}
 ```
 
-To fix the issue you need to provide a feature name.
+To fix this issue, you need to provide the `feature` field. Example:
 
 ```
 #![feature(staged_api)]
@@ -25,3 +25,10 @@ fn unstable_fn() {}
 #[stable(feature = "stable_fn", since = "1.0.0")] // ok!
 fn stable_fn() {}
 ```
+
+See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
+of the Book and the [Stability attributes][stability-attributes] section of the
+Rustc Dev Guide for more details.
+
+[how-rust-made-nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+[stability-attributes]: https://rustc-dev-guide.rust-lang.org/stability.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0547.md b/compiler/rustc_error_codes/src/error_codes/E0547.md
new file mode 100644
index 00000000000..1aa4b354248
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0547.md
@@ -0,0 +1,37 @@
+The `issue` value is missing in a stability attribute.
+
+Erroneous code example:
+
+```compile_fail,E0547
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[unstable(feature = "_unstable_fn")] // invalid
+fn _unstable_fn() {}
+
+#[rustc_const_unstable(feature = "_unstable_const_fn")] // invalid
+fn _unstable_const_fn() {}
+```
+
+To fix this issue, you need to provide the `issue` field. Example:
+
+```
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[unstable(feature = "_unstable_fn", issue = "none")] // ok!
+fn _unstable_fn() {}
+
+#[rustc_const_unstable(
+    feature = "_unstable_const_fn",
+    issue = "none"
+)] // ok!
+fn _unstable_const_fn() {}
+```
+
+See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
+of the Book and the [Stability attributes][stability-attributes] section of the
+Rustc Dev Guide for more details.
+
+[how-rust-made-nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+[stability-attributes]: https://rustc-dev-guide.rust-lang.org/stability.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0549.md b/compiler/rustc_error_codes/src/error_codes/E0549.md
new file mode 100644
index 00000000000..d4b78e7e0d6
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0549.md
@@ -0,0 +1,37 @@
+A `rustc_deprecated` attribute wasn't paired with a `stable`/`unstable`
+attribute.
+
+Erroneous code example:
+
+```compile_fail,E0549
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[rustc_deprecated(
+    since = "1.0.1",
+    reason = "explanation for deprecation"
+)] // invalid
+fn _deprecated_fn() {}
+```
+
+To fix this issue, you need to add also an attribute `stable` or `unstable`.
+Example:
+
+```
+#![feature(staged_api)]
+#![stable(since = "1.0.0", feature = "test")]
+
+#[stable(since = "1.0.0", feature = "test")]
+#[rustc_deprecated(
+    since = "1.0.1",
+    reason = "explanation for deprecation"
+)] // ok!
+fn _deprecated_fn() {}
+```
+
+See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix
+of the Book and the [Stability attributes][stability-attributes] section of the
+Rustc Dev Guide for more details.
+
+[how-rust-made-nightly]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+[stability-attributes]: https://rustc-dev-guide.rust-lang.org/stability.html
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index e61476bf23e..ef4a45cab41 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -4,7 +4,9 @@ use crate::Level;
 use crate::Substitution;
 use crate::SubstitutionPart;
 use crate::SuggestionStyle;
+use crate::ToolMetadata;
 use rustc_lint_defs::Applicability;
+use rustc_serialize::json::Json;
 use rustc_span::{MultiSpan, Span, DUMMY_SP};
 use std::fmt;
 
@@ -303,6 +305,7 @@ impl Diagnostic {
             msg: msg.to_owned(),
             style: SuggestionStyle::ShowCode,
             applicability,
+            tool_metadata: Default::default(),
         });
         self
     }
@@ -328,6 +331,7 @@ impl Diagnostic {
             msg: msg.to_owned(),
             style: SuggestionStyle::ShowCode,
             applicability,
+            tool_metadata: Default::default(),
         });
         self
     }
@@ -354,6 +358,7 @@ impl Diagnostic {
             msg: msg.to_owned(),
             style: SuggestionStyle::CompletelyHidden,
             applicability,
+            tool_metadata: Default::default(),
         });
         self
     }
@@ -408,6 +413,7 @@ impl Diagnostic {
             msg: msg.to_owned(),
             style,
             applicability,
+            tool_metadata: Default::default(),
         });
         self
     }
@@ -446,6 +452,7 @@ impl Diagnostic {
             msg: msg.to_owned(),
             style: SuggestionStyle::ShowCode,
             applicability,
+            tool_metadata: Default::default(),
         });
         self
     }
@@ -515,6 +522,23 @@ impl Diagnostic {
         self
     }
 
+    /// Adds a suggestion intended only for a tool. The intent is that the metadata encodes
+    /// the suggestion in a tool-specific way, as it may not even directly involve Rust code.
+    pub fn tool_only_suggestion_with_metadata(
+        &mut self,
+        msg: &str,
+        applicability: Applicability,
+        tool_metadata: Json,
+    ) {
+        self.suggestions.push(CodeSuggestion {
+            substitutions: vec![],
+            msg: msg.to_owned(),
+            style: SuggestionStyle::CompletelyHidden,
+            applicability,
+            tool_metadata: ToolMetadata::new(tool_metadata),
+        })
+    }
+
     pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
         self.span = sp.into();
         if let Some(span) = self.span.primary_span() {
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index ea62e215230..42c3d5e48fe 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -1713,7 +1713,18 @@ impl EmitterWriter {
         let max_line_num_len = if self.ui_testing {
             ANONYMIZED_LINE_NUM.len()
         } else {
-            self.get_max_line_num(span, children).to_string().len()
+            // Instead of using .to_string().len(), we iteratively count the
+            // number of digits to avoid allocation. This strategy has sizable
+            // performance gains over the old string strategy.
+            let mut n = self.get_max_line_num(span, children);
+            let mut num_digits = 0;
+            loop {
+                num_digits += 1;
+                n /= 10;
+                if n == 0 {
+                    break num_digits;
+                }
+            }
         };
 
         match self.emit_message_default(span, message, code, level, max_line_num_len, false) {
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index d57beb1148a..c27b39a9d62 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -14,6 +14,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap};
 use crate::emitter::{Emitter, HumanReadableErrorType};
 use crate::registry::Registry;
 use crate::DiagnosticId;
+use crate::ToolMetadata;
 use crate::{CodeSuggestion, SubDiagnostic};
 use rustc_lint_defs::{Applicability, FutureBreakage};
 
@@ -26,6 +27,7 @@ use std::sync::{Arc, Mutex};
 use std::vec;
 
 use rustc_serialize::json::{as_json, as_pretty_json};
+use rustc_serialize::{Encodable, Encoder};
 
 #[cfg(test)]
 mod tests;
@@ -168,7 +170,8 @@ impl Emitter for JsonEmitter {
 
 // The following data types are provided just for serialisation.
 
-#[derive(Encodable)]
+// NOTE: this has a manual implementation of Encodable which needs to be updated in
+// parallel.
 struct Diagnostic {
     /// The primary error message.
     message: String,
@@ -180,6 +183,65 @@ struct Diagnostic {
     children: Vec<Diagnostic>,
     /// The message as rustc would render it.
     rendered: Option<String>,
+    /// Extra tool metadata
+    tool_metadata: ToolMetadata,
+}
+
+macro_rules! encode_fields {
+    (
+        $enc:expr,                  // encoder
+        $idx:expr,                  // starting field index
+        $struct:expr,               // struct we're serializing
+        $struct_name:ident,         // struct name
+        [ $($name:ident),+$(,)? ],  // fields to encode
+        [ $($ignore:ident),+$(,)? ] // fields we're skipping
+    ) => {
+        {
+            // Pattern match to make sure all fields are accounted for
+            let $struct_name { $($name,)+ $($ignore: _,)+ } = $struct;
+            let mut idx = $idx;
+            $(
+                $enc.emit_struct_field(
+                    stringify!($name),
+                    idx,
+                    |enc| $name.encode(enc),
+                )?;
+                idx += 1;
+            )+
+            idx
+        }
+    };
+}
+
+// Special-case encoder to skip tool_metadata if not set
+impl<E: Encoder> Encodable<E> for Diagnostic {
+    fn encode(&self, s: &mut E) -> Result<(), E::Error> {
+        s.emit_struct("diagnostic", 7, |s| {
+            let mut idx = 0;
+
+            idx = encode_fields!(
+                s,
+                idx,
+                self,
+                Self,
+                [message, code, level, spans, children, rendered],
+                [tool_metadata]
+            );
+            if self.tool_metadata.is_set() {
+                idx = encode_fields!(
+                    s,
+                    idx,
+                    self,
+                    Self,
+                    [tool_metadata],
+                    [message, code, level, spans, children, rendered]
+                );
+            }
+
+            let _ = idx;
+            Ok(())
+        })
+    }
 }
 
 #[derive(Encodable)]
@@ -269,6 +331,7 @@ impl Diagnostic {
             spans: DiagnosticSpan::from_suggestion(sugg, je),
             children: vec![],
             rendered: None,
+            tool_metadata: sugg.tool_metadata.clone(),
         });
 
         // generate regular command line output and store it in the json
@@ -312,6 +375,7 @@ impl Diagnostic {
                 .chain(sugg)
                 .collect(),
             rendered: Some(output),
+            tool_metadata: ToolMetadata::default(),
         }
     }
 
@@ -327,6 +391,7 @@ impl Diagnostic {
                 .unwrap_or_else(|| DiagnosticSpan::from_multispan(&diag.span, je)),
             children: vec![],
             rendered: None,
+            tool_metadata: ToolMetadata::default(),
         }
     }
 }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index e184e929b07..9800ed9bfa9 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -23,10 +23,13 @@ use rustc_data_structures::sync::{self, Lock, Lrc};
 use rustc_data_structures::AtomicRef;
 use rustc_lint_defs::FutureBreakage;
 pub use rustc_lint_defs::{pluralize, Applicability};
+use rustc_serialize::json::Json;
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::source_map::SourceMap;
 use rustc_span::{Loc, MultiSpan, Span};
 
 use std::borrow::Cow;
+use std::hash::{Hash, Hasher};
 use std::panic;
 use std::path::Path;
 use std::{error, fmt};
@@ -73,6 +76,39 @@ impl SuggestionStyle {
     }
 }
 
+#[derive(Clone, Debug, PartialEq, Default)]
+pub struct ToolMetadata(pub Option<Json>);
+
+impl ToolMetadata {
+    fn new(json: Json) -> Self {
+        ToolMetadata(Some(json))
+    }
+
+    fn is_set(&self) -> bool {
+        self.0.is_some()
+    }
+}
+
+impl Hash for ToolMetadata {
+    fn hash<H: Hasher>(&self, _state: &mut H) {}
+}
+
+// Doesn't really need to round-trip
+impl<D: Decoder> Decodable<D> for ToolMetadata {
+    fn decode(_d: &mut D) -> Result<Self, D::Error> {
+        Ok(ToolMetadata(None))
+    }
+}
+
+impl<S: Encoder> Encodable<S> for ToolMetadata {
+    fn encode(&self, e: &mut S) -> Result<(), S::Error> {
+        match &self.0 {
+            None => e.emit_unit(),
+            Some(json) => json.encode(e),
+        }
+    }
+}
+
 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub struct CodeSuggestion {
     /// Each substitute can have multiple variants due to multiple
@@ -106,6 +142,8 @@ pub struct CodeSuggestion {
     /// which are useful for users but not useful for
     /// tools like rustfix
     pub applicability: Applicability,
+    /// Tool-specific metadata
+    pub tool_metadata: ToolMetadata,
 }
 
 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
@@ -775,7 +813,6 @@ impl HandlerInner {
         }
 
         let already_emitted = |this: &mut Self| {
-            use std::hash::Hash;
             let mut hasher = StableHasher::new();
             diagnostic.hash(&mut hasher);
             let diagnostic_hash = hasher.finish();
@@ -901,7 +938,7 @@ impl HandlerInner {
 
     fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> ! {
         self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
-        panic!(ExplicitBug);
+        panic::panic_any(ExplicitBug);
     }
 
     fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
@@ -955,7 +992,7 @@ impl HandlerInner {
 
     fn bug(&mut self, msg: &str) -> ! {
         self.emit_diagnostic(&Diagnostic::new(Bug, msg));
-        panic!(ExplicitBug);
+        panic::panic_any(ExplicitBug);
     }
 
     fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml
index 7413b0d9431..59c1604e844 100644
--- a/compiler/rustc_expand/Cargo.toml
+++ b/compiler/rustc_expand/Cargo.toml
@@ -23,5 +23,5 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_parse = { path = "../rustc_parse" }
 rustc_session = { path = "../rustc_session" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 08543d1622a..e3dc793a7fa 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -141,7 +141,10 @@ impl Annotatable {
     }
 
     crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
-        nt_to_tokenstream(&self.into_nonterminal(), sess, CanSynthesizeMissingTokens::No)
+        // Tokens of an attribute target may be invalidated by some outer `#[derive]` performing
+        // "full configuration" (attributes following derives on the same item should be the most
+        // common case), that's why synthesizing tokens is allowed.
+        nt_to_tokenstream(&self.into_nonterminal(), sess, CanSynthesizeMissingTokens::Yes)
     }
 
     pub fn expect_item(self) -> P<ast::Item> {
@@ -234,25 +237,6 @@ impl Annotatable {
             _ => panic!("expected variant"),
         }
     }
-
-    pub fn derive_allowed(&self) -> bool {
-        match *self {
-            Annotatable::Stmt(ref stmt) => match stmt.kind {
-                ast::StmtKind::Item(ref item) => matches!(
-                    item.kind,
-                    ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..)
-                ),
-                _ => false,
-            },
-            Annotatable::Item(ref item) => match item.kind {
-                ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => {
-                    true
-                }
-                _ => false,
-            },
-            _ => false,
-        }
-    }
 }
 
 /// Result of an expansion that may need to be retried.
@@ -854,12 +838,6 @@ impl SyntaxExtension {
     }
 }
 
-/// Result of resolving a macro invocation.
-pub enum InvocationRes {
-    Single(Lrc<SyntaxExtension>),
-    DeriveContainer(Vec<Lrc<SyntaxExtension>>),
-}
-
 /// Error type that denotes indeterminacy.
 pub struct Indeterminate;
 
@@ -885,16 +863,29 @@ pub trait ResolverExpand {
         invoc: &Invocation,
         eager_expansion_root: ExpnId,
         force: bool,
-    ) -> Result<InvocationRes, Indeterminate>;
+    ) -> Result<Lrc<SyntaxExtension>, Indeterminate>;
 
     fn check_unused_macros(&mut self);
 
     /// Some parent node that is close enough to the given macro call.
-    fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId;
+    fn lint_node_id(&self, expn_id: ExpnId) -> NodeId;
 
     // Resolver interfaces for specific built-in macros.
     /// Does `#[derive(...)]` attribute with the given `ExpnId` have built-in `Copy` inside it?
     fn has_derive_copy(&self, expn_id: ExpnId) -> bool;
+    /// Resolve paths inside the `#[derive(...)]` attribute with the given `ExpnId`.
+    fn resolve_derives(
+        &mut self,
+        expn_id: ExpnId,
+        derives: Vec<ast::Path>,
+        force: bool,
+    ) -> Result<(), Indeterminate>;
+    /// Take resolutions for paths inside the `#[derive(...)]` attribute with the given `ExpnId`
+    /// back from resolver.
+    fn take_derive_resolutions(
+        &mut self,
+        expn_id: ExpnId,
+    ) -> Option<Vec<(Lrc<SyntaxExtension>, ast::Path)>>;
     /// Path resolution logic for `#[cfg_accessible(path)]`.
     fn cfg_accessible(&mut self, expn_id: ExpnId, path: &ast::Path) -> Result<bool, Indeterminate>;
 }
@@ -1052,6 +1043,10 @@ impl<'a> ExtCtxt<'a> {
             .chain(components.iter().map(|&s| Ident::with_dummy_span(s)))
             .collect()
     }
+    pub fn def_site_path(&self, components: &[Symbol]) -> Vec<Ident> {
+        let def_site = self.with_def_site_ctxt(DUMMY_SP);
+        components.iter().map(|&s| Ident::new(s, def_site)).collect()
+    }
 
     pub fn check_unused_macros(&mut self) {
         self.resolver.check_unused_macros();
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index b07bce94870..ad04fa9a958 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -209,7 +209,7 @@ pub fn features(sess: &Session, mut krate: ast::Crate) -> (ast::Crate, Features)
         None => {
             // The entire crate is unconfigured.
             krate.attrs = Vec::new();
-            krate.module.items = Vec::new();
+            krate.items = Vec::new();
             Features::default()
         }
         Some(attrs) => {
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 5fdb7fc5915..5a4737842f0 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1,26 +1,28 @@
 use crate::base::*;
 use crate::config::StripUnconfigured;
 use crate::configure;
-use crate::hygiene::{ExpnData, ExpnKind, SyntaxContext};
+use crate::hygiene::SyntaxContext;
 use crate::mbe::macro_rules::annotate_err_with_kind;
 use crate::module::{parse_external_mod, push_directory, Directory, DirectoryOwnership};
 use crate::placeholders::{placeholder, PlaceholderExpander};
-use crate::proc_macro::collect_derives;
 
+use rustc_ast as ast;
 use rustc_ast::mut_visit::*;
 use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{self as ast, AttrItem, AttrStyle, Block, LitKind, NodeId, PatKind, Path};
-use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind, Unsafe};
+use rustc_ast::{AttrItem, AttrStyle, Block, Inline, ItemKind, LitKind, MacArgs};
+use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
+use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
 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_data_structures::sync::Lrc;
+use rustc_errors::{Applicability, PResult};
 use rustc_feature::Features;
-use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, Parser};
+use rustc_parse::parser::{AttemptLocalParseRecovery, ForceCollect, GateOr, Parser, RecoverComma};
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
 use rustc_session::lint::BuiltinLintDiagnostics;
@@ -302,20 +304,11 @@ pub enum InvocationKind {
         item: Annotatable,
         // Required for resolving derive helper attributes.
         derives: Vec<Path>,
-        // We temporarily report errors for attribute macros placed after derives
-        after_derive: bool,
     },
     Derive {
         path: Path,
         item: Annotatable,
     },
-    /// "Invocation" that contains all derives from an item,
-    /// broken into multiple `Derive` invocations when expanded.
-    /// FIXME: Find a way to remove it.
-    DeriveContainer {
-        derives: Vec<Path>,
-        item: Annotatable,
-    },
 }
 
 impl InvocationKind {
@@ -328,7 +321,6 @@ impl InvocationKind {
         match self {
             InvocationKind::Attr { item: Annotatable::StructField(field), .. }
             | InvocationKind::Derive { item: Annotatable::StructField(field), .. }
-            | InvocationKind::DeriveContainer { item: Annotatable::StructField(field), .. }
                 if field.ident.is_none() =>
             {
                 Some(field.vis.clone())
@@ -344,7 +336,6 @@ impl Invocation {
             InvocationKind::Bang { span, .. } => *span,
             InvocationKind::Attr { attr, .. } => attr.span,
             InvocationKind::Derive { path, .. } => path.span,
-            InvocationKind::DeriveContainer { item, .. } => item.span(),
         }
     }
 }
@@ -359,6 +350,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         MacroExpander { cx, monotonic }
     }
 
+    // FIXME: Avoid visiting the crate as a `Mod` item,
+    // make crate a first class expansion target instead.
     pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
         let mut module = ModuleData {
             mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)],
@@ -371,12 +364,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         self.cx.root_path = module.directory.clone();
         self.cx.current_expansion.module = Rc::new(module);
 
-        let orig_mod_span = krate.module.inner;
-
         let krate_item = AstFragment::Items(smallvec![P(ast::Item {
             attrs: krate.attrs,
             span: krate.span,
-            kind: ast::ItemKind::Mod(krate.module),
+            kind: ast::ItemKind::Mod(
+                Unsafe::No,
+                ModKind::Loaded(krate.items, Inline::Yes, krate.span)
+            ),
             ident: Ident::invalid(),
             id: ast::DUMMY_NODE_ID,
             vis: ast::Visibility {
@@ -388,28 +382,22 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         })]);
 
         match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) {
-            Some(ast::Item { attrs, kind: ast::ItemKind::Mod(module), .. }) => {
+            Some(ast::Item {
+                attrs,
+                kind: ast::ItemKind::Mod(_, ModKind::Loaded(items, ..)),
+                ..
+            }) => {
                 krate.attrs = attrs;
-                krate.module = module;
+                krate.items = items;
             }
             None => {
                 // Resolution failed so we return an empty expansion
                 krate.attrs = vec![];
-                krate.module = ast::Mod {
-                    inner: orig_mod_span,
-                    unsafety: Unsafe::No,
-                    items: vec![],
-                    inline: true,
-                };
+                krate.items = vec![];
             }
             Some(ast::Item { span, kind, .. }) => {
                 krate.attrs = vec![];
-                krate.module = ast::Mod {
-                    inner: orig_mod_span,
-                    unsafety: Unsafe::No,
-                    items: vec![],
-                    inline: true,
-                };
+                krate.items = vec![];
                 self.cx.span_err(
                     span,
                     &format!(
@@ -446,7 +434,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let mut undetermined_invocations = Vec::new();
         let (mut progress, mut force) = (false, !self.monotonic);
         loop {
-            let (invoc, res) = if let Some(invoc) = invocations.pop() {
+            let (invoc, ext) = if let Some(invoc) = invocations.pop() {
                 invoc
             } else {
                 self.resolve_imports();
@@ -464,8 +452,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 continue;
             };
 
-            let res = match res {
-                Some(res) => res,
+            let ext = match ext {
+                Some(ext) => ext,
                 None => {
                     let eager_expansion_root = if self.monotonic {
                         invoc.expansion_data.id
@@ -477,7 +465,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         eager_expansion_root,
                         force,
                     ) {
-                        Ok(res) => res,
+                        Ok(ext) => ext,
                         Err(Indeterminate) => {
                             // Cannot resolve, will retry this invocation later.
                             undetermined_invocations.push((invoc, None));
@@ -491,86 +479,78 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             self.cx.current_expansion = invoc.expansion_data.clone();
             self.cx.force_mode = force;
 
-            // FIXME(jseyfried): Refactor out the following logic
             let fragment_kind = invoc.fragment_kind;
-            let (expanded_fragment, new_invocations) = match res {
-                InvocationRes::Single(ext) => match self.expand_invoc(invoc, &ext.kind) {
-                    ExpandResult::Ready(fragment) => self.collect_invocations(fragment, &[]),
-                    ExpandResult::Retry(invoc) => {
-                        if force {
-                            self.cx.span_bug(
-                                invoc.span(),
-                                "expansion entered force mode but is still stuck",
-                            );
-                        } else {
-                            // Cannot expand, will retry this invocation later.
-                            undetermined_invocations
-                                .push((invoc, Some(InvocationRes::Single(ext))));
-                            continue;
-                        }
-                    }
-                },
-                InvocationRes::DeriveContainer(_exts) => {
-                    // FIXME: Consider using the derive resolutions (`_exts`) immediately,
-                    // instead of enqueuing the derives to be resolved again later.
-                    let (derives, mut item) = match invoc.kind {
-                        InvocationKind::DeriveContainer { derives, item } => (derives, item),
-                        _ => unreachable!(),
-                    };
-                    let (item, derive_placeholders) = if !item.derive_allowed() {
-                        self.error_derive_forbidden_on_non_adt(&derives, &item);
-                        item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
-                        (item, Vec::new())
-                    } else {
-                        let mut visitor = StripUnconfigured {
-                            sess: self.cx.sess,
-                            features: self.cx.ecfg.features,
-                            modified: false,
-                        };
-                        let mut item = visitor.fully_configure(item);
-                        item.visit_attrs(|attrs| attrs.retain(|a| !a.has_name(sym::derive)));
-                        if visitor.modified && !derives.is_empty() {
-                            // Erase the tokens if cfg-stripping modified the item
-                            // This will cause us to synthesize fake tokens
-                            // when `nt_to_tokenstream` is called on this item.
-                            match &mut item {
-                                Annotatable::Item(item) => item.tokens = None,
-                                Annotatable::Stmt(stmt) => {
-                                    if let StmtKind::Item(item) = &mut stmt.kind {
-                                        item.tokens = None
-                                    } else {
-                                        panic!("Unexpected stmt {:?}", stmt);
-                                    }
-                                }
-                                _ => panic!("Unexpected annotatable {:?}", item),
+            let (expanded_fragment, new_invocations) = match self.expand_invoc(invoc, &ext.kind) {
+                ExpandResult::Ready(fragment) => {
+                    let derive_placeholders = self
+                        .cx
+                        .resolver
+                        .take_derive_resolutions(expn_id)
+                        .map(|derives| {
+                            enum AnnotatableRef<'a> {
+                                Item(&'a P<ast::Item>),
+                                Stmt(&'a ast::Stmt),
                             }
-                        }
+                            let item = match &fragment {
+                                AstFragment::Items(items) => match &items[..] {
+                                    [item] => AnnotatableRef::Item(item),
+                                    _ => unreachable!(),
+                                },
+                                AstFragment::Stmts(stmts) => match &stmts[..] {
+                                    [stmt] => AnnotatableRef::Stmt(stmt),
+                                    _ => unreachable!(),
+                                },
+                                _ => unreachable!(),
+                            };
 
-                        invocations.reserve(derives.len());
-                        let derive_placeholders = derives
-                            .into_iter()
-                            .map(|path| {
-                                let expn_id = ExpnId::fresh(None);
-                                invocations.push((
-                                    Invocation {
-                                        kind: InvocationKind::Derive { path, item: item.clone() },
-                                        fragment_kind,
-                                        expansion_data: ExpansionData {
-                                            id: expn_id,
-                                            ..self.cx.current_expansion.clone()
+                            invocations.reserve(derives.len());
+                            derives
+                                .into_iter()
+                                .map(|(_exts, path)| {
+                                    // FIXME: Consider using the derive resolutions (`_exts`)
+                                    // instead of enqueuing the derives to be resolved again later.
+                                    let expn_id = ExpnId::fresh(None);
+                                    invocations.push((
+                                        Invocation {
+                                            kind: InvocationKind::Derive {
+                                                path,
+                                                item: match item {
+                                                    AnnotatableRef::Item(item) => {
+                                                        Annotatable::Item(item.clone())
+                                                    }
+                                                    AnnotatableRef::Stmt(stmt) => {
+                                                        Annotatable::Stmt(P(stmt.clone()))
+                                                    }
+                                                },
+                                            },
+                                            fragment_kind,
+                                            expansion_data: ExpansionData {
+                                                id: expn_id,
+                                                ..self.cx.current_expansion.clone()
+                                            },
                                         },
-                                    },
-                                    None,
-                                ));
-                                NodeId::placeholder_from_expn_id(expn_id)
-                            })
-                            .collect::<Vec<_>>();
-                        (item, derive_placeholders)
-                    };
+                                        None,
+                                    ));
+                                    NodeId::placeholder_from_expn_id(expn_id)
+                                })
+                                .collect::<Vec<_>>()
+                        })
+                        .unwrap_or_default();
 
-                    let fragment = fragment_kind.expect_from_annotatables(::std::iter::once(item));
                     self.collect_invocations(fragment, &derive_placeholders)
                 }
+                ExpandResult::Retry(invoc) => {
+                    if force {
+                        self.cx.span_bug(
+                            invoc.span(),
+                            "expansion entered force mode but is still stuck",
+                        );
+                    } else {
+                        // Cannot expand, will retry this invocation later.
+                        undetermined_invocations.push((invoc, Some(ext)));
+                        continue;
+                    }
+                }
             };
 
             progress = true;
@@ -596,29 +576,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         fragment_with_placeholders
     }
 
-    fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) {
-        let attr = self.cx.sess.find_by_name(item.attrs(), sym::derive);
-        let span = attr.map_or(item.span(), |attr| attr.span);
-        let mut err = struct_span_err!(
-            self.cx.sess,
-            span,
-            E0774,
-            "`derive` may only be applied to structs, enums and unions",
-        );
-        if let Some(ast::Attribute { style: ast::AttrStyle::Inner, .. }) = attr {
-            let trait_list = derives.iter().map(|t| pprust::path_to_string(t)).collect::<Vec<_>>();
-            let suggestion = format!("#[derive({})]", trait_list.join(", "));
-            err.span_suggestion(
-                span,
-                "try an outer attribute",
-                suggestion,
-                // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT
-                Applicability::MaybeIncorrect,
-            );
-        }
-        err.emit();
-    }
-
     fn resolve_imports(&mut self) {
         if self.monotonic {
             self.cx.resolver.resolve_imports();
@@ -633,7 +590,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         &mut self,
         mut fragment: AstFragment,
         extra_placeholders: &[NodeId],
-    ) -> (AstFragment, Vec<(Invocation, Option<InvocationRes>)>) {
+    ) -> (AstFragment, Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>) {
         // Resolve `$crate`s in the fragment for pretty-printing.
         self.cx.resolver.resolve_dollar_crates();
 
@@ -733,7 +690,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
                 _ => unreachable!(),
             },
-            InvocationKind::Attr { attr, mut item, derives, after_derive } => match ext {
+            InvocationKind::Attr { attr, mut item, derives } => match ext {
                 SyntaxExtensionKind::Attr(expander) => {
                     self.gate_proc_macro_input(&item);
                     self.gate_proc_macro_attr_item(span, &item);
@@ -764,12 +721,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                                 ExpandResult::Retry(item) => {
                                     // Reassemble the original invocation for retrying.
                                     return ExpandResult::Retry(Invocation {
-                                        kind: InvocationKind::Attr {
-                                            attr,
-                                            item,
-                                            derives,
-                                            after_derive,
-                                        },
+                                        kind: InvocationKind::Attr { attr, item, derives },
                                         ..invoc
                                     });
                                 }
@@ -813,7 +765,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
                 _ => unreachable!(),
             },
-            InvocationKind::DeriveContainer { .. } => unreachable!(),
         })
     }
 
@@ -860,7 +811,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
             fn visit_item(&mut self, item: &'ast ast::Item) {
                 match &item.kind {
-                    ast::ItemKind::Mod(module) if !module.inline => {
+                    ast::ItemKind::Mod(_, mod_kind)
+                        if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
+                    {
                         feature_err(
                             self.parse_sess,
                             sym::proc_macro_hygiene,
@@ -960,7 +913,9 @@ pub fn parse_ast_fragment<'a>(
             }
         }
         AstFragmentKind::Ty => AstFragment::Ty(this.parse_ty()?),
-        AstFragmentKind::Pat => AstFragment::Pat(this.parse_pat(None)?),
+        AstFragmentKind::Pat => {
+            AstFragment::Pat(this.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)?)
+        }
         AstFragmentKind::Arms
         | AstFragmentKind::Fields
         | AstFragmentKind::FieldPats
@@ -1011,29 +966,13 @@ pub fn ensure_complete_parse<'a>(
 struct InvocationCollector<'a, 'b> {
     cx: &'a mut ExtCtxt<'b>,
     cfg: StripUnconfigured<'a>,
-    invocations: Vec<(Invocation, Option<InvocationRes>)>,
+    invocations: Vec<(Invocation, Option<Lrc<SyntaxExtension>>)>,
     monotonic: bool,
 }
 
 impl<'a, 'b> InvocationCollector<'a, 'b> {
     fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment {
-        // Expansion data for all the collected invocations is set upon their resolution,
-        // with exception of the derive container case which is not resolved and can get
-        // its expansion data immediately.
-        let expn_data = match &kind {
-            InvocationKind::DeriveContainer { item, .. } => {
-                let mut expn_data = ExpnData::default(
-                    ExpnKind::Macro(MacroKind::Attr, sym::derive),
-                    item.span(),
-                    self.cx.sess.parse_sess.edition,
-                    None,
-                );
-                expn_data.parent = self.cx.current_expansion.id;
-                Some(expn_data)
-            }
-            _ => None,
-        };
-        let expn_id = ExpnId::fresh(expn_data);
+        let expn_id = ExpnId::fresh(None);
         let vis = kind.placeholder_visibility();
         self.invocations.push((
             Invocation {
@@ -1061,64 +1000,44 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
 
     fn collect_attr(
         &mut self,
-        (attr, derives, after_derive): (Option<ast::Attribute>, Vec<Path>, bool),
+        (attr, derives): (ast::Attribute, Vec<Path>),
         item: Annotatable,
         kind: AstFragmentKind,
     ) -> AstFragment {
-        self.collect(
-            kind,
-            match attr {
-                Some(attr) => InvocationKind::Attr { attr, item, derives, after_derive },
-                None => InvocationKind::DeriveContainer { derives, item },
-            },
-        )
-    }
-
-    fn find_attr_invoc(
-        &self,
-        attrs: &mut Vec<ast::Attribute>,
-        after_derive: &mut bool,
-    ) -> Option<ast::Attribute> {
-        attrs
-            .iter()
-            .position(|a| {
-                if a.has_name(sym::derive) {
-                    *after_derive = true;
-                }
-                !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a)
-            })
-            .map(|i| attrs.remove(i))
-    }
-
-    /// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
-    fn take_first_attr(
-        &mut self,
-        item: &mut impl HasAttrs,
-    ) -> Option<(Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)> {
-        let (mut attr, mut traits, mut after_derive) = (None, Vec::new(), false);
-
-        item.visit_attrs(|mut attrs| {
-            attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
-            traits = collect_derives(&mut self.cx, &mut attrs);
-        });
-
-        if attr.is_some() || !traits.is_empty() { Some((attr, traits, after_derive)) } else { None }
+        self.collect(kind, InvocationKind::Attr { attr, item, derives })
     }
 
-    /// Alternative to `take_first_attr()` that ignores `#[derive]` so invocations fallthrough
-    /// to the unused-attributes lint (making it an error on statements and expressions
-    /// is a breaking change)
-    fn take_first_attr_no_derive(
-        &mut self,
-        nonitem: &mut impl HasAttrs,
-    ) -> Option<(Option<ast::Attribute>, Vec<Path>, /* after_derive */ bool)> {
-        let (mut attr, mut after_derive) = (None, false);
-
-        nonitem.visit_attrs(|mut attrs| {
-            attr = self.find_attr_invoc(&mut attrs, &mut after_derive);
+    /// If `item` is an attribute invocation, remove the attribute and return it together with
+    /// derives following it. We have to collect the derives in order to resolve legacy derive
+    /// helpers (helpers written before derives that introduce them).
+    fn take_first_attr(&mut self, item: &mut impl HasAttrs) -> Option<(ast::Attribute, Vec<Path>)> {
+        let mut attr = None;
+
+        item.visit_attrs(|attrs| {
+            attr = attrs
+                .iter()
+                .position(|a| !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a))
+                .map(|attr_pos| {
+                    let attr = attrs.remove(attr_pos);
+                    let following_derives = attrs[attr_pos..]
+                        .iter()
+                        .filter(|a| a.has_name(sym::derive))
+                        .flat_map(|a| a.meta_item_list().unwrap_or_default())
+                        .filter_map(|nested_meta| match nested_meta {
+                            NestedMetaItem::MetaItem(ast::MetaItem {
+                                kind: MetaItemKind::Word,
+                                path,
+                                ..
+                            }) => Some(path),
+                            _ => None,
+                        })
+                        .collect();
+
+                    (attr, following_derives)
+                })
         });
 
-        attr.map(|attr| (Some(attr), Vec::new(), after_derive))
+        attr
     }
 
     fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
@@ -1132,17 +1051,6 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         for attr in attrs.iter() {
             rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
             validate_attr::check_meta(&self.cx.sess.parse_sess, attr);
-
-            // macros are expanded before any lint passes so this warning has to be hardcoded
-            if attr.has_name(sym::derive) {
-                self.cx
-                    .parse_sess()
-                    .span_diagnostic
-                    .struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations")
-                    .note("this may become a hard error in a future release")
-                    .emit();
-            }
-
             if attr.doc_str().is_some() {
                 self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
                     &UNUSED_DOC_COMMENTS,
@@ -1160,14 +1068,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
         self.cfg.configure_expr(expr);
         visit_clobber(expr.deref_mut(), |mut expr| {
-            self.cfg.configure_expr_kind(&mut expr.kind);
-
-            if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
+            if let Some(attr) = self.take_first_attr(&mut expr) {
                 // Collect the invoc regardless of whether or not attributes are permitted here
                 // expansion will eat the attribute so it won't error later.
-                if let Some(attr) = attr.0.as_ref() {
-                    self.cfg.maybe_emit_expr_attr_err(attr)
-                }
+                self.cfg.maybe_emit_expr_attr_err(&attr.0);
 
                 // AstFragmentKind::Expr requires the macro to emit an expression.
                 return self
@@ -1261,12 +1165,8 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
         let expr = configure!(self, expr);
         expr.filter_map(|mut expr| {
-            self.cfg.configure_expr_kind(&mut expr.kind);
-
-            if let Some(attr) = self.take_first_attr_no_derive(&mut expr) {
-                if let Some(attr) = attr.0.as_ref() {
-                    self.cfg.maybe_emit_expr_attr_err(attr)
-                }
+            if let Some(attr) = self.take_first_attr(&mut expr) {
+                self.cfg.maybe_emit_expr_attr_err(&attr.0);
 
                 return self
                     .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr)
@@ -1289,7 +1189,6 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
     }
 
     fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
-        self.cfg.configure_pat(pat);
         match pat.kind {
             PatKind::MacCall(_) => {}
             _ => return noop_visit_pat(pat, self),
@@ -1308,15 +1207,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
 
         // we'll expand attributes on expressions separately
         if !stmt.is_expr() {
-            let attr = if stmt.is_item() {
-                self.take_first_attr(&mut stmt)
-            } else {
-                // Ignore derives on non-item statements for backwards compatibility.
-                // This will result in a unused attribute warning
-                self.take_first_attr_no_derive(&mut stmt)
-            };
-
-            if let Some(attr) = attr {
+            if let Some(attr) = self.take_first_attr(&mut stmt) {
                 return self
                     .collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts)
                     .make_stmts();
@@ -1379,52 +1270,47 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
                     _ => unreachable!(),
                 })
             }
-            ast::ItemKind::Mod(ref mut old_mod @ ast::Mod { .. }) if ident != Ident::invalid() => {
+            ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::invalid() => {
                 let sess = &self.cx.sess.parse_sess;
                 let orig_ownership = self.cx.current_expansion.directory_ownership;
                 let mut module = (*self.cx.current_expansion.module).clone();
 
                 let pushed = &mut false; // Record `parse_external_mod` pushing so we can pop.
                 let dir = Directory { ownership: orig_ownership, path: module.directory };
-                let Directory { ownership, path } = if old_mod.inline {
-                    // Inline `mod foo { ... }`, but we still need to push directories.
-                    item.attrs = attrs;
-                    push_directory(&self.cx.sess, ident, &item.attrs, dir)
-                } else {
-                    // We have an outline `mod foo;` so we need to parse the file.
-                    let (new_mod, dir) = parse_external_mod(
-                        &self.cx.sess,
-                        ident,
-                        span,
-                        old_mod.unsafety,
-                        dir,
-                        &mut attrs,
-                        pushed,
-                    );
-
-                    let krate = ast::Crate {
-                        span: new_mod.inner,
-                        module: new_mod,
-                        attrs,
-                        proc_macros: vec![],
-                    };
-                    if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
-                        extern_mod_loaded(&krate, ident);
+                let Directory { ownership, path } = match mod_kind {
+                    ModKind::Loaded(_, Inline::Yes, _) => {
+                        // Inline `mod foo { ... }`, but we still need to push directories.
+                        item.attrs = attrs;
+                        push_directory(&self.cx.sess, ident, &item.attrs, dir)
                     }
+                    ModKind::Loaded(_, Inline::No, _) => {
+                        panic!("`mod` item is loaded from a file for the second time")
+                    }
+                    ModKind::Unloaded => {
+                        // We have an outline `mod foo;` so we need to parse the file.
+                        let (items, inner_span, dir) =
+                            parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed);
+
+                        let krate =
+                            ast::Crate { attrs, items, span: inner_span, proc_macros: vec![] };
+                        if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
+                            extern_mod_loaded(&krate, ident);
+                        }
 
-                    *old_mod = krate.module;
-                    item.attrs = krate.attrs;
-                    // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure.
-                    item = match self.configure(item) {
-                        Some(node) => node,
-                        None => {
-                            if *pushed {
-                                sess.included_mod_stack.borrow_mut().pop();
+                        *mod_kind = ModKind::Loaded(krate.items, Inline::No, inner_span);
+                        item.attrs = krate.attrs;
+                        // File can have inline attributes, e.g., `#![cfg(...)]` & co. => Reconfigure.
+                        item = match self.configure(item) {
+                            Some(node) => node,
+                            None => {
+                                if *pushed {
+                                    sess.included_mod_stack.borrow_mut().pop();
+                                }
+                                return Default::default();
                             }
-                            return Default::default();
-                        }
-                    };
-                    dir
+                        };
+                        dir
+                    }
                 };
 
                 // Set the module info before we flat map.
@@ -1511,15 +1397,12 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         });
     }
 
-    fn visit_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) {
-        self.cfg.configure_foreign_mod(foreign_mod);
-        noop_visit_foreign_mod(foreign_mod, self);
-    }
-
     fn flat_map_foreign_item(
         &mut self,
-        mut foreign_item: P<ast::ForeignItem>,
+        foreign_item: P<ast::ForeignItem>,
     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
+        let mut foreign_item = configure!(self, foreign_item);
+
         if let Some(attr) = self.take_first_attr(&mut foreign_item) {
             return self
                 .collect_attr(
@@ -1544,11 +1427,6 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         }
     }
 
-    fn visit_item_kind(&mut self, item: &mut ast::ItemKind) {
-        self.cfg.configure_item_kind(item);
-        noop_visit_item_kind(item, self);
-    }
-
     fn flat_map_generic_param(
         &mut self,
         param: ast::GenericParam,
@@ -1707,11 +1585,6 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
             *id = self.cx.resolver.next_node_id()
         }
     }
-
-    fn visit_fn_decl(&mut self, mut fn_decl: &mut P<ast::FnDecl>) {
-        self.cfg.configure_fn_decl(&mut fn_decl);
-        noop_visit_fn_decl(fn_decl, self);
-    }
 }
 
 pub struct ExpansionConfig<'feat> {
@@ -1719,9 +1592,8 @@ pub struct ExpansionConfig<'feat> {
     pub features: Option<&'feat Features>,
     pub recursion_limit: Limit,
     pub trace_mac: bool,
-    pub should_test: bool, // If false, strip `#[test]` nodes
-    pub keep_macs: bool,
-    pub span_debug: bool, // If true, use verbose debugging for `proc_macro::Span`
+    pub should_test: bool,          // If false, strip `#[test]` nodes
+    pub span_debug: bool,           // If true, use verbose debugging for `proc_macro::Span`
     pub proc_macro_backtrace: bool, // If true, show backtraces for proc-macro panics
 }
 
@@ -1733,7 +1605,6 @@ impl<'feat> ExpansionConfig<'feat> {
             recursion_limit: Limit::new(1024),
             trace_mac: false,
             should_test: false,
-            keep_macs: false,
             span_debug: false,
             proc_macro_backtrace: false,
         }
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 3b722c04cb1..c5d8ff25ea9 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,4 +1,3 @@
-#![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(or_patterns)]
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index 171cb3fa8e6..076d3b02be9 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -1,4 +1,5 @@
-use rustc_ast::{token, Attribute, Mod, Unsafe};
+use rustc_ast::ptr::P;
+use rustc_ast::{token, Attribute, Item};
 use rustc_errors::{struct_span_err, PResult};
 use rustc_parse::new_parser_from_file;
 use rustc_session::parse::ParseSess;
@@ -42,11 +43,10 @@ crate fn parse_external_mod(
     sess: &Session,
     id: Ident,
     span: Span, // The span to blame on errors.
-    unsafety: Unsafe,
     Directory { mut ownership, path }: Directory,
     attrs: &mut Vec<Attribute>,
     pop_mod_stack: &mut bool,
-) -> (Mod, Directory) {
+) -> (Vec<P<Item>>, Span, Directory) {
     // We bail on the first error, but that error does not cause a fatal error... (1)
     let result: PResult<'_, _> = try {
         // Extract the file path and the new ownership.
@@ -62,26 +62,22 @@ crate fn parse_external_mod(
 
         // Actually parse the external file as a module.
         let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span));
-        let mut module = parser.parse_mod(&token::Eof, unsafety)?;
-        module.0.inline = false;
-        module
+        let (mut inner_attrs, items, inner_span) = parser.parse_mod(&token::Eof)?;
+        attrs.append(&mut inner_attrs);
+        (items, inner_span)
     };
     // (1) ...instead, we return a dummy module.
-    let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_else(|_| {
-        let module = Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false };
-        (module, Vec::new())
-    });
-    attrs.append(&mut new_attrs);
+    let (items, inner_span) = result.map_err(|mut err| err.emit()).unwrap_or_default();
 
-    // Extract the directory path for submodules of `module`.
-    let path = sess.source_map().span_to_unmapped_path(module.inner);
+    // Extract the directory path for submodules of  the module.
+    let path = sess.source_map().span_to_unmapped_path(inner_span);
     let mut path = match path {
         FileName::Real(name) => name.into_local_path(),
         other => PathBuf::from(other.to_string()),
     };
     path.pop();
 
-    (module, Directory { ownership, path })
+    (items, inner_span, Directory { ownership, path })
 }
 
 fn error_on_circular_module<'a>(
diff --git a/compiler/rustc_expand/src/mut_visit/tests.rs b/compiler/rustc_expand/src/mut_visit/tests.rs
index be0300bad98..7e7155ad278 100644
--- a/compiler/rustc_expand/src/mut_visit/tests.rs
+++ b/compiler/rustc_expand/src/mut_visit/tests.rs
@@ -7,8 +7,8 @@ use rustc_span::symbol::Ident;
 use rustc_span::with_default_session_globals;
 
 // This version doesn't care about getting comments or doc-strings in.
-fn fake_print_crate(s: &mut pprust::State<'_>, krate: &ast::Crate) {
-    s.print_mod(&krate.module, &krate.attrs)
+fn print_crate_items(krate: &ast::Crate) -> String {
+    krate.items.iter().map(|i| pprust::item_to_string(i)).collect::<Vec<_>>().join(" ")
 }
 
 // Change every identifier to "zz".
@@ -46,7 +46,7 @@ fn ident_transformation() {
         assert_pred!(
             matches_codepattern,
             "matches_codepattern",
-            pprust::to_string(|s| fake_print_crate(s, &krate)),
+            print_crate_items(&krate),
             "#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string()
         );
     })
@@ -66,7 +66,7 @@ fn ident_transformation_in_defs() {
         assert_pred!(
             matches_codepattern,
             "matches_codepattern",
-            pprust::to_string(|s| fake_print_crate(s, &krate)),
+            print_crate_items(&krate),
             "macro_rules! zz{(zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+))}".to_string()
         );
     })
diff --git a/compiler/rustc_expand/src/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs
index f4fcaf5c0a4..56f25ffdb01 100644
--- a/compiler/rustc_expand/src/parse/tests.rs
+++ b/compiler/rustc_expand/src/parse/tests.rs
@@ -309,8 +309,8 @@ fn out_of_line_mod() {
         .unwrap()
         .unwrap();
 
-        if let ast::ItemKind::Mod(ref m) = item.kind {
-            assert!(m.items.len() == 2);
+        if let ast::ItemKind::Mod(_, ref mod_kind) = item.kind {
+            assert!(matches!(mod_kind, ast::ModKind::Loaded(items, ..) if items.len() == 2));
         } else {
             panic!();
         }
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index d040539cd7e..98682ba4295 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -371,12 +371,4 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
             }
         }
     }
-
-    fn visit_mod(&mut self, module: &mut ast::Mod) {
-        noop_visit_mod(module, self);
-        // remove macro definitions
-        module.items.retain(
-            |item| !matches!(item.kind, ast::ItemKind::MacCall(_) if !self.cx.ecfg.keep_macs),
-        );
-    }
 }
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 6779734cfc1..8cbaa7c945a 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -1,16 +1,14 @@
 use crate::base::{self, *};
 use crate::proc_macro_server;
 
+use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
-use rustc_ast::{self as ast, *};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{struct_span_err, Applicability, ErrorReported};
-use rustc_lexer::is_ident;
+use rustc_errors::ErrorReported;
 use rustc_parse::nt_to_tokenstream;
 use rustc_parse::parser::ForceCollect;
-use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
 
 const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread;
@@ -142,91 +140,3 @@ impl MultiItemModifier for ProcMacroDerive {
         ExpandResult::Ready(items)
     }
 }
-
-crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
-    let mut result = Vec::new();
-    attrs.retain(|attr| {
-        if !attr.has_name(sym::derive) {
-            return true;
-        }
-
-        // 1) First let's ensure that it's a meta item.
-        let nmis = match attr.meta_item_list() {
-            None => {
-                cx.struct_span_err(attr.span, "malformed `derive` attribute input")
-                    .span_suggestion(
-                        attr.span,
-                        "missing traits to be derived",
-                        "#[derive(Trait1, Trait2, ...)]".to_owned(),
-                        Applicability::HasPlaceholders,
-                    )
-                    .emit();
-                return false;
-            }
-            Some(x) => x,
-        };
-
-        let mut error_reported_filter_map = false;
-        let mut error_reported_map = false;
-        let traits = nmis
-            .into_iter()
-            // 2) Moreover, let's ensure we have a path and not `#[derive("foo")]`.
-            .filter_map(|nmi| match nmi {
-                NestedMetaItem::Literal(lit) => {
-                    error_reported_filter_map = true;
-                    let mut err = struct_span_err!(
-                        cx.sess,
-                        lit.span,
-                        E0777,
-                        "expected path to a trait, found literal",
-                    );
-                    let token = lit.token.to_string();
-                    if token.starts_with('"')
-                        && token.len() > 2
-                        && is_ident(&token[1..token.len() - 1])
-                    {
-                        err.help(&format!("try using `#[derive({})]`", &token[1..token.len() - 1]));
-                    } else {
-                        err.help("for example, write `#[derive(Debug)]` for `Debug`");
-                    }
-                    err.emit();
-                    None
-                }
-                NestedMetaItem::MetaItem(mi) => Some(mi),
-            })
-            // 3) Finally, we only accept `#[derive($path_0, $path_1, ..)]`
-            // but not e.g. `#[derive($path_0 = "value", $path_1(abc))]`.
-            // In this case we can still at least determine that the user
-            // wanted this trait to be derived, so let's keep it.
-            .map(|mi| {
-                let mut traits_dont_accept = |title, action| {
-                    error_reported_map = true;
-                    let sp = mi.span.with_lo(mi.path.span.hi());
-                    cx.struct_span_err(sp, title)
-                        .span_suggestion(
-                            sp,
-                            action,
-                            String::new(),
-                            Applicability::MachineApplicable,
-                        )
-                        .emit();
-                };
-                match &mi.kind {
-                    MetaItemKind::List(..) => traits_dont_accept(
-                        "traits in `#[derive(...)]` don't accept arguments",
-                        "remove the arguments",
-                    ),
-                    MetaItemKind::NameValue(..) => traits_dont_accept(
-                        "traits in `#[derive(...)]` don't accept values",
-                        "remove the value",
-                    ),
-                    MetaItemKind::Word => {}
-                }
-                mi.path
-            });
-
-        result.extend(traits);
-        !error_reported_filter_map && !error_reported_map
-    });
-    result
-}
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 818f6c70de0..2d0009c225c 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -631,6 +631,13 @@ declare_features! (
 
     /// Allows `extern "C-cmse-nonsecure-call" fn()`.
     (active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None),
+
+    /// Lessens the requirements for structs to implement `Unsize`.
+    (active, relaxed_struct_unsize, "1.51.0", Some(1), None),
+
+    /// Allows macro attributes to observe output of `#[derive]`.
+    (active, macro_attributes_in_derive_output, "1.51.0", Some(81119), 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 3ed5320da73..ac50703b544 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -188,7 +188,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")),
 
     // Macros:
-    ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")),
     ungated!(automatically_derived, Normal, template!(Word)),
     // FIXME(#14407)
     ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")),
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index c14165454ed..d41b81f8f21 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -17,4 +17,4 @@ rustc_span = { path = "../rustc_span" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_ast = { path = "../rustc_ast" }
 tracing = "0.1"
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 1c16dc02667..4df8c44e62b 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 use crate::def::{DefKind, Namespace, Res};
 use crate::def_id::DefId;
 crate use crate::hir_id::HirId;
@@ -358,7 +359,7 @@ impl GenericArgs<'_> {
             .iter()
             .filter(|arg| !arg.is_synthetic())
             .map(|arg| arg.span())
-            .fold_first(|span1, span2| span1.to(span2))
+            .reduce(|span1, span2| span1.to(span2))
     }
 
     /// Returns span encompassing arguments and their surrounding `<>` or `()`
@@ -615,11 +616,11 @@ pub struct WhereEqPredicate<'hir> {
     pub rhs_ty: &'hir Ty<'hir>,
 }
 
-#[derive(Encodable, Debug, HashStable_Generic)]
+#[derive(Default, Encodable, Debug, HashStable_Generic)]
 pub struct ModuleItems {
     // Use BTreeSets here so items are in the same order as in the
     // list of all items in Crate
-    pub items: BTreeSet<HirId>,
+    pub items: BTreeSet<ItemId>,
     pub trait_items: BTreeSet<TraitItemId>,
     pub impl_items: BTreeSet<ImplItemId>,
     pub foreign_items: BTreeSet<ForeignItemId>,
@@ -652,13 +653,13 @@ pub struct Crate<'hir> {
     // does, because it can affect the order in which errors are
     // detected, which in turn can make UI tests yield
     // slightly different results.
-    pub items: BTreeMap<HirId, Item<'hir>>,
+    pub items: BTreeMap<ItemId, Item<'hir>>,
 
     pub trait_items: BTreeMap<TraitItemId, TraitItem<'hir>>,
     pub impl_items: BTreeMap<ImplItemId, ImplItem<'hir>>,
     pub foreign_items: BTreeMap<ForeignItemId, ForeignItem<'hir>>,
     pub bodies: BTreeMap<BodyId, Body<'hir>>,
-    pub trait_impls: BTreeMap<DefId, Vec<HirId>>,
+    pub trait_impls: BTreeMap<DefId, Vec<LocalDefId>>,
 
     /// A list of the body ids written out in the order in which they
     /// appear in the crate. If you're going to process all the bodies
@@ -668,7 +669,7 @@ pub struct Crate<'hir> {
 
     /// A list of modules written out in the order in which they
     /// appear in the crate. This includes the main crate module.
-    pub modules: BTreeMap<HirId, ModuleItems>,
+    pub modules: BTreeMap<LocalDefId, ModuleItems>,
     /// A list of proc macro HirIds, written out in the order in which
     /// they are declared in the static array generated by proc_macro_harness.
     pub proc_macros: Vec<HirId>,
@@ -677,7 +678,7 @@ pub struct Crate<'hir> {
 }
 
 impl Crate<'hir> {
-    pub fn item(&self, id: HirId) -> &Item<'hir> {
+    pub fn item(&self, id: ItemId) -> &Item<'hir> {
         &self.items[&id]
     }
 
@@ -761,16 +762,22 @@ impl Crate<'_> {
 /// A macro definition, in this crate or imported from another.
 ///
 /// Not parsed directly, but created on macro import or `macro_rules!` expansion.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug)]
 pub struct MacroDef<'hir> {
     pub ident: Ident,
     pub vis: Visibility<'hir>,
     pub attrs: &'hir [Attribute],
-    pub hir_id: HirId,
+    pub def_id: LocalDefId,
     pub span: Span,
     pub ast: ast::MacroDef,
 }
 
+impl MacroDef<'_> {
+    pub fn hir_id(&self) -> HirId {
+        HirId::make_owner(self.def_id)
+    }
+}
+
 /// A block of statements `{ .. }`, which may have a label (in this case the
 /// `targeted_by_break` field will be `true`) and may be `unsafe` by means of
 /// the `rules` being anything but `DefaultBlock`.
@@ -1112,25 +1119,25 @@ pub type BinOp = Spanned<BinOpKind>;
 #[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
 pub enum UnOp {
     /// The `*` operator (deferencing).
-    UnDeref,
+    Deref,
     /// The `!` operator (logical negation).
-    UnNot,
+    Not,
     /// The `-` operator (negation).
-    UnNeg,
+    Neg,
 }
 
 impl UnOp {
     pub fn as_str(self) -> &'static str {
         match self {
-            Self::UnDeref => "*",
-            Self::UnNot => "!",
-            Self::UnNeg => "-",
+            Self::Deref => "*",
+            Self::Not => "!",
+            Self::Neg => "-",
         }
     }
 
     /// Returns `true` if the unary operator takes its argument by value.
     pub fn is_by_value(self) -> bool {
-        matches!(self, Self::UnNeg | Self::UnNot)
+        matches!(self, Self::Neg | Self::Not)
     }
 }
 
@@ -1274,7 +1281,7 @@ impl Body<'hir> {
 }
 
 /// The type of source expression that caused this generator to be created.
-#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
 pub enum GeneratorKind {
     /// An explicit `async` block or the body of an async function.
     Async(AsyncGeneratorKind),
@@ -1292,12 +1299,21 @@ impl fmt::Display for GeneratorKind {
     }
 }
 
+impl GeneratorKind {
+    pub fn descr(&self) -> &'static str {
+        match self {
+            GeneratorKind::Async(ask) => ask.descr(),
+            GeneratorKind::Gen => "generator",
+        }
+    }
+}
+
 /// In the case of a generator created as part of an async construct,
 /// which kind of async construct caused it to be created?
 ///
 /// This helps error messages but is also used to drive coercions in
 /// type-checking (see #60424).
-#[derive(Clone, PartialEq, Eq, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic, Encodable, Decodable, Debug, Copy)]
 pub enum AsyncGeneratorKind {
     /// An explicit `async` block written by the user.
     Block,
@@ -1319,6 +1335,16 @@ impl fmt::Display for AsyncGeneratorKind {
     }
 }
 
+impl AsyncGeneratorKind {
+    pub fn descr(&self) -> &'static str {
+        match self {
+            AsyncGeneratorKind::Block => "`async` block",
+            AsyncGeneratorKind::Closure => "`async` closure body",
+            AsyncGeneratorKind::Fn => "`async fn` body",
+        }
+    }
+}
+
 #[derive(Copy, Clone, Debug)]
 pub enum BodyOwnerKind {
     /// Functions and methods.
@@ -1413,10 +1439,6 @@ pub struct Expr<'hir> {
     pub span: Span,
 }
 
-// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(target_arch = "x86_64")]
-rustc_data_structures::static_assert_size!(Expr<'static>, 72);
-
 impl Expr<'_> {
     pub fn precedence(&self) -> ExprPrecedence {
         match self.kind {
@@ -1477,7 +1499,7 @@ impl Expr<'_> {
             // https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries
             ExprKind::Type(ref e, _) => e.is_place_expr(allow_projections_from),
 
-            ExprKind::Unary(UnOp::UnDeref, _) => true,
+            ExprKind::Unary(UnOp::Deref, _) => true,
 
             ExprKind::Field(ref base, _) | ExprKind::Index(ref base, _) => {
                 allow_projections_from(base) || base.is_place_expr(allow_projections_from)
@@ -1911,7 +1933,14 @@ pub struct FnSig<'hir> {
 // so it can fetched later.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Debug)]
 pub struct TraitItemId {
-    pub hir_id: HirId,
+    pub def_id: LocalDefId,
+}
+
+impl TraitItemId {
+    pub fn hir_id(&self) -> HirId {
+        // Items are always HIR owners.
+        HirId::make_owner(self.def_id)
+    }
 }
 
 /// Represents an item declaration within a trait declaration,
@@ -1921,13 +1950,24 @@ pub struct TraitItemId {
 #[derive(Debug)]
 pub struct TraitItem<'hir> {
     pub ident: Ident,
-    pub hir_id: HirId,
+    pub def_id: LocalDefId,
     pub attrs: &'hir [Attribute],
     pub generics: Generics<'hir>,
     pub kind: TraitItemKind<'hir>,
     pub span: Span,
 }
 
+impl TraitItem<'_> {
+    pub fn hir_id(&self) -> HirId {
+        // Items are always HIR owners.
+        HirId::make_owner(self.def_id)
+    }
+
+    pub fn trait_item_id(&self) -> TraitItemId {
+        TraitItemId { def_id: self.def_id }
+    }
+}
+
 /// Represents a trait method's body (or just argument names).
 #[derive(Encodable, Debug, HashStable_Generic)]
 pub enum TraitFn<'hir> {
@@ -1955,14 +1995,21 @@ pub enum TraitItemKind<'hir> {
 // so it can fetched later.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Debug)]
 pub struct ImplItemId {
-    pub hir_id: HirId,
+    pub def_id: LocalDefId,
+}
+
+impl ImplItemId {
+    pub fn hir_id(&self) -> HirId {
+        // Items are always HIR owners.
+        HirId::make_owner(self.def_id)
+    }
 }
 
 /// Represents anything within an `impl` block.
 #[derive(Debug)]
 pub struct ImplItem<'hir> {
     pub ident: Ident,
-    pub hir_id: HirId,
+    pub def_id: LocalDefId,
     pub vis: Visibility<'hir>,
     pub defaultness: Defaultness,
     pub attrs: &'hir [Attribute],
@@ -1971,6 +2018,17 @@ pub struct ImplItem<'hir> {
     pub span: Span,
 }
 
+impl ImplItem<'_> {
+    pub fn hir_id(&self) -> HirId {
+        // Items are always HIR owners.
+        HirId::make_owner(self.def_id)
+    }
+
+    pub fn impl_item_id(&self) -> ImplItemId {
+        ImplItemId { def_id: self.def_id }
+    }
+}
+
 /// Represents various kinds of content within an `impl`.
 #[derive(Debug, HashStable_Generic)]
 pub enum ImplItemKind<'hir> {
@@ -2015,6 +2073,7 @@ pub struct TypeBinding<'hir> {
     pub hir_id: HirId,
     #[stable_hasher(project(name))]
     pub ident: Ident,
+    pub gen_args: &'hir GenericArgs<'hir>,
     pub kind: TypeBindingKind<'hir>,
     pub span: Span,
 }
@@ -2057,6 +2116,28 @@ pub enum PrimTy {
 }
 
 impl PrimTy {
+    /// All of the primitive types
+    pub const ALL: [Self; 17] = [
+        // any changes here should also be reflected in `PrimTy::from_name`
+        Self::Int(IntTy::I8),
+        Self::Int(IntTy::I16),
+        Self::Int(IntTy::I32),
+        Self::Int(IntTy::I64),
+        Self::Int(IntTy::I128),
+        Self::Int(IntTy::Isize),
+        Self::Uint(UintTy::U8),
+        Self::Uint(UintTy::U16),
+        Self::Uint(UintTy::U32),
+        Self::Uint(UintTy::U64),
+        Self::Uint(UintTy::U128),
+        Self::Uint(UintTy::Usize),
+        Self::Float(FloatTy::F32),
+        Self::Float(FloatTy::F64),
+        Self::Bool,
+        Self::Char,
+        Self::Str,
+    ];
+
     pub fn name_str(self) -> &'static str {
         match self {
             PrimTy::Int(i) => i.name_str(),
@@ -2078,6 +2159,33 @@ impl PrimTy {
             PrimTy::Char => sym::char,
         }
     }
+
+    /// Returns the matching `PrimTy` for a `Symbol` such as "str" or "i32".
+    /// Returns `None` if no matching type is found.
+    pub fn from_name(name: Symbol) -> Option<Self> {
+        let ty = match name {
+            // any changes here should also be reflected in `PrimTy::ALL`
+            sym::i8 => Self::Int(IntTy::I8),
+            sym::i16 => Self::Int(IntTy::I16),
+            sym::i32 => Self::Int(IntTy::I32),
+            sym::i64 => Self::Int(IntTy::I64),
+            sym::i128 => Self::Int(IntTy::I128),
+            sym::isize => Self::Int(IntTy::Isize),
+            sym::u8 => Self::Uint(UintTy::U8),
+            sym::u16 => Self::Uint(UintTy::U16),
+            sym::u32 => Self::Uint(UintTy::U32),
+            sym::u64 => Self::Uint(UintTy::U64),
+            sym::u128 => Self::Uint(UintTy::U128),
+            sym::usize => Self::Uint(UintTy::Usize),
+            sym::f32 => Self::Float(FloatTy::F32),
+            sym::f64 => Self::Float(FloatTy::F64),
+            sym::bool => Self::Bool,
+            sym::char => Self::Char,
+            sym::str => Self::Str,
+            _ => return None,
+        };
+        Some(ty)
+    }
 }
 
 #[derive(Debug, HashStable_Generic)]
@@ -2495,9 +2603,16 @@ impl VariantData<'hir> {
 // The bodies for items are stored "out of line", in a separate
 // hashmap in the `Crate`. Here we just record the hir-id of the item
 // so it can fetched later.
-#[derive(Copy, Clone, Encodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Debug, Hash)]
 pub struct ItemId {
-    pub id: HirId,
+    pub def_id: LocalDefId,
+}
+
+impl ItemId {
+    pub fn hir_id(&self) -> HirId {
+        // Items are always HIR owners.
+        HirId::make_owner(self.def_id)
+    }
 }
 
 /// An item
@@ -2506,13 +2621,24 @@ pub struct ItemId {
 #[derive(Debug)]
 pub struct Item<'hir> {
     pub ident: Ident,
-    pub hir_id: HirId,
+    pub def_id: LocalDefId,
     pub attrs: &'hir [Attribute],
     pub kind: ItemKind<'hir>,
     pub vis: Visibility<'hir>,
     pub span: Span,
 }
 
+impl Item<'_> {
+    pub fn hir_id(&self) -> HirId {
+        // Items are always HIR owners.
+        HirId::make_owner(self.def_id)
+    }
+
+    pub fn item_id(&self) -> ItemId {
+        ItemId { def_id: self.def_id }
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 #[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum Unsafety {
@@ -2683,7 +2809,14 @@ pub enum AssocItemKind {
 // so it can fetched later.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Debug)]
 pub struct ForeignItemId {
-    pub hir_id: HirId,
+    pub def_id: LocalDefId,
+}
+
+impl ForeignItemId {
+    pub fn hir_id(&self) -> HirId {
+        // Items are always HIR owners.
+        HirId::make_owner(self.def_id)
+    }
 }
 
 /// A reference from a foreign block to one of its items. This
@@ -2701,17 +2834,27 @@ pub struct ForeignItemRef<'hir> {
     pub vis: Visibility<'hir>,
 }
 
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug)]
 pub struct ForeignItem<'hir> {
-    #[stable_hasher(project(name))]
     pub ident: Ident,
     pub attrs: &'hir [Attribute],
     pub kind: ForeignItemKind<'hir>,
-    pub hir_id: HirId,
+    pub def_id: LocalDefId,
     pub span: Span,
     pub vis: Visibility<'hir>,
 }
 
+impl ForeignItem<'_> {
+    pub fn hir_id(&self) -> HirId {
+        // Items are always HIR owners.
+        HirId::make_owner(self.def_id)
+    }
+
+    pub fn foreign_item_id(&self) -> ForeignItemId {
+        ForeignItemId { def_id: self.def_id }
+    }
+}
+
 /// An item within an `extern` block.
 #[derive(Debug, HashStable_Generic)]
 pub enum ForeignItemKind<'hir> {
@@ -2821,11 +2964,12 @@ impl<'hir> Node<'hir> {
 
     pub fn hir_id(&self) -> Option<HirId> {
         match self {
-            Node::Item(Item { hir_id, .. })
-            | Node::ForeignItem(ForeignItem { hir_id, .. })
-            | Node::TraitItem(TraitItem { hir_id, .. })
-            | Node::ImplItem(ImplItem { hir_id, .. })
-            | Node::Field(StructField { hir_id, .. })
+            Node::Item(Item { def_id, .. })
+            | Node::TraitItem(TraitItem { def_id, .. })
+            | Node::ImplItem(ImplItem { def_id, .. })
+            | Node::ForeignItem(ForeignItem { def_id, .. })
+            | Node::MacroDef(MacroDef { def_id, .. }) => Some(HirId::make_owner(*def_id)),
+            Node::Field(StructField { hir_id, .. })
             | Node::AnonConst(AnonConst { hir_id, .. })
             | Node::Expr(Expr { hir_id, .. })
             | Node::Stmt(Stmt { hir_id, .. })
@@ -2835,7 +2979,6 @@ impl<'hir> Node<'hir> {
             | Node::Arm(Arm { hir_id, .. })
             | Node::Block(Block { hir_id, .. })
             | Node::Local(Local { hir_id, .. })
-            | Node::MacroDef(MacroDef { hir_id, .. })
             | Node::Lifetime(Lifetime { hir_id, .. })
             | Node::Param(Param { hir_id, .. })
             | Node::GenericParam(GenericParam { hir_id, .. }) => Some(*hir_id),
@@ -2847,3 +2990,18 @@ impl<'hir> Node<'hir> {
         }
     }
 }
+
+// Some nodes are used a lot. Make sure they don't unintentionally get bigger.
+#[cfg(target_arch = "x86_64")]
+mod size_asserts {
+    rustc_data_structures::static_assert_size!(super::Block<'static>, 48);
+    rustc_data_structures::static_assert_size!(super::Expr<'static>, 72);
+    rustc_data_structures::static_assert_size!(super::Pat<'static>, 88);
+    rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
+    rustc_data_structures::static_assert_size!(super::Ty<'static>, 72);
+
+    rustc_data_structures::static_assert_size!(super::Item<'static>, 200);
+    rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 144);
+    rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 168);
+    rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 152);
+}
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index cc8ac4cf5be..dd5cddd8525 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -18,6 +18,21 @@ pub struct HirId {
     pub local_id: ItemLocalId,
 }
 
+impl HirId {
+    pub fn expect_owner(self) -> LocalDefId {
+        assert_eq!(self.local_id.index(), 0);
+        self.owner
+    }
+
+    pub fn as_owner(self) -> Option<LocalDefId> {
+        if self.local_id.index() == 0 { Some(self.owner) } else { None }
+    }
+
+    pub fn make_owner(owner: LocalDefId) -> Self {
+        Self { owner, local_id: ItemLocalId::from_u32(0) }
+    }
+}
+
 impl fmt::Display for HirId {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{:?}", self)
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 6c1bee2335a..6a2719c2d66 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -133,7 +133,7 @@ pub trait Map<'hir> {
     /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
     fn find(&self, hir_id: HirId) -> Option<Node<'hir>>;
     fn body(&self, id: BodyId) -> &'hir Body<'hir>;
-    fn item(&self, id: HirId) -> &'hir Item<'hir>;
+    fn item(&self, id: ItemId) -> &'hir Item<'hir>;
     fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir>;
     fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir>;
     fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir>;
@@ -150,7 +150,7 @@ impl<'hir> Map<'hir> for ErasedMap<'hir> {
     fn body(&self, id: BodyId) -> &'hir Body<'hir> {
         self.0.body(id)
     }
-    fn item(&self, id: HirId) -> &'hir Item<'hir> {
+    fn item(&self, id: ItemId) -> &'hir Item<'hir> {
         self.0.item(id)
     }
     fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
@@ -269,7 +269,7 @@ pub trait Visitor<'v>: Sized {
     /// reason to override this method is if you want a nested pattern
     /// but cannot supply a `Map`; see `nested_visit_map` for advice.
     fn visit_nested_item(&mut self, id: ItemId) {
-        let opt_item = self.nested_visit_map().inter().map(|map| map.item(id.id));
+        let opt_item = self.nested_visit_map().inter().map(|map| map.item(id));
         walk_list!(self, visit_item, opt_item);
     }
 
@@ -489,7 +489,7 @@ pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate<'v>) {
 }
 
 pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef<'v>) {
-    visitor.visit_id(macro_def.hir_id);
+    visitor.visit_id(macro_def.hir_id());
     visitor.visit_ident(macro_def.ident);
     walk_list!(visitor, visit_attribute, macro_def.attrs);
 }
@@ -565,16 +565,16 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
     visitor.visit_ident(item.ident);
     match item.kind {
         ItemKind::ExternCrate(orig_name) => {
-            visitor.visit_id(item.hir_id);
+            visitor.visit_id(item.hir_id());
             if let Some(orig_name) = orig_name {
                 visitor.visit_name(item.span, orig_name);
             }
         }
         ItemKind::Use(ref path, _) => {
-            visitor.visit_use(path, item.hir_id);
+            visitor.visit_use(path, item.hir_id());
         }
         ItemKind::Static(ref typ, _, body) | ItemKind::Const(ref typ, body) => {
-            visitor.visit_id(item.hir_id);
+            visitor.visit_id(item.hir_id());
             visitor.visit_ty(typ);
             visitor.visit_nested_body(body);
         }
@@ -583,33 +583,33 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
             &sig.decl,
             body_id,
             item.span,
-            item.hir_id,
+            item.hir_id(),
         ),
         ItemKind::Mod(ref module) => {
             // `visit_mod()` takes care of visiting the `Item`'s `HirId`.
-            visitor.visit_mod(module, item.span, item.hir_id)
+            visitor.visit_mod(module, item.span, item.hir_id())
         }
         ItemKind::ForeignMod { abi: _, items } => {
-            visitor.visit_id(item.hir_id);
+            visitor.visit_id(item.hir_id());
             walk_list!(visitor, visit_foreign_item_ref, items);
         }
         ItemKind::GlobalAsm(_) => {
-            visitor.visit_id(item.hir_id);
+            visitor.visit_id(item.hir_id());
         }
         ItemKind::TyAlias(ref ty, ref generics) => {
-            visitor.visit_id(item.hir_id);
+            visitor.visit_id(item.hir_id());
             visitor.visit_ty(ty);
             visitor.visit_generics(generics)
         }
         ItemKind::OpaqueTy(OpaqueTy { ref generics, bounds, .. }) => {
-            visitor.visit_id(item.hir_id);
+            visitor.visit_id(item.hir_id());
             walk_generics(visitor, generics);
             walk_list!(visitor, visit_param_bound, bounds);
         }
         ItemKind::Enum(ref enum_definition, ref generics) => {
             visitor.visit_generics(generics);
             // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
-            visitor.visit_enum_def(enum_definition, generics, item.hir_id, item.span)
+            visitor.visit_enum_def(enum_definition, generics, item.hir_id(), item.span)
         }
         ItemKind::Impl(Impl {
             unsafety: _,
@@ -622,7 +622,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
             ref self_ty,
             items,
         }) => {
-            visitor.visit_id(item.hir_id);
+            visitor.visit_id(item.hir_id());
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_trait_ref, of_trait);
             visitor.visit_ty(self_ty);
@@ -631,23 +631,23 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
         ItemKind::Struct(ref struct_definition, ref generics)
         | ItemKind::Union(ref struct_definition, ref generics) => {
             visitor.visit_generics(generics);
-            visitor.visit_id(item.hir_id);
+            visitor.visit_id(item.hir_id());
             visitor.visit_variant_data(
                 struct_definition,
                 item.ident.name,
                 generics,
-                item.hir_id,
+                item.hir_id(),
                 item.span,
             );
         }
         ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => {
-            visitor.visit_id(item.hir_id);
+            visitor.visit_id(item.hir_id());
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
         }
         ItemKind::TraitAlias(ref generics, bounds) => {
-            visitor.visit_id(item.hir_id);
+            visitor.visit_id(item.hir_id());
             visitor.visit_generics(generics);
             walk_list!(visitor, visit_param_bound, bounds);
         }
@@ -781,6 +781,7 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
 ) {
     visitor.visit_id(type_binding.hir_id);
     visitor.visit_ident(type_binding.ident);
+    visitor.visit_generic_args(type_binding.span, type_binding.gen_args);
     match type_binding.kind {
         TypeBindingKind::Equality { ref ty } => {
             visitor.visit_ty(ty);
@@ -835,7 +836,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
 }
 
 pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem<'v>) {
-    visitor.visit_id(foreign_item.hir_id);
+    visitor.visit_id(foreign_item.hir_id());
     visitor.visit_vis(&foreign_item.vis);
     visitor.visit_ident(foreign_item.ident);
 
@@ -963,12 +964,12 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
     visitor.visit_generics(&trait_item.generics);
     match trait_item.kind {
         TraitItemKind::Const(ref ty, default) => {
-            visitor.visit_id(trait_item.hir_id);
+            visitor.visit_id(trait_item.hir_id());
             visitor.visit_ty(ty);
             walk_list!(visitor, visit_nested_body, default);
         }
         TraitItemKind::Fn(ref sig, TraitFn::Required(param_names)) => {
-            visitor.visit_id(trait_item.hir_id);
+            visitor.visit_id(trait_item.hir_id());
             visitor.visit_fn_decl(&sig.decl);
             for &param_name in param_names {
                 visitor.visit_ident(param_name);
@@ -980,11 +981,11 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
                 &sig.decl,
                 body_id,
                 trait_item.span,
-                trait_item.hir_id,
+                trait_item.hir_id(),
             );
         }
         TraitItemKind::Type(bounds, ref default) => {
-            visitor.visit_id(trait_item.hir_id);
+            visitor.visit_id(trait_item.hir_id());
             walk_list!(visitor, visit_param_bound, bounds);
             walk_list!(visitor, visit_ty, default);
         }
@@ -1003,7 +1004,7 @@ pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref:
 pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
     // N.B., deliberately force a compilation error if/when new fields are added.
     let ImplItem {
-        hir_id: _,
+        def_id: _,
         ident,
         ref vis,
         ref defaultness,
@@ -1020,7 +1021,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
     visitor.visit_generics(generics);
     match *kind {
         ImplItemKind::Const(ref ty, body) => {
-            visitor.visit_id(impl_item.hir_id);
+            visitor.visit_id(impl_item.hir_id());
             visitor.visit_ty(ty);
             visitor.visit_nested_body(body);
         }
@@ -1030,11 +1031,11 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
                 &sig.decl,
                 body_id,
                 impl_item.span,
-                impl_item.hir_id,
+                impl_item.hir_id(),
             );
         }
         ImplItemKind::TyAlias(ref ty) => {
-            visitor.visit_id(impl_item.hir_id);
+            visitor.visit_id(impl_item.hir_id());
             visitor.visit_ty(ty);
         }
     }
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 26ce30cb511..03524569ce7 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -201,6 +201,10 @@ language_item_table! {
     // The associated item of `trait DiscriminantKind`.
     Discriminant,            sym::discriminant_type,   discriminant_type,          Target::AssocTy;
 
+    PointeeTrait,            sym::pointee_trait,       pointee_trait,              Target::Trait;
+    Metadata,                sym::metadata_type,       metadata_type,              Target::AssocTy;
+    DynMetadata,             sym::dyn_metadata,        dyn_metadata,               Target::Struct;
+
     Freeze,                  sym::freeze,              freeze_trait,               Target::Trait;
 
     Drop,                    sym::drop,                drop_trait,                 Target::Trait;
@@ -238,6 +242,7 @@ language_item_table! {
 
     Deref,                   sym::deref,               deref_trait,                Target::Trait;
     DerefMut,                sym::deref_mut,           deref_mut_trait,            Target::Trait;
+    DerefTarget,             sym::deref_target,        deref_target,               Target::AssocTy;
     Receiver,                sym::receiver,            receiver_trait,             Target::Trait;
 
     Fn,                      kw::Fn,                   fn_trait,                   Target::Trait;
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index efc516a662f..c69a9b063ae 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -6,7 +6,6 @@
 #![feature(const_fn)] // For the unsizing cast on `&[]`
 #![feature(const_panic)]
 #![feature(in_band_lifetimes)]
-#![feature(iterator_fold_self)]
 #![feature(once_cell)]
 #![feature(or_patterns)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 439fb88039b..5fb4b8a58c2 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -1,8 +1,8 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 
 use crate::hir::{
-    BodyId, Expr, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, Mod, TraitItem, TraitItemId,
-    Ty, VisibilityKind,
+    BodyId, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item, ItemId, MacroDef, Mod,
+    TraitItem, TraitItemId, Ty, VisibilityKind,
 };
 use crate::hir_id::{HirId, ItemLocalId};
 use rustc_span::def_id::{DefPathHash, LocalDefId};
@@ -34,30 +34,39 @@ impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
     }
 }
 
+impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ItemId {
+    type KeyType = DefPathHash;
+
+    #[inline]
+    fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
+        hcx.local_def_path_hash(self.def_id)
+    }
+}
+
 impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for TraitItemId {
-    type KeyType = (DefPathHash, ItemLocalId);
+    type KeyType = DefPathHash;
 
     #[inline]
-    fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
-        self.hir_id.to_stable_hash_key(hcx)
+    fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
+        hcx.local_def_path_hash(self.def_id)
     }
 }
 
 impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ImplItemId {
-    type KeyType = (DefPathHash, ItemLocalId);
+    type KeyType = DefPathHash;
 
     #[inline]
-    fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
-        self.hir_id.to_stable_hash_key(hcx)
+    fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
+        hcx.local_def_path_hash(self.def_id)
     }
 }
 
 impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for ForeignItemId {
-    type KeyType = (DefPathHash, ItemLocalId);
+    type KeyType = DefPathHash;
 
     #[inline]
-    fn to_stable_hash_key(&self, hcx: &HirCtx) -> (DefPathHash, ItemLocalId) {
-        self.hir_id.to_stable_hash_key(hcx)
+    fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
+        hcx.local_def_path_hash(self.def_id)
     }
 }
 
@@ -82,25 +91,25 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for BodyId {
 
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ItemId {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_reference_to_item(self.id, hasher)
+        hcx.hash_reference_to_item(self.hir_id(), hasher)
     }
 }
 
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ForeignItemId {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_reference_to_item(self.hir_id, hasher)
+        hcx.hash_reference_to_item(self.hir_id(), hasher)
     }
 }
 
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItemId {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_reference_to_item(self.hir_id, hasher)
+        hcx.hash_reference_to_item(self.hir_id(), hasher)
     }
 }
 
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItemId {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_reference_to_item(self.hir_id, hasher)
+        hcx.hash_reference_to_item(self.hir_id(), hasher)
     }
 }
 
@@ -130,7 +139,7 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for VisibilityKind<'_>
 
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItem<'_> {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        let TraitItem { hir_id: _, ident, ref attrs, ref generics, ref kind, span } = *self;
+        let TraitItem { def_id: _, ident, ref attrs, ref generics, ref kind, span } = *self;
 
         hcx.hash_hir_item_like(|hcx| {
             ident.name.hash_stable(hcx, hasher);
@@ -145,7 +154,7 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItem<'_> {
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItem<'_> {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         let ImplItem {
-            hir_id: _,
+            def_id: _,
             ident,
             ref vis,
             defaultness,
@@ -167,9 +176,23 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItem<'_> {
     }
 }
 
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ForeignItem<'_> {
+    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+        let ForeignItem { def_id: _, ident, ref attrs, ref kind, span, ref vis } = *self;
+
+        hcx.hash_hir_item_like(|hcx| {
+            ident.name.hash_stable(hcx, hasher);
+            attrs.hash_stable(hcx, hasher);
+            kind.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+            vis.hash_stable(hcx, hasher);
+        });
+    }
+}
+
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Item<'_> {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        let Item { ident, ref attrs, hir_id: _, ref kind, ref vis, span } = *self;
+        let Item { ident, ref attrs, def_id: _, ref kind, ref vis, span } = *self;
 
         hcx.hash_hir_item_like(|hcx| {
             ident.name.hash_stable(hcx, hasher);
@@ -180,3 +203,17 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Item<'_> {
         });
     }
 }
+
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for MacroDef<'_> {
+    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+        let MacroDef { ident, ref attrs, def_id: _, ref ast, ref vis, span } = *self;
+
+        hcx.hash_hir_item_like(|hcx| {
+            ident.name.hash_stable(hcx, hasher);
+            attrs.hash_stable(hcx, hasher);
+            ast.hash_stable(hcx, hasher);
+            vis.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        });
+    }
+}
diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index 6dbcfb963ee..473477bf22d 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -54,6 +54,7 @@ pub enum Target {
     ForeignTy,
     GenericParam(GenericParamKind),
     MacroDef,
+    Param,
 }
 
 impl Display for Target {
@@ -96,6 +97,7 @@ impl Display for Target {
                     GenericParamKind::Const => "const parameter",
                 },
                 Target::MacroDef => "macro def",
+                Target::Param => "function param",
             }
         )
     }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index f1c2a6b7e6e..416918e3344 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -54,7 +54,7 @@ pub const NO_ANN: &dyn PpAnn = &NoAnn;
 impl PpAnn for hir::Crate<'_> {
     fn nested(&self, state: &mut State<'_>, nested: Nested) {
         match nested {
-            Nested::Item(id) => state.print_item(self.item(id.id)),
+            Nested::Item(id) => state.print_item(self.item(id)),
             Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
             Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
             Nested::ForeignItem(id) => state.print_foreign_item(self.foreign_item(id)),
@@ -69,7 +69,7 @@ impl PpAnn for hir::Crate<'_> {
 impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> {
     fn nested(&self, state: &mut State<'_>, nested: Nested) {
         match nested {
-            Nested::Item(id) => state.print_item(self.item(id.id)),
+            Nested::Item(id) => state.print_item(self.item(id)),
             Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
             Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
             Nested::ForeignItem(id) => state.print_foreign_item(self.foreign_item(id)),
@@ -392,7 +392,7 @@ impl<'a> State<'a> {
                     &f.decl,
                     None,
                     &f.generic_params,
-                    &f.param_names[..],
+                    f.param_names,
                 );
             }
             hir::TyKind::OpaqueDef(..) => self.s.word("/*impl Trait*/"),
@@ -934,7 +934,7 @@ impl<'a> State<'a> {
     }
 
     pub fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) {
-        self.ann.pre(self, AnnNode::SubItem(ti.hir_id));
+        self.ann.pre(self, AnnNode::SubItem(ti.hir_id()));
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(ti.span.lo());
         self.print_outer_attributes(&ti.attrs);
@@ -969,11 +969,11 @@ impl<'a> State<'a> {
                 );
             }
         }
-        self.ann.post(self, AnnNode::SubItem(ti.hir_id))
+        self.ann.post(self, AnnNode::SubItem(ti.hir_id()))
     }
 
     pub fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) {
-        self.ann.pre(self, AnnNode::SubItem(ii.hir_id));
+        self.ann.pre(self, AnnNode::SubItem(ii.hir_id()));
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(ii.span.lo());
         self.print_outer_attributes(&ii.attrs);
@@ -995,7 +995,7 @@ impl<'a> State<'a> {
                 self.print_associated_type(ii.ident, &ii.generics, None, Some(ty));
             }
         }
-        self.ann.post(self, AnnNode::SubItem(ii.hir_id))
+        self.ann.post(self, AnnNode::SubItem(ii.hir_id()))
     }
 
     pub fn print_local(&mut self, init: Option<&hir::Expr<'_>>, decl: impl Fn(&mut Self)) {
@@ -1200,7 +1200,7 @@ impl<'a> State<'a> {
         self.s.word("{");
         self.commasep_cmnt(
             Consistent,
-            &fields[..],
+            fields,
             |s, field| {
                 s.ibox(INDENT_UNIT);
                 if !field.is_shorthand {
@@ -1840,6 +1840,7 @@ impl<'a> State<'a> {
             for binding in generic_args.bindings.iter() {
                 start_or_comma(self);
                 self.print_ident(binding.ident);
+                self.print_generic_args(binding.gen_args, false, false);
                 self.s.space();
                 match generic_args.bindings[0].kind {
                     hir::TypeBindingKind::Equality { ref ty } => {
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index f39a92b9a32..1162379d3d9 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -167,17 +167,17 @@ impl Visitor<'tcx> for IfThisChanged<'tcx> {
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        self.process_attrs(item.hir_id, &item.attrs);
+        self.process_attrs(item.hir_id(), &item.attrs);
         intravisit::walk_item(self, item);
     }
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
-        self.process_attrs(trait_item.hir_id, &trait_item.attrs);
+        self.process_attrs(trait_item.hir_id(), &trait_item.attrs);
         intravisit::walk_trait_item(self, trait_item);
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
-        self.process_attrs(impl_item.hir_id, &impl_item.attrs);
+        self.process_attrs(impl_item.hir_id(), &impl_item.attrs);
         intravisit::walk_impl_item(self, impl_item);
     }
 
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index e1c60050d94..8a83149d732 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -17,7 +17,7 @@ use rustc_ast::{self as ast, Attribute, NestedMetaItem};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::Node as HirNode;
@@ -179,7 +179,7 @@ pub struct DirtyCleanVisitor<'tcx> {
 
 impl DirtyCleanVisitor<'tcx> {
     /// Possibly "deserialize" the attribute into a clean/dirty assertion
-    fn assertion_maybe(&mut self, item_id: hir::HirId, attr: &Attribute) -> Option<Assertion> {
+    fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> {
         let is_clean = if self.tcx.sess.check_name(attr, sym::rustc_dirty) {
             false
         } else if self.tcx.sess.check_name(attr, sym::rustc_clean) {
@@ -207,7 +207,7 @@ impl DirtyCleanVisitor<'tcx> {
     /// Gets the "auto" assertion on pre-validated attr, along with the `except` labels.
     fn assertion_auto(
         &mut self,
-        item_id: hir::HirId,
+        item_id: LocalDefId,
         attr: &Attribute,
         is_clean: bool,
     ) -> Assertion {
@@ -253,8 +253,9 @@ impl DirtyCleanVisitor<'tcx> {
 
     /// Return all DepNode labels that should be asserted for this item.
     /// index=0 is the "name" used for error messages
-    fn auto_labels(&mut self, item_id: hir::HirId, attr: &Attribute) -> (&'static str, Labels) {
-        let node = self.tcx.hir().get(item_id);
+    fn auto_labels(&mut self, item_id: LocalDefId, attr: &Attribute) -> (&'static str, Labels) {
+        let hir_id = self.tcx.hir().local_def_id_to_hir_id(item_id);
+        let node = self.tcx.hir().get(hir_id);
         let (name, labels) = match node {
             HirNode::Item(item) => {
                 match item.kind {
@@ -430,18 +431,17 @@ impl DirtyCleanVisitor<'tcx> {
         }
     }
 
-    fn check_item(&mut self, item_id: hir::HirId, item_span: Span) {
-        let def_id = self.tcx.hir().local_def_id(item_id);
-        for attr in self.tcx.get_attrs(def_id.to_def_id()).iter() {
+    fn check_item(&mut self, item_id: LocalDefId, item_span: Span) {
+        for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() {
             let assertion = match self.assertion_maybe(item_id, attr) {
                 Some(a) => a,
                 None => continue,
             };
             self.checked_attrs.insert(attr.id);
-            for dep_node in self.dep_nodes(&assertion.clean, def_id.to_def_id()) {
+            for dep_node in self.dep_nodes(&assertion.clean, item_id.to_def_id()) {
                 self.assert_clean(item_span, dep_node);
             }
-            for dep_node in self.dep_nodes(&assertion.dirty, def_id.to_def_id()) {
+            for dep_node in self.dep_nodes(&assertion.dirty, item_id.to_def_id()) {
                 self.assert_dirty(item_span, dep_node);
             }
         }
@@ -450,19 +450,19 @@ impl DirtyCleanVisitor<'tcx> {
 
 impl ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        self.check_item(item.hir_id, item.span);
+        self.check_item(item.def_id, item.span);
     }
 
     fn visit_trait_item(&mut self, item: &hir::TraitItem<'_>) {
-        self.check_item(item.hir_id, item.span);
+        self.check_item(item.def_id, item.span);
     }
 
     fn visit_impl_item(&mut self, item: &hir::ImplItem<'_>) {
-        self.check_item(item.hir_id, item.span);
+        self.check_item(item.def_id, item.span);
     }
 
     fn visit_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
-        self.check_item(item.hir_id, item.span);
+        self.check_item(item.def_id, item.span);
     }
 }
 
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index 087f83c2475..374a9eb41e5 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -109,7 +109,7 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &
     debug!("read_file: {}", message);
 
     if report_incremental_info {
-        println!(
+        eprintln!(
             "[incremental] ignoring cache artifact `{}`: {}",
             file.file_name().unwrap().to_string_lossy(),
             message
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 7a1976bed4b..c7a6c1195c5 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -440,12 +440,12 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result<bo
     }
 
     if sess.opts.debugging_opts.incremental_info {
-        println!(
+        eprintln!(
             "[incremental] session directory: \
                   {} files hard-linked",
             files_linked
         );
-        println!(
+        eprintln!(
             "[incremental] session directory: \
                  {} files copied",
             files_copied
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 0add0c5aa26..2b5649bb059 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -170,7 +170,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
 
                 if prev_commandline_args_hash != expected_hash {
                     if report_incremental_info {
-                        println!(
+                        eprintln!(
                             "[incremental] completely ignoring cache because of \
                                     differing commandline arguments"
                         );
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 0b501da7cd9..100824f4b94 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -707,6 +707,18 @@ impl<T: Idx> GrowableBitSet<T> {
         self.bit_set.insert(elem)
     }
 
+    /// Returns `true` if the set has changed.
+    #[inline]
+    pub fn remove(&mut self, elem: T) -> bool {
+        self.ensure(elem.index() + 1);
+        self.bit_set.remove(elem)
+    }
+
+    #[inline]
+    pub fn is_empty(&self) -> bool {
+        self.bit_set.is_empty()
+    }
+
     #[inline]
     pub fn contains(&self, elem: T) -> bool {
         let (word_index, mask) = word_index_and_mask(elem);
diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs
index 6cc3e9427d1..c11b98e77aa 100644
--- a/compiler/rustc_index/src/bit_set/tests.rs
+++ b/compiler/rustc_index/src/bit_set/tests.rs
@@ -1,6 +1,7 @@
 use super::*;
 
 extern crate test;
+use std::hint::black_box;
 use test::Bencher;
 
 #[test]
@@ -364,3 +365,36 @@ fn union_hybrid_sparse_full_small_domain(b: &mut Bencher) {
         sparse.union(&dense);
     })
 }
+
+#[bench]
+fn bench_insert(b: &mut Bencher) {
+    let mut bs = BitSet::new_filled(99999usize);
+    b.iter(|| {
+        black_box(bs.insert(black_box(100u32)));
+    });
+}
+
+#[bench]
+fn bench_remove(b: &mut Bencher) {
+    let mut bs = BitSet::new_filled(99999usize);
+    b.iter(|| {
+        black_box(bs.remove(black_box(100u32)));
+    });
+}
+
+#[bench]
+fn bench_iter(b: &mut Bencher) {
+    let bs = BitSet::new_filled(99999usize);
+    b.iter(|| {
+        bs.iter().map(|b: usize| black_box(b)).for_each(drop);
+    });
+}
+
+#[bench]
+fn bench_intersect(b: &mut Bencher) {
+    let mut ba: BitSet<u32> = BitSet::new_filled(99999usize);
+    let bb = BitSet::new_filled(99999usize);
+    b.iter(|| {
+        ba.intersect(black_box(&bb));
+    });
+}
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index eaef4c7b54a..995034e81da 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -8,3 +8,7 @@
 
 pub mod bit_set;
 pub mod vec;
+
+// FIXME(#56935): Work around ICEs during cross-compilation.
+#[allow(unused)]
+extern crate rustc_macros;
diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml
index 5dba4106c94..a75ad7b31a6 100644
--- a/compiler/rustc_infer/Cargo.toml
+++ b/compiler/rustc_infer/Cargo.toml
@@ -20,5 +20,5 @@ rustc_session = { path = "../rustc_session" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_ast = { path = "../rustc_ast" }
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index a7749d33b7c..11ee8fb17ad 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -55,6 +55,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
 pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
     fn to_trace(
+        tcx: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -178,7 +179,7 @@ impl<'a, 'tcx> At<'a, 'tcx> {
     where
         T: ToTrace<'tcx>,
     {
-        let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
+        let trace = ToTrace::to_trace(self.infcx.tcx, self.cause, a_is_expected, a, b);
         Trace { at: self, trace, a_is_expected }
     }
 }
@@ -251,6 +252,7 @@ impl<'a, 'tcx> Trace<'a, 'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -262,6 +264,7 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -273,6 +276,7 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -284,6 +288,7 @@ impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -298,6 +303,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
 
 impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
     fn to_trace(
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
@@ -309,3 +315,20 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
         }
     }
 }
+
+impl<'tcx> ToTrace<'tcx> for ty::ProjectionTy<'tcx> {
+    fn to_trace(
+        tcx: TyCtxt<'tcx>,
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Self,
+        b: Self,
+    ) -> TypeTrace<'tcx> {
+        let a_ty = tcx.mk_projection(a.item_def_id, a.substs);
+        let b_ty = tcx.mk_projection(b.item_def_id, b.substs);
+        TypeTrace {
+            cause: cause.clone(),
+            values: Types(ExpectedFound::new(a_is_expected, a_ty, b_ty)),
+        }
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 1546c1e559f..2ec9b9e0be4 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -507,12 +507,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
 
         // Unify the original value for each variable with the value
         // taken from `query_response` (after applying `result_subst`).
-        Ok(self.unify_canonical_vars(
-            cause,
-            param_env,
-            original_values,
-            substituted_query_response,
-        )?)
+        self.unify_canonical_vars(cause, param_env, original_values, substituted_query_response)
     }
 
     /// Converts the region constraints resulting from a query into an
@@ -639,6 +634,10 @@ struct QueryTypeRelatingDelegate<'a, 'tcx> {
 }
 
 impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
+    fn param_env(&self) -> ty::ParamEnv<'tcx> {
+        self.param_env
+    }
+
     fn create_next_universe(&mut self) -> ty::UniverseIndex {
         self.infcx.create_next_universe()
     }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index e034ac5e8fd..5e11932eafc 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -221,6 +221,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
     /// As `3 + 4` contains `N` in its substs, this must not succeed.
     ///
     /// See `src/test/ui/const-generics/occurs-check/` for more examples where this is relevant.
+    #[instrument(level = "debug", skip(self))]
     fn unify_const_variable(
         &self,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 84aa19aedeb..9e55f7e5589 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1509,7 +1509,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
 
         impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-                if let Some((kind, def_id)) = TyCategory::from_ty(t) {
+                if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) {
                     let span = self.tcx.def_span(def_id);
                     // Avoid cluttering the output when the "found" and error span overlap:
                     //
@@ -1582,11 +1582,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         };
         if let Some((expected, found)) = expected_found {
             let expected_label = match exp_found {
-                Mismatch::Variable(ef) => ef.expected.prefix_string(),
+                Mismatch::Variable(ef) => ef.expected.prefix_string(self.tcx),
                 Mismatch::Fixed(s) => s.into(),
             };
             let found_label = match exp_found {
-                Mismatch::Variable(ef) => ef.found.prefix_string(),
+                Mismatch::Variable(ef) => ef.found.prefix_string(self.tcx),
                 Mismatch::Fixed(s) => s.into(),
             };
             let exp_found = match exp_found {
@@ -2248,13 +2248,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "...",
                 );
                 if let Some(infer::RelateParamBound(_, t)) = origin {
+                    let return_impl_trait = self
+                        .in_progress_typeck_results
+                        .map(|typeck_results| typeck_results.borrow().hir_owner)
+                        .and_then(|owner| self.tcx.return_type_impl_trait(owner))
+                        .is_some();
                     let t = self.resolve_vars_if_possible(t);
                     match t.kind() {
                         // We've got:
                         // fn get_later<G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_
                         // suggest:
                         // fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
-                        ty::Closure(_, _substs) | ty::Opaque(_, _substs) => {
+                        ty::Closure(_, _substs) | ty::Opaque(_, _substs) if return_impl_trait => {
                             new_binding_suggestion(&mut err, type_param_span, bound_kind);
                         }
                         _ => {
@@ -2484,7 +2489,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
 pub enum TyCategory {
     Closure,
     Opaque,
-    Generator,
+    Generator(hir::GeneratorKind),
     Foreign,
 }
 
@@ -2493,16 +2498,18 @@ impl TyCategory {
         match self {
             Self::Closure => "closure",
             Self::Opaque => "opaque type",
-            Self::Generator => "generator",
+            Self::Generator(gk) => gk.descr(),
             Self::Foreign => "foreign type",
         }
     }
 
-    pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> {
+    pub fn from_ty(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Self, DefId)> {
         match *ty.kind() {
             ty::Closure(def_id, _) => Some((Self::Closure, def_id)),
             ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)),
-            ty::Generator(def_id, ..) => Some((Self::Generator, def_id)),
+            ty::Generator(def_id, ..) => {
+                Some((Self::Generator(tcx.generator_kind(def_id).unwrap()), def_id))
+            }
             ty::Foreign(def_id) => Some((Self::Foreign, def_id)),
             _ => None,
         }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index bd43d3c01e2..d533e267fd7 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -383,7 +383,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 InferenceDiagnosticsData {
                     name: s,
                     span: None,
-                    kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string() },
+                    kind: UnderspecifiedArgKind::Type { prefix: ty.prefix_string(self.tcx) },
                     parent: None,
                 }
             }
@@ -671,7 +671,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 if !impl_candidates.is_empty() && e.span.contains(span) {
                     if let Some(expr) = exprs.first() {
                         if let ExprKind::Path(hir::QPath::Resolved(_, path)) = expr.kind {
-                            if let [path_segment] = &path.segments[..] {
+                            if let [path_segment] = path.segments {
                                 let candidate_len = impl_candidates.len();
                                 let suggestions = impl_candidates.iter().map(|candidate| {
                                     format!(
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
index cc8f1816bc3..0599c78ebfd 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
@@ -43,7 +43,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
         self.infcx.tcx
     }
 
-    pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'cx>> {
+    pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx>> {
         // Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
         // the nice region errors are required when running under the MIR borrow checker.
         self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict())
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index e3c613b1d6a..2f622231a08 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -9,7 +9,7 @@ use rustc_middle::ty;
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// When given a `ConcreteFailure` for a function with parameters containing a named region and
     /// an anonymous region, emit an descriptive diagnostic error.
-    pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'a>> {
+    pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'tcx>> {
         let (span, sub, sup) = self.regions()?;
 
         debug!(
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index e8e0326d978..4aecc2f40b8 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -16,7 +16,7 @@ use std::fmt::{self, Write};
 impl NiceRegionError<'me, 'tcx> {
     /// When given a `ConcreteFailure` for a function with arguments containing a named region and
     /// an anonymous region, emit a descriptive diagnostic error.
-    pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder<'me>> {
+    pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder<'tcx>> {
         match &self.error {
             ///////////////////////////////////////////////////////////////////////////
             // NB. The ordering of cases in this match is very
@@ -30,157 +30,153 @@ impl NiceRegionError<'me, 'tcx> {
             Some(RegionResolutionError::SubSupConflict(
                 vid,
                 _,
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sub_placeholder @ ty::RePlaceholder(_),
                 _,
                 sup_placeholder @ ty::RePlaceholder(_),
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+            )) => self.try_report_trait_placeholder_mismatch(
                 Some(self.tcx().mk_region(ty::ReVar(*vid))),
                 cause,
                 Some(sub_placeholder),
                 Some(sup_placeholder),
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::SubSupConflict(
                 vid,
                 _,
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sub_placeholder @ ty::RePlaceholder(_),
                 _,
                 _,
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+            )) => self.try_report_trait_placeholder_mismatch(
                 Some(self.tcx().mk_region(ty::ReVar(*vid))),
                 cause,
                 Some(sub_placeholder),
                 None,
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::SubSupConflict(
                 vid,
                 _,
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 _,
                 _,
                 sup_placeholder @ ty::RePlaceholder(_),
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+            )) => self.try_report_trait_placeholder_mismatch(
                 Some(self.tcx().mk_region(ty::ReVar(*vid))),
                 cause,
                 None,
                 Some(*sup_placeholder),
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::SubSupConflict(
                 vid,
                 _,
                 _,
                 _,
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sup_placeholder @ ty::RePlaceholder(_),
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+            )) => self.try_report_trait_placeholder_mismatch(
                 Some(self.tcx().mk_region(ty::ReVar(*vid))),
                 cause,
                 None,
                 Some(*sup_placeholder),
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::UpperBoundUniverseConflict(
                 vid,
                 _,
                 _,
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sup_placeholder @ ty::RePlaceholder(_),
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+            )) => self.try_report_trait_placeholder_mismatch(
                 Some(self.tcx().mk_region(ty::ReVar(*vid))),
                 cause,
                 None,
                 Some(*sup_placeholder),
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::ConcreteFailure(
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sub_region @ ty::RePlaceholder(_),
                 sup_region @ ty::RePlaceholder(_),
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
+            )) => self.try_report_trait_placeholder_mismatch(
                 None,
                 cause,
                 Some(*sub_region),
                 Some(*sup_region),
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::ConcreteFailure(
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sub_region @ ty::RePlaceholder(_),
                 sup_region,
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
-                Some(sup_region),
+            )) => self.try_report_trait_placeholder_mismatch(
+                (!sup_region.has_name()).then_some(sup_region),
                 cause,
-                Some(*sub_region),
+                Some(sub_region),
                 None,
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                values,
+            ),
 
             Some(RegionResolutionError::ConcreteFailure(
-                SubregionOrigin::Subtype(box TypeTrace {
-                    cause,
-                    values: ValuePairs::TraitRefs(ExpectedFound { expected, found }),
-                }),
+                SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sub_region,
                 sup_region @ ty::RePlaceholder(_),
-            )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait(
-                Some(sub_region),
+            )) => self.try_report_trait_placeholder_mismatch(
+                (!sub_region.has_name()).then_some(sub_region),
                 cause,
                 None,
-                Some(*sup_region),
-                expected.def_id,
-                expected.substs,
-                found.substs,
-            )),
+                Some(sup_region),
+                values,
+            ),
 
             _ => None,
         }
     }
 
+    fn try_report_trait_placeholder_mismatch(
+        &self,
+        vid: Option<ty::Region<'tcx>>,
+        cause: &ObligationCause<'tcx>,
+        sub_placeholder: Option<ty::Region<'tcx>>,
+        sup_placeholder: Option<ty::Region<'tcx>>,
+        value_pairs: &ValuePairs<'tcx>,
+    ) -> Option<DiagnosticBuilder<'tcx>> {
+        let (expected_substs, found_substs, trait_def_id) = match value_pairs {
+            ValuePairs::TraitRefs(ExpectedFound { expected, found })
+                if expected.def_id == found.def_id =>
+            {
+                (expected.substs, found.substs, expected.def_id)
+            }
+            ValuePairs::PolyTraitRefs(ExpectedFound { expected, found })
+                if expected.def_id() == found.def_id() =>
+            {
+                // It's possible that the placeholders come from a binder
+                // outside of this value pair. Use `no_bound_vars` as a
+                // simple heuristic for that.
+                (expected.no_bound_vars()?.substs, found.no_bound_vars()?.substs, expected.def_id())
+            }
+            _ => return None,
+        };
+
+        Some(self.report_trait_placeholder_mismatch(
+            vid,
+            cause,
+            sub_placeholder,
+            sup_placeholder,
+            trait_def_id,
+            expected_substs,
+            found_substs,
+        ))
+    }
+
     // error[E0308]: implementation of `Foo` does not apply to enough lifetimes
     //   --> /home/nmatsakis/tmp/foo.rs:12:5
     //    |
@@ -190,7 +186,8 @@ impl NiceRegionError<'me, 'tcx> {
     //    = note: Due to a where-clause on the function `all`,
     //    = note: `T` must implement `...` for any two lifetimes `'1` and `'2`.
     //    = note: However, the type `T` only implements `...` for some specific lifetime `'2`.
-    fn try_report_placeholders_trait(
+    #[instrument(level = "debug", skip(self))]
+    fn report_trait_placeholder_mismatch(
         &self,
         vid: Option<ty::Region<'tcx>>,
         cause: &ObligationCause<'tcx>,
@@ -199,28 +196,13 @@ impl NiceRegionError<'me, 'tcx> {
         trait_def_id: DefId,
         expected_substs: SubstsRef<'tcx>,
         actual_substs: SubstsRef<'tcx>,
-    ) -> DiagnosticBuilder<'me> {
-        debug!(
-            "try_report_placeholders_trait(\
-             vid={:?}, \
-             sub_placeholder={:?}, \
-             sup_placeholder={:?}, \
-             trait_def_id={:?}, \
-             expected_substs={:?}, \
-             actual_substs={:?})",
-            vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs
-        );
-
+    ) -> DiagnosticBuilder<'tcx> {
         let span = cause.span(self.tcx());
         let msg = format!(
             "implementation of `{}` is not general enough",
             self.tcx().def_path_str(trait_def_id),
         );
         let mut err = self.tcx().sess.struct_span_err(span, &msg);
-        err.span_label(
-            self.tcx().def_span(trait_def_id),
-            format!("trait `{}` defined here", self.tcx().def_path_str(trait_def_id)),
-        );
 
         let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = cause.code {
             err.span_label(span, "doesn't satisfy where-clause");
@@ -285,17 +267,13 @@ impl NiceRegionError<'me, 'tcx> {
 
         let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid;
 
-        debug!("try_report_placeholders_trait: actual_has_vid={:?}", actual_has_vid);
-        debug!("try_report_placeholders_trait: expected_has_vid={:?}", expected_has_vid);
-        debug!("try_report_placeholders_trait: has_sub={:?}", has_sub);
-        debug!("try_report_placeholders_trait: has_sup={:?}", has_sup);
         debug!(
-            "try_report_placeholders_trait: actual_self_ty_has_vid={:?}",
-            actual_self_ty_has_vid
-        );
-        debug!(
-            "try_report_placeholders_trait: expected_self_ty_has_vid={:?}",
-            expected_self_ty_has_vid
+            ?actual_has_vid,
+            ?expected_has_vid,
+            ?has_sub,
+            ?has_sup,
+            ?actual_self_ty_has_vid,
+            ?expected_self_ty_has_vid,
         );
 
         self.explain_actual_impl_that_was_found(
@@ -388,6 +366,8 @@ impl NiceRegionError<'me, 'tcx> {
             value: trait_ref,
         };
 
+        let same_self_type = actual_trait_ref.self_ty() == expected_trait_ref.self_ty();
+
         let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
         expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
         expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
@@ -403,7 +383,42 @@ impl NiceRegionError<'me, 'tcx> {
                 }
             };
 
-            let mut note = if passive_voice {
+            let mut note = if same_self_type {
+                let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
+                self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
+
+                if self_ty.value.is_closure()
+                    && self
+                        .tcx()
+                        .fn_trait_kind_from_lang_item(expected_trait_ref.value.def_id)
+                        .is_some()
+                {
+                    let closure_sig = self_ty.map(|closure| {
+                        if let ty::Closure(_, substs) = closure.kind() {
+                            self.tcx().signature_unclosure(
+                                substs.as_closure().sig(),
+                                rustc_hir::Unsafety::Normal,
+                            )
+                        } else {
+                            bug!("type is not longer closure");
+                        }
+                    });
+
+                    format!(
+                        "{}closure with signature `{}` must implement `{}`",
+                        if leading_ellipsis { "..." } else { "" },
+                        closure_sig,
+                        expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+                    )
+                } else {
+                    format!(
+                        "{}`{}` must implement `{}`",
+                        if leading_ellipsis { "..." } else { "" },
+                        self_ty,
+                        expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+                    )
+                }
+            } else if passive_voice {
                 format!(
                     "{}`{}` would have to be implemented for the type `{}`",
                     if leading_ellipsis { "..." } else { "" },
@@ -449,7 +464,12 @@ impl NiceRegionError<'me, 'tcx> {
                 None => true,
             };
 
-            let mut note = if passive_voice {
+            let mut note = if same_self_type {
+                format!(
+                    "...but it actually implements `{}`",
+                    actual_trait_ref.map(|tr| tr.print_only_trait_path()),
+                )
+            } else if passive_voice {
                 format!(
                     "...but `{}` is actually implemented for the type `{}`",
                     actual_trait_ref.map(|tr| tr.print_only_trait_path()),
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index c6ae71ba330..fa0d5b83013 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -7,10 +7,7 @@ use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
-use rustc_hir::{
-    self as hir, GenericBound, ImplItem, Item, ItemKind, Lifetime, LifetimeName, Node, TraitItem,
-    TyKind,
-};
+use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
 use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor};
 use rustc_span::symbol::Ident;
 use rustc_span::{MultiSpan, Span};
@@ -234,7 +231,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             }
             match fn_return.kind {
                 TyKind::OpaqueDef(item_id, _) => {
-                    let item = tcx.hir().item(item_id.id);
+                    let item = tcx.hir().item(item_id);
                     let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
                         opaque
                     } else {
@@ -343,17 +340,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
         let tcx = self.tcx();
         match tcx.hir().get_if_local(def_id) {
-            Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => {
-                match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) {
+            Some(Node::ImplItem(impl_item)) => {
+                match tcx.hir().find(tcx.hir().get_parent_item(impl_item.hir_id())) {
                     Some(Node::Item(Item {
                         kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
                         ..
-                    })) => Some((*ident, self_ty)),
+                    })) => Some((impl_item.ident, self_ty)),
                     _ => None,
                 }
             }
-            Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => {
-                let parent_id = tcx.hir().get_parent_item(*hir_id);
+            Some(Node::TraitItem(trait_item)) => {
+                let parent_id = tcx.hir().get_parent_item(trait_item.hir_id());
                 match tcx.hir().find(parent_id) {
                     Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
                         // The method being called is defined in the `trait`, but the `'static`
@@ -364,8 +361,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                             .hir()
                             .trait_impls(trait_did)
                             .iter()
-                            .filter_map(|impl_node| {
-                                let impl_did = tcx.hir().local_def_id(*impl_node);
+                            .filter_map(|&impl_did| {
                                 match tcx.hir().get_if_local(impl_did.to_def_id()) {
                                     Some(Node::Item(Item {
                                         kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
@@ -389,7 +385,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                             })
                             .next()
                         {
-                            Some(self_ty) => Some((*ident, self_ty)),
+                            Some(self_ty) => Some((trait_item.ident, self_ty)),
                             _ => None,
                         }
                     }
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/README.md b/compiler/rustc_infer/src/infer/lexical_region_resolve/README.md
index e0b2c0bffee..0a7da8c8063 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/README.md
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/README.md
@@ -1,4 +1,3 @@
-
 Lexical Region Resolution was removed in https://github.com/rust-lang/rust/pull/64790.
 
 Rust now uses Non-lexical lifetimes. For more info, please see the [borrowck
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 97ef685cf6f..e720a6f1308 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -72,6 +72,8 @@ where
 }
 
 pub trait TypeRelatingDelegate<'tcx> {
+    fn param_env(&self) -> ty::ParamEnv<'tcx>;
+
     /// Push a constraint `sup: sub` -- this constraint must be
     /// satisfied for the two types to be related. `sub` and `sup` may
     /// be regions from the type or new variables created through the
@@ -473,9 +475,8 @@ where
         self.infcx.tcx
     }
 
-    // FIXME(oli-obk): not sure how to get the correct ParamEnv
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        ty::ParamEnv::empty()
+        self.delegate.param_env()
     }
 
     fn tag(&self) -> &'static str {
@@ -819,9 +820,8 @@ where
         self.infcx.tcx
     }
 
-    // FIXME(oli-obk): not sure how to get the correct ParamEnv
     fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        ty::ParamEnv::empty()
+        self.delegate.param_env()
     }
 
     fn tag(&self) -> &'static str {
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index 2cfd6bb904c..4be0e7948f7 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -15,7 +15,7 @@ pub struct Snapshot<'tcx> {
     _marker: PhantomData<&'tcx ()>,
 }
 
-/// Records the 'undo' data fora single operation that affects some form of inference variable.
+/// Records the "undo" data for a single operation that affects some form of inference variable.
 pub(crate) enum UndoLog<'tcx> {
     TypeVariables(type_variable::UndoLog<'tcx>),
     ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 13cf1e1083f..87684c2715f 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -1,9 +1,10 @@
 use smallvec::smallvec;
 
 use crate::traits::{Obligation, ObligationCause, PredicateObligation};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_middle::ty::outlives::Component;
 use rustc_middle::ty::{self, ToPredicate, TyCtxt, WithConstness};
+use rustc_span::symbol::Ident;
 
 pub fn anonymize_predicate<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -282,6 +283,44 @@ pub fn transitive_bounds<'tcx>(
     elaborate_trait_refs(tcx, bounds).filter_to_traits()
 }
 
+/// A specialized variant of `elaborate_trait_refs` that only elaborates trait references that may
+/// define the given associated type `assoc_name`. It uses the
+/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that
+/// aren't related to `assoc_item`.  This is used when resolving types like `Self::Item` or
+/// `T::Item` and helps to avoid cycle errors (see e.g. #35237).
+pub fn transitive_bounds_that_define_assoc_type<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
+    assoc_name: Ident,
+) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
+    let mut stack: Vec<_> = bounds.collect();
+    let mut visited = FxIndexSet::default();
+
+    std::iter::from_fn(move || {
+        while let Some(trait_ref) = stack.pop() {
+            let anon_trait_ref = tcx.anonymize_late_bound_regions(trait_ref);
+            if visited.insert(anon_trait_ref) {
+                let super_predicates = tcx.super_predicates_that_define_assoc_type((
+                    trait_ref.def_id(),
+                    Some(assoc_name),
+                ));
+                for (super_predicate, _) in super_predicates.predicates {
+                    let bound_predicate = super_predicate.kind();
+                    let subst_predicate = super_predicate
+                        .subst_supertrait(tcx, &bound_predicate.rebind(trait_ref.skip_binder()));
+                    if let Some(binder) = subst_predicate.to_opt_poly_trait_ref() {
+                        stack.push(binder.value);
+                    }
+                }
+
+                return Some(trait_ref);
+            }
+        }
+
+        return None;
+    })
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // Other
 ///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index 2481a27dee7..cfe98a630c1 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -10,8 +10,9 @@ doctest = false
 [dependencies]
 libc = "0.2"
 tracing = "0.1"
+rustc-rayon-core = "0.3.0"
 rayon = { version = "0.3.0", package = "rustc-rayon" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_builtin_macros = { path = "../rustc_builtin_macros" }
@@ -30,6 +31,7 @@ rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
 rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
 rustc_codegen_llvm = { path = "../rustc_codegen_llvm", optional = true }
 rustc_hir = { path = "../rustc_hir" }
+rustc_index = { path = "../rustc_index" }
 rustc_metadata = { path = "../rustc_metadata" }
 rustc_mir = { path = "../rustc_mir" }
 rustc_mir_build = { path = "../rustc_mir_build" }
@@ -39,6 +41,7 @@ rustc_lint = { path = "../rustc_lint" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_plugin_impl = { path = "../rustc_plugin_impl" }
 rustc_privacy = { path = "../rustc_privacy" }
+rustc_query_impl = { path = "../rustc_query_impl" }
 rustc_resolve = { path = "../rustc_resolve" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_ty_utils = { path = "../rustc_ty_utils" }
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 28eb1fed6a0..502e7155c2e 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::OnDrop;
 use rustc_errors::registry::Registry;
-use rustc_errors::ErrorReported;
+use rustc_errors::{ErrorReported, Handler};
 use rustc_lint::LintStore;
 use rustc_middle::ty;
 use rustc_parse::new_parser_from_source_str;
@@ -213,3 +213,24 @@ pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R
         || create_compiler_and_run(config, f),
     )
 }
+
+pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
+    eprintln!("query stack during panic:");
+
+    // Be careful relying 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 i = ty::tls::with_context_opt(|icx| {
+        if let Some(icx) = icx {
+            icx.tcx.queries.try_print_query_stack(icx.tcx, icx.query, handler, num_frames)
+        } else {
+            0
+        }
+    });
+
+    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_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 56aa3939b22..6358855ac32 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -15,6 +15,7 @@ use rustc_expand::base::ExtCtxt;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_hir::Crate;
+use rustc_index::vec::IndexVec;
 use rustc_lint::LintStore;
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
@@ -27,6 +28,7 @@ use rustc_mir_build as mir_build;
 use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
 use rustc_passes::{self, hir_stats, layout_test};
 use rustc_plugin_impl as plugin;
+use rustc_query_impl::Queries as TcxQueries;
 use rustc_resolve::{Resolver, ResolverArenas};
 use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode};
 use rustc_session::lint;
@@ -64,8 +66,8 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
     }
 
     if sess.opts.debugging_opts.input_stats {
-        println!("Lines of code:             {}", sess.source_map().count_lines());
-        println!("Pre-expansion node count:  {}", count_nodes(&krate));
+        eprintln!("Lines of code:             {}", sess.source_map().count_lines());
+        eprintln!("Pre-expansion node count:  {}", count_nodes(&krate));
     }
 
     if let Some(ref s) = sess.opts.debugging_opts.show_span {
@@ -394,7 +396,7 @@ fn configure_and_expand_inner<'a>(
     // Done with macro expansion!
 
     if sess.opts.debugging_opts.input_stats {
-        println!("Post-expansion node count: {}", count_nodes(&krate));
+        eprintln!("Post-expansion node count: {}", count_nodes(&krate));
     }
 
     if sess.opts.debugging_opts.hir_stats {
@@ -738,20 +740,18 @@ pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy<Providers> = SyncLazy::new(|
     extern_providers
 });
 
-pub struct QueryContext<'tcx>(&'tcx GlobalCtxt<'tcx>);
+pub struct QueryContext<'tcx> {
+    gcx: &'tcx GlobalCtxt<'tcx>,
+}
 
 impl<'tcx> QueryContext<'tcx> {
     pub fn enter<F, R>(&mut self, f: F) -> R
     where
         F: FnOnce(TyCtxt<'tcx>) -> R,
     {
-        let icx = ty::tls::ImplicitCtxt::new(self.0);
+        let icx = ty::tls::ImplicitCtxt::new(self.gcx);
         ty::tls::enter_context(&icx, |_| f(icx.tcx))
     }
-
-    pub fn print_stats(&mut self) {
-        self.enter(ty::query::print_stats)
-    }
 }
 
 pub fn create_global_ctxt<'tcx>(
@@ -762,6 +762,7 @@ pub fn create_global_ctxt<'tcx>(
     mut resolver_outputs: ResolverOutputs,
     outputs: OutputFilenames,
     crate_name: &str,
+    queries: &'tcx OnceCell<TcxQueries<'tcx>>,
     global_ctxt: &'tcx OnceCell<GlobalCtxt<'tcx>>,
     arena: &'tcx WorkerLocal<Arena<'tcx>>,
 ) -> QueryContext<'tcx> {
@@ -785,26 +786,33 @@ pub fn create_global_ctxt<'tcx>(
         callback(sess, &mut local_providers, &mut extern_providers);
     }
 
+    let queries = {
+        let crates = resolver_outputs.cstore.crates_untracked();
+        let max_cnum = crates.iter().map(|c| c.as_usize()).max().unwrap_or(0);
+        let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1);
+        providers[LOCAL_CRATE] = local_providers;
+        queries.get_or_init(|| TcxQueries::new(providers, extern_providers))
+    };
+
     let gcx = sess.time("setup_global_ctxt", || {
         global_ctxt.get_or_init(|| {
             TyCtxt::create_global_ctxt(
                 sess,
                 lint_store,
-                local_providers,
-                extern_providers,
                 arena,
                 resolver_outputs,
                 krate,
                 defs,
                 dep_graph,
                 query_result_on_disk_cache,
+                queries.as_dyn(),
                 &crate_name,
                 &outputs,
             )
         })
     });
 
-    QueryContext(gcx)
+    QueryContext { gcx }
 }
 
 /// Runs the resolution, type-checking, region checking and other
@@ -831,12 +839,11 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
             },
             {
                 par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
-                    let local_def_id = tcx.hir().local_def_id(module);
-                    tcx.ensure().check_mod_loops(local_def_id);
-                    tcx.ensure().check_mod_attrs(local_def_id);
-                    tcx.ensure().check_mod_naked_functions(local_def_id);
-                    tcx.ensure().check_mod_unstable_api_usage(local_def_id);
-                    tcx.ensure().check_mod_const_bodies(local_def_id);
+                    tcx.ensure().check_mod_loops(module);
+                    tcx.ensure().check_mod_attrs(module);
+                    tcx.ensure().check_mod_naked_functions(module);
+                    tcx.ensure().check_mod_unstable_api_usage(module);
+                    tcx.ensure().check_mod_const_bodies(module);
                 });
             }
         );
@@ -861,10 +868,8 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
                         // "not all control paths return a value" is reported here.
                         //
                         // maybe move the check to a MIR pass?
-                        let local_def_id = tcx.hir().local_def_id(module);
-
-                        tcx.ensure().check_mod_liveness(local_def_id);
-                        tcx.ensure().check_mod_intrinsics(local_def_id);
+                        tcx.ensure().check_mod_liveness(module);
+                        tcx.ensure().check_mod_intrinsics(module);
                     });
                 });
             }
@@ -926,7 +931,7 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
             {
                 sess.time("privacy_checking_modules", || {
                     par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
-                        tcx.ensure().check_mod_privacy(tcx.hir().local_def_id(module));
+                        tcx.ensure().check_mod_privacy(module);
                     });
                 });
             }
diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs
index de08a4c8242..d0262935c89 100644
--- a/compiler/rustc_interface/src/proc_macro_decls.rs
+++ b/compiler/rustc_interface/src/proc_macro_decls.rs
@@ -26,7 +26,7 @@ struct Finder<'tcx> {
 impl<'v> ItemLikeVisitor<'v> for Finder<'_> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
         if self.tcx.sess.contains_name(&item.attrs, sym::rustc_proc_macro_decls) {
-            self.decls = Some(item.hir_id);
+            self.decls = Some(item.hir_id());
         }
     }
 
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index ac6b6d03115..9c38d2b91ab 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -14,6 +14,7 @@ use rustc_lint::LintStore;
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::ty::{GlobalCtxt, ResolverOutputs, TyCtxt};
+use rustc_query_impl::Queries as TcxQueries;
 use rustc_serialize::json;
 use rustc_session::config::{self, OutputFilenames, OutputType};
 use rustc_session::{output::find_crate_name, Session};
@@ -71,6 +72,7 @@ impl<T> Default for Query<T> {
 pub struct Queries<'tcx> {
     compiler: &'tcx Compiler,
     gcx: OnceCell<GlobalCtxt<'tcx>>,
+    queries: OnceCell<TcxQueries<'tcx>>,
 
     arena: WorkerLocal<Arena<'tcx>>,
     hir_arena: WorkerLocal<rustc_ast_lowering::Arena<'tcx>>,
@@ -92,6 +94,7 @@ impl<'tcx> Queries<'tcx> {
         Queries {
             compiler,
             gcx: OnceCell::new(),
+            queries: OnceCell::new(),
             arena: WorkerLocal::new(|_| Arena::default()),
             hir_arena: WorkerLocal::new(|_| rustc_ast_lowering::Arena::default()),
             dep_graph_future: Default::default(),
@@ -265,6 +268,7 @@ impl<'tcx> Queries<'tcx> {
                 resolver_outputs.steal(),
                 outputs,
                 &crate_name,
+                &self.queries,
                 &self.gcx,
                 &self.arena,
             ))
@@ -425,11 +429,11 @@ impl Compiler {
             {
                 let _prof_timer =
                     queries.session().prof.generic_activity("self_profile_alloc_query_strings");
-                gcx.enter(|tcx| tcx.alloc_self_profile_query_strings());
+                gcx.enter(rustc_query_impl::alloc_self_profile_query_strings);
             }
 
             if self.session().opts.debugging_opts.query_stats {
-                gcx.print_stats();
+                gcx.enter(rustc_query_impl::print_stats);
             }
         }
 
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index b7dc539c6d6..798996263c7 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -10,6 +10,8 @@ use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::registry::Registry;
 use rustc_metadata::dynamic_lib::DynamicLibrary;
+#[cfg(parallel_compiler)]
+use rustc_middle::ty::tls;
 use rustc_resolve::{self, Resolver};
 use rustc_session as session;
 use rustc_session::config::{self, CrateType};
@@ -29,11 +31,12 @@ use std::io;
 use std::lazy::SyncOnceCell;
 use std::mem;
 use std::ops::DerefMut;
+#[cfg(not(parallel_compiler))]
+use std::panic;
 use std::path::{Path, PathBuf};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::{Arc, Mutex, Once};
-#[cfg(not(parallel_compiler))]
-use std::{panic, thread};
+use std::thread;
 use tracing::info;
 
 /// Adds `target_feature = "..."` cfgs for a variety of platform
@@ -156,6 +159,28 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
     scoped_thread(cfg, main_handler)
 }
 
+/// Creates a new thread and forwards information in thread locals to it.
+/// The new thread runs the deadlock handler.
+/// Must only be called when a deadlock is about to happen.
+#[cfg(parallel_compiler)]
+unsafe fn handle_deadlock() {
+    let registry = rustc_rayon_core::Registry::current();
+
+    let context = tls::get_tlv();
+    assert!(context != 0);
+    rustc_data_structures::sync::assert_sync::<tls::ImplicitCtxt<'_, '_>>();
+    let icx: &tls::ImplicitCtxt<'_, '_> = &*(context as *const tls::ImplicitCtxt<'_, '_>);
+
+    let session_globals = rustc_span::SESSION_GLOBALS.with(|sg| sg as *const _);
+    let session_globals = &*session_globals;
+    thread::spawn(move || {
+        tls::enter_context(icx, |_| {
+            rustc_span::SESSION_GLOBALS
+                .set(session_globals, || tls::with(|tcx| tcx.queries.deadlock(tcx, &registry)))
+        });
+    });
+}
+
 #[cfg(parallel_compiler)]
 pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     edition: Edition,
@@ -163,7 +188,6 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
     stderr: &Option<Arc<Mutex<Vec<u8>>>>,
     f: F,
 ) -> R {
-    use rustc_middle::ty;
     crate::callbacks::setup_callbacks();
 
     let mut config = rayon::ThreadPoolBuilder::new()
@@ -171,7 +195,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
         .acquire_thread_handler(jobserver::acquire_thread)
         .release_thread_handler(jobserver::release_thread)
         .num_threads(threads)
-        .deadlock_handler(|| unsafe { ty::query::handle_deadlock() });
+        .deadlock_handler(|| unsafe { handle_deadlock() });
 
     if let Some(size) = get_stack_size() {
         config = config.stack_size(size);
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index c56eb09b634..90badd3d573 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -19,5 +19,6 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_feature = { path = "../rustc_feature" }
 rustc_index = { path = "../rustc_index" }
 rustc_session = { path = "../rustc_session" }
+rustc_serialize = { path = "../rustc_serialize" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_parse_format = { path = "../rustc_parse_format" }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 2cedef62519..71017fcde87 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -36,9 +36,9 @@ use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, Att
 use rustc_feature::{GateIssue, Stability};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet};
 use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind};
-use rustc_hir::{HirId, HirIdSet, Node};
+use rustc_hir::{HirId, Node};
 use rustc_index::vec::Idx;
 use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -173,8 +173,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers {
             | hir::ItemKind::Enum(..)
             | hir::ItemKind::Struct(..)
             | hir::ItemKind::Union(..) => {
-                let def_id = cx.tcx.hir().local_def_id(it.hir_id);
-                self.check_heap_type(cx, it.span, cx.tcx.type_of(def_id))
+                self.check_heap_type(cx, it.span, cx.tcx.type_of(it.def_id))
             }
             _ => (),
         }
@@ -328,6 +327,18 @@ impl UnsafeCode {
 
         cx.struct_span_lint(UNSAFE_CODE, span, decorate);
     }
+
+    fn report_overriden_symbol_name(&self, cx: &EarlyContext<'_>, span: Span, msg: &str) {
+        self.report_unsafe(cx, span, |lint| {
+            lint.build(msg)
+                .note(
+                    "the linker's behavior with multiple libraries exporting duplicate symbol \
+                    names is undefined and Rust cannot provide guarantees when you manually \
+                    override them",
+                )
+                .emit();
+        })
+    }
 }
 
 impl EarlyLintPass for UnsafeCode {
@@ -367,6 +378,40 @@ impl EarlyLintPass for UnsafeCode {
                     lint.build("implementation of an `unsafe` trait").emit()
                 }),
 
+            ast::ItemKind::Fn(..) => {
+                if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
+                    self.report_overriden_symbol_name(
+                        cx,
+                        attr.span,
+                        "declaration of a `no_mangle` function",
+                    );
+                }
+                if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
+                    self.report_overriden_symbol_name(
+                        cx,
+                        attr.span,
+                        "declaration of a function with `export_name`",
+                    );
+                }
+            }
+
+            ast::ItemKind::Static(..) => {
+                if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
+                    self.report_overriden_symbol_name(
+                        cx,
+                        attr.span,
+                        "declaration of a `no_mangle` static",
+                    );
+                }
+                if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::export_name) {
+                    self.report_overriden_symbol_name(
+                        cx,
+                        attr.span,
+                        "declaration of a static with `export_name`",
+                    );
+                }
+            }
+
             _ => {}
         }
     }
@@ -539,9 +584,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             hir::ItemKind::Trait(.., trait_item_refs) => {
                 // Issue #11592: traits are always considered exported, even when private.
                 if let hir::VisibilityKind::Inherited = it.vis.node {
-                    self.private_traits.insert(it.hir_id);
+                    self.private_traits.insert(it.hir_id());
                     for trait_item_ref in trait_item_refs {
-                        self.private_traits.insert(trait_item_ref.id.hir_id);
+                        self.private_traits.insert(trait_item_ref.id.hir_id());
                     }
                     return;
                 }
@@ -555,7 +600,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
                     if let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) {
                         if let hir::VisibilityKind::Inherited = item.vis.node {
                             for impl_item_ref in items {
-                                self.private_traits.insert(impl_item_ref.id.hir_id);
+                                self.private_traits.insert(impl_item_ref.id.hir_id());
                             }
                         }
                     }
@@ -575,23 +620,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
             _ => return,
         };
 
-        let def_id = cx.tcx.hir().local_def_id(it.hir_id);
-        let (article, desc) = cx.tcx.article_and_description(def_id.to_def_id());
+        let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
 
-        self.check_missing_docs_attrs(cx, Some(it.hir_id), &it.attrs, it.span, article, desc);
+        self.check_missing_docs_attrs(cx, Some(it.hir_id()), &it.attrs, it.span, article, desc);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
-        if self.private_traits.contains(&trait_item.hir_id) {
+        if self.private_traits.contains(&trait_item.hir_id()) {
             return;
         }
 
-        let def_id = cx.tcx.hir().local_def_id(trait_item.hir_id);
-        let (article, desc) = cx.tcx.article_and_description(def_id.to_def_id());
+        let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
 
         self.check_missing_docs_attrs(
             cx,
-            Some(trait_item.hir_id),
+            Some(trait_item.hir_id()),
             &trait_item.attrs,
             trait_item.span,
             article,
@@ -601,15 +644,14 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
         // If the method is an impl for a trait, don't doc.
-        if method_context(cx, impl_item.hir_id) == MethodLateContext::TraitImpl {
+        if method_context(cx, impl_item.hir_id()) == MethodLateContext::TraitImpl {
             return;
         }
 
-        let def_id = cx.tcx.hir().local_def_id(impl_item.hir_id);
-        let (article, desc) = cx.tcx.article_and_description(def_id.to_def_id());
+        let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
         self.check_missing_docs_attrs(
             cx,
-            Some(impl_item.hir_id),
+            Some(impl_item.hir_id()),
             &impl_item.attrs,
             impl_item.span,
             article,
@@ -618,11 +660,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
-        let def_id = cx.tcx.hir().local_def_id(foreign_item.hir_id);
-        let (article, desc) = cx.tcx.article_and_description(def_id.to_def_id());
+        let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id());
         self.check_missing_docs_attrs(
             cx,
-            Some(foreign_item.hir_id),
+            Some(foreign_item.hir_id()),
             &foreign_item.attrs,
             foreign_item.span,
             article,
@@ -686,7 +727,7 @@ declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS])
 
 impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        if !cx.access_levels.is_reachable(item.hir_id) {
+        if !cx.access_levels.is_reachable(item.hir_id()) {
             return;
         }
         let (def, ty) = match item.kind {
@@ -694,21 +735,21 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
-                let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.hir_id));
+                let def = cx.tcx.adt_def(item.def_id);
                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
             }
             hir::ItemKind::Union(_, ref ast_generics) => {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
-                let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.hir_id));
+                let def = cx.tcx.adt_def(item.def_id);
                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
             }
             hir::ItemKind::Enum(_, ref ast_generics) => {
                 if !ast_generics.params.is_empty() {
                     return;
                 }
-                let def = cx.tcx.adt_def(cx.tcx.hir().local_def_id(item.hir_id));
+                let def = cx.tcx.adt_def(item.def_id);
                 (def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
             }
             _ => return,
@@ -766,14 +807,14 @@ declare_lint! {
 
 #[derive(Default)]
 pub struct MissingDebugImplementations {
-    impling_types: Option<HirIdSet>,
+    impling_types: Option<LocalDefIdSet>,
 }
 
 impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
 
 impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        if !cx.access_levels.is_reachable(item.hir_id) {
+        if !cx.access_levels.is_reachable(item.hir_id()) {
             return;
         }
 
@@ -788,11 +829,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
         };
 
         if self.impling_types.is_none() {
-            let mut impls = HirIdSet::default();
+            let mut impls = LocalDefIdSet::default();
             cx.tcx.for_each_impl(debug, |d| {
                 if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
                     if let Some(def_id) = ty_def.did.as_local() {
-                        impls.insert(cx.tcx.hir().local_def_id_to_hir_id(def_id));
+                        impls.insert(def_id);
                     }
                 }
             });
@@ -801,7 +842,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
             debug!("{:?}", self.impling_types);
         }
 
-        if !self.impling_types.as_ref().unwrap().contains(&item.hir_id) {
+        if !self.impling_types.as_ref().unwrap().contains(&item.def_id) {
             cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| {
                 lint.build(&format!(
                     "type does not implement `{}`; consider adding `#[derive(Debug)]` \
@@ -1316,14 +1357,14 @@ impl UnreachablePub {
 
 impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
-        self.perform_lint(cx, "item", item.hir_id, &item.vis, item.span, true);
+        self.perform_lint(cx, "item", item.hir_id(), &item.vis, item.span, true);
     }
 
     fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
         self.perform_lint(
             cx,
             "item",
-            foreign_item.hir_id,
+            foreign_item.hir_id(),
             &foreign_item.vis,
             foreign_item.span,
             true,
@@ -1335,7 +1376,7 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
-        self.perform_lint(cx, "item", impl_item.hir_id, &impl_item.vis, impl_item.span, false);
+        self.perform_lint(cx, "item", impl_item.hir_id(), &impl_item.vis, impl_item.span, false);
     }
 }
 
@@ -1557,8 +1598,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
         use rustc_middle::ty::PredicateKind::*;
 
         if cx.tcx.features().trivial_bounds {
-            let def_id = cx.tcx.hir().local_def_id(item.hir_id);
-            let predicates = cx.tcx.predicates_of(def_id);
+            let predicates = cx.tcx.predicates_of(item.def_id);
             for &(predicate, span) in predicates.predicates {
                 let predicate_kind_name = match predicate.kind().skip_binder() {
                     Trait(..) => "Trait",
@@ -1764,7 +1804,7 @@ declare_lint! {
 }
 
 pub struct UnnameableTestItems {
-    boundary: Option<hir::HirId>, // HirId of the item under which things are not nameable
+    boundary: Option<LocalDefId>, // Id of the item under which things are not nameable
     items_nameable: bool,
 }
 
@@ -1782,7 +1822,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
             if let hir::ItemKind::Mod(..) = it.kind {
             } else {
                 self.items_nameable = false;
-                self.boundary = Some(it.hir_id);
+                self.boundary = Some(it.def_id);
             }
             return;
         }
@@ -1795,7 +1835,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
     }
 
     fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) {
-        if !self.items_nameable && self.boundary == Some(it.hir_id) {
+        if !self.items_nameable && self.boundary == Some(it.def_id) {
             self.items_nameable = true;
         }
     }
@@ -2079,7 +2119,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
         use rustc_middle::middle::resolve_lifetime::Region;
 
         let infer_static = cx.tcx.features().infer_static_outlives_requirements;
-        let def_id = cx.tcx.hir().local_def_id(item.hir_id);
+        let def_id = item.def_id;
         if let hir::ItemKind::Struct(_, ref hir_generics)
         | hir::ItemKind::Enum(_, ref hir_generics)
         | hir::ItemKind::Union(_, ref hir_generics) = item.kind
@@ -2634,10 +2674,7 @@ impl ClashingExternDeclarations {
     /// Insert a new foreign item into the seen set. If a symbol with the same name already exists
     /// for the item, return its HirId without updating the set.
     fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
-        let hid = fi.hir_id;
-
-        let local_did = tcx.hir().local_def_id(fi.hir_id);
-        let did = local_did.to_def_id();
+        let did = fi.def_id.to_def_id();
         let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
         let name = Symbol::intern(tcx.symbol_name(instance).name);
         if let Some(&hir_id) = self.seen_decls.get(&name) {
@@ -2646,7 +2683,7 @@ impl ClashingExternDeclarations {
             // This lets us avoid emitting "knock-on" diagnostics.
             Some(hir_id)
         } else {
-            self.seen_decls.insert(name, hid)
+            self.seen_decls.insert(name, fi.hir_id())
         }
     }
 
@@ -2654,16 +2691,15 @@ impl ClashingExternDeclarations {
     /// the name specified in a #[link_name = ...] attribute if one was specified, else, just the
     /// symbol's name.
     fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName {
-        let did = tcx.hir().local_def_id(fi.hir_id);
         if let Some((overridden_link_name, overridden_link_name_span)) =
-            tcx.codegen_fn_attrs(did).link_name.map(|overridden_link_name| {
+            tcx.codegen_fn_attrs(fi.def_id).link_name.map(|overridden_link_name| {
                 // FIXME: Instead of searching through the attributes again to get span
                 // information, we could have codegen_fn_attrs also give span information back for
                 // where the attribute was defined. However, until this is found to be a
                 // bottleneck, this does just fine.
                 (
                     overridden_link_name,
-                    tcx.get_attrs(did.to_def_id())
+                    tcx.get_attrs(fi.def_id.to_def_id())
                         .iter()
                         .find(|at| tcx.sess.check_name(at, sym::link_name))
                         .unwrap()
@@ -2891,10 +2927,10 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
             let tcx = cx.tcx;
             if let Some(existing_hid) = self.insert(tcx, this_fi) {
                 let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid));
-                let this_decl_ty = tcx.type_of(tcx.hir().local_def_id(this_fi.hir_id));
+                let this_decl_ty = tcx.type_of(this_fi.def_id);
                 debug!(
                     "ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
-                    existing_hid, existing_decl_ty, this_fi.hir_id, this_decl_ty
+                    existing_hid, existing_decl_ty, this_fi.def_id, this_decl_ty
                 );
                 // Check that the declarations match.
                 if !Self::structurally_same_type(
@@ -2916,7 +2952,7 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
                     // Finally, emit the diagnostic.
                     tcx.struct_span_lint_hir(
                         CLASHING_EXTERN_DECLARATIONS,
-                        this_fi.hir_id,
+                        this_fi.hir_id(),
                         get_relevant_span(this_fi),
                         |lint| {
                             let mut expected_str = DiagnosticStyledString::new();
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 8bd9dad785c..b8db51f590d 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -21,7 +21,9 @@ use crate::passes::{EarlyLintPassObject, LateLintPassObject};
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync;
-use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err, Applicability};
+use rustc_errors::{
+    add_elided_lifetime_in_path_suggestion, struct_span_err, Applicability, SuggestionStyle,
+};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId};
@@ -32,13 +34,15 @@ use rustc_middle::middle::stability;
 use rustc_middle::ty::layout::{LayoutError, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
-use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_serialize::json::Json;
+use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec};
 use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
 use rustc_session::Session;
 use rustc_session::SessionLintStore;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
 use rustc_target::abi::LayoutOf;
+use tracing::debug;
 
 use std::cell::Cell;
 use std::slice;
@@ -336,6 +340,20 @@ impl LintStore {
         }
     }
 
+    /// True if this symbol represents a lint group name.
+    pub fn is_lint_group(&self, lint_name: Symbol) -> bool {
+        debug!(
+            "is_lint_group(lint_name={:?}, lint_groups={:?})",
+            lint_name,
+            self.lint_groups.keys().collect::<Vec<_>>()
+        );
+        let lint_name_str = &*lint_name.as_str();
+        self.lint_groups.contains_key(&lint_name_str) || {
+            let warnings_name_str = crate::WARNINGS.name_lower();
+            lint_name_str == &*warnings_name_str
+        }
+    }
+
     /// Checks the name of a lint for its existence, and whether it was
     /// renamed or removed. Generates a DiagnosticBuilder containing a
     /// warning for renamed and removed lints. This is over both lint
@@ -621,6 +639,33 @@ pub trait LintContext: Sized {
                     db.span_label(span, "ABI should be specified here");
                     db.help(&format!("the default ABI is {}", default_abi.name()));
                 }
+                BuiltinLintDiagnostics::LegacyDeriveHelpers(span) => {
+                    db.span_label(span, "the attribute is introduced here");
+                }
+                BuiltinLintDiagnostics::ExternDepSpec(krate, loc) => {
+                    let json = match loc {
+                        ExternDepSpec::Json(json) => {
+                            db.help(&format!("remove unnecessary dependency `{}`", krate));
+                            json
+                        }
+                        ExternDepSpec::Raw(raw) => {
+                            db.help(&format!("remove unnecessary dependency `{}` at `{}`", krate, raw));
+                            db.span_suggestion_with_style(
+                                DUMMY_SP,
+                                "raw extern location",
+                                raw.clone(),
+                                Applicability::Unspecified,
+                                SuggestionStyle::CompletelyHidden,
+                            );
+                            Json::String(raw)
+                        }
+                    };
+                    db.tool_only_suggestion_with_metadata(
+                        "json extern location",
+                        Applicability::Unspecified,
+                        json
+                    );
+                }
             }
             // Rewrap `db`, and pass control to the user.
             decorate(LintDiagnosticBuilder::new(db));
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 231edf442eb..cc3bf4095fd 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -188,13 +188,6 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         run_early_pass!(self, check_ident, ident);
     }
 
-    fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) {
-        run_early_pass!(self, check_mod, m, s, n);
-        self.check_id(n);
-        ast_visit::walk_mod(self, m);
-        run_early_pass!(self, check_mod_post, m, s, n);
-    }
-
     fn visit_local(&mut self, l: &'a ast::Local) {
         self.with_lint_attrs(l.id, &l.attrs, |cx| {
             run_early_pass!(cx, check_local, l);
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 3821a393efb..e019b621aa3 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -142,8 +142,8 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
         self.context.generics = it.kind.generics();
         let old_cached_typeck_results = self.context.cached_typeck_results.take();
         let old_enclosing_body = self.context.enclosing_body.take();
-        self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
-            cx.with_param_env(it.hir_id, |cx| {
+        self.with_lint_attrs(it.hir_id(), &it.attrs, |cx| {
+            cx.with_param_env(it.hir_id(), |cx| {
                 lint_callback!(cx, check_item, it);
                 hir_visit::walk_item(cx, it);
                 lint_callback!(cx, check_item_post, it);
@@ -155,8 +155,8 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
     }
 
     fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
-        self.with_lint_attrs(it.hir_id, &it.attrs, |cx| {
-            cx.with_param_env(it.hir_id, |cx| {
+        self.with_lint_attrs(it.hir_id(), &it.attrs, |cx| {
+            cx.with_param_env(it.hir_id(), |cx| {
                 lint_callback!(cx, check_foreign_item, it);
                 hir_visit::walk_foreign_item(cx, it);
                 lint_callback!(cx, check_foreign_item_post, it);
@@ -178,7 +178,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
     }
 
     fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
-        let get_item = |id: hir::ItemId| self.context.tcx.hir().item(id.id);
+        let get_item = |id: hir::ItemId| self.context.tcx.hir().item(id);
         let attrs = &s.kind.attrs(get_item);
         // See `EarlyContextAndPass::visit_stmt` for an explanation
         // of why we call `walk_stmt` outside of `with_lint_attrs`
@@ -301,8 +301,8 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         let generics = self.context.generics.take();
         self.context.generics = Some(&trait_item.generics);
-        self.with_lint_attrs(trait_item.hir_id, &trait_item.attrs, |cx| {
-            cx.with_param_env(trait_item.hir_id, |cx| {
+        self.with_lint_attrs(trait_item.hir_id(), &trait_item.attrs, |cx| {
+            cx.with_param_env(trait_item.hir_id(), |cx| {
                 lint_callback!(cx, check_trait_item, trait_item);
                 hir_visit::walk_trait_item(cx, trait_item);
                 lint_callback!(cx, check_trait_item_post, trait_item);
@@ -314,8 +314,8 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         let generics = self.context.generics.take();
         self.context.generics = Some(&impl_item.generics);
-        self.with_lint_attrs(impl_item.hir_id, &impl_item.attrs, |cx| {
-            cx.with_param_env(impl_item.hir_id, |cx| {
+        self.with_lint_attrs(impl_item.hir_id(), &impl_item.attrs, |cx| {
+            cx.with_param_env(impl_item.hir_id(), |cx| {
                 lint_callback!(cx, check_impl_item, impl_item);
                 hir_visit::walk_impl_item(cx, impl_item);
                 lint_callback!(cx, check_impl_item_post, impl_item);
@@ -496,7 +496,7 @@ pub fn check_crate<'tcx, T: LateLintPass<'tcx>>(
             tcx.sess.time("module_lints", || {
                 // Run per-module lints
                 par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
-                    tcx.ensure().lint_mod(tcx.hir().local_def_id(module));
+                    tcx.ensure().lint_mod(module);
                 });
             });
         },
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 18cd25e5d2a..cc5b7ef0987 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -5,7 +5,7 @@ use rustc_ast::attr;
 use rustc_ast::unwrap_or;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{struct_span_err, Applicability};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_hir::{intravisit, HirId};
@@ -17,11 +17,15 @@ use rustc_middle::lint::{
 };
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::lint::{builtin, Level, Lint, LintId};
+use rustc_session::lint::{
+    builtin::{self, FORBIDDEN_LINT_GROUPS},
+    Level, Lint, LintId,
+};
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP};
+use tracing::debug;
 
 use std::cmp;
 
@@ -37,7 +41,7 @@ fn lint_levels(tcx: TyCtxt<'_>, cnum: CrateNum) -> LintLevelMap {
     let push = builder.levels.push(&krate.item.attrs, &store, true);
     builder.levels.register_id(hir::CRATE_HIR_ID);
     for macro_def in krate.exported_macros {
-        builder.levels.register_id(macro_def.hir_id);
+        builder.levels.register_id(macro_def.hir_id());
     }
     intravisit::walk_crate(&mut builder, krate);
     builder.levels.pop(push);
@@ -51,6 +55,7 @@ pub struct LintLevelsBuilder<'s> {
     id_to_set: FxHashMap<HirId, u32>,
     cur: u32,
     warn_about_weird_lints: bool,
+    store: &'s LintStore,
 }
 
 pub struct BuilderPush {
@@ -59,13 +64,14 @@ pub struct BuilderPush {
 }
 
 impl<'s> LintLevelsBuilder<'s> {
-    pub fn new(sess: &'s Session, warn_about_weird_lints: bool, store: &LintStore) -> Self {
+    pub fn new(sess: &'s Session, warn_about_weird_lints: bool, store: &'s LintStore) -> Self {
         let mut builder = LintLevelsBuilder {
             sess,
             sets: LintLevelSets::new(),
             cur: 0,
             id_to_set: Default::default(),
             warn_about_weird_lints,
+            store,
         };
         builder.process_command_line(sess, store);
         assert_eq!(builder.sets.list.len(), 1);
@@ -120,36 +126,75 @@ impl<'s> LintLevelsBuilder<'s> {
             if let (Level::Forbid, old_src) =
                 self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess)
             {
-                let mut diag_builder = struct_span_err!(
-                    self.sess,
-                    src.span(),
-                    E0453,
-                    "{}({}) incompatible with previous forbid",
-                    level.as_str(),
-                    src.name(),
+                // Backwards compatibility check:
+                //
+                // We used to not consider `forbid(lint_group)`
+                // as preventing `allow(lint)` for some lint `lint` in
+                // `lint_group`. For now, issue a future-compatibility
+                // warning for this case.
+                let id_name = id.lint.name_lower();
+                let fcw_warning = match old_src {
+                    LintLevelSource::Default => false,
+                    LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol),
+                    LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
+                };
+                debug!(
+                    "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
+                    fcw_warning, specs, old_src, id_name
                 );
-                diag_builder.span_label(src.span(), "overruled by previous forbid");
-                match old_src {
-                    LintLevelSource::Default => {
-                        diag_builder.note(&format!(
-                            "`forbid` lint level is the default for {}",
-                            id.to_string()
-                        ));
-                    }
-                    LintLevelSource::Node(_, forbid_source_span, reason) => {
-                        diag_builder.span_label(forbid_source_span, "`forbid` level set here");
-                        if let Some(rationale) = reason {
-                            diag_builder.note(&rationale.as_str());
+
+                let decorate_diag_builder = |mut diag_builder: DiagnosticBuilder<'_>| {
+                    diag_builder.span_label(src.span(), "overruled by previous forbid");
+                    match old_src {
+                        LintLevelSource::Default => {
+                            diag_builder.note(&format!(
+                                "`forbid` lint level is the default for {}",
+                                id.to_string()
+                            ));
+                        }
+                        LintLevelSource::Node(_, forbid_source_span, reason) => {
+                            diag_builder.span_label(forbid_source_span, "`forbid` level set here");
+                            if let Some(rationale) = reason {
+                                diag_builder.note(&rationale.as_str());
+                            }
+                        }
+                        LintLevelSource::CommandLine(_, _) => {
+                            diag_builder.note("`forbid` lint level was set on command line");
                         }
                     }
-                    LintLevelSource::CommandLine(_, _) => {
-                        diag_builder.note("`forbid` lint level was set on command line");
-                    }
+                    diag_builder.emit();
+                };
+                if !fcw_warning {
+                    let diag_builder = struct_span_err!(
+                        self.sess,
+                        src.span(),
+                        E0453,
+                        "{}({}) incompatible with previous forbid",
+                        level.as_str(),
+                        src.name(),
+                    );
+                    decorate_diag_builder(diag_builder);
+                } else {
+                    self.struct_lint(
+                        FORBIDDEN_LINT_GROUPS,
+                        Some(src.span().into()),
+                        |diag_builder| {
+                            let diag_builder = diag_builder.build(&format!(
+                                "{}({}) incompatible with previous forbid",
+                                level.as_str(),
+                                src.name(),
+                            ));
+                            decorate_diag_builder(diag_builder);
+                        },
+                    );
                 }
-                diag_builder.emit();
 
-                // Retain the forbid lint level
-                return;
+                // Retain the forbid lint level, unless we are
+                // issuing a FCW. In the FCW case, we want to
+                // respect the new setting.
+                if !fcw_warning {
+                    return;
+                }
             }
         }
         specs.insert(id, (level, src));
@@ -532,13 +577,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> {
     }
 
     fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
-        self.with_lint_attrs(it.hir_id, &it.attrs, |builder| {
+        self.with_lint_attrs(it.hir_id(), &it.attrs, |builder| {
             intravisit::walk_item(builder, it);
         });
     }
 
     fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {
-        self.with_lint_attrs(it.hir_id, &it.attrs, |builder| {
+        self.with_lint_attrs(it.hir_id(), &it.attrs, |builder| {
             intravisit::walk_foreign_item(builder, it);
         })
     }
@@ -586,13 +631,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> {
     }
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
-        self.with_lint_attrs(trait_item.hir_id, &trait_item.attrs, |builder| {
+        self.with_lint_attrs(trait_item.hir_id(), &trait_item.attrs, |builder| {
             intravisit::walk_trait_item(builder, trait_item);
         });
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
-        self.with_lint_attrs(impl_item.hir_id, &impl_item.attrs, |builder| {
+        self.with_lint_attrs(impl_item.hir_id(), &impl_item.attrs, |builder| {
             intravisit::walk_impl_item(builder, impl_item);
         });
     }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 6f44436e2a0..638b73c27a8 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -55,8 +55,8 @@ mod late;
 mod levels;
 mod methods;
 mod non_ascii_idents;
+mod non_fmt_panic;
 mod nonstandard_style;
-mod panic_fmt;
 mod passes;
 mod redundant_semicolon;
 mod traits;
@@ -81,8 +81,8 @@ use builtin::*;
 use internal::*;
 use methods::*;
 use non_ascii_idents::*;
+use non_fmt_panic::NonPanicFmt;
 use nonstandard_style::*;
-use panic_fmt::PanicFmt;
 use redundant_semicolon::*;
 use traits::*;
 use types::*;
@@ -169,7 +169,7 @@ macro_rules! late_lint_passes {
                 ClashingExternDeclarations: ClashingExternDeclarations::new(),
                 DropTraitConstraints: DropTraitConstraints,
                 TemporaryCStringAsPtr: TemporaryCStringAsPtr,
-                PanicFmt: PanicFmt,
+                NonPanicFmt: NonPanicFmt,
             ]
         );
     };
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
new file mode 100644
index 00000000000..e98297b692c
--- /dev/null
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -0,0 +1,197 @@
+use crate::{LateContext, LateLintPass, LintContext};
+use rustc_ast as ast;
+use rustc_errors::{pluralize, Applicability};
+use rustc_hir as hir;
+use rustc_middle::ty;
+use rustc_parse_format::{ParseMode, Parser, Piece};
+use rustc_span::{sym, symbol::kw, InnerSpan, Span, Symbol};
+
+declare_lint! {
+    /// The `non_fmt_panic` lint detects `panic!(..)` invocations where the first
+    /// argument is not a formatting string.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,no_run
+    /// panic!("{}");
+    /// panic!(123);
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In Rust 2018 and earlier, `panic!(x)` directly uses `x` as the message.
+    /// That means that `panic!("{}")` panics with the message `"{}"` instead
+    /// of using it as a formatting string, and `panic!(123)` will panic with
+    /// an `i32` as message.
+    ///
+    /// Rust 2021 always interprets the first argument as format string.
+    NON_FMT_PANIC,
+    Warn,
+    "detect single-argument panic!() invocations in which the argument is not a format string",
+    report_in_external_macro
+}
+
+declare_lint_pass!(NonPanicFmt => [NON_FMT_PANIC]);
+
+impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+        if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
+            if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
+                if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
+                    || Some(def_id) == cx.tcx.lang_items().panic_fn()
+                    || Some(def_id) == cx.tcx.lang_items().panic_str()
+                {
+                    if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
+                        if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id)
+                            || cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id)
+                        {
+                            check_panic(cx, f, arg);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) {
+    if let hir::ExprKind::Lit(lit) = &arg.kind {
+        if let ast::LitKind::Str(sym, _) = lit.node {
+            // The argument is a string literal.
+            check_panic_str(cx, f, arg, &sym.as_str());
+            return;
+        }
+    }
+
+    // The argument is *not* a string literal.
+
+    let (span, panic) = panic_call(cx, f);
+
+    cx.struct_span_lint(NON_FMT_PANIC, arg.span, |lint| {
+        let mut l = lint.build("panic message is not a string literal");
+        l.note("this is no longer accepted in Rust 2021");
+        if span.contains(arg.span) {
+            l.span_suggestion_verbose(
+                arg.span.shrink_to_lo(),
+                "add a \"{}\" format string to Display the message",
+                "\"{}\", ".into(),
+                Applicability::MaybeIncorrect,
+            );
+            if panic == sym::std_panic_macro {
+                l.span_suggestion_verbose(
+                    span.until(arg.span),
+                    "or use std::panic::panic_any instead",
+                    "std::panic::panic_any(".into(),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+        l.emit();
+    });
+}
+
+fn check_panic_str<'tcx>(
+    cx: &LateContext<'tcx>,
+    f: &'tcx hir::Expr<'tcx>,
+    arg: &'tcx hir::Expr<'tcx>,
+    fmt: &str,
+) {
+    if !fmt.contains(&['{', '}'][..]) {
+        // No brace, no problem.
+        return;
+    }
+
+    let fmt_span = arg.span.source_callsite();
+
+    let (snippet, style) = match cx.sess().parse_sess.source_map().span_to_snippet(fmt_span) {
+        Ok(snippet) => {
+            // Count the number of `#`s between the `r` and `"`.
+            let style = snippet.strip_prefix('r').and_then(|s| s.find('"'));
+            (Some(snippet), style)
+        }
+        Err(_) => (None, None),
+    };
+
+    let mut fmt_parser =
+        Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format);
+    let n_arguments = (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count();
+
+    let (span, _) = panic_call(cx, f);
+
+    if n_arguments > 0 && fmt_parser.errors.is_empty() {
+        let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
+            [] => vec![fmt_span],
+            v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
+        };
+        cx.struct_span_lint(NON_FMT_PANIC, arg_spans, |lint| {
+            let mut l = lint.build(match n_arguments {
+                1 => "panic message contains an unused formatting placeholder",
+                _ => "panic message contains unused formatting placeholders",
+            });
+            l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021");
+            if span.contains(arg.span) {
+                l.span_suggestion(
+                    arg.span.shrink_to_hi(),
+                    &format!("add the missing argument{}", pluralize!(n_arguments)),
+                    ", ...".into(),
+                    Applicability::HasPlaceholders,
+                );
+                l.span_suggestion(
+                    arg.span.shrink_to_lo(),
+                    "or add a \"{}\" format string to use the message literally",
+                    "\"{}\", ".into(),
+                    Applicability::MachineApplicable,
+                );
+            }
+            l.emit();
+        });
+    } else {
+        let brace_spans: Option<Vec<_>> =
+            snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| {
+                s.char_indices()
+                    .filter(|&(_, c)| c == '{' || c == '}')
+                    .map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 }))
+                    .collect()
+            });
+        let msg = match &brace_spans {
+            Some(v) if v.len() == 1 => "panic message contains a brace",
+            _ => "panic message contains braces",
+        };
+        cx.struct_span_lint(NON_FMT_PANIC, brace_spans.unwrap_or(vec![span]), |lint| {
+            let mut l = lint.build(msg);
+            l.note("this message is not used as a format string, but will be in Rust 2021");
+            if span.contains(arg.span) {
+                l.span_suggestion(
+                    arg.span.shrink_to_lo(),
+                    "add a \"{}\" format string to use the message literally",
+                    "\"{}\", ".into(),
+                    Applicability::MachineApplicable,
+                );
+            }
+            l.emit();
+        });
+    }
+}
+
+fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, Symbol) {
+    let mut expn = f.span.ctxt().outer_expn_data();
+
+    let mut panic_macro = kw::Empty;
+
+    // Unwrap more levels of macro expansion, as panic_2015!()
+    // was likely expanded from panic!() and possibly from
+    // [debug_]assert!().
+    for &i in
+        &[sym::std_panic_macro, sym::core_panic_macro, sym::assert_macro, sym::debug_assert_macro]
+    {
+        let parent = expn.call_site.ctxt().outer_expn_data();
+        if parent.macro_def_id.map_or(false, |id| cx.tcx.is_diagnostic_item(i, id)) {
+            expn = parent;
+            panic_macro = i;
+        }
+    }
+
+    (expn.call_site, panic_macro)
+}
diff --git a/compiler/rustc_lint/src/panic_fmt.rs b/compiler/rustc_lint/src/panic_fmt.rs
deleted file mode 100644
index 4a6aca72acb..00000000000
--- a/compiler/rustc_lint/src/panic_fmt.rs
+++ /dev/null
@@ -1,155 +0,0 @@
-use crate::{LateContext, LateLintPass, LintContext};
-use rustc_ast as ast;
-use rustc_errors::{pluralize, Applicability};
-use rustc_hir as hir;
-use rustc_middle::ty;
-use rustc_parse_format::{ParseMode, Parser, Piece};
-use rustc_span::{sym, InnerSpan};
-
-declare_lint! {
-    /// The `panic_fmt` lint detects `panic!("..")` with `{` or `}` in the string literal.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,no_run
-    /// panic!("{}");
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// In Rust 2018 and earlier, `panic!("{}")` panics with the message `"{}"`,
-    /// as a `panic!()` invocation with a single argument does not use `format_args!()`.
-    /// Rust 2021 interprets this string as format string, which breaks this.
-    PANIC_FMT,
-    Warn,
-    "detect braces in single-argument panic!() invocations",
-    report_in_external_macro
-}
-
-declare_lint_pass!(PanicFmt => [PANIC_FMT]);
-
-impl<'tcx> LateLintPass<'tcx> for PanicFmt {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
-        if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
-            if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
-                if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
-                    || Some(def_id) == cx.tcx.lang_items().panic_fn()
-                {
-                    check_panic(cx, f, arg);
-                }
-            }
-        }
-    }
-}
-
-fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) {
-    if let hir::ExprKind::Lit(lit) = &arg.kind {
-        if let ast::LitKind::Str(sym, _) = lit.node {
-            let mut expn = f.span.ctxt().outer_expn_data();
-            if let Some(id) = expn.macro_def_id {
-                if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id)
-                    || cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id)
-                {
-                    let fmt = sym.as_str();
-                    if !fmt.contains(&['{', '}'][..]) {
-                        return;
-                    }
-
-                    let fmt_span = arg.span.source_callsite();
-
-                    let (snippet, style) =
-                        match cx.sess().parse_sess.source_map().span_to_snippet(fmt_span) {
-                            Ok(snippet) => {
-                                // Count the number of `#`s between the `r` and `"`.
-                                let style = snippet.strip_prefix('r').and_then(|s| s.find('"'));
-                                (Some(snippet), style)
-                            }
-                            Err(_) => (None, None),
-                        };
-
-                    let mut fmt_parser =
-                        Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format);
-                    let n_arguments =
-                        (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count();
-
-                    // Unwrap more levels of macro expansion, as panic_2015!()
-                    // was likely expanded from panic!() and possibly from
-                    // [debug_]assert!().
-                    for &assert in &[
-                        sym::std_panic_macro,
-                        sym::core_panic_macro,
-                        sym::assert_macro,
-                        sym::debug_assert_macro,
-                    ] {
-                        let parent = expn.call_site.ctxt().outer_expn_data();
-                        if parent
-                            .macro_def_id
-                            .map_or(false, |id| cx.tcx.is_diagnostic_item(assert, id))
-                        {
-                            expn = parent;
-                        }
-                    }
-
-                    if n_arguments > 0 && fmt_parser.errors.is_empty() {
-                        let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
-                            [] => vec![fmt_span],
-                            v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
-                        };
-                        cx.struct_span_lint(PANIC_FMT, arg_spans, |lint| {
-                            let mut l = lint.build(match n_arguments {
-                                1 => "panic message contains an unused formatting placeholder",
-                                _ => "panic message contains unused formatting placeholders",
-                            });
-                            l.note("this message is not used as a format string when given without arguments, but will be in a future Rust edition");
-                            if expn.call_site.contains(arg.span) {
-                                l.span_suggestion(
-                                    arg.span.shrink_to_hi(),
-                                    &format!("add the missing argument{}", pluralize!(n_arguments)),
-                                    ", ...".into(),
-                                    Applicability::HasPlaceholders,
-                                );
-                                l.span_suggestion(
-                                    arg.span.shrink_to_lo(),
-                                    "or add a \"{}\" format string to use the message literally",
-                                    "\"{}\", ".into(),
-                                    Applicability::MachineApplicable,
-                                );
-                            }
-                            l.emit();
-                        });
-                    } else {
-                        let brace_spans: Option<Vec<_>> = snippet
-                            .filter(|s| s.starts_with('"') || s.starts_with("r#"))
-                            .map(|s| {
-                                s.char_indices()
-                                    .filter(|&(_, c)| c == '{' || c == '}')
-                                    .map(|(i, _)| {
-                                        fmt_span.from_inner(InnerSpan { start: i, end: i + 1 })
-                                    })
-                                    .collect()
-                            });
-                        let msg = match &brace_spans {
-                            Some(v) if v.len() == 1 => "panic message contains a brace",
-                            _ => "panic message contains braces",
-                        };
-                        cx.struct_span_lint(PANIC_FMT, brace_spans.unwrap_or(vec![expn.call_site]), |lint| {
-                            let mut l = lint.build(msg);
-                            l.note("this message is not used as a format string, but will be in a future Rust edition");
-                            if expn.call_site.contains(arg.span) {
-                                l.span_suggestion(
-                                    arg.span.shrink_to_lo(),
-                                    "add a \"{}\" format string to use the message literally",
-                                    "\"{}\", ".into(),
-                                    Applicability::MachineApplicable,
-                                );
-                            }
-                            l.emit();
-                        });
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index 828f283d2a9..ffbed3a0aff 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -160,8 +160,6 @@ macro_rules! early_lint_methods {
             fn check_ident(a: Ident);
             fn check_crate(a: &ast::Crate);
             fn check_crate_post(a: &ast::Crate);
-            fn check_mod(a: &ast::Mod, b: Span, c: ast::NodeId);
-            fn check_mod_post(a: &ast::Mod, b: Span, c: ast::NodeId);
             fn check_foreign_item(a: &ast::ForeignItem);
             fn check_foreign_item_post(a: &ast::ForeignItem);
             fn check_item(a: &ast::Item);
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index b031c1108c6..e632f29e672 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -47,8 +47,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
         use rustc_middle::ty::PredicateKind::*;
 
-        let def_id = cx.tcx.hir().local_def_id(item.hir_id);
-        let predicates = cx.tcx.explicit_predicates_of(def_id);
+        let predicates = cx.tcx.explicit_predicates_of(item.def_id);
         for &(predicate, span) in predicates.predicates {
             let trait_predicate = match predicate.kind().skip_binder() {
                 Trait(trait_predicate, _constness) => trait_predicate,
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 1e879d29370..792655ff35a 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -225,7 +225,7 @@ fn report_bin_hex_error(
                 (t.name_str(), actually.to_string())
             }
         };
-        let mut err = lint.build(&format!("literal out of range for {}", t));
+        let mut err = lint.build(&format!("literal out of range for `{}`", t));
         err.note(&format!(
             "the literal `{}` (decimal `{}`) does not fit into \
              the type `{}` and will become `{}{}`",
@@ -238,12 +238,12 @@ fn report_bin_hex_error(
                 let (sans_suffix, _) = repr_str.split_at(pos);
                 err.span_suggestion(
                     expr.span,
-                    &format!("consider using `{}` instead", sugg_ty),
+                    &format!("consider using the type `{}` instead", sugg_ty),
                     format!("{}{}", sans_suffix, sugg_ty),
                     Applicability::MachineApplicable,
                 );
             } else {
-                err.help(&format!("consider using `{}` instead", sugg_ty));
+                err.help(&format!("consider using the type `{}` instead", sugg_ty));
             }
         }
         err.emit();
@@ -338,18 +338,23 @@ fn lint_int_literal<'tcx>(
         }
 
         cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
-            lint.build(&format!("literal out of range for `{}`", t.name_str()))
-                .note(&format!(
-                    "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`",
-                    cx.sess()
-                        .source_map()
-                        .span_to_snippet(lit.span)
-                        .expect("must get snippet from literal"),
-                    t.name_str(),
-                    min,
-                    max,
-                ))
-                .emit();
+            let mut err = lint.build(&format!("literal out of range for `{}`", t.name_str()));
+            err.note(&format!(
+                "the literal `{}` does not fit into the type `{}` whose range is `{}..={}`",
+                cx.sess()
+                    .source_map()
+                    .span_to_snippet(lit.span)
+                    .expect("must get snippet from literal"),
+                t.name_str(),
+                min,
+                max,
+            ));
+            if let Some(sugg_ty) =
+                get_type_suggestion(&cx.typeck_results().node_type(e.hir_id), v, negative)
+            {
+                err.help(&format!("consider using the type `{}` instead", sugg_ty));
+            }
+            err.emit();
         });
     }
 }
@@ -472,7 +477,7 @@ fn lint_literal<'tcx>(
 impl<'tcx> LateLintPass<'tcx> for TypeLimits {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
         match e.kind {
-            hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => {
+            hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => {
                 // propagate negation, if the negation itself isn't negated
                 if self.negated_expr_id != Some(e.hir_id) {
                     self.negated_expr_id = Some(expr.hir_id);
@@ -672,7 +677,7 @@ pub fn transparent_newtype_field<'a, 'tcx>(
 }
 
 /// Is type known to be non-null?
-crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
+fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
     let tcx = cx.tcx;
     match ty.kind() {
         ty::FnPtr(_) => true,
@@ -685,6 +690,12 @@ crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: C
                 return true;
             }
 
+            // Types with a `#[repr(no_niche)]` attribute have their niche hidden.
+            // The attribute is used by the UnsafeCell for example (the only use so far).
+            if def.repr.hide_niche() {
+                return false;
+            }
+
             for variant in &def.variants {
                 if let Some(field) = transparent_newtype_field(cx.tcx, variant) {
                     if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) {
@@ -1256,15 +1267,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations {
     fn check_foreign_item(&mut self, cx: &LateContext<'_>, it: &hir::ForeignItem<'_>) {
         let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Declaration };
-        let abi = cx.tcx.hir().get_foreign_abi(it.hir_id);
+        let abi = cx.tcx.hir().get_foreign_abi(it.hir_id());
 
         if !vis.is_internal_abi(abi) {
             match it.kind {
                 hir::ForeignItemKind::Fn(ref decl, _, _) => {
-                    vis.check_foreign_fn(it.hir_id, decl);
+                    vis.check_foreign_fn(it.hir_id(), decl);
                 }
                 hir::ForeignItemKind::Static(ref ty, _) => {
-                    vis.check_foreign_static(it.hir_id, ty.span);
+                    vis.check_foreign_static(it.hir_id(), ty.span);
                 }
                 hir::ForeignItemKind::Type => (),
             }
@@ -1302,8 +1313,7 @@ declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]);
 impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
     fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
         if let hir::ItemKind::Enum(ref enum_definition, _) = it.kind {
-            let item_def_id = cx.tcx.hir().local_def_id(it.hir_id);
-            let t = cx.tcx.type_of(item_def_id);
+            let t = cx.tcx.type_of(it.def_id);
             let ty = cx.tcx.erase_regions(t);
             let layout = match cx.layout_of(ty) {
                 Ok(layout) => layout,
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 43376003840..686d09dd7fc 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -1,4 +1,5 @@
 // ignore-tidy-filelength
+
 //! Some lints that are built in to the compiler.
 //!
 //! These are the built-in lints that are emitted direct in the main
@@ -10,6 +11,42 @@ use rustc_span::edition::Edition;
 use rustc_span::symbol::sym;
 
 declare_lint! {
+    /// The `forbidden_lint_groups` lint detects violations of
+    /// `forbid` applied to a lint group. Due to a bug in the compiler,
+    /// these used to be overlooked entirely. They now generate a warning.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![forbid(warnings)]
+    /// #![deny(bad_style)]
+    ///
+    /// fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Recommended fix
+    ///
+    /// If your crate is using `#![forbid(warnings)]`,
+    /// we recommend that you change to `#![deny(warnings)]`.
+    ///
+    /// ### Explanation
+    ///
+    /// Due to a compiler bug, applying `forbid` to lint groups
+    /// previously had no effect. The bug is now fixed but instead of
+    /// enforcing `forbid` we issue this future-compatibility warning
+    /// to avoid breaking existing crates.
+    pub FORBIDDEN_LINT_GROUPS,
+    Warn,
+    "applying forbid to lint-groups",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #81670 <https://github.com/rust-lang/rust/issues/81670>",
+        edition: None,
+    };
+}
+
+declare_lint! {
     /// The `ill_formed_attribute_input` lint detects ill-formed attribute
     /// inputs that were previously accepted and used in practice.
     ///
@@ -1777,14 +1814,12 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `irrefutable_let_patterns` lint detects detects [irrefutable
-    /// patterns] in [if-let] and [while-let] statements.
-    ///
-    ///
+    /// The `irrefutable_let_patterns` lint detects [irrefutable patterns]
+    /// in [`if let`]s, [`while let`]s, and `if let` guards.
     ///
     /// ### Example
     ///
-    /// ```rust
+    /// ```
     /// if let _ = 123 {
     ///     println!("always runs!");
     /// }
@@ -1795,7 +1830,7 @@ declare_lint! {
     /// ### Explanation
     ///
     /// There usually isn't a reason to have an irrefutable pattern in an
-    /// if-let or while-let statement, because the pattern will always match
+    /// `if let` or `while let` statement, because the pattern will always match
     /// successfully. A [`let`] or [`loop`] statement will suffice. However,
     /// when generating code with a macro, forbidding irrefutable patterns
     /// would require awkward workarounds in situations where the macro
@@ -1806,14 +1841,14 @@ declare_lint! {
     /// See [RFC 2086] for more details.
     ///
     /// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability
-    /// [if-let]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
-    /// [while-let]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
+    /// [`if let`]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
+    /// [`while let`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
     /// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements
     /// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops
     /// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md
     pub IRREFUTABLE_LET_PATTERNS,
     Warn,
-    "detects irrefutable patterns in if-let and while-let statements"
+    "detects irrefutable patterns in `if let` and `while let` statements"
 }
 
 declare_lint! {
@@ -2884,10 +2919,57 @@ declare_lint! {
     };
 }
 
+declare_lint! {
+    /// The `legacy_derive_helpers` lint detects derive helper attributes
+    /// that are used before they are introduced.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs extern crate)
+    /// #[serde(rename_all = "camelCase")]
+    /// #[derive(Deserialize)]
+    /// struct S { /* fields */ }
+    /// ```
+    ///
+    /// produces:
+    ///
+    /// ```text
+    /// warning: derive helper attribute is used before it is introduced
+    ///   --> $DIR/legacy-derive-helpers.rs:1:3
+    ///    |
+    ///  1 | #[serde(rename_all = "camelCase")]
+    ///    |   ^^^^^
+    /// ...
+    ///  2 | #[derive(Deserialize)]
+    ///    |          ----------- the attribute is introduced here
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Attributes like this work for historical reasons, but attribute expansion works in
+    /// left-to-right order in general, so, to resolve `#[serde]`, compiler has to try to "look
+    /// into the future" at not yet expanded part of the item , but such attempts are not always
+    /// reliable.
+    ///
+    /// To fix the warning place the helper attribute after its corresponding derive.
+    /// ```rust,ignore (needs extern crate)
+    /// #[derive(Deserialize)]
+    /// #[serde(rename_all = "camelCase")]
+    /// struct S { /* fields */ }
+    /// ```
+    pub LEGACY_DERIVE_HELPERS,
+    Warn,
+    "detects derive helper attributes that are used before they are introduced",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #79202 <https://github.com/rust-lang/rust/issues/79202>",
+    };
+}
+
 declare_lint_pass! {
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// that are used by other parts of the compiler.
     HardwiredLints => [
+        FORBIDDEN_LINT_GROUPS,
         ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
         ARITHMETIC_OVERFLOW,
         UNCONDITIONAL_PANIC,
@@ -2973,6 +3055,7 @@ declare_lint_pass! {
         MISSING_ABI,
         SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
         DISJOINT_CAPTURE_DROP_REORDER,
+        LEGACY_DERIVE_HELPERS,
     ]
 }
 
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 9d60a51a0af..4c7d3f6c8c0 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -4,6 +4,7 @@ extern crate rustc_macros;
 pub use self::Level::*;
 use rustc_ast::node_id::{NodeId, NodeMap};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_serialize::json::Json;
 use rustc_span::edition::Edition;
 use rustc_span::{sym, symbol::Ident, MultiSpan, Span, Symbol};
 use rustc_target::spec::abi::Abi;
@@ -239,6 +240,13 @@ impl<HCX> ToStableHashKey<HCX> for LintId {
     }
 }
 
+// Duplicated from rustc_session::config::ExternDepSpec to avoid cyclic dependency
+#[derive(PartialEq)]
+pub enum ExternDepSpec {
+    Json(Json),
+    Raw(String),
+}
+
 // This could be a closure, but then implementing derive trait
 // becomes hacky (and it gets allocated).
 #[derive(PartialEq)]
@@ -256,6 +264,8 @@ pub enum BuiltinLintDiagnostics {
     MissingAbi(Span, Abi),
     UnusedDocComment(Span),
     PatternsInFnsWithoutBody(Span, Ident),
+    LegacyDeriveHelpers(Span),
+    ExternDepSpec(String, ExternDepSpec),
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
index 57b8664d3b6..0e3bf5615af 100644
--- a/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
+++ b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
@@ -85,6 +85,7 @@ enum LLVMRustAttribute {
   ReturnsTwice = 25,
   ReadNone = 26,
   InaccessibleMemOnly = 27,
+  SanitizeHWAddress = 28,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 2264908995b..5263d5dcf3e 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -33,6 +33,7 @@
 #include "llvm/Support/TimeProfiler.h"
 #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
 #include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
+#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
 #include "llvm/Transforms/Utils/CanonicalizeAliases.h"
 #include "llvm/Transforms/Utils/NameAnonGlobals.h"
 
@@ -133,6 +134,12 @@ extern "C" LLVMPassRef LLVMRustCreateThreadSanitizerPass() {
   return wrap(createThreadSanitizerLegacyPassPass());
 }
 
+extern "C" LLVMPassRef LLVMRustCreateHWAddressSanitizerPass(bool Recover) {
+  const bool CompileKernel = false;
+
+  return wrap(createHWAddressSanitizerLegacyPassPass(CompileKernel, Recover));
+}
+
 extern "C" LLVMRustPassKind LLVMRustPassKind(LLVMPassRef RustPass) {
   assert(RustPass);
   Pass *Pass = unwrap(RustPass);
@@ -722,6 +729,8 @@ struct LLVMRustSanitizerOptions {
   bool SanitizeMemoryRecover;
   int  SanitizeMemoryTrackOrigins;
   bool SanitizeThread;
+  bool SanitizeHWAddress;
+  bool SanitizeHWAddressRecover;
 };
 
 extern "C" void
@@ -888,6 +897,23 @@ LLVMRustOptimizeWithNewPassManager(
       );
 #endif
     }
+    if (SanitizerOptions->SanitizeHWAddress) {
+#if LLVM_VERSION_GE(11, 0)
+      OptimizerLastEPCallbacks.push_back(
+        [SanitizerOptions](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) {
+          MPM.addPass(HWAddressSanitizerPass(
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
+        }
+      );
+#else
+      PipelineStartEPCallbacks.push_back(
+        [SanitizerOptions](ModulePassManager &MPM) {
+          MPM.addPass(HWAddressSanitizerPass(
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
+        }
+      );
+#endif
+    }
   }
 
   ModulePassManager MPM(DebugPassManager);
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 4118e930745..45835990cec 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -205,6 +205,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::ReadNone;
   case InaccessibleMemOnly:
     return Attribute::InaccessibleMemOnly;
+  case SanitizeHWAddress:
+    return Attribute::SanitizeHWAddress;
   }
   report_fatal_error("bad AttributeKind");
 }
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index cff8e983318..3e67525567f 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -97,7 +97,7 @@ impl Parse for QueryModifier {
             Ok(QueryModifier::Cache(args, block))
         } else if modifier == "load_cached" {
             // Parse a load_cached modifier like:
-            // `load_cached(tcx, id) { tcx.queries.on_disk_cache.try_load_query_result(tcx, id) }`
+            // `load_cached(tcx, id) { tcx.on_disk_cache.try_load_query_result(tcx, id) }`
             let args;
             parenthesized!(args in input);
             let tcx = args.parse()?;
@@ -344,7 +344,6 @@ fn add_query_description_impl(
     impls: &mut proc_macro2::TokenStream,
 ) {
     let name = &query.name;
-    let arg = &query.arg;
     let key = &query.key.0;
 
     // Find out if we should cache the query on disk
@@ -354,7 +353,7 @@ fn add_query_description_impl(
             quote! {
                 #[inline]
                 fn try_load_from_disk(
-                    #tcx: TyCtxt<'tcx>,
+                    #tcx: QueryCtxt<'tcx>,
                     #id: SerializedDepNodeIndex
                 ) -> Option<Self::Value> {
                     #block
@@ -365,10 +364,10 @@ fn add_query_description_impl(
             quote! {
                 #[inline]
                 fn try_load_from_disk(
-                    tcx: TyCtxt<'tcx>,
+                    tcx: QueryCtxt<'tcx>,
                     id: SerializedDepNodeIndex
                 ) -> Option<Self::Value> {
-                    tcx.queries.on_disk_cache.as_ref().and_then(|c| c.try_load_query_result(tcx, id))
+                    tcx.on_disk_cache.as_ref()?.try_load_query_result(*tcx, id)
                 }
             }
         };
@@ -393,7 +392,7 @@ fn add_query_description_impl(
             #[inline]
             #[allow(unused_variables, unused_braces)]
             fn cache_on_disk(
-                #tcx: TyCtxt<'tcx>,
+                #tcx: QueryCtxt<'tcx>,
                 #key: &Self::Key,
                 #value: Option<&Self::Value>
             ) -> bool {
@@ -414,16 +413,14 @@ fn add_query_description_impl(
 
     let desc = quote! {
         #[allow(unused_variables)]
-        fn describe(
-            #tcx: TyCtxt<'tcx>,
-            #key: #arg,
-        ) -> Cow<'static, str> {
+        fn describe(tcx: QueryCtxt<'tcx>, key: Self::Key) -> String {
+            let (#tcx, #key) = (*tcx, key);
             ::rustc_middle::ty::print::with_no_trimmed_paths(|| format!(#desc).into())
         }
     };
 
     impls.extend(quote! {
-        impl<'tcx> QueryDescription<TyCtxt<'tcx>> for queries::#name<'tcx> {
+        impl<'tcx> QueryDescription<QueryCtxt<'tcx>> for queries::#name<'tcx> {
             #desc
             #cache
         }
@@ -498,6 +495,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
     }
 
     TokenStream::from(quote! {
+        #[macro_export]
         macro_rules! rustc_query_append {
             ([$($macro:tt)*][$($other:tt)*]) => {
                 $($macro)* {
@@ -517,12 +515,15 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
                 );
             }
         }
+        #[macro_export]
         macro_rules! rustc_cached_queries {
             ($($macro:tt)*) => {
                 $($macro)*(#cached_queries);
             }
         }
-
-        #query_description_stream
+        #[macro_export]
+        macro_rules! rustc_query_description {
+            () => { #query_description_stream }
+        }
     })
 }
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index f1975e78801..2aabc2c407b 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -12,7 +12,7 @@ libc = "0.2"
 snap = "1"
 tracing = "0.1"
 memmap = "0.7"
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_middle = { path = "../rustc_middle" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index e3fbd1a2b29..63c6f369eb6 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -16,8 +16,9 @@ use rustc_index::vec::IndexVec;
 use rustc_middle::middle::cstore::{CrateDepKind, CrateSource, ExternCrate};
 use rustc_middle::middle::cstore::{ExternCrateSource, MetadataLoaderDyn};
 use rustc_middle::ty::TyCtxt;
+use rustc_serialize::json::ToJson;
 use rustc_session::config::{self, CrateType, ExternLocation};
-use rustc_session::lint;
+use rustc_session::lint::{self, BuiltinLintDiagnostics, ExternDepSpec};
 use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
 use rustc_session::{CrateDisambiguator, Session};
@@ -27,6 +28,7 @@ use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
 
 use proc_macro::bridge::client::ProcMacro;
+use std::collections::BTreeMap;
 use std::path::Path;
 use std::{cmp, env};
 use tracing::{debug, info};
@@ -871,8 +873,25 @@ impl<'a> CrateLoader<'a> {
                 // Don't worry about pathless `--extern foo` sysroot references
                 continue;
             }
-            if !self.used_extern_options.contains(&Symbol::intern(name)) {
-                self.sess.parse_sess.buffer_lint(
+            if self.used_extern_options.contains(&Symbol::intern(name)) {
+                continue;
+            }
+
+            // Got a real unused --extern
+            let diag = match self.sess.opts.extern_dep_specs.get(name) {
+                Some(loc) => BuiltinLintDiagnostics::ExternDepSpec(name.clone(), loc.into()),
+                None => {
+                    // If we don't have a specific location, provide a json encoding of the `--extern`
+                    // option.
+                    let meta: BTreeMap<String, String> =
+                        std::iter::once(("name".to_string(), name.to_string())).collect();
+                    BuiltinLintDiagnostics::ExternDepSpec(
+                        name.clone(),
+                        ExternDepSpec::Json(meta.to_json()),
+                    )
+                }
+            };
+            self.sess.parse_sess.buffer_lint_with_diagnostic(
                     lint::builtin::UNUSED_CRATE_DEPENDENCIES,
                     span,
                     ast::CRATE_NODE_ID,
@@ -881,8 +900,8 @@ impl<'a> CrateLoader<'a> {
                         name,
                         self.local_crate_name,
                         name),
+                    diag,
                 );
-            }
         }
     }
 
diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs
index 4785b6c379c..3d3071c18f2 100644
--- a/compiler/rustc_metadata/src/foreign_modules.rs
+++ b/compiler/rustc_metadata/src/foreign_modules.rs
@@ -4,29 +4,24 @@ use rustc_middle::middle::cstore::ForeignModule;
 use rustc_middle::ty::TyCtxt;
 
 crate fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
-    let mut collector = Collector { tcx, modules: Vec::new() };
+    let mut collector = Collector { modules: Vec::new() };
     tcx.hir().krate().visit_all_item_likes(&mut collector);
     collector.modules
 }
 
-struct Collector<'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct Collector {
     modules: Vec<ForeignModule>,
 }
 
-impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
+impl ItemLikeVisitor<'tcx> for Collector {
     fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
         let items = match it.kind {
             hir::ItemKind::ForeignMod { items, .. } => items,
             _ => return,
         };
 
-        let foreign_items =
-            items.iter().map(|it| self.tcx.hir().local_def_id(it.id.hir_id).to_def_id()).collect();
-        self.modules.push(ForeignModule {
-            foreign_items,
-            def_id: self.tcx.hir().local_def_id(it.hir_id).to_def_id(),
-        });
+        let foreign_items = items.iter().map(|it| it.id.def_id.to_def_id()).collect();
+        self.modules.push(ForeignModule { foreign_items, def_id: it.def_id.to_def_id() });
     }
 
     fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem<'tcx>) {}
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 8d0994320e3..4d63b6d074a 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -53,7 +53,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
                 name: None,
                 kind: NativeLibKind::Unspecified,
                 cfg: None,
-                foreign_module: Some(self.tcx.hir().local_def_id(it.hir_id).to_def_id()),
+                foreign_module: Some(it.def_id.to_def_id()),
                 wasm_import_module: None,
             };
             let mut kind_specified = false;
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 3961adaceca..61265d7204c 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -2,15 +2,17 @@ use crate::rmeta::table::{FixedSizeEncoding, TableBuilder};
 use crate::rmeta::*;
 
 use rustc_data_structures::fingerprint::{Fingerprint, FingerprintEncoder};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::stable_hasher::StableHasher;
-use rustc_data_structures::sync::{join, Lrc};
+use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind};
-use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{
+    CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE,
+};
 use rustc_hir::definitions::DefPathData;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::itemlikevisit::{ItemLikeVisitor, ParItemLikeVisitor};
+use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::lang_items;
 use rustc_hir::{AnonConst, GenericParamKind};
 use rustc_index::bit_set::GrowableBitSet;
@@ -65,11 +67,6 @@ pub(super) struct EncodeContext<'a, 'tcx> {
     required_source_files: Option<GrowableBitSet<usize>>,
     is_proc_macro: bool,
     hygiene_ctxt: &'a HygieneEncodeContext,
-
-    // Determines if MIR used for code generation will be included in the crate
-    // metadata. When emitting only metadata (e.g., cargo check), we can avoid
-    // generating optimized MIR altogether.
-    emit_codegen_mir: bool,
 }
 
 /// If the current crate is a proc-macro, returns early with `Lazy:empty()`.
@@ -436,7 +433,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
     fn encode_info_for_items(&mut self) {
         let krate = self.tcx.hir().krate();
-        self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module);
+        self.encode_info_for_mod(CRATE_DEF_ID, &krate.item.module);
 
         // Proc-macro crates only export proc-macro items, which are looked
         // up using `proc_macro_data`
@@ -577,6 +574,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         let tcx = self.tcx;
 
+        // Encode MIR.
+        i = self.position();
+        self.encode_mir();
+        let mir_bytes = self.position() - i;
+
         // Encode the items.
         i = self.position();
         self.encode_def_ids();
@@ -693,22 +695,23 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 }
             }
 
-            println!("metadata stats:");
-            println!("             dep bytes: {}", dep_bytes);
-            println!("     lib feature bytes: {}", lib_feature_bytes);
-            println!("       lang item bytes: {}", lang_item_bytes);
-            println!(" diagnostic item bytes: {}", diagnostic_item_bytes);
-            println!("          native bytes: {}", native_lib_bytes);
-            println!("      source_map bytes: {}", source_map_bytes);
-            println!("            impl bytes: {}", impl_bytes);
-            println!("    exp. symbols bytes: {}", exported_symbols_bytes);
-            println!("  def-path table bytes: {}", def_path_table_bytes);
-            println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
-            println!("            item bytes: {}", item_bytes);
-            println!("           table bytes: {}", tables_bytes);
-            println!("         hygiene bytes: {}", hygiene_bytes);
-            println!("            zero bytes: {}", zero_bytes);
-            println!("           total bytes: {}", total_bytes);
+            eprintln!("metadata stats:");
+            eprintln!("             dep bytes: {}", dep_bytes);
+            eprintln!("     lib feature bytes: {}", lib_feature_bytes);
+            eprintln!("       lang item bytes: {}", lang_item_bytes);
+            eprintln!(" diagnostic item bytes: {}", diagnostic_item_bytes);
+            eprintln!("          native bytes: {}", native_lib_bytes);
+            eprintln!("      source_map bytes: {}", source_map_bytes);
+            eprintln!("            impl bytes: {}", impl_bytes);
+            eprintln!("    exp. symbols bytes: {}", exported_symbols_bytes);
+            eprintln!("  def-path table bytes: {}", def_path_table_bytes);
+            eprintln!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
+            eprintln!("             mir bytes: {}", mir_bytes);
+            eprintln!("            item bytes: {}", item_bytes);
+            eprintln!("           table bytes: {}", tables_bytes);
+            eprintln!("         hygiene bytes: {}", hygiene_bytes);
+            eprintln!("            zero bytes: {}", zero_bytes);
+            eprintln!("           total bytes: {}", total_bytes);
         }
 
         root
@@ -785,6 +788,53 @@ fn should_encode_stability(def_kind: DefKind) -> bool {
     }
 }
 
+/// Whether we should encode MIR.
+///
+/// Computing, optimizing and encoding the MIR is a relatively expensive operation.
+/// We want to avoid this work when not required. Therefore:
+/// - we only compute `mir_for_ctfe` on items with const-eval semantics;
+/// - we skip `optimized_mir` for check runs.
+///
+/// Return a pair, resp. for CTFE and for LLVM.
+fn should_encode_mir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> (bool, bool) {
+    match tcx.def_kind(def_id) {
+        // Constructors
+        DefKind::Ctor(_, _) => {
+            let mir_opt_base = tcx.sess.opts.output_types.should_codegen()
+                || tcx.sess.opts.debugging_opts.always_encode_mir;
+            (true, mir_opt_base)
+        }
+        // Constants
+        DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => {
+            (true, false)
+        }
+        // Full-fledged functions
+        DefKind::AssocFn | DefKind::Fn => {
+            let generics = tcx.generics_of(def_id);
+            let needs_inline = (generics.requires_monomorphization(tcx)
+                || tcx.codegen_fn_attrs(def_id).requests_inline())
+                && tcx.sess.opts.output_types.should_codegen();
+            // Only check the presence of the `const` modifier.
+            let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id());
+            let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir;
+            (is_const_fn, needs_inline || always_encode_mir)
+        }
+        // Closures can't be const fn.
+        DefKind::Closure => {
+            let generics = tcx.generics_of(def_id);
+            let needs_inline = (generics.requires_monomorphization(tcx)
+                || tcx.codegen_fn_attrs(def_id).requests_inline())
+                && tcx.sess.opts.output_types.should_codegen();
+            let always_encode_mir = tcx.sess.opts.debugging_opts.always_encode_mir;
+            (false, needs_inline || always_encode_mir)
+        }
+        // Generators require optimized MIR to compute layout.
+        DefKind::Generator => (false, true),
+        // The others don't have MIR.
+        _ => (false, false),
+    }
+}
+
 impl EncodeContext<'a, 'tcx> {
     fn encode_def_ids(&mut self) {
         if self.is_proc_macro {
@@ -818,7 +868,7 @@ impl EncodeContext<'a, 'tcx> {
 
     fn encode_variances_of(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_variances_of({:?})", def_id);
-        record!(self.tables.variances[def_id] <- &self.tcx.variances_of(def_id)[..]);
+        record!(self.tables.variances[def_id] <- self.tcx.variances_of(def_id));
     }
 
     fn encode_item_type(&mut self, def_id: DefId) {
@@ -882,16 +932,10 @@ impl EncodeContext<'a, 'tcx> {
         self.encode_generics(def_id);
         self.encode_explicit_predicates(def_id);
         self.encode_inferred_outlives(def_id);
-        let opt_mir = tcx.sess.opts.debugging_opts.always_encode_mir || self.emit_codegen_mir;
-        if opt_mir {
-            self.encode_optimized_mir(def_id.expect_local());
-        }
-        self.encode_mir_for_ctfe(def_id.expect_local());
     }
 
-    fn encode_info_for_mod(&mut self, id: hir::HirId, md: &hir::Mod<'_>) {
+    fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
         let tcx = self.tcx;
-        let local_def_id = tcx.hir().local_def_id(id);
         let def_id = local_def_id.to_def_id();
         debug!("EncodeContext::encode_info_for_mod({:?})", def_id);
 
@@ -926,7 +970,7 @@ impl EncodeContext<'a, 'tcx> {
             record!(self.tables.children[def_id] <- &[]);
         } else {
             record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| {
-                tcx.hir().local_def_id(item_id.id).local_def_index
+                item_id.def_id.local_def_index
             }));
         }
     }
@@ -972,11 +1016,6 @@ impl EncodeContext<'a, 'tcx> {
         self.encode_generics(def_id);
         self.encode_explicit_predicates(def_id);
         self.encode_inferred_outlives(def_id);
-        let opt_mir = tcx.sess.opts.debugging_opts.always_encode_mir || self.emit_codegen_mir;
-        if opt_mir {
-            self.encode_optimized_mir(def_id.expect_local());
-        }
-        self.encode_mir_for_ctfe(def_id.expect_local());
     }
 
     fn encode_generics(&mut self, def_id: DefId) {
@@ -1082,34 +1121,6 @@ impl EncodeContext<'a, 'tcx> {
         self.encode_generics(def_id);
         self.encode_explicit_predicates(def_id);
         self.encode_inferred_outlives(def_id);
-
-        // This should be kept in sync with `PrefetchVisitor.visit_trait_item`.
-        match trait_item.kind {
-            ty::AssocKind::Type => {}
-            ty::AssocKind::Const => {
-                if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id.expect_local()) {
-                    self.encode_mir_for_ctfe(def_id.expect_local());
-                    self.encode_promoted_mir(def_id.expect_local());
-                }
-            }
-            ty::AssocKind::Fn => {
-                let opt_mir =
-                    tcx.sess.opts.debugging_opts.always_encode_mir || self.emit_codegen_mir;
-                if opt_mir {
-                    if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id.expect_local()) {
-                        self.encode_optimized_mir(def_id.expect_local());
-                        self.encode_promoted_mir(def_id.expect_local());
-                    }
-                }
-            }
-        }
-    }
-
-    fn should_encode_fn_opt_mir(&self, def_id: DefId) -> bool {
-        self.tcx.sess.opts.debugging_opts.always_encode_mir
-            || (self.emit_codegen_mir
-                && (self.tcx.generics_of(def_id).requires_monomorphization(self.tcx)
-                    || self.tcx.codegen_fn_attrs(def_id).requests_inline()))
     }
 
     fn encode_info_for_impl_item(&mut self, def_id: DefId) {
@@ -1171,27 +1182,6 @@ impl EncodeContext<'a, 'tcx> {
         self.encode_generics(def_id);
         self.encode_explicit_predicates(def_id);
         self.encode_inferred_outlives(def_id);
-
-        // The following part should be kept in sync with `PrefetchVisitor.visit_impl_item`.
-
-        let (mir, mir_const) = match ast_item.kind {
-            hir::ImplItemKind::Const(..) => (false, true),
-            hir::ImplItemKind::Fn(ref sig, _) => {
-                let opt_mir = self.should_encode_fn_opt_mir(def_id);
-                let is_const_fn = sig.header.constness == hir::Constness::Const;
-                (opt_mir, is_const_fn)
-            }
-            hir::ImplItemKind::TyAlias(..) => (false, false),
-        };
-        if mir {
-            self.encode_optimized_mir(def_id.expect_local());
-        }
-        if mir || mir_const {
-            self.encode_promoted_mir(def_id.expect_local());
-        }
-        if mir_const {
-            self.encode_mir_for_ctfe(def_id.expect_local());
-        }
     }
 
     fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Ident]> {
@@ -1202,34 +1192,48 @@ impl EncodeContext<'a, 'tcx> {
         self.lazy(param_names.iter())
     }
 
-    fn encode_mir_for_ctfe(&mut self, def_id: LocalDefId) {
-        debug!("EntryBuilder::encode_mir_for_ctfe({:?})", def_id);
-        record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
-
-        let unused = self.tcx.unused_generic_params(def_id);
-        if !unused.is_empty() {
-            record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
+    fn encode_mir(&mut self) {
+        if self.is_proc_macro {
+            return;
         }
 
-        let abstract_const = self.tcx.mir_abstract_const(def_id);
-        if let Ok(Some(abstract_const)) = abstract_const {
-            record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
-        }
-    }
+        let mut keys_and_jobs = self
+            .tcx
+            .mir_keys(LOCAL_CRATE)
+            .iter()
+            .filter_map(|&def_id| {
+                let (encode_const, encode_opt) = should_encode_mir(self.tcx, def_id);
+                if encode_const || encode_opt {
+                    Some((def_id, encode_const, encode_opt))
+                } else {
+                    None
+                }
+            })
+            .collect::<Vec<_>>();
+        // Sort everything to ensure a stable order for diagnotics.
+        keys_and_jobs.sort_by_key(|&(def_id, _, _)| def_id);
+        for (def_id, encode_const, encode_opt) in keys_and_jobs.into_iter() {
+            debug_assert!(encode_const || encode_opt);
 
-    fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
-        debug!("EntryBuilder::encode_optimized_mir({:?})", def_id);
-        record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
+            debug!("EntryBuilder::encode_mir({:?})", def_id);
+            if encode_opt {
+                record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
+            }
+            if encode_const {
+                record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
 
-        let unused = self.tcx.unused_generic_params(def_id);
-        if !unused.is_empty() {
-            record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
-        }
-    }
+                let abstract_const = self.tcx.mir_abstract_const(def_id);
+                if let Ok(Some(abstract_const)) = abstract_const {
+                    record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
+                }
+            }
+            record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
 
-    fn encode_promoted_mir(&mut self, def_id: LocalDefId) {
-        debug!("EncodeContext::encode_promoted_mir({:?})", def_id);
-        record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
+            let unused = self.tcx.unused_generic_params(def_id);
+            if !unused.is_empty() {
+                record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
+            }
+        }
     }
 
     // Encodes the inherent implementations of a structure, enumeration, or trait.
@@ -1309,7 +1313,7 @@ impl EncodeContext<'a, 'tcx> {
                 EntryKind::Fn(self.lazy(data))
             }
             hir::ItemKind::Mod(ref m) => {
-                return self.encode_info_for_mod(item.hir_id, m);
+                return self.encode_info_for_mod(item.def_id, m);
             }
             hir::ItemKind::ForeignMod { .. } => EntryKind::ForeignMod,
             hir::ItemKind::GlobalAsm(..) => EntryKind::GlobalAsm,
@@ -1407,8 +1411,7 @@ impl EncodeContext<'a, 'tcx> {
             hir::ItemKind::ForeignMod { items, .. } => record!(self.tables.children[def_id] <-
                 items
                     .iter()
-                    .map(|foreign_item| tcx.hir().local_def_id(
-                        foreign_item.id.hir_id).local_def_index)
+                    .map(|foreign_item| foreign_item.id.def_id.local_def_index)
             ),
             hir::ItemKind::Enum(..) => record!(self.tables.children[def_id] <-
                 self.tcx.adt_def(def_id).variants.iter().map(|v| {
@@ -1487,33 +1490,11 @@ impl EncodeContext<'a, 'tcx> {
             }
             _ => {}
         }
-
-        // The following part should be kept in sync with `PrefetchVisitor.visit_item`.
-
-        let (mir, const_mir) = match item.kind {
-            hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => (false, true),
-            hir::ItemKind::Fn(ref sig, ..) => {
-                let opt_mir = self.should_encode_fn_opt_mir(def_id);
-                let is_const_fn = sig.header.constness == hir::Constness::Const;
-                // We don't need the optimized MIR for const fns.
-                (opt_mir, is_const_fn)
-            }
-            _ => (false, false),
-        };
-        if mir {
-            self.encode_optimized_mir(def_id.expect_local());
-        }
-        if mir || const_mir {
-            self.encode_promoted_mir(def_id.expect_local());
-        }
-        if const_mir {
-            self.encode_mir_for_ctfe(def_id.expect_local());
-        }
     }
 
     /// Serialize the text of exported macros
     fn encode_info_for_macro_def(&mut self, macro_def: &hir::MacroDef<'_>) {
-        let def_id = self.tcx.hir().local_def_id(macro_def.hir_id).to_def_id();
+        let def_id = macro_def.def_id.to_def_id();
         record!(self.tables.kind[def_id] <- EntryKind::MacroDef(self.lazy(macro_def.ast.clone())));
         self.encode_ident_span(def_id, macro_def.ident);
     }
@@ -1550,14 +1531,6 @@ impl EncodeContext<'a, 'tcx> {
             record!(self.tables.fn_sig[def_id] <- substs.as_closure().sig());
         }
         self.encode_generics(def_id.to_def_id());
-        let opt_mir = // FIXME: Optimized MIR is necessary to determine the layout of generators.
-            matches!(ty.kind(), ty::Generator(..))
-            || self.tcx.sess.opts.debugging_opts.always_encode_mir
-            || self.emit_codegen_mir;
-        if opt_mir {
-            self.encode_optimized_mir(def_id);
-            self.encode_promoted_mir(def_id);
-        }
     }
 
     fn encode_info_for_anon_const(&mut self, def_id: LocalDefId) {
@@ -1572,8 +1545,6 @@ impl EncodeContext<'a, 'tcx> {
         self.encode_generics(def_id.to_def_id());
         self.encode_explicit_predicates(def_id.to_def_id());
         self.encode_inferred_outlives(def_id.to_def_id());
-        self.encode_mir_for_ctfe(def_id);
-        self.encode_promoted_mir(def_id);
     }
 
     fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> {
@@ -1879,17 +1850,15 @@ impl Visitor<'tcx> for EncodeContext<'a, 'tcx> {
     }
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         intravisit::walk_item(self, item);
-        let def_id = self.tcx.hir().local_def_id(item.hir_id);
         match item.kind {
             hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these
-            _ => self.encode_info_for_item(def_id.to_def_id(), item),
+            _ => self.encode_info_for_item(item.def_id.to_def_id(), item),
         }
         self.encode_addl_info_for_item(item);
     }
     fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) {
         intravisit::walk_foreign_item(self, ni);
-        let def_id = self.tcx.hir().local_def_id(ni.hir_id);
-        self.encode_info_for_foreign_item(def_id.to_def_id(), ni);
+        self.encode_info_for_foreign_item(ni.def_id.to_def_id(), ni);
     }
     fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
         intravisit::walk_generics(self, generics);
@@ -1949,7 +1918,6 @@ impl EncodeContext<'a, 'tcx> {
     /// so it's easier to do that here then to wait until we would encounter
     /// normally in the visitor walk.
     fn encode_addl_info_for_item(&mut self, item: &hir::Item<'_>) {
-        let def_id = self.tcx.hir().local_def_id(item.hir_id);
         match item.kind {
             hir::ItemKind::Static(..)
             | hir::ItemKind::Const(..)
@@ -1965,7 +1933,7 @@ impl EncodeContext<'a, 'tcx> {
                 // no sub-item recording needed in these cases
             }
             hir::ItemKind::Enum(..) => {
-                let def = self.tcx.adt_def(def_id.to_def_id());
+                let def = self.tcx.adt_def(item.def_id.to_def_id());
                 self.encode_fields(def);
 
                 for (i, variant) in def.variants.iter_enumerated() {
@@ -1977,7 +1945,7 @@ impl EncodeContext<'a, 'tcx> {
                 }
             }
             hir::ItemKind::Struct(ref struct_def, _) => {
-                let def = self.tcx.adt_def(def_id.to_def_id());
+                let def = self.tcx.adt_def(item.def_id.to_def_id());
                 self.encode_fields(def);
 
                 // If the struct has a constructor, encode it.
@@ -1987,18 +1955,19 @@ impl EncodeContext<'a, 'tcx> {
                 }
             }
             hir::ItemKind::Union(..) => {
-                let def = self.tcx.adt_def(def_id.to_def_id());
+                let def = self.tcx.adt_def(item.def_id.to_def_id());
                 self.encode_fields(def);
             }
             hir::ItemKind::Impl { .. } => {
                 for &trait_item_def_id in
-                    self.tcx.associated_item_def_ids(def_id.to_def_id()).iter()
+                    self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
                 {
                     self.encode_info_for_impl_item(trait_item_def_id);
                 }
             }
             hir::ItemKind::Trait(..) => {
-                for &item_def_id in self.tcx.associated_item_def_ids(def_id.to_def_id()).iter() {
+                for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
+                {
                     self.encode_info_for_trait_item(item_def_id);
                 }
             }
@@ -2014,15 +1983,14 @@ struct ImplVisitor<'tcx> {
 impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
         if let hir::ItemKind::Impl { .. } = item.kind {
-            let impl_id = self.tcx.hir().local_def_id(item.hir_id);
-            if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id.to_def_id()) {
+            if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id.to_def_id()) {
                 let simplified_self_ty =
                     ty::fast_reject::simplify_type(self.tcx, trait_ref.self_ty(), false);
 
                 self.impls
                     .entry(trait_ref.def_id)
                     .or_default()
-                    .push((impl_id.local_def_index, simplified_self_ty));
+                    .push((item.def_id.local_def_index, simplified_self_ty));
             }
         }
     }
@@ -2038,90 +2006,25 @@ impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> {
 
 /// Used to prefetch queries which will be needed later by metadata encoding.
 /// Only a subset of the queries are actually prefetched to keep this code smaller.
-struct PrefetchVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    mir_keys: &'tcx FxHashSet<LocalDefId>,
-}
-
-impl<'tcx> PrefetchVisitor<'tcx> {
-    fn prefetch_ctfe_mir(&self, def_id: LocalDefId) {
-        if self.mir_keys.contains(&def_id) {
-            self.tcx.ensure().mir_for_ctfe(def_id);
-            self.tcx.ensure().promoted_mir(def_id);
-        }
+fn prefetch_mir(tcx: TyCtxt<'_>) {
+    if !tcx.sess.opts.output_types.should_codegen() {
+        // We won't emit MIR, so don't prefetch it.
+        return;
     }
-    fn prefetch_mir(&self, def_id: LocalDefId) {
-        if self.mir_keys.contains(&def_id) {
-            self.tcx.ensure().optimized_mir(def_id);
-            self.tcx.ensure().promoted_mir(def_id);
-        }
-    }
-}
 
-impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> {
-    fn visit_item(&self, item: &hir::Item<'_>) {
-        // This should be kept in sync with `encode_info_for_item`.
-        let tcx = self.tcx;
-        match item.kind {
-            hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
-                self.prefetch_ctfe_mir(tcx.hir().local_def_id(item.hir_id))
-            }
-            hir::ItemKind::Fn(ref sig, ..) => {
-                let def_id = tcx.hir().local_def_id(item.hir_id);
-                let opt_mir = tcx.generics_of(def_id.to_def_id()).requires_monomorphization(tcx)
-                    || tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
-                if opt_mir {
-                    self.prefetch_mir(def_id)
-                }
-                if sig.header.constness == hir::Constness::Const {
-                    self.prefetch_ctfe_mir(def_id);
-                }
-            }
-            _ => (),
-        }
-    }
+    par_iter(tcx.mir_keys(LOCAL_CRATE)).for_each(|&def_id| {
+        let (encode_const, encode_opt) = should_encode_mir(tcx, def_id);
 
-    fn visit_trait_item(&self, trait_item: &'v hir::TraitItem<'v>) {
-        // This should be kept in sync with `encode_info_for_trait_item`.
-        let def_id = self.tcx.hir().local_def_id(trait_item.hir_id);
-        match trait_item.kind {
-            hir::TraitItemKind::Type(..) => {}
-            hir::TraitItemKind::Const(..) => {
-                self.prefetch_ctfe_mir(def_id);
-            }
-            hir::TraitItemKind::Fn(..) => {
-                self.prefetch_mir(def_id);
-            }
+        if encode_const {
+            tcx.ensure().mir_for_ctfe(def_id);
         }
-    }
-
-    fn visit_impl_item(&self, impl_item: &'v hir::ImplItem<'v>) {
-        // This should be kept in sync with `encode_info_for_impl_item`.
-        let tcx = self.tcx;
-        match impl_item.kind {
-            hir::ImplItemKind::Const(..) => {
-                self.prefetch_ctfe_mir(tcx.hir().local_def_id(impl_item.hir_id))
-            }
-            hir::ImplItemKind::Fn(ref sig, _) => {
-                let def_id = tcx.hir().local_def_id(impl_item.hir_id);
-                let opt_mir = tcx.generics_of(def_id.to_def_id()).requires_monomorphization(tcx)
-                    || tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
-                let is_const_fn = sig.header.constness == hir::Constness::Const;
-                if opt_mir {
-                    self.prefetch_mir(def_id)
-                }
-                if is_const_fn {
-                    self.prefetch_ctfe_mir(def_id);
-                }
-            }
-            hir::ImplItemKind::TyAlias(..) => (),
+        if encode_opt {
+            tcx.ensure().optimized_mir(def_id);
         }
-    }
-
-    fn visit_foreign_item(&self, _foreign_item: &'v hir::ForeignItem<'v>) {
-        // This should be kept in sync with `encode_info_for_foreign_item`.
-        // Foreign items contain no MIR.
-    }
+        if encode_opt || encode_const {
+            tcx.ensure().promoted_mir(def_id);
+        }
+    })
 }
 
 // NOTE(eddyb) The following comment was preserved for posterity, even
@@ -2161,19 +2064,7 @@ pub(super) fn encode_metadata(tcx: TyCtxt<'_>) -> EncodedMetadata {
             // Prefetch some queries used by metadata encoding.
             // This is not necessary for correctness, but is only done for performance reasons.
             // It can be removed if it turns out to cause trouble or be detrimental to performance.
-            join(
-                || {
-                    if !tcx.sess.opts.output_types.should_codegen() {
-                        // We won't emit MIR, so don't prefetch it.
-                        return;
-                    }
-                    tcx.hir().krate().par_visit_all_item_likes(&PrefetchVisitor {
-                        tcx,
-                        mir_keys: tcx.mir_keys(LOCAL_CRATE),
-                    });
-                },
-                || tcx.exported_symbols(LOCAL_CRATE),
-            );
+            join(|| prefetch_mir(tcx), || tcx.exported_symbols(LOCAL_CRATE));
         },
     )
     .0
@@ -2206,7 +2097,6 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata {
         required_source_files,
         is_proc_macro: tcx.sess.crate_types().contains(&CrateType::ProcMacro),
         hygiene_ctxt: &hygiene_ctxt,
-        emit_codegen_mir: tcx.sess.opts.output_types.should_codegen(),
     };
 
     // Encode the rustc version string in a predictable location.
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index d33aad3b710..7de398a1898 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -27,7 +27,7 @@ rustc_serialize = { path = "../rustc_serialize" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
 chalk-ir = "0.55.0"
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 measureme = "9.0.0"
 rustc_session = { path = "../rustc_session" }
 rustc_type_ir = { path = "../rustc_type_ir" }
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 1cb75757379..ba9d0a40732 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -62,7 +62,6 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::definitions::DefPathHash;
 use rustc_hir::HirId;
 use rustc_span::symbol::Symbol;
-use rustc_span::DUMMY_SP;
 use std::hash::Hash;
 
 pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};
@@ -91,53 +90,6 @@ pub struct DepKindStruct {
     // FIXME: Make this a simple boolean once DepNodeParams::can_reconstruct_query_key
     // can be made a specialized associated const.
     can_reconstruct_query_key: fn() -> bool,
-
-    /// The red/green evaluation system will try to mark a specific DepNode in the
-    /// dependency graph as green by recursively trying to mark the dependencies of
-    /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
-    /// where we don't know if it is red or green and we therefore actually have
-    /// to recompute its value in order to find out. Since the only piece of
-    /// information that we have at that point is the `DepNode` we are trying to
-    /// re-evaluate, we need some way to re-run a query from just that. This is what
-    /// `force_from_dep_node()` implements.
-    ///
-    /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
-    /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
-    /// is usually constructed by computing a stable hash of the query-key that the
-    /// `DepNode` corresponds to. Consequently, it is not in general possible to go
-    /// back from hash to query-key (since hash functions are not reversible). For
-    /// this reason `force_from_dep_node()` is expected to fail from time to time
-    /// because we just cannot find out, from the `DepNode` alone, what the
-    /// corresponding query-key is and therefore cannot re-run the query.
-    ///
-    /// The system deals with this case letting `try_mark_green` fail which forces
-    /// the root query to be re-evaluated.
-    ///
-    /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
-    /// Fortunately, we can use some contextual information that will allow us to
-    /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
-    /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
-    /// valid `DefPathHash`. Since we also always build a huge table that maps every
-    /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
-    /// everything we need to re-run the query.
-    ///
-    /// Take the `mir_promoted` query as an example. Like many other queries, it
-    /// just has a single parameter: the `DefId` of the item it will compute the
-    /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
-    /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
-    /// is actually a `DefPathHash`, and can therefore just look up the corresponding
-    /// `DefId` in `tcx.def_path_hash_to_def_id`.
-    ///
-    /// When you implement a new query, it will likely have a corresponding new
-    /// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As
-    /// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter,
-    /// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
-    /// add it to the "We don't have enough information to reconstruct..." group in
-    /// the match below.
-    pub(super) force_from_dep_node: fn(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool,
-
-    /// Invoke a query to put the on-disk cached value in memory.
-    pub(super) try_load_from_on_disk_cache: fn(TyCtxt<'_>, &DepNode),
 }
 
 impl std::ops::Deref for DepKind {
@@ -196,8 +148,7 @@ macro_rules! contains_eval_always_attr {
 #[allow(non_upper_case_globals)]
 pub mod dep_kind {
     use super::*;
-    use crate::ty::query::{queries, query_keys};
-    use rustc_query_system::query::{force_query, QueryDescription};
+    use crate::ty::query::query_keys;
 
     // We use this for most things when incr. comp. is turned off.
     pub const Null: DepKindStruct = DepKindStruct {
@@ -206,8 +157,6 @@ pub mod dep_kind {
         is_eval_always: false,
 
         can_reconstruct_query_key: || true,
-        force_from_dep_node: |_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node),
-        try_load_from_on_disk_cache: |_, _| {},
     };
 
     pub const TraitSelect: DepKindStruct = DepKindStruct {
@@ -216,8 +165,6 @@ pub mod dep_kind {
         is_eval_always: false,
 
         can_reconstruct_query_key: || true,
-        force_from_dep_node: |_, _| false,
-        try_load_from_on_disk_cache: |_, _| {},
     };
 
     pub const CompileCodegenUnit: DepKindStruct = DepKindStruct {
@@ -226,8 +173,6 @@ pub mod dep_kind {
         is_eval_always: false,
 
         can_reconstruct_query_key: || false,
-        force_from_dep_node: |_, _| false,
-        try_load_from_on_disk_cache: |_, _| {},
     };
 
     macro_rules! define_query_dep_kinds {
@@ -246,59 +191,11 @@ pub mod dep_kind {
                         ::can_reconstruct_query_key()
                 }
 
-                fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$variant<'tcx>> {
-                    <query_keys::$variant<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node)
-                }
-
-                fn force_from_dep_node(tcx: TyCtxt<'_>, dep_node: &DepNode) -> bool {
-                    if is_anon {
-                        return false;
-                    }
-
-                    if !can_reconstruct_query_key() {
-                        return false;
-                    }
-
-                    if let Some(key) = recover(tcx, dep_node) {
-                        force_query::<queries::$variant<'_>, _>(
-                            tcx,
-                            key,
-                            DUMMY_SP,
-                            *dep_node
-                        );
-                        return true;
-                    }
-
-                    false
-                }
-
-                fn try_load_from_on_disk_cache(tcx: TyCtxt<'_>, dep_node: &DepNode) {
-                    if is_anon {
-                        return
-                    }
-
-                    if !can_reconstruct_query_key() {
-                        return
-                    }
-
-                    debug_assert!(tcx.dep_graph
-                                     .node_color(dep_node)
-                                     .map(|c| c.is_green())
-                                     .unwrap_or(false));
-
-                    let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
-                    if queries::$variant::cache_on_disk(tcx, &key, None) {
-                        let _ = tcx.$variant(key);
-                    }
-                }
-
                 DepKindStruct {
                     has_params,
                     is_anon,
                     is_eval_always,
                     can_reconstruct_query_key,
-                    force_from_dep_node,
-                    try_load_from_on_disk_cache,
                 }
             };)*
         );
@@ -314,7 +211,12 @@ macro_rules! define_dep_nodes {
         $variant:ident $(( $tuple_arg_ty:ty $(,)? ))*
       ,)*
     ) => (
-        static DEP_KINDS: &[DepKindStruct] = &[ $(dep_kind::$variant),* ];
+        #[macro_export]
+        macro_rules! make_dep_kind_array {
+            ($mod:ident) => {[ $(($mod::$variant),)* ]};
+        }
+
+        static DEP_KINDS: &[DepKindStruct] = &make_dep_kind_array!(dep_kind);
 
         /// This enum serves as an index into the `DEP_KINDS` array.
         #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
@@ -414,10 +316,7 @@ impl DepNodeExt for DepNode {
     /// has been removed.
     fn extract_def_id(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
         if self.kind.can_reconstruct_query_key() {
-            tcx.queries
-                .on_disk_cache
-                .as_ref()?
-                .def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into()))
+            tcx.on_disk_cache.as_ref()?.def_path_hash_to_def_id(tcx, DefPathHash(self.hash.into()))
         } else {
             None
         }
@@ -472,7 +371,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for DefId {
         // we will use the old DefIndex as an initial guess for
         // a lookup into the crate metadata.
         if !self.is_local() {
-            if let Some(cache) = &tcx.queries.on_disk_cache {
+            if let Some(cache) = &tcx.on_disk_cache {
                 cache.store_foreign_def_id_hash(*self, hash);
             }
         }
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index b88ffa2bb73..d862db2674e 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -2,10 +2,8 @@ use crate::ich::StableHashingContext;
 use crate::ty::{self, TyCtxt};
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sync::Lock;
-use rustc_data_structures::thin_vec::ThinVec;
-use rustc_errors::Diagnostic;
-use rustc_hir::def_id::LocalDefId;
 
+#[macro_use]
 mod dep_node;
 
 pub use rustc_query_system::dep_graph::{
@@ -94,7 +92,7 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
     type StableHashingContext = StableHashingContext<'tcx>;
 
     fn register_reused_dep_node(&self, dep_node: &DepNode) {
-        if let Some(cache) = self.queries.on_disk_cache.as_ref() {
+        if let Some(cache) = self.on_disk_cache.as_ref() {
             cache.register_reused_dep_node(*self, dep_node)
         }
     }
@@ -111,104 +109,12 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
             || self.sess.opts.debugging_opts.query_dep_graph
     }
 
-    fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool {
-        // FIXME: This match is just a workaround for incremental bugs and should
-        // be removed. https://github.com/rust-lang/rust/issues/62649 is one such
-        // bug that must be fixed before removing this.
-        match dep_node.kind {
-            DepKind::hir_owner | DepKind::hir_owner_nodes => {
-                if let Some(def_id) = dep_node.extract_def_id(*self) {
-                    if !def_id_corresponds_to_hir_dep_node(*self, def_id.expect_local()) {
-                        // This `DefPath` does not have a
-                        // corresponding `DepNode` (e.g. a
-                        // struct field), and the ` DefPath`
-                        // collided with the `DefPath` of a
-                        // proper item that existed in the
-                        // previous compilation session.
-                        //
-                        // Since the given `DefPath` does not
-                        // denote the item that previously
-                        // existed, we just fail to mark green.
-                        return false;
-                    }
-                } else {
-                    // If the node does not exist anymore, we
-                    // just fail to mark green.
-                    return false;
-                }
-            }
-            _ => {
-                // For other kinds of nodes it's OK to be
-                // forced.
-            }
-        }
-
-        debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
-
-        // We must avoid ever having to call `force_from_dep_node()` for a
-        // `DepNode::codegen_unit`:
-        // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
-        // would always end up having to evaluate the first caller of the
-        // `codegen_unit` query that *is* reconstructible. This might very well be
-        // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
-        // to re-trigger calling the `codegen_unit` query with the right key. At
-        // that point we would already have re-done all the work we are trying to
-        // avoid doing in the first place.
-        // The solution is simple: Just explicitly call the `codegen_unit` query for
-        // each CGU, right after partitioning. This way `try_mark_green` will always
-        // hit the cache instead of having to go through `force_from_dep_node`.
-        // This assertion makes sure, we actually keep applying the solution above.
-        debug_assert!(
-            dep_node.kind != DepKind::codegen_unit,
-            "calling force_from_dep_node() on DepKind::codegen_unit"
-        );
-
-        (dep_node.kind.force_from_dep_node)(*self, dep_node)
-    }
-
-    fn has_errors_or_delayed_span_bugs(&self) -> bool {
-        self.sess.has_errors_or_delayed_span_bugs()
-    }
-
-    fn diagnostic(&self) -> &rustc_errors::Handler {
-        self.sess.diagnostic()
-    }
-
-    // Interactions with on_disk_cache
-    fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) {
-        (dep_node.kind.try_load_from_on_disk_cache)(*self, dep_node)
-    }
-
-    fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic> {
-        self.queries
-            .on_disk_cache
-            .as_ref()
-            .map(|c| c.load_diagnostics(*self, prev_dep_node_index))
-            .unwrap_or_default()
-    }
-
-    fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>) {
-        if let Some(c) = self.queries.on_disk_cache.as_ref() {
-            c.store_diagnostics(dep_node_index, diagnostics)
-        }
-    }
-
-    fn store_diagnostics_for_anon_node(
-        &self,
-        dep_node_index: DepNodeIndex,
-        diagnostics: ThinVec<Diagnostic>,
-    ) {
-        if let Some(c) = self.queries.on_disk_cache.as_ref() {
-            c.store_diagnostics_for_anon_node(dep_node_index, diagnostics)
-        }
+    #[inline]
+    fn dep_graph(&self) -> &DepGraph {
+        &self.dep_graph
     }
 
     fn profiler(&self) -> &SelfProfilerRef {
         &self.prof
     }
 }
-
-fn def_id_corresponds_to_hir_dep_node(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    def_id == hir_id.owner
-}
diff --git a/compiler/rustc_middle/src/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs
index 9d392c7b26b..9222ce1015e 100644
--- a/compiler/rustc_middle/src/hir/map/blocks.rs
+++ b/compiler/rustc_middle/src/hir/map/blocks.rs
@@ -215,7 +215,7 @@ impl<'a> FnLikeNode<'a> {
         match self.node {
             Node::Item(i) => match i.kind {
                 hir::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts {
-                    id: i.hir_id,
+                    id: i.hir_id(),
                     ident: i.ident,
                     decl: &sig.decl,
                     body: block,
@@ -229,13 +229,13 @@ impl<'a> FnLikeNode<'a> {
             },
             Node::TraitItem(ti) => match ti.kind {
                 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
-                    method(ti.hir_id, ti.ident, sig, None, body, ti.span, &ti.attrs)
+                    method(ti.hir_id(), ti.ident, sig, None, body, ti.span, &ti.attrs)
                 }
                 _ => bug!("trait method FnLikeNode that is not fn-like"),
             },
             Node::ImplItem(ii) => match ii.kind {
                 hir::ImplItemKind::Fn(ref sig, body) => {
-                    method(ii.hir_id, ii.ident, sig, Some(&ii.vis), body, ii.span, &ii.attrs)
+                    method(ii.hir_id(), ii.ident, sig, Some(&ii.vis), body, ii.span, &ii.attrs)
                 }
                 _ => bug!("impl method FnLikeNode that is not fn-like"),
             },
diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs
index 872fcb0f581..a5ffa9c7a54 100644
--- a/compiler/rustc_middle/src/hir/map/collector.rs
+++ b/compiler/rustc_middle/src/hir/map/collector.rs
@@ -55,22 +55,19 @@ fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V
     map[k] = Some(v);
 }
 
-fn hash(
-    hcx: &mut StableHashingContext<'_>,
-    input: impl for<'a> HashStable<StableHashingContext<'a>>,
-) -> Fingerprint {
-    let mut stable_hasher = StableHasher::new();
-    input.hash_stable(hcx, &mut stable_hasher);
-    stable_hasher.finish()
-}
-
 fn hash_body(
     hcx: &mut StableHashingContext<'_>,
     def_path_hash: DefPathHash,
     item_like: impl for<'a> HashStable<StableHashingContext<'a>>,
     hir_body_nodes: &mut Vec<(DefPathHash, Fingerprint)>,
 ) -> Fingerprint {
-    let hash = hash(hcx, HirItemLike { item_like: &item_like });
+    let hash = {
+        let mut stable_hasher = StableHasher::new();
+        hcx.while_hashing_hir_bodies(true, |hcx| {
+            item_like.hash_stable(hcx, &mut stable_hasher);
+        });
+        stable_hasher.finish()
+    };
     hir_body_nodes.push((def_path_hash, hash));
     hash
 }
@@ -309,7 +306,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
 
     fn visit_nested_item(&mut self, item: ItemId) {
         debug!("visit_nested_item: {:?}", item);
-        self.visit_item(self.krate.item(item.id));
+        self.visit_item(self.krate.item(item));
     }
 
     fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
@@ -338,13 +335,10 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
 
     fn visit_item(&mut self, i: &'hir Item<'hir>) {
         debug!("visit_item: {:?}", i);
-        debug_assert_eq!(
-            i.hir_id.owner,
-            self.definitions.opt_hir_id_to_local_def_id(i.hir_id).unwrap()
-        );
-        self.with_dep_node_owner(i.hir_id.owner, i, |this, hash| {
-            this.insert_with_hash(i.span, i.hir_id, Node::Item(i), hash);
-            this.with_parent(i.hir_id, |this| {
+        self.with_dep_node_owner(i.def_id, i, |this, hash| {
+            let hir_id = i.hir_id();
+            this.insert_with_hash(i.span, hir_id, Node::Item(i), hash);
+            this.with_parent(hir_id, |this| {
                 if let ItemKind::Struct(ref struct_def, _) = i.kind {
                     // If this is a tuple or unit-like struct, register the constructor.
                     if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
@@ -357,14 +351,10 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
-        debug_assert_eq!(
-            fi.hir_id.owner,
-            self.definitions.opt_hir_id_to_local_def_id(fi.hir_id).unwrap()
-        );
-        self.with_dep_node_owner(fi.hir_id.owner, fi, |this, hash| {
-            this.insert_with_hash(fi.span, fi.hir_id, Node::ForeignItem(fi), hash);
+        self.with_dep_node_owner(fi.def_id, fi, |this, hash| {
+            this.insert_with_hash(fi.span, fi.hir_id(), Node::ForeignItem(fi), hash);
 
-            this.with_parent(fi.hir_id, |this| {
+            this.with_parent(fi.hir_id(), |this| {
                 intravisit::walk_foreign_item(this, fi);
             });
         });
@@ -394,28 +384,20 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
     }
 
     fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
-        debug_assert_eq!(
-            ti.hir_id.owner,
-            self.definitions.opt_hir_id_to_local_def_id(ti.hir_id).unwrap()
-        );
-        self.with_dep_node_owner(ti.hir_id.owner, ti, |this, hash| {
-            this.insert_with_hash(ti.span, ti.hir_id, Node::TraitItem(ti), hash);
+        self.with_dep_node_owner(ti.def_id, ti, |this, hash| {
+            this.insert_with_hash(ti.span, ti.hir_id(), Node::TraitItem(ti), hash);
 
-            this.with_parent(ti.hir_id, |this| {
+            this.with_parent(ti.hir_id(), |this| {
                 intravisit::walk_trait_item(this, ti);
             });
         });
     }
 
     fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
-        debug_assert_eq!(
-            ii.hir_id.owner,
-            self.definitions.opt_hir_id_to_local_def_id(ii.hir_id).unwrap()
-        );
-        self.with_dep_node_owner(ii.hir_id.owner, ii, |this, hash| {
-            this.insert_with_hash(ii.span, ii.hir_id, Node::ImplItem(ii), hash);
+        self.with_dep_node_owner(ii.def_id, ii, |this, hash| {
+            this.insert_with_hash(ii.span, ii.hir_id(), Node::ImplItem(ii), hash);
 
-            this.with_parent(ii.hir_id, |this| {
+            this.with_parent(ii.hir_id(), |this| {
                 intravisit::walk_impl_item(this, ii);
             });
         });
@@ -532,15 +514,15 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         // Exported macros are visited directly from the crate root,
         // so they do not have `parent_node` set.
         // Find the correct enclosing module from their DefKey.
-        let def_key = self.definitions.def_key(macro_def.hir_id.owner);
+        let def_key = self.definitions.def_key(macro_def.def_id);
         let parent = def_key.parent.map_or(hir::CRATE_HIR_ID, |local_def_index| {
             self.definitions.local_def_id_to_hir_id(LocalDefId { local_def_index })
         });
         self.with_parent(parent, |this| {
-            this.with_dep_node_owner(macro_def.hir_id.owner, macro_def, |this, hash| {
+            this.with_dep_node_owner(macro_def.def_id, macro_def, |this, hash| {
                 this.insert_with_hash(
                     macro_def.span,
-                    macro_def.hir_id,
+                    macro_def.hir_id(),
                     Node::MacroDef(macro_def),
                     hash,
                 );
@@ -590,18 +572,3 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         self.visit_nested_foreign_item(id);
     }
 }
-
-struct HirItemLike<T> {
-    item_like: T,
-}
-
-impl<'hir, T> HashStable<StableHashingContext<'hir>> for HirItemLike<T>
-where
-    T: HashStable<StableHashingContext<'hir>>,
-{
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, hasher: &mut StableHasher) {
-        hcx.while_hashing_hir_bodies(true, |hcx| {
-            self.item_like.hash_stable(hcx, hasher);
-        });
-    }
-}
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index ee12c0e786d..5c2bd575e7d 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -285,7 +285,7 @@ impl<'hir> Map<'hir> {
             let owner = self.tcx.hir_owner_nodes(id.owner);
             owner.and_then(|owner| {
                 let node = owner.nodes[id.local_id].as_ref();
-                // FIXME(eddyb) use a single generic type insted of having both
+                // FIXME(eddyb) use a single generic type instead of having both
                 // `Entry` and `ParentedNode`, which are effectively the same.
                 // Alternatively, rewrite code using `Entry` to use `ParentedNode`.
                 node.map(|node| Entry {
@@ -300,29 +300,29 @@ impl<'hir> Map<'hir> {
         self.find_entry(id).unwrap()
     }
 
-    pub fn item(&self, id: HirId) -> &'hir Item<'hir> {
-        match self.find(id).unwrap() {
+    pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
+        match self.find(id.hir_id()).unwrap() {
             Node::Item(item) => item,
             _ => bug!(),
         }
     }
 
     pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
-        match self.find(id.hir_id).unwrap() {
+        match self.find(id.hir_id()).unwrap() {
             Node::TraitItem(item) => item,
             _ => bug!(),
         }
     }
 
     pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
-        match self.find(id.hir_id).unwrap() {
+        match self.find(id.hir_id()).unwrap() {
             Node::ImplItem(item) => item,
             _ => bug!(),
         }
     }
 
     pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
-        match self.find(id.hir_id).unwrap() {
+        match self.find(id.hir_id()).unwrap() {
             Node::ForeignItem(item) => item,
             _ => bug!(),
         }
@@ -449,7 +449,7 @@ impl<'hir> Map<'hir> {
         }
     }
 
-    pub fn trait_impls(&self, trait_did: DefId) -> &'hir [HirId] {
+    pub fn trait_impls(&self, trait_did: DefId) -> &'hir [LocalDefId] {
         self.tcx.all_local_trait_impls(LOCAL_CRATE).get(&trait_did).map_or(&[], |xs| &xs[..])
     }
 
@@ -479,19 +479,19 @@ impl<'hir> Map<'hir> {
         let module = self.tcx.hir_module_items(module);
 
         for id in &module.items {
-            visitor.visit_item(self.expect_item(*id));
+            visitor.visit_item(self.item(*id));
         }
 
         for id in &module.trait_items {
-            visitor.visit_trait_item(self.expect_trait_item(id.hir_id));
+            visitor.visit_trait_item(self.trait_item(*id));
         }
 
         for id in &module.impl_items {
-            visitor.visit_impl_item(self.expect_impl_item(id.hir_id));
+            visitor.visit_impl_item(self.impl_item(*id));
         }
 
         for id in &module.foreign_items {
-            visitor.visit_foreign_item(self.expect_foreign_item(id.hir_id));
+            visitor.visit_foreign_item(self.foreign_item(*id));
         }
     }
 
@@ -500,7 +500,7 @@ impl<'hir> Map<'hir> {
         V: Visitor<'hir>,
     {
         for id in self.krate().exported_macros {
-            visitor.visit_macro_def(self.expect_macro_def(id.hir_id));
+            visitor.visit_macro_def(self.expect_macro_def(id.hir_id()));
         }
     }
 
@@ -854,22 +854,22 @@ impl<'hir> Map<'hir> {
     /// corresponding to the node-ID.
     pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] {
         self.find_entry(id).map_or(&[], |entry| match entry.node {
-            Node::Param(a) => &a.attrs[..],
+            Node::Param(a) => a.attrs,
             Node::Local(l) => &l.attrs[..],
-            Node::Item(i) => &i.attrs[..],
-            Node::ForeignItem(fi) => &fi.attrs[..],
-            Node::TraitItem(ref ti) => &ti.attrs[..],
-            Node::ImplItem(ref ii) => &ii.attrs[..],
-            Node::Variant(ref v) => &v.attrs[..],
-            Node::Field(ref f) => &f.attrs[..],
+            Node::Item(i) => i.attrs,
+            Node::ForeignItem(fi) => fi.attrs,
+            Node::TraitItem(ref ti) => ti.attrs,
+            Node::ImplItem(ref ii) => ii.attrs,
+            Node::Variant(ref v) => v.attrs,
+            Node::Field(ref f) => f.attrs,
             Node::Expr(ref e) => &*e.attrs,
-            Node::Stmt(ref s) => s.kind.attrs(|id| self.item(id.id)),
+            Node::Stmt(ref s) => s.kind.attrs(|id| self.item(id)),
             Node::Arm(ref a) => &*a.attrs,
-            Node::GenericParam(param) => &param.attrs[..],
+            Node::GenericParam(param) => param.attrs,
             // Unit/tuple structs/variants take the attributes straight from
             // the struct/variant definition.
             Node::Ctor(..) => self.attrs(self.get_parent_item(id)),
-            Node::Crate(item) => &item.attrs[..],
+            Node::Crate(item) => item.attrs,
             Node::MacroDef(def) => def.attrs,
             Node::AnonConst(..)
             | Node::PathSegment(..)
@@ -977,7 +977,7 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> {
         self.body(id)
     }
 
-    fn item(&self, id: HirId) -> &'hir Item<'hir> {
+    fn item(&self, id: ItemId) -> &'hir Item<'hir> {
         self.item(id)
     }
 
@@ -994,47 +994,6 @@ impl<'hir> intravisit::Map<'hir> for Map<'hir> {
     }
 }
 
-trait Named {
-    fn name(&self) -> Symbol;
-}
-
-impl<T: Named> Named for Spanned<T> {
-    fn name(&self) -> Symbol {
-        self.node.name()
-    }
-}
-
-impl Named for Item<'_> {
-    fn name(&self) -> Symbol {
-        self.ident.name
-    }
-}
-impl Named for ForeignItem<'_> {
-    fn name(&self) -> Symbol {
-        self.ident.name
-    }
-}
-impl Named for Variant<'_> {
-    fn name(&self) -> Symbol {
-        self.ident.name
-    }
-}
-impl Named for StructField<'_> {
-    fn name(&self) -> Symbol {
-        self.ident.name
-    }
-}
-impl Named for TraitItem<'_> {
-    fn name(&self) -> Symbol {
-        self.ident.name
-    }
-}
-impl Named for ImplItem<'_> {
-    fn name(&self) -> Symbol {
-        self.ident.name
-    }
-}
-
 pub(super) fn index_hir<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> &'tcx IndexedHir<'tcx> {
     assert_eq!(cnum, LOCAL_CRATE);
 
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 6934e06d4c2..5f9cf8771ea 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -73,11 +73,7 @@ pub fn provide(providers: &mut Providers) {
     };
     providers.hir_crate = |tcx, _| tcx.untracked_crate;
     providers.index_hir = map::index_hir;
-    providers.hir_module_items = |tcx, id| {
-        let hir = tcx.hir();
-        let module = hir.local_def_id_to_hir_id(id);
-        &tcx.untracked_crate.modules[&module]
-    };
+    providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
     providers.hir_owner = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].signature;
     providers.hir_owner_nodes = |tcx, id| tcx.index_hir(LOCAL_CRATE).map[id].with_bodies.as_deref();
     providers.def_span = |tcx, def_id| tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP);
diff --git a/compiler/rustc_middle/src/ich/impls_hir.rs b/compiler/rustc_middle/src/ich/impls_hir.rs
index d6c6cef1751..5ef70a89051 100644
--- a/compiler/rustc_middle/src/ich/impls_hir.rs
+++ b/compiler/rustc_middle/src/ich/impls_hir.rs
@@ -55,8 +55,7 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
         let item_ids_hash = item_ids
             .iter()
             .map(|id| {
-                let (def_path_hash, local_id) = id.id.to_stable_hash_key(hcx);
-                debug_assert_eq!(local_id, hir::ItemLocalId::from_u32(0));
+                let def_path_hash = id.to_stable_hash_key(hcx);
                 def_path_hash.0
             })
             .fold(Fingerprint::ZERO, |a, b| a.combine_commutative(b));
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 6ae83a7f667..d9e88265050 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -76,6 +76,7 @@ pub mod query;
 
 #[macro_use]
 pub mod arena;
+#[macro_use]
 pub mod dep_graph;
 pub mod hir;
 pub mod ich;
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 0bdccf7b5f0..ca73481b216 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -5,7 +5,10 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::{DiagnosticBuilder, DiagnosticId};
 use rustc_hir::HirId;
-use rustc_session::lint::{builtin, Level, Lint, LintId};
+use rustc_session::lint::{
+    builtin::{self, FORBIDDEN_LINT_GROUPS},
+    Level, Lint, LintId,
+};
 use rustc_session::{DiagnosticMessageId, Session};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
@@ -89,7 +92,12 @@ impl LintLevelSets {
         // If we're about to issue a warning, check at the last minute for any
         // directives against the warnings "lint". If, for example, there's an
         // `allow(warnings)` in scope then we want to respect that instead.
-        if level == Level::Warn {
+        //
+        // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically
+        // triggers in cases (like #80988) where you have `forbid(warnings)`,
+        // and so if we turned that into an error, it'd defeat the purpose of the
+        // future compatibility warning.
+        if level == Level::Warn && LintId::of(lint) != LintId::of(FORBIDDEN_LINT_GROUPS) {
             let (warnings_level, warnings_src) =
                 self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux);
             if let Some(configured_warning_level) = warnings_level {
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index cf931ece712..26ce3c2c3db 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -40,29 +40,45 @@ pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'
     struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
 }
 
+#[cfg(target_arch = "x86_64")]
+static_assert_size!(InterpErrorInfo<'_>, 8);
+
 /// Packages the kind of error we got from the const code interpreter
 /// up with a Rust-level backtrace of where the error occurred.
 /// Thsese should always be constructed by calling `.into()` on
 /// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*`
 /// macros for this.
 #[derive(Debug)]
-pub struct InterpErrorInfo<'tcx> {
-    pub kind: InterpError<'tcx>,
+pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>);
+
+#[derive(Debug)]
+struct InterpErrorInfoInner<'tcx> {
+    kind: InterpError<'tcx>,
     backtrace: Option<Box<Backtrace>>,
 }
 
 impl fmt::Display for InterpErrorInfo<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", self.kind)
+        write!(f, "{}", self.0.kind)
     }
 }
 
-impl InterpErrorInfo<'_> {
+impl InterpErrorInfo<'tcx> {
     pub fn print_backtrace(&self) {
-        if let Some(backtrace) = self.backtrace.as_ref() {
+        if let Some(backtrace) = self.0.backtrace.as_ref() {
             print_backtrace(backtrace);
         }
     }
+
+    pub fn into_kind(self) -> InterpError<'tcx> {
+        let InterpErrorInfo(box InterpErrorInfoInner { kind, .. }) = self;
+        kind
+    }
+
+    #[inline]
+    pub fn kind(&self) -> &InterpError<'tcx> {
+        &self.0.kind
+    }
 }
 
 fn print_backtrace(backtrace: &Backtrace) {
@@ -108,7 +124,7 @@ impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
             }
         };
 
-        InterpErrorInfo { kind, backtrace }
+        InterpErrorInfo(Box::new(InterpErrorInfoInner { kind, backtrace }))
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 0517ec5bb1a..3e7b93b32a6 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -31,6 +31,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still
     /// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
     /// returned.
+    #[instrument(level = "debug", skip(self))]
     pub fn const_eval_resolve(
         self,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index eb13c89544c..6c2468b9ffe 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -7,7 +7,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
-use rustc_hir::HirId;
+use rustc_hir::{HirId, ItemId};
 use rustc_session::config::OptLevel;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
@@ -43,7 +43,7 @@ pub enum InstantiationMode {
 pub enum MonoItem<'tcx> {
     Fn(Instance<'tcx>),
     Static(DefId),
-    GlobalAsm(HirId),
+    GlobalAsm(ItemId),
 }
 
 impl<'tcx> MonoItem<'tcx> {
@@ -71,9 +71,8 @@ impl<'tcx> MonoItem<'tcx> {
         match *self {
             MonoItem::Fn(instance) => tcx.symbol_name(instance),
             MonoItem::Static(def_id) => tcx.symbol_name(Instance::mono(tcx, def_id)),
-            MonoItem::GlobalAsm(hir_id) => {
-                let def_id = tcx.hir().local_def_id(hir_id);
-                SymbolName::new(tcx, &format!("global_asm_{:?}", def_id))
+            MonoItem::GlobalAsm(item_id) => {
+                SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.def_id))
             }
         }
     }
@@ -178,7 +177,7 @@ impl<'tcx> MonoItem<'tcx> {
             MonoItem::Static(def_id) => {
                 def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
             }
-            MonoItem::GlobalAsm(hir_id) => Some(hir_id),
+            MonoItem::GlobalAsm(item_id) => Some(item_id.hir_id()),
         }
         .map(|hir_id| tcx.hir().span(hir_id))
     }
@@ -195,9 +194,9 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
             MonoItem::Static(def_id) => {
                 def_id.hash_stable(hcx, hasher);
             }
-            MonoItem::GlobalAsm(node_id) => {
+            MonoItem::GlobalAsm(item_id) => {
                 hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-                    node_id.hash_stable(hcx, hasher);
+                    item_id.hash_stable(hcx, hasher);
                 })
             }
         }
@@ -351,7 +350,7 @@ impl<'tcx> CodegenUnit<'tcx> {
                     MonoItem::Static(def_id) => {
                         def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
                     }
-                    MonoItem::GlobalAsm(hir_id) => Some(hir_id),
+                    MonoItem::GlobalAsm(item_id) => Some(item_id.hir_id()),
                 },
                 item.symbol_name(tcx),
             )
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index ca528b2f091..4207e2dea34 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1,28 +1,3 @@
-use crate::dep_graph::SerializedDepNodeIndex;
-use crate::mir::interpret::{GlobalId, LitToConstInput};
-use crate::traits;
-use crate::traits::query::{
-    CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
-    CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
-    CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
-};
-use crate::ty::query::queries;
-use crate::ty::subst::{GenericArg, SubstsRef};
-use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
-use rustc_query_system::query::QueryDescription;
-
-use rustc_span::symbol::Symbol;
-use std::borrow::Cow;
-
-fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
-    if def_id.is_top_level_module() {
-        "top-level module".to_string()
-    } else {
-        format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
-    }
-}
-
 // Each of these queries corresponds to a function pointer field in the
 // `Providers` struct for requesting a value of that type, and a method
 // on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way
@@ -126,11 +101,6 @@ rustc_queries! {
         desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) }
         storage(ArenaCacheSelector<'tcx>)
         cache_on_disk_if { key.is_local() }
-        load_cached(tcx, id) {
-            let generics: Option<ty::Generics> = tcx.queries.on_disk_cache.as_ref()
-                                                    .and_then(|c| c.try_load_query_result(tcx, id));
-            generics
-        }
     }
 
     /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
@@ -443,12 +413,23 @@ rustc_queries! {
     /// full predicates are available (note that supertraits have
     /// additional acyclicity requirements).
     query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
-        desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) }
+        desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) }
+    }
+
+    /// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query
+    /// returns the full set of predicates. If `Some<Ident>`, then the query returns only the
+    /// subset of super-predicates that reference traits that define the given associated type.
+    /// This is used to avoid cycles in resolving types like `T::Item`.
+    query super_predicates_that_define_assoc_type(key: (DefId, Option<rustc_span::symbol::Ident>)) -> ty::GenericPredicates<'tcx> {
+        desc { |tcx| "computing the super traits of `{}`{}",
+            tcx.def_path_str(key.0),
+            if let Some(assoc_name) = key.1 { format!(" with associated type name `{}`", assoc_name) } else { "".to_string() },
+        }
     }
 
     /// To avoid cycles within the predicates of a single item we compute
     /// per-type-parameter predicates for resolving `T::AssocTy`.
-    query type_param_predicates(key: (DefId, LocalDefId)) -> ty::GenericPredicates<'tcx> {
+    query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> {
         desc { |tcx| "computing the bounds for type parameter `{}`", {
             let id = tcx.hir().local_def_id_to_hir_id(key.1);
             tcx.hir().ty_param_name(id)
@@ -692,8 +673,8 @@ rustc_queries! {
         cache_on_disk_if { true }
         load_cached(tcx, id) {
             let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
-                .queries.on_disk_cache.as_ref()
-                .and_then(|c| c.try_load_query_result(tcx, id));
+                .on_disk_cache.as_ref()
+                .and_then(|c| c.try_load_query_result(*tcx, id));
 
             typeck_results.map(|x| &*tcx.arena.alloc(x))
         }
@@ -946,7 +927,7 @@ rustc_queries! {
     /// Passing in any other crate will cause an ICE.
     ///
     /// [`LOCAL_CRATE`]: rustc_hir::def_id::LOCAL_CRATE
-    query all_local_trait_impls(local_crate: CrateNum) -> &'tcx BTreeMap<DefId, Vec<hir::HirId>> {
+    query all_local_trait_impls(local_crate: CrateNum) -> &'tcx BTreeMap<DefId, Vec<LocalDefId>> {
         desc { "local trait impls" }
     }
 
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 163b400973b..9deeaf462d6 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -228,7 +228,10 @@ pub enum ObligationCauseCode<'tcx> {
     /// Inline asm operand type must be `Sized`.
     InlineAsmSized,
     /// `[T, ..n]` implies that `T` must be `Copy`.
-    RepeatVec,
+    /// If the function in the array repeat expression is a `const fn`,
+    /// display a help message suggesting to move the function call to a
+    /// new `const` item while saying that `T` doesn't implement `Copy`.
+    RepeatVec(bool),
 
     /// Types of fields (other than the last, except for packed structs) in a struct must be sized.
     FieldSized {
@@ -476,6 +479,9 @@ pub enum ImplSource<'tcx, N> {
     /// ImplSource for a builtin `DeterminantKind` trait implementation.
     DiscriminantKind(ImplSourceDiscriminantKindData),
 
+    /// ImplSource for a builtin `Pointee` trait implementation.
+    Pointee(ImplSourcePointeeData),
+
     /// ImplSource automatically generated for a generator.
     Generator(ImplSourceGeneratorData<'tcx, N>),
 
@@ -494,7 +500,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
             ImplSource::Generator(c) => c.nested,
             ImplSource::Object(d) => d.nested,
             ImplSource::FnPointer(d) => d.nested,
-            ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(),
+            ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
+            | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
             ImplSource::TraitAlias(d) => d.nested,
         }
     }
@@ -509,7 +516,8 @@ impl<'tcx, N> ImplSource<'tcx, N> {
             ImplSource::Generator(c) => &c.nested[..],
             ImplSource::Object(d) => &d.nested[..],
             ImplSource::FnPointer(d) => &d.nested[..],
-            ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => &[],
+            ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
+            | ImplSource::Pointee(ImplSourcePointeeData) => &[],
             ImplSource::TraitAlias(d) => &d.nested[..],
         }
     }
@@ -554,6 +562,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
             ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => {
                 ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
             }
+            ImplSource::Pointee(ImplSourcePointeeData) => {
+                ImplSource::Pointee(ImplSourcePointeeData)
+            }
             ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData {
                 alias_def_id: d.alias_def_id,
                 substs: d.substs,
@@ -632,6 +643,9 @@ pub struct ImplSourceFnPointerData<'tcx, N> {
 #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub struct ImplSourceDiscriminantKindData;
 
+#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
+pub struct ImplSourcePointeeData;
+
 #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceTraitAliasData<'tcx, N> {
     pub alias_def_id: DefId,
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index e056240f941..ab085175762 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -125,6 +125,9 @@ pub enum SelectionCandidate<'tcx> {
     /// Builtin implementation of `DiscriminantKind`.
     DiscriminantKindCandidate,
 
+    /// Builtin implementation of `Pointee`.
+    PointeeCandidate,
+
     TraitAliasCandidate(DefId),
 
     /// Matching `dyn Trait` with a supertrait of `Trait`. The index is the
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index 5a17d38c734..4f978e63630 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -19,6 +19,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> {
 
             super::ImplSource::DiscriminantKind(ref d) => write!(f, "{:?}", d),
 
+            super::ImplSource::Pointee(ref d) => write!(f, "{:?}", d),
+
             super::ImplSource::Object(ref d) => write!(f, "{:?}", d),
 
             super::ImplSource::Param(ref n, ct) => {
@@ -110,4 +112,5 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx,
 TrivialTypeFoldableAndLiftImpls! {
     super::IfExpressionCause,
     super::ImplSourceDiscriminantKindData,
+    super::ImplSourcePointeeData,
 }
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 0dad5df4855..73ad87a9ef2 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -253,7 +253,7 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for SubstsRef<'tcx> {
     fn decode(decoder: &mut D) -> Result<Self, D::Error> {
         let len = decoder.read_usize()?;
         let tcx = decoder.tcx();
-        Ok(tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))?)
+        tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))
     }
 }
 
@@ -314,7 +314,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::AdtDef {
 impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> {
     fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
         let len = decoder.read_usize()?;
-        Ok(decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))?)
+        decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))
     }
 }
 
@@ -323,9 +323,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D>
 {
     fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
         let len = decoder.read_usize()?;
-        Ok(decoder
-            .tcx()
-            .mk_poly_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))?)
+        decoder.tcx().mk_poly_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 041c040f0b7..ed953b98113 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -55,7 +55,7 @@ impl<'tcx> Const<'tcx> {
 
         let lit_input = match expr.kind {
             hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
-            hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind {
+            hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
                 hir::ExprKind::Lit(ref lit) => {
                     Some(LitToConstInput { lit: &lit.node, ty, neg: true })
                 }
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 1255302f743..d316d595b1a 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -14,7 +14,7 @@ use crate::middle::stability;
 use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
 use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted};
 use crate::traits;
-use crate::ty::query::{self, TyCtxtAt};
+use crate::ty::query::{self, OnDiskCache, TyCtxtAt};
 use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
 use crate::ty::TyKind::*;
 use crate::ty::{
@@ -52,7 +52,7 @@ use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
 use rustc_session::lint::{Level, Lint};
 use rustc_session::Session;
 use rustc_span::source_map::MultiSpan;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{Layout, TargetDataLayout, VariantIdx};
 use rustc_target::spec::abi;
@@ -962,7 +962,14 @@ pub struct GlobalCtxt<'tcx> {
     pub(crate) untracked_crate: &'tcx hir::Crate<'tcx>,
     pub(crate) definitions: &'tcx Definitions,
 
-    pub queries: query::Queries<'tcx>,
+    /// This provides access to the incremental compilation on-disk cache for query results.
+    /// Do not access this directly. It is only meant to be used by
+    /// `DepGraph::try_mark_green()` and the query infrastructure.
+    /// This is `None` if we are not incremental compilation mode
+    pub on_disk_cache: Option<OnDiskCache<'tcx>>,
+
+    pub queries: &'tcx dyn query::QueryEngine<'tcx>,
+    pub query_caches: query::QueryCaches<'tcx>,
 
     maybe_unused_trait_imports: FxHashSet<LocalDefId>,
     maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
@@ -1102,14 +1109,13 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn create_global_ctxt(
         s: &'tcx Session,
         lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
-        local_providers: ty::query::Providers,
-        extern_providers: ty::query::Providers,
         arena: &'tcx WorkerLocal<Arena<'tcx>>,
         resolutions: ty::ResolverOutputs,
         krate: &'tcx hir::Crate<'tcx>,
         definitions: &'tcx Definitions,
         dep_graph: DepGraph,
-        on_disk_query_result_cache: Option<query::OnDiskCache<'tcx>>,
+        on_disk_cache: Option<query::OnDiskCache<'tcx>>,
+        queries: &'tcx dyn query::QueryEngine<'tcx>,
         crate_name: &str,
         output_filenames: &OutputFilenames,
     ) -> GlobalCtxt<'tcx> {
@@ -1121,10 +1127,6 @@ impl<'tcx> TyCtxt<'tcx> {
         let common_lifetimes = CommonLifetimes::new(&interners);
         let common_consts = CommonConsts::new(&interners, &common_types);
         let cstore = resolutions.cstore;
-        let crates = cstore.crates_untracked();
-        let max_cnum = crates.iter().map(|c| c.as_usize()).max().unwrap_or(0);
-        let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1);
-        providers[LOCAL_CRATE] = local_providers;
 
         let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
         for (hir_id, v) in krate.trait_map.iter() {
@@ -1153,7 +1155,9 @@ impl<'tcx> TyCtxt<'tcx> {
             extern_prelude: resolutions.extern_prelude,
             untracked_crate: krate,
             definitions,
-            queries: query::Queries::new(providers, extern_providers, on_disk_query_result_cache),
+            on_disk_cache,
+            queries,
+            query_caches: query::QueryCaches::default(),
             ty_rcache: Default::default(),
             pred_rcache: Default::default(),
             selection_cache: Default::default(),
@@ -1318,7 +1322,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     pub fn serialize_query_result_cache(self, encoder: &mut FileEncoder) -> FileEncodeResult {
-        self.queries.on_disk_cache.as_ref().map_or(Ok(()), |c| c.serialize(self, encoder))
+        self.on_disk_cache.as_ref().map_or(Ok(()), |c| c.serialize(self, encoder))
     }
 
     /// If `true`, we should use the MIR-based borrowck, but also
@@ -2053,6 +2057,42 @@ impl<'tcx> TyCtxt<'tcx> {
         self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }))
     }
 
+    /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name`
+    /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`.
+    pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool {
+        self.super_traits_of(trait_def_id).any(|trait_did| {
+            self.associated_items(trait_did)
+                .find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, trait_did)
+                .is_some()
+        })
+    }
+
+    /// Computes the def-ids of the transitive super-traits of `trait_def_id`. This (intentionally)
+    /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used
+    /// to identify which traits may define a given associated type to help avoid cycle errors.
+    /// Returns a `DefId` iterator.
+    fn super_traits_of(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx {
+        let mut set = FxHashSet::default();
+        let mut stack = vec![trait_def_id];
+
+        set.insert(trait_def_id);
+
+        iter::from_fn(move || -> Option<DefId> {
+            let trait_did = stack.pop()?;
+            let generic_predicates = self.super_predicates_of(trait_did);
+
+            for (predicate, _) in generic_predicates.predicates {
+                if let ty::PredicateKind::Trait(data, _) = predicate.kind().skip_binder() {
+                    if set.insert(data.def_id()) {
+                        stack.push(data.def_id());
+                    }
+                }
+            }
+
+            Some(trait_did)
+        })
+    }
+
     /// Given a closure signature, returns an equivalent fn signature. Detuples
     /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then
     /// you would get a `fn(u32, i32)`.
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 4a131a4ec05..f41bb7e6d63 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -75,6 +75,36 @@ impl<'tcx> TyS<'tcx> {
     }
 }
 
+pub fn suggest_arbitrary_trait_bound(
+    generics: &hir::Generics<'_>,
+    err: &mut DiagnosticBuilder<'_>,
+    param_name: &str,
+    constraint: &str,
+) -> bool {
+    let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name);
+    match (param, param_name) {
+        (Some(_), "Self") => return false,
+        _ => {}
+    }
+    // Suggest a where clause bound for a non-type paremeter.
+    let (action, prefix) = if generics.where_clause.predicates.is_empty() {
+        ("introducing a", " where ")
+    } else {
+        ("extending the", ", ")
+    };
+    err.span_suggestion_verbose(
+        generics.where_clause.tail_span_for_suggestion(),
+        &format!(
+            "consider {} `where` bound, but there might be an alternative better way to express \
+             this requirement",
+            action,
+        ),
+        format!("{}{}: {}", prefix, param_name, constraint),
+        Applicability::MaybeIncorrect,
+    );
+    true
+}
+
 /// Suggest restricting a type param with a new bound.
 pub fn suggest_constraining_type_param(
     tcx: TyCtxt<'_>,
@@ -289,7 +319,7 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
             }
             hir::TyKind::OpaqueDef(item_id, _) => {
                 self.0.push(ty);
-                let item = self.1.expect_item(item_id.id);
+                let item = self.1.item(item_id);
                 hir::intravisit::walk_item(self, item);
             }
             _ => {}
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 1669c59d7f1..bf315c81588 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -1,5 +1,6 @@
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use crate::ty::diagnostics::suggest_constraining_type_param;
+use crate::ty::print::{FmtPrinter, Printer};
 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{pluralize, DiagnosticBuilder};
@@ -228,12 +229,17 @@ impl<'tcx> ty::TyS<'tcx> {
             ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.def_path_str(def.did)).into(),
             ty::Foreign(def_id) => format!("extern type `{}`", tcx.def_path_str(def_id)).into(),
             ty::Array(t, n) => {
+                if t.is_simple_ty() {
+                    return format!("array `{}`", self).into();
+                }
+
                 let n = tcx.lift(n).unwrap();
-                match n.try_eval_usize(tcx, ty::ParamEnv::empty()) {
-                    _ if t.is_simple_ty() => format!("array `{}`", self).into(),
-                    Some(n) => format!("array of {} element{}", n, pluralize!(n)).into(),
-                    None => "array".into(),
+                if let ty::ConstKind::Value(v) = n.val {
+                    if let Some(n) = v.try_to_machine_usize(tcx) {
+                        return format!("array of {} element{}", n, pluralize!(n)).into();
+                    }
                 }
+                "array".into()
             }
             ty::Slice(ty) if ty.is_simple_ty() => format!("slice `{}`", self).into(),
             ty::Slice(_) => "slice".into(),
@@ -264,7 +270,7 @@ impl<'tcx> ty::TyS<'tcx> {
                 }
             }
             ty::Closure(..) => "closure".into(),
-            ty::Generator(..) => "generator".into(),
+            ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
             ty::GeneratorWitness(..) => "generator witness".into(),
             ty::Tuple(..) => "tuple".into(),
             ty::Infer(ty::TyVar(_)) => "inferred type".into(),
@@ -282,7 +288,7 @@ impl<'tcx> ty::TyS<'tcx> {
         }
     }
 
-    pub fn prefix_string(&self) -> Cow<'static, str> {
+    pub fn prefix_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
         match *self.kind() {
             ty::Infer(_)
             | ty::Error(_)
@@ -308,7 +314,7 @@ impl<'tcx> ty::TyS<'tcx> {
             ty::FnPtr(_) => "fn pointer".into(),
             ty::Dynamic(..) => "trait object".into(),
             ty::Closure(..) => "closure".into(),
-            ty::Generator(..) => "generator".into(),
+            ty::Generator(def_id, ..) => tcx.generator_kind(def_id).unwrap().descr().into(),
             ty::GeneratorWitness(..) => "generator witness".into(),
             ty::Tuple(..) => "tuple".into(),
             ty::Placeholder(..) => "higher-ranked type".into(),
@@ -400,14 +406,22 @@ impl<'tcx> TyCtxt<'tcx> {
                         {
                             // Synthesize the associated type restriction `Add<Output = Expected>`.
                             // FIXME: extract this logic for use in other diagnostics.
-                            let trait_ref = proj.trait_ref(self);
+                            let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
                             let path =
                                 self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
                             let item_name = self.item_name(proj.item_def_id);
+                            let item_args = self.format_generic_args(assoc_substs);
+
                             let path = if path.ends_with('>') {
-                                format!("{}, {} = {}>", &path[..path.len() - 1], item_name, p)
+                                format!(
+                                    "{}, {}{} = {}>",
+                                    &path[..path.len() - 1],
+                                    item_name,
+                                    item_args,
+                                    p
+                                )
                             } else {
-                                format!("{}<{} = {}>", path, item_name, p)
+                                format!("{}<{}{} = {}>", path, item_name, item_args, p)
                             };
                             note = !suggest_constraining_type_param(
                                 self,
@@ -556,7 +570,7 @@ impl<T> Trait<T> for X {
         ty: Ty<'tcx>,
     ) -> bool {
         let assoc = self.associated_item(proj_ty.item_def_id);
-        let trait_ref = proj_ty.trait_ref(self);
+        let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
         if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
             if let Some(hir_generics) = item.generics() {
                 // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
@@ -590,6 +604,7 @@ impl<T> Trait<T> for X {
                             &trait_ref,
                             pred.bounds,
                             &assoc,
+                            assoc_substs,
                             ty,
                             msg,
                         ) {
@@ -607,6 +622,7 @@ impl<T> Trait<T> for X {
                             &trait_ref,
                             param.bounds,
                             &assoc,
+                            assoc_substs,
                             ty,
                             msg,
                         );
@@ -692,6 +708,7 @@ impl<T> Trait<T> for X {
                 db,
                 self.def_span(def_id),
                 &assoc,
+                proj_ty.trait_ref_and_own_substs(self).1,
                 values.found,
                 &msg,
             ) {
@@ -816,7 +833,7 @@ fn foo(&self) -> Self::T { String::new() }
                             // an assoc type as a return type (#72076).
                             if let hir::Defaultness::Default { has_value: true } = item.defaultness
                             {
-                                if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found {
+                                if self.type_of(item.id.def_id) == found {
                                     db.span_label(
                                         item.span,
                                         "associated type defaults can't be assumed inside the \
@@ -836,7 +853,7 @@ fn foo(&self) -> Self::T { String::new() }
             })) => {
                 for item in &items[..] {
                     if let hir::AssocItemKind::Type = item.kind {
-                        if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found {
+                        if self.type_of(item.id.def_id) == found {
                             db.span_label(item.span, "expected this associated type");
                             return true;
                         }
@@ -856,6 +873,7 @@ fn foo(&self) -> Self::T { String::new() }
         trait_ref: &ty::TraitRef<'tcx>,
         bounds: hir::GenericBounds<'_>,
         assoc: &ty::AssocItem,
+        assoc_substs: &[ty::GenericArg<'tcx>],
         ty: Ty<'tcx>,
         msg: &str,
     ) -> bool {
@@ -865,7 +883,12 @@ fn foo(&self) -> Self::T { String::new() }
                 // Relate the type param against `T` in `<A as T>::Foo`.
                 ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id)
                     && self.constrain_associated_type_structured_suggestion(
-                        db, ptr.span, assoc, ty, msg,
+                        db,
+                        ptr.span,
+                        assoc,
+                        assoc_substs,
+                        ty,
+                        msg,
                     )
             }
             _ => false,
@@ -879,6 +902,7 @@ fn foo(&self) -> Self::T { String::new() }
         db: &mut DiagnosticBuilder<'_>,
         span: Span,
         assoc: &ty::AssocItem,
+        assoc_substs: &[ty::GenericArg<'tcx>],
         ty: Ty<'tcx>,
         msg: &str,
     ) -> bool {
@@ -890,11 +914,20 @@ fn foo(&self) -> Self::T { String::new() }
                 let span = Span::new(pos, pos, span.ctxt());
                 (span, format!(", {} = {}", assoc.ident, ty))
             } else {
-                (span.shrink_to_hi(), format!("<{} = {}>", assoc.ident, ty))
+                let item_args = self.format_generic_args(assoc_substs);
+                (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty))
             };
             db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
             return true;
         }
         false
     }
+
+    fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
+        let mut item_args = String::new();
+        FmtPrinter::new(self, &mut item_args, hir::def::Namespace::TypeNS)
+            .path_generic_args(Ok, args)
+            .expect("could not write to `String`.");
+        item_args
+    }
 }
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 6ca5dcc532d..de012a69574 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -347,6 +347,7 @@ impl<'tcx> Instance<'tcx> {
     }
 
     // This should be kept up to date with `resolve`.
+    #[instrument(level = "debug", skip(tcx))]
     pub fn resolve_opt_const_arg(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 596e4f67174..0b592ca4710 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -188,6 +188,13 @@ pub const FAT_PTR_ADDR: usize = 0;
 /// - For a slice, this is the length.
 pub const FAT_PTR_EXTRA: usize = 1;
 
+/// The maximum supported number of lanes in a SIMD vector.
+///
+/// This value is selected based on backend support:
+/// * LLVM does not appear to have a vector width limit.
+/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
+pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
+
 #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable)]
 pub enum LayoutError<'tcx> {
     Unknown(Ty<'tcx>),
@@ -717,10 +724,22 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                 };
 
                 // SIMD vectors of zero length are not supported.
+                // Additionally, lengths are capped at 2^16 as a fixed maximum backends must
+                // support.
                 //
                 // Can't be caught in typeck if the array length is generic.
                 if e_len == 0 {
                     tcx.sess.fatal(&format!("monomorphising SIMD type `{}` of zero length", ty));
+                } else if !e_len.is_power_of_two() {
+                    tcx.sess.fatal(&format!(
+                        "monomorphising SIMD type `{}` of non-power-of-two length",
+                        ty
+                    ));
+                } else if e_len > MAX_SIMD_LANES {
+                    tcx.sess.fatal(&format!(
+                        "monomorphising SIMD type `{}` of length greater than {}",
+                        ty, MAX_SIMD_LANES,
+                    ));
                 }
 
                 // Compute the ABI of the element type:
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index babab005edb..018d269bfd1 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -100,8 +100,6 @@ pub use self::list::List;
 
 pub use self::trait_def::TraitDef;
 
-pub use self::query::queries;
-
 pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt};
 
 pub mod _match;
@@ -1289,8 +1287,22 @@ impl<'tcx> PolyProjectionPredicate<'tcx> {
         self.skip_binder().projection_ty.item_def_id
     }
 
+    /// Returns the `DefId` of the trait of the associated item being projected.
+    #[inline]
+    pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
+        self.skip_binder().projection_ty.trait_def_id(tcx)
+    }
+
+    #[inline]
+    pub fn projection_self_ty(&self) -> Binder<Ty<'tcx>> {
+        self.map_bound(|predicate| predicate.projection_ty.self_ty())
+    }
+
+    /// Get the [PolyTraitRef] required for this projection to be well formed.
+    /// Note that for generic associated types the predicates of the associated
+    /// type also need to be checked.
     #[inline]
-    pub fn to_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
+    pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
         // Note: unlike with `TraitRef::to_poly_trait_ref()`,
         // `self.0.trait_ref` is permitted to have escaping regions.
         // This is because here `self` has a `Binder` and so does our
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 4937fdd7314..53c164d44b3 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -607,7 +607,7 @@ pub trait PrettyPrinter<'tcx>:
                     return Ok(self);
                 }
 
-                return Ok(with_no_queries(|| {
+                return with_no_queries(|| {
                     let def_key = self.tcx().def_key(def_id);
                     if let Some(name) = def_key.disambiguated_data.data.get_opt_name() {
                         p!(write("{}", name));
@@ -649,7 +649,7 @@ pub trait PrettyPrinter<'tcx>:
                         p!(" Sized");
                     }
                     Ok(self)
-                })?);
+                });
             }
             ty::Str => p!("str"),
             ty::Generator(did, substs, movability) => {
@@ -1018,7 +1018,7 @@ pub trait PrettyPrinter<'tcx>:
                 p!(write("{:?}", char::try_from(int).unwrap()))
             }
             // Raw pointers
-            (Scalar::Int(int), ty::RawPtr(_)) => {
+            (Scalar::Int(int), ty::RawPtr(_) | ty::FnPtr(_)) => {
                 let data = int.assert_bits(self.tcx().data_layout.pointer_size);
                 self = self.typed_value(
                     |mut this| {
@@ -1030,15 +1030,18 @@ pub trait PrettyPrinter<'tcx>:
                 )?;
             }
             (Scalar::Ptr(ptr), ty::FnPtr(_)) => {
-                // FIXME: this can ICE when the ptr is dangling or points to a non-function.
-                // We should probably have a helper method to share code with the "Byte strings"
+                // FIXME: We should probably have a helper method to share code with the "Byte strings"
                 // printing above (which also has to handle pointers to all sorts of things).
-                let instance = self.tcx().global_alloc(ptr.alloc_id).unwrap_fn();
-                self = self.typed_value(
-                    |this| this.print_value_path(instance.def_id(), instance.substs),
-                    |this| this.print_type(ty),
-                    " as ",
-                )?;
+                match self.tcx().get_global_alloc(ptr.alloc_id) {
+                    Some(GlobalAlloc::Function(instance)) => {
+                        self = self.typed_value(
+                            |this| this.print_value_path(instance.def_id(), instance.substs),
+                            |this| this.print_type(ty),
+                            " as ",
+                        )?;
+                    }
+                    _ => self = self.pretty_print_const_pointer(ptr, ty, print_ty)?,
+                }
             }
             // For function type zsts just printing the path is enough
             (Scalar::Int(int), ty::FnDef(d, s)) if int == ScalarInt::ZST => {
@@ -2107,11 +2110,9 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
             continue;
         }
 
-        if let Some(local_def_id) = hir.definitions().opt_hir_id_to_local_def_id(item.hir_id) {
-            let def_id = local_def_id.to_def_id();
-            let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
-            collect_fn(&item.ident, ns, def_id);
-        }
+        let def_id = item.def_id.to_def_id();
+        let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
+        collect_fn(&item.ident, ns, def_id);
     }
 
     // Now take care of extern crate items.
@@ -2143,6 +2144,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
 
             match child.res {
                 def::Res::Def(DefKind::AssocTy, _) => {}
+                def::Res::Def(DefKind::TyAlias, _) => {}
                 def::Res::Def(defkind, def_id) => {
                     if let Some(ns) = defkind.ns() {
                         collect_fn(&child.ident, ns, def_id);
diff --git a/compiler/rustc_middle/src/ty/query/job.rs b/compiler/rustc_middle/src/ty/query/job.rs
deleted file mode 100644
index bd2e7747b7d..00000000000
--- a/compiler/rustc_middle/src/ty/query/job.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use crate::ty::tls;
-
-use rustc_query_system::query::deadlock;
-use rustc_rayon_core as rayon_core;
-use std::thread;
-
-/// Creates a new thread and forwards information in thread locals to it.
-/// The new thread runs the deadlock handler.
-/// Must only be called when a deadlock is about to happen.
-pub unsafe fn handle_deadlock() {
-    let registry = rayon_core::Registry::current();
-
-    let context = tls::get_tlv();
-    assert!(context != 0);
-    rustc_data_structures::sync::assert_sync::<tls::ImplicitCtxt<'_, '_>>();
-    let icx: &tls::ImplicitCtxt<'_, '_> = &*(context as *const tls::ImplicitCtxt<'_, '_>);
-
-    let session_globals = rustc_span::SESSION_GLOBALS.with(|sg| sg as *const _);
-    let session_globals = &*session_globals;
-    thread::spawn(move || {
-        tls::enter_context(icx, |_| {
-            rustc_span::SESSION_GLOBALS
-                .set(session_globals, || tls::with(|tcx| deadlock(tcx, &registry)))
-        })
-    });
-}
diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs
index f580cb14dc9..51a214bc07b 100644
--- a/compiler/rustc_middle/src/ty/query/mod.rs
+++ b/compiler/rustc_middle/src/ty/query/mod.rs
@@ -31,19 +31,19 @@ use crate::traits::{self, ImplSource};
 use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
-use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::stable_hasher::StableVec;
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::ErrorReported;
+use rustc_errors::{ErrorReported, Handler};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId};
 use rustc_hir::lang_items::{LangItem, LanguageItems};
 use rustc_hir::{Crate, ItemLocalId, TraitCandidate};
 use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
+use rustc_serialize::opaque;
 use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
 use rustc_session::utils::NativeLibKind;
 use rustc_session::CrateDisambiguator;
@@ -53,41 +53,216 @@ use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
-use std::borrow::Cow;
 use std::collections::BTreeMap;
 use std::ops::Deref;
 use std::path::PathBuf;
 use std::sync::Arc;
 
-#[macro_use]
-mod plumbing;
-pub(crate) use rustc_query_system::query::CycleError;
+pub(crate) use rustc_query_system::query::QueryJobId;
 use rustc_query_system::query::*;
 
-mod stats;
-pub use self::stats::print_stats;
+pub mod on_disk_cache;
+pub use self::on_disk_cache::OnDiskCache;
 
-#[cfg(parallel_compiler)]
-mod job;
-#[cfg(parallel_compiler)]
-pub use self::job::handle_deadlock;
-pub use rustc_query_system::query::{QueryInfo, QueryJob, QueryJobId};
+#[derive(Copy, Clone)]
+pub struct TyCtxtAt<'tcx> {
+    pub tcx: TyCtxt<'tcx>,
+    pub span: Span,
+}
 
-mod keys;
-use self::keys::Key;
+impl Deref for TyCtxtAt<'tcx> {
+    type Target = TyCtxt<'tcx>;
+    #[inline(always)]
+    fn deref(&self) -> &Self::Target {
+        &self.tcx
+    }
+}
 
-mod values;
-use self::values::Value;
+#[derive(Copy, Clone)]
+pub struct TyCtxtEnsure<'tcx> {
+    pub tcx: TyCtxt<'tcx>,
+}
 
-use rustc_query_system::query::QueryAccessors;
-pub use rustc_query_system::query::QueryConfig;
-pub(crate) use rustc_query_system::query::QueryDescription;
+impl TyCtxt<'tcx> {
+    /// Returns a transparent wrapper for `TyCtxt`, which ensures queries
+    /// are executed instead of just returning their results.
+    #[inline(always)]
+    pub fn ensure(self) -> TyCtxtEnsure<'tcx> {
+        TyCtxtEnsure { tcx: self }
+    }
 
-mod on_disk_cache;
-pub use self::on_disk_cache::OnDiskCache;
+    /// Returns a transparent wrapper for `TyCtxt` which uses
+    /// `span` as the location of queries performed through it.
+    #[inline(always)]
+    pub fn at(self, span: Span) -> TyCtxtAt<'tcx> {
+        TyCtxtAt { tcx: self, span }
+    }
+
+    pub fn try_mark_green(self, dep_node: &dep_graph::DepNode) -> bool {
+        self.queries.try_mark_green(self, dep_node)
+    }
+}
+
+macro_rules! query_helper_param_ty {
+    (DefId) => { impl IntoQueryParam<DefId> };
+    ($K:ty) => { $K };
+}
+
+macro_rules! query_storage {
+    ([][$K:ty, $V:ty]) => {
+        <DefaultCacheSelector as CacheSelector<$K, $V>>::Cache
+    };
+    ([storage($ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => {
+        <$ty as CacheSelector<$K, $V>>::Cache
+    };
+    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
+        query_storage!([$($($modifiers)*)*][$($args)*])
+    };
+}
+
+macro_rules! define_callbacks {
+    (<$tcx:tt>
+     $($(#[$attr:meta])*
+        [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
+
+        // HACK(eddyb) this is like the `impl QueryConfig for queries::$name`
+        // below, but using type aliases instead of associated types, to bypass
+        // the limitations around normalizing under HRTB - for example, this:
+        // `for<'tcx> fn(...) -> <queries::$name<'tcx> as QueryConfig<TyCtxt<'tcx>>>::Value`
+        // doesn't currently normalize to `for<'tcx> fn(...) -> query_values::$name<'tcx>`.
+        // This is primarily used by the `provide!` macro in `rustc_metadata`.
+        #[allow(nonstandard_style, unused_lifetimes)]
+        pub mod query_keys {
+            use super::*;
+
+            $(pub type $name<$tcx> = $($K)*;)*
+        }
+        #[allow(nonstandard_style, unused_lifetimes)]
+        pub mod query_values {
+            use super::*;
+
+            $(pub type $name<$tcx> = $V;)*
+        }
+        #[allow(nonstandard_style, unused_lifetimes)]
+        pub mod query_storage {
+            use super::*;
+
+            $(pub type $name<$tcx> = query_storage!([$($modifiers)*][$($K)*, $V]);)*
+        }
+        #[allow(nonstandard_style, unused_lifetimes)]
+        pub mod query_stored {
+            use super::*;
+
+            $(pub type $name<$tcx> = <query_storage::$name<$tcx> as QueryStorage>::Stored;)*
+        }
 
-mod profiling_support;
-pub use self::profiling_support::{IntoSelfProfilingString, QueryKeyStringBuilder};
+        #[derive(Default)]
+        pub struct QueryCaches<$tcx> {
+            $($(#[$attr])* pub $name: QueryCacheStore<query_storage::$name<$tcx>>,)*
+        }
+
+        impl TyCtxtEnsure<$tcx> {
+            $($(#[$attr])*
+            #[inline(always)]
+            pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
+                let key = key.into_query_param();
+                let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |_| {});
+
+                let lookup = match cached {
+                    Ok(()) => return,
+                    Err(lookup) => lookup,
+                };
+
+                self.tcx.queries.$name(self.tcx, DUMMY_SP, key, lookup, QueryMode::Ensure);
+            })*
+        }
+
+        impl TyCtxt<$tcx> {
+            $($(#[$attr])*
+            #[inline(always)]
+            #[must_use]
+            pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx>
+            {
+                self.at(DUMMY_SP).$name(key)
+            })*
+        }
+
+        impl TyCtxtAt<$tcx> {
+            $($(#[$attr])*
+            #[inline(always)]
+            pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$tcx>
+            {
+                let key = key.into_query_param();
+                let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, |value| {
+                    value.clone()
+                });
+
+                let lookup = match cached {
+                    Ok(value) => return value,
+                    Err(lookup) => lookup,
+                };
+
+                self.tcx.queries.$name(self.tcx, self.span, key, lookup, QueryMode::Get).unwrap()
+            })*
+        }
+
+        pub struct Providers {
+            $(pub $name: for<'tcx> fn(
+                TyCtxt<'tcx>,
+                query_keys::$name<'tcx>,
+            ) -> query_values::$name<'tcx>,)*
+        }
+
+        impl Default for Providers {
+            fn default() -> Self {
+                Providers {
+                    $($name: |_, key| bug!(
+                        "`tcx.{}({:?})` unsupported by its crate",
+                         stringify!($name), key
+                    ),)*
+                }
+            }
+        }
+
+        impl Copy for Providers {}
+        impl Clone for Providers {
+            fn clone(&self) -> Self { *self }
+        }
+
+        pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync {
+            unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry);
+
+            fn encode_query_results(
+                &'tcx self,
+                tcx: TyCtxt<'tcx>,
+                encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>,
+                query_result_index: &mut on_disk_cache::EncodedQueryResultIndex,
+            ) -> opaque::FileEncodeResult;
+
+            fn exec_cache_promotions(&'tcx self, tcx: TyCtxt<'tcx>);
+
+            fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool;
+
+            fn try_print_query_stack(
+                &'tcx self,
+                tcx: TyCtxt<'tcx>,
+                query: Option<QueryJobId<dep_graph::DepKind>>,
+                handler: &Handler,
+                num_frames: Option<usize>,
+            ) -> usize;
+
+            $($(#[$attr])*
+            fn $name(
+                &'tcx self,
+                tcx: TyCtxt<$tcx>,
+                span: Span,
+                key: query_keys::$name<$tcx>,
+                lookup: QueryLookup,
+                mode: QueryMode,
+            ) -> Option<query_stored::$name<$tcx>>;)*
+        }
+    };
+}
 
 // Each of these queries corresponds to a function pointer field in the
 // `Providers` struct for requesting a value of that type, and a method
@@ -101,7 +276,7 @@ pub use self::profiling_support::{IntoSelfProfilingString, QueryKeyStringBuilder
 // Queries marked with `fatal_cycle` do not need the latter implementation,
 // as they will raise an fatal error on query cycles instead.
 
-rustc_query_append! { [define_queries!][<'tcx>] }
+rustc_query_append! { [define_callbacks!][<'tcx>] }
 
 mod sealed {
     use super::{DefId, LocalDefId};
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 cfe47004e01..d0cd8a48f99 100644
--- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
@@ -14,6 +14,8 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathHash;
 use rustc_hir::definitions::Definitions;
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_query_system::dep_graph::DepContext;
+use rustc_query_system::query::QueryContext;
 use rustc_serialize::{
     opaque::{self, FileEncodeResult, FileEncoder},
     Decodable, Decoder, Encodable, Encoder,
@@ -132,7 +134,7 @@ struct Footer {
     foreign_def_path_hashes: UnhashMap<DefPathHash, RawDefId>,
 }
 
-type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
+pub type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
 type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
 type EncodedDiagnostics = Vec<Diagnostic>;
 
@@ -140,7 +142,7 @@ type EncodedDiagnostics = Vec<Diagnostic>;
 struct SourceFileIndex(u32);
 
 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Encodable, Decodable)]
-struct AbsoluteBytePos(u32);
+pub struct AbsoluteBytePos(u32);
 
 impl AbsoluteBytePos {
     fn new(pos: usize) -> AbsoluteBytePos {
@@ -284,7 +286,7 @@ impl<'sess> OnDiskCache<'sess> {
             // Do this *before* we clone 'latest_foreign_def_path_hashes', since
             // loading existing queries may cause us to create new DepNodes, which
             // may in turn end up invoking `store_foreign_def_id_hash`
-            tcx.dep_graph.exec_cache_promotions(tcx);
+            tcx.queries.exec_cache_promotions(tcx);
 
             let latest_foreign_def_path_hashes = self.latest_foreign_def_path_hashes.lock().clone();
             let hygiene_encode_context = HygieneEncodeContext::default();
@@ -307,22 +309,7 @@ impl<'sess> OnDiskCache<'sess> {
             tcx.sess.time("encode_query_results", || -> FileEncodeResult {
                 let enc = &mut encoder;
                 let qri = &mut query_result_index;
-
-                macro_rules! encode_queries {
-                    ($($query:ident,)*) => {
-                        $(
-                            encode_query_results::<ty::query::queries::$query<'_>>(
-                                tcx,
-                                enc,
-                                qri
-                            )?;
-                        )*
-                    }
-                }
-
-                rustc_cached_queries!(encode_queries!);
-
-                Ok(())
+                tcx.queries.encode_query_results(tcx, enc, qri)
             })?;
 
             // Encode diagnostics.
@@ -427,7 +414,7 @@ impl<'sess> OnDiskCache<'sess> {
 
             fn sorted_cnums_including_local_crate(tcx: TyCtxt<'_>) -> Vec<CrateNum> {
                 let mut cnums = vec![LOCAL_CRATE];
-                cnums.extend_from_slice(&tcx.crates()[..]);
+                cnums.extend_from_slice(tcx.crates());
                 cnums.sort_unstable();
                 // Just to be sure...
                 cnums.dedup();
@@ -515,7 +502,7 @@ impl<'sess> OnDiskCache<'sess> {
 
     /// Returns the cached query result if there is something in the cache for
     /// the given `SerializedDepNodeIndex`; otherwise returns `None`.
-    crate fn try_load_query_result<'tcx, T>(
+    pub fn try_load_query_result<'tcx, T>(
         &self,
         tcx: TyCtxt<'tcx>,
         dep_node_index: SerializedDepNodeIndex,
@@ -678,7 +665,7 @@ impl<'sess> OnDiskCache<'sess> {
 /// A decoder that can read from the incremental compilation cache. It is similar to the one
 /// we use for crate metadata decoding in that it can rebase spans and eventually
 /// will also handle things that contain `Ty` instances.
-crate struct CacheDecoder<'a, 'tcx> {
+pub struct CacheDecoder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     opaque: opaque::Decoder<'a>,
     source_map: &'a SourceMap,
@@ -918,7 +905,6 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
         // which means that the definition with this hash is guaranteed to
         // still exist in the current compilation session.
         Ok(d.tcx()
-            .queries
             .on_disk_cache
             .as_ref()
             .unwrap()
@@ -973,7 +959,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Span] {
 
 //- ENCODING -------------------------------------------------------------------
 
-trait OpaqueEncoder: Encoder {
+pub trait OpaqueEncoder: Encoder {
     fn position(&self) -> usize;
 }
 
@@ -985,7 +971,7 @@ impl OpaqueEncoder for FileEncoder {
 }
 
 /// An encoder that can write to the incremental compilation cache.
-struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
+pub struct CacheEncoder<'a, 'tcx, E: OpaqueEncoder> {
     tcx: TyCtxt<'tcx>,
     encoder: &'a mut E,
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
@@ -1230,24 +1216,24 @@ impl<'a> Decodable<opaque::Decoder<'a>> for IntEncodedWithFixedSize {
     }
 }
 
-fn encode_query_results<'a, 'tcx, Q>(
-    tcx: TyCtxt<'tcx>,
+pub fn encode_query_results<'a, 'tcx, CTX, Q>(
+    tcx: CTX,
     encoder: &mut CacheEncoder<'a, 'tcx, FileEncoder>,
     query_result_index: &mut EncodedQueryResultIndex,
 ) -> FileEncodeResult
 where
-    Q: super::QueryDescription<TyCtxt<'tcx>> + super::QueryAccessors<TyCtxt<'tcx>>,
+    CTX: QueryContext + 'tcx,
+    Q: super::QueryDescription<CTX> + super::QueryAccessors<CTX>,
     Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>,
 {
     let _timer = tcx
-        .sess
-        .prof
+        .dep_context()
+        .profiler()
         .extra_verbose_generic_activity("encode_query_results_for", std::any::type_name::<Q>());
 
-    let state = Q::query_state(tcx);
-    assert!(state.all_inactive());
-
-    state.iter_results(|results| {
+    assert!(Q::query_state(tcx).all_inactive());
+    let cache = Q::query_cache(tcx);
+    cache.iter_results(|results| {
         for (key, value, dep_node) in results {
             if Q::cache_on_disk(tcx, &key, Some(value)) {
                 let dep_node = SerializedDepNodeIndex::new(dep_node.index());
diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs
deleted file mode 100644
index d0730bd121c..00000000000
--- a/compiler/rustc_middle/src/ty/query/plumbing.rs
+++ /dev/null
@@ -1,576 +0,0 @@
-//! The implementation of the query system itself. This defines the macros that
-//! generate the actual methods on tcx which find and execute the provider,
-//! manage the caches, and so forth.
-
-use crate::dep_graph::DepGraph;
-use crate::ty::query::Query;
-use crate::ty::tls::{self, ImplicitCtxt};
-use crate::ty::{self, TyCtxt};
-use rustc_query_system::query::QueryContext;
-use rustc_query_system::query::{CycleError, QueryJobId, QueryJobInfo};
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lock;
-use rustc_data_structures::thin_vec::ThinVec;
-use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder, Handler, Level};
-use rustc_span::def_id::DefId;
-use rustc_span::Span;
-
-impl QueryContext for TyCtxt<'tcx> {
-    type Query = Query<'tcx>;
-
-    fn incremental_verify_ich(&self) -> bool {
-        self.sess.opts.debugging_opts.incremental_verify_ich
-    }
-    fn verbose(&self) -> bool {
-        self.sess.verbose()
-    }
-
-    fn def_path_str(&self, def_id: DefId) -> String {
-        TyCtxt::def_path_str(*self, def_id)
-    }
-
-    fn dep_graph(&self) -> &DepGraph {
-        &self.dep_graph
-    }
-
-    fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>> {
-        tls::with_related_context(*self, |icx| icx.query)
-    }
-
-    fn try_collect_active_jobs(
-        &self,
-    ) -> Option<FxHashMap<QueryJobId<Self::DepKind>, QueryJobInfo<Self::DepKind, Self::Query>>>
-    {
-        self.queries.try_collect_active_jobs()
-    }
-
-    /// Executes a job by changing the `ImplicitCtxt` to point to the
-    /// new query job while it executes. It returns the diagnostics
-    /// captured during execution and the actual result.
-    #[inline(always)]
-    fn start_query<R>(
-        &self,
-        token: QueryJobId<Self::DepKind>,
-        diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
-        compute: impl FnOnce(Self) -> R,
-    ) -> R {
-        // The `TyCtxt` stored in TLS has the same global interner lifetime
-        // as `self`, so we use `with_related_context` to relate the 'tcx lifetimes
-        // when accessing the `ImplicitCtxt`.
-        tls::with_related_context(*self, move |current_icx| {
-            // Update the `ImplicitCtxt` to point to our new query job.
-            let new_icx = ImplicitCtxt {
-                tcx: *self,
-                query: Some(token),
-                diagnostics,
-                layout_depth: current_icx.layout_depth,
-                task_deps: current_icx.task_deps,
-            };
-
-            // Use the `ImplicitCtxt` while we execute the query.
-            tls::enter_context(&new_icx, |_| {
-                rustc_data_structures::stack::ensure_sufficient_stack(|| compute(*self))
-            })
-        })
-    }
-}
-
-impl<'tcx> TyCtxt<'tcx> {
-    #[inline(never)]
-    #[cold]
-    pub(super) fn report_cycle(
-        self,
-        CycleError { usage, cycle: stack }: CycleError<Query<'tcx>>,
-    ) -> DiagnosticBuilder<'tcx> {
-        assert!(!stack.is_empty());
-
-        let fix_span = |span: Span, query: &Query<'tcx>| {
-            self.sess.source_map().guess_head_span(query.default_span(self, span))
-        };
-
-        // Disable naming impls with types in this path, since that
-        // sometimes cycles itself, leading to extra cycle errors.
-        // (And cycle errors around impls tend to occur during the
-        // collect/coherence phases anyhow.)
-        ty::print::with_forced_impl_filename_line(|| {
-            let span = fix_span(stack[1 % stack.len()].span, &stack[0].query);
-            let mut err = struct_span_err!(
-                self.sess,
-                span,
-                E0391,
-                "cycle detected when {}",
-                stack[0].query.describe(self)
-            );
-
-            for i in 1..stack.len() {
-                let query = &stack[i].query;
-                let span = fix_span(stack[(i + 1) % stack.len()].span, query);
-                err.span_note(span, &format!("...which requires {}...", query.describe(self)));
-            }
-
-            err.note(&format!(
-                "...which again requires {}, completing the cycle",
-                stack[0].query.describe(self)
-            ));
-
-            if let Some((span, query)) = usage {
-                err.span_note(
-                    fix_span(span, &query),
-                    &format!("cycle used when {}", query.describe(self)),
-                );
-            }
-
-            err
-        })
-    }
-
-    pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
-        eprintln!("query stack during panic:");
-
-        // Be careful relying 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;
-
-                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
-                        } else {
-                            break;
-                        };
-                    let mut diag = Diagnostic::new(
-                        Level::FailureNote,
-                        &format!(
-                            "#{} [{}] {}",
-                            i,
-                            query_info.info.query.name(),
-                            query_info.info.query.describe(icx.tcx)
-                        ),
-                    );
-                    diag.span =
-                        icx.tcx.sess.source_map().guess_head_span(query_info.info.span).into();
-                    handler.force_print_diagnostic(diag);
-
-                    current_query = query_info.job.parent;
-                    i += 1;
-                }
-            }
-        });
-
-        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");
-        }
-    }
-}
-
-macro_rules! handle_cycle_error {
-    ([][$tcx: expr, $error:expr]) => {{
-        $tcx.report_cycle($error).emit();
-        Value::from_cycle_error($tcx)
-    }};
-    ([fatal_cycle $($rest:tt)*][$tcx:expr, $error:expr]) => {{
-        $tcx.report_cycle($error).emit();
-        $tcx.sess.abort_if_errors();
-        unreachable!()
-    }};
-    ([cycle_delay_bug $($rest:tt)*][$tcx:expr, $error:expr]) => {{
-        $tcx.report_cycle($error).delay_as_bug();
-        Value::from_cycle_error($tcx)
-    }};
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
-        handle_cycle_error!([$($($modifiers)*)*][$($args)*])
-    };
-}
-
-macro_rules! is_anon {
-    ([]) => {{
-        false
-    }};
-    ([anon $($rest:tt)*]) => {{
-        true
-    }};
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => {
-        is_anon!([$($($modifiers)*)*])
-    };
-}
-
-macro_rules! is_eval_always {
-    ([]) => {{
-        false
-    }};
-    ([eval_always $($rest:tt)*]) => {{
-        true
-    }};
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => {
-        is_eval_always!([$($($modifiers)*)*])
-    };
-}
-
-macro_rules! query_storage {
-    ([][$K:ty, $V:ty]) => {
-        <<$K as Key>::CacheSelector as CacheSelector<$K, $V>>::Cache
-    };
-    ([storage($ty:ty) $($rest:tt)*][$K:ty, $V:ty]) => {
-        <$ty as CacheSelector<$K, $V>>::Cache
-    };
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
-        query_storage!([$($($modifiers)*)*][$($args)*])
-    };
-}
-
-macro_rules! hash_result {
-    ([][$hcx:expr, $result:expr]) => {{
-        dep_graph::hash_result($hcx, &$result)
-    }};
-    ([no_hash $($rest:tt)*][$hcx:expr, $result:expr]) => {{
-        None
-    }};
-    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
-        hash_result!([$($($modifiers)*)*][$($args)*])
-    };
-}
-
-macro_rules! query_helper_param_ty {
-    (DefId) => { impl IntoQueryParam<DefId> };
-    ($K:ty) => { $K };
-}
-
-macro_rules! define_queries {
-    (<$tcx:tt>
-     $($(#[$attr:meta])*
-        [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
-
-        use std::mem;
-        use crate::{
-            rustc_data_structures::stable_hasher::HashStable,
-            rustc_data_structures::stable_hasher::StableHasher,
-            ich::StableHashingContext
-        };
-
-        define_queries_struct! {
-            tcx: $tcx,
-            input: ($(([$($modifiers)*] [$($attr)*] [$name]))*)
-        }
-
-        #[allow(nonstandard_style)]
-        #[derive(Clone, Debug)]
-        pub enum Query<$tcx> {
-            $($(#[$attr])* $name($($K)*)),*
-        }
-
-        impl<$tcx> Query<$tcx> {
-            pub fn name(&self) -> &'static str {
-                match *self {
-                    $(Query::$name(_) => stringify!($name),)*
-                }
-            }
-
-            pub fn describe(&self, tcx: TyCtxt<$tcx>) -> Cow<'static, str> {
-                let (r, name) = match *self {
-                    $(Query::$name(key) => {
-                        (queries::$name::describe(tcx, key), stringify!($name))
-                    })*
-                };
-                if tcx.sess.verbose() {
-                    format!("{} [{}]", r, name).into()
-                } else {
-                    r
-                }
-            }
-
-            // FIXME(eddyb) Get more valid `Span`s on queries.
-            pub fn default_span(&self, tcx: TyCtxt<$tcx>, span: Span) -> Span {
-                if !span.is_dummy() {
-                    return span;
-                }
-                // The `def_span` query is used to calculate `default_span`,
-                // so exit to avoid infinite recursion.
-                if let Query::def_span(..) = *self {
-                    return span
-                }
-                match *self {
-                    $(Query::$name(key) => key.default_span(tcx),)*
-                }
-            }
-        }
-
-        impl<'a, $tcx> HashStable<StableHashingContext<'a>> for Query<$tcx> {
-            fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-                mem::discriminant(self).hash_stable(hcx, hasher);
-                match *self {
-                    $(Query::$name(key) => key.hash_stable(hcx, hasher),)*
-                }
-            }
-        }
-
-        #[allow(nonstandard_style)]
-        pub mod queries {
-            use std::marker::PhantomData;
-
-            $(pub struct $name<$tcx> {
-                data: PhantomData<&$tcx ()>
-            })*
-        }
-
-        // HACK(eddyb) this is like the `impl QueryConfig for queries::$name`
-        // below, but using type aliases instead of associated types, to bypass
-        // the limitations around normalizing under HRTB - for example, this:
-        // `for<'tcx> fn(...) -> <queries::$name<'tcx> as QueryConfig<TyCtxt<'tcx>>>::Value`
-        // doesn't currently normalize to `for<'tcx> fn(...) -> query_values::$name<'tcx>`.
-        // This is primarily used by the `provide!` macro in `rustc_metadata`.
-        #[allow(nonstandard_style, unused_lifetimes)]
-        pub mod query_keys {
-            use super::*;
-
-            $(pub type $name<$tcx> = $($K)*;)*
-        }
-        #[allow(nonstandard_style, unused_lifetimes)]
-        pub mod query_values {
-            use super::*;
-
-            $(pub type $name<$tcx> = $V;)*
-        }
-
-        $(impl<$tcx> QueryConfig for queries::$name<$tcx> {
-            type Key = $($K)*;
-            type Value = $V;
-            type Stored = <
-                query_storage!([$($modifiers)*][$($K)*, $V])
-                as QueryStorage
-            >::Stored;
-            const NAME: &'static str = stringify!($name);
-        }
-
-        impl<$tcx> QueryAccessors<TyCtxt<$tcx>> for queries::$name<$tcx> {
-            const ANON: bool = is_anon!([$($modifiers)*]);
-            const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
-            const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$name;
-
-            type Cache = query_storage!([$($modifiers)*][$($K)*, $V]);
-
-            #[inline(always)]
-            fn query_state<'a>(tcx: TyCtxt<$tcx>) -> &'a QueryState<crate::dep_graph::DepKind, <TyCtxt<$tcx> as QueryContext>::Query, Self::Cache> {
-                &tcx.queries.$name
-            }
-
-            #[inline]
-            fn compute(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value {
-                let provider = tcx.queries.providers.get(key.query_crate())
-                    // HACK(eddyb) it's possible crates may be loaded after
-                    // the query engine is created, and because crate loading
-                    // is not yet integrated with the query engine, such crates
-                    // would be missing appropriate entries in `providers`.
-                    .unwrap_or(&tcx.queries.fallback_extern_providers)
-                    .$name;
-                provider(tcx, key)
-            }
-
-            fn hash_result(
-                _hcx: &mut StableHashingContext<'_>,
-                _result: &Self::Value
-            ) -> Option<Fingerprint> {
-                hash_result!([$($modifiers)*][_hcx, _result])
-            }
-
-            fn handle_cycle_error(
-                tcx: TyCtxt<'tcx>,
-                error: CycleError<Query<'tcx>>
-            ) -> Self::Value {
-                handle_cycle_error!([$($modifiers)*][tcx, error])
-            }
-        })*
-
-        #[derive(Copy, Clone)]
-        pub struct TyCtxtEnsure<'tcx> {
-            pub tcx: TyCtxt<'tcx>,
-        }
-
-        impl TyCtxtEnsure<$tcx> {
-            $($(#[$attr])*
-            #[inline(always)]
-            pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
-                ensure_query::<queries::$name<'_>, _>(self.tcx, key.into_query_param())
-            })*
-        }
-
-        #[derive(Copy, Clone)]
-        pub struct TyCtxtAt<'tcx> {
-            pub tcx: TyCtxt<'tcx>,
-            pub span: Span,
-        }
-
-        impl Deref for TyCtxtAt<'tcx> {
-            type Target = TyCtxt<'tcx>;
-            #[inline(always)]
-            fn deref(&self) -> &Self::Target {
-                &self.tcx
-            }
-        }
-
-        impl TyCtxt<$tcx> {
-            /// Returns a transparent wrapper for `TyCtxt`, which ensures queries
-            /// are executed instead of just returning their results.
-            #[inline(always)]
-            pub fn ensure(self) -> TyCtxtEnsure<$tcx> {
-                TyCtxtEnsure {
-                    tcx: self,
-                }
-            }
-
-            /// Returns a transparent wrapper for `TyCtxt` which uses
-            /// `span` as the location of queries performed through it.
-            #[inline(always)]
-            pub fn at(self, span: Span) -> TyCtxtAt<$tcx> {
-                TyCtxtAt {
-                    tcx: self,
-                    span
-                }
-            }
-
-            $($(#[$attr])*
-            #[inline(always)]
-            #[must_use]
-            pub fn $name(self, key: query_helper_param_ty!($($K)*))
-                -> <queries::$name<$tcx> as QueryConfig>::Stored
-            {
-                self.at(DUMMY_SP).$name(key.into_query_param())
-            })*
-
-            /// All self-profiling events generated by the query engine use
-            /// virtual `StringId`s for their `event_id`. This method makes all
-            /// those virtual `StringId`s point to actual strings.
-            ///
-            /// If we are recording only summary data, the ids will point to
-            /// just the query names. If we are recording query keys too, we
-            /// allocate the corresponding strings here.
-            pub fn alloc_self_profile_query_strings(self) {
-                use crate::ty::query::profiling_support::{
-                    alloc_self_profile_query_strings_for_query_cache,
-                    QueryKeyStringCache,
-                };
-
-                if !self.prof.enabled() {
-                    return;
-                }
-
-                let mut string_cache = QueryKeyStringCache::new();
-
-                $({
-                    alloc_self_profile_query_strings_for_query_cache(
-                        self,
-                        stringify!($name),
-                        &self.queries.$name,
-                        &mut string_cache,
-                    );
-                })*
-            }
-        }
-
-        impl TyCtxtAt<$tcx> {
-            $($(#[$attr])*
-            #[inline(always)]
-            pub fn $name(self, key: query_helper_param_ty!($($K)*))
-                -> <queries::$name<$tcx> as QueryConfig>::Stored
-            {
-                get_query::<queries::$name<'_>, _>(self.tcx, self.span, key.into_query_param())
-            })*
-        }
-
-        define_provider_struct! {
-            tcx: $tcx,
-            input: ($(([$($modifiers)*] [$name] [$($K)*] [$V]))*)
-        }
-
-        impl Copy for Providers {}
-        impl Clone for Providers {
-            fn clone(&self) -> Self { *self }
-        }
-    }
-}
-
-// FIXME(eddyb) this macro (and others?) use `$tcx` and `'tcx` interchangeably.
-// We should either not take `$tcx` at all and use `'tcx` everywhere, or use
-// `$tcx` everywhere (even if that isn't necessary due to lack of hygiene).
-macro_rules! define_queries_struct {
-    (tcx: $tcx:tt,
-     input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
-        pub struct Queries<$tcx> {
-            /// This provides access to the incremental compilation on-disk cache for query results.
-            /// Do not access this directly. It is only meant to be used by
-            /// `DepGraph::try_mark_green()` and the query infrastructure.
-            /// This is `None` if we are not incremental compilation mode
-            pub(crate) on_disk_cache: Option<OnDiskCache<'tcx>>,
-
-            providers: IndexVec<CrateNum, Providers>,
-            fallback_extern_providers: Box<Providers>,
-
-            $($(#[$attr])*  $name: QueryState<
-                crate::dep_graph::DepKind,
-                <TyCtxt<$tcx> as QueryContext>::Query,
-                <queries::$name<$tcx> as QueryAccessors<TyCtxt<'tcx>>>::Cache,
-            >,)*
-        }
-
-        impl<$tcx> Queries<$tcx> {
-            pub(crate) fn new(
-                providers: IndexVec<CrateNum, Providers>,
-                fallback_extern_providers: Providers,
-                on_disk_cache: Option<OnDiskCache<'tcx>>,
-            ) -> Self {
-                Queries {
-                    providers,
-                    fallback_extern_providers: Box::new(fallback_extern_providers),
-                    on_disk_cache,
-                    $($name: Default::default()),*
-                }
-            }
-
-            pub(crate) fn try_collect_active_jobs(
-                &self
-            ) -> Option<FxHashMap<QueryJobId<crate::dep_graph::DepKind>, QueryJobInfo<crate::dep_graph::DepKind, <TyCtxt<$tcx> as QueryContext>::Query>>> {
-                let mut jobs = FxHashMap::default();
-
-                $(
-                    self.$name.try_collect_active_jobs(
-                        <queries::$name<'tcx> as QueryAccessors<TyCtxt<'tcx>>>::DEP_KIND,
-                        Query::$name,
-                        &mut jobs,
-                    )?;
-                )*
-
-                Some(jobs)
-            }
-        }
-    };
-}
-
-macro_rules! define_provider_struct {
-    (tcx: $tcx:tt,
-     input: ($(([$($modifiers:tt)*] [$name:ident] [$K:ty] [$R:ty]))*)) => {
-        pub struct Providers {
-            $(pub $name: for<$tcx> fn(TyCtxt<$tcx>, $K) -> $R,)*
-        }
-
-        impl Default for Providers {
-            fn default() -> Self {
-                $(fn $name<$tcx>(_: TyCtxt<$tcx>, key: $K) -> $R {
-                    bug!("`tcx.{}({:?})` unsupported by its crate",
-                         stringify!($name), key);
-                })*
-                Providers { $($name),* }
-            }
-        }
-    };
-}
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 293b3c6b047..315e5d63d2b 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -154,7 +154,7 @@ pub fn relate_substs<R: TypeRelation<'tcx>>(
         relation.relate_with_variance(variance, a, b)
     });
 
-    Ok(tcx.mk_substs(params)?)
+    tcx.mk_substs(params)
 }
 
 impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
@@ -647,7 +647,7 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::Binder<ty::ExistentialPredicate<'
                 _ => Err(TypeError::ExistentialMismatch(expected_found(relation, a, b))),
             }
         });
-        Ok(tcx.mk_poly_existential_predicates(v)?)
+        tcx.mk_poly_existential_predicates(v)
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 6b4f08d9f93..bbf64c69d83 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -17,7 +17,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::Idx;
 use rustc_macros::HashStable;
-use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::symbol::{kw, Symbol};
 use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi;
 use std::borrow::Cow;
@@ -1112,27 +1112,34 @@ pub struct ProjectionTy<'tcx> {
 }
 
 impl<'tcx> ProjectionTy<'tcx> {
-    /// Construct a `ProjectionTy` by searching the trait from `trait_ref` for the
-    /// associated item named `item_name`.
-    pub fn from_ref_and_name(
-        tcx: TyCtxt<'_>,
-        trait_ref: ty::TraitRef<'tcx>,
-        item_name: Ident,
-    ) -> ProjectionTy<'tcx> {
-        let item_def_id = tcx
-            .associated_items(trait_ref.def_id)
-            .find_by_name_and_kind(tcx, item_name, ty::AssocKind::Type, trait_ref.def_id)
-            .unwrap()
-            .def_id;
+    pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
+        tcx.associated_item(self.item_def_id).container.id()
+    }
 
-        ProjectionTy { substs: trait_ref.substs, item_def_id }
+    /// Extracts the underlying trait reference and own substs from this projection.
+    /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
+    /// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
+    pub fn trait_ref_and_own_substs(
+        &self,
+        tcx: TyCtxt<'tcx>,
+    ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
+        let def_id = tcx.associated_item(self.item_def_id).container.id();
+        let trait_generics = tcx.generics_of(def_id);
+        (
+            ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, trait_generics) },
+            &self.substs[trait_generics.count()..],
+        )
     }
 
     /// Extracts the underlying trait reference from this projection.
     /// For example, if this is a projection of `<T as Iterator>::Item`,
     /// then this function would return a `T: Iterator` trait reference.
+    ///
+    /// WARNING: This will drop the substs for generic associated types
+    /// consider calling [Self::trait_ref_and_own_substs] to get those
+    /// as well.
     pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
-        let def_id = tcx.associated_item(self.item_def_id).container.id();
+        let def_id = self.trait_def_id(tcx);
         ty::TraitRef { def_id, substs: self.substs.truncate_to(tcx, tcx.generics_of(def_id)) }
     }
 
@@ -1485,12 +1492,11 @@ impl<'tcx> ExistentialProjection<'tcx> {
     /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
     /// then this function would return a `exists T. T: Iterator` existential trait
     /// reference.
-    pub fn trait_ref(&self, tcx: TyCtxt<'_>) -> ty::ExistentialTraitRef<'tcx> {
-        // FIXME(generic_associated_types): substs is the substs of the
-        // associated type, which should be truncated to get the correct substs
-        // for the trait.
+    pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
         let def_id = tcx.associated_item(self.item_def_id).container.id();
-        ty::ExistentialTraitRef { def_id, substs: self.substs }
+        let subst_count = tcx.generics_of(def_id).count() - 1;
+        let substs = tcx.intern_substs(&self.substs[..subst_count]);
+        ty::ExistentialTraitRef { def_id, substs }
     }
 
     pub fn with_self_ty(
@@ -1509,6 +1515,20 @@ impl<'tcx> ExistentialProjection<'tcx> {
             ty: self.ty,
         }
     }
+
+    pub fn erase_self_ty(
+        tcx: TyCtxt<'tcx>,
+        projection_predicate: ty::ProjectionPredicate<'tcx>,
+    ) -> Self {
+        // Assert there is a Self.
+        projection_predicate.projection_ty.substs.type_at(0);
+
+        Self {
+            item_def_id: projection_predicate.projection_ty.item_def_id,
+            substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
+            ty: projection_predicate.ty,
+        }
+    }
 }
 
 impl<'tcx> PolyExistentialProjection<'tcx> {
@@ -1837,6 +1857,15 @@ impl<'tcx> TyS<'tcx> {
         )
     }
 
+    /// Get the mutability of the reference or `None` when not a reference
+    #[inline]
+    pub fn ref_mutability(&self) -> Option<hir::Mutability> {
+        match self.kind() {
+            Ref(_, _, mutability) => Some(*mutability),
+            _ => None,
+        }
+    }
+
     #[inline]
     pub fn is_unsafe_ptr(&self) -> bool {
         matches!(self.kind(), RawPtr(_))
@@ -2116,6 +2145,54 @@ impl<'tcx> TyS<'tcx> {
         }
     }
 
+    /// Returns the type of metadata for (potentially fat) pointers to this type.
+    pub fn ptr_metadata_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+        // FIXME: should this normalize?
+        let tail = tcx.struct_tail_without_normalization(self);
+        match tail.kind() {
+            // Sized types
+            ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+            | ty::Uint(_)
+            | ty::Int(_)
+            | ty::Bool
+            | ty::Float(_)
+            | ty::FnDef(..)
+            | ty::FnPtr(_)
+            | ty::RawPtr(..)
+            | ty::Char
+            | ty::Ref(..)
+            | ty::Generator(..)
+            | ty::GeneratorWitness(..)
+            | ty::Array(..)
+            | ty::Closure(..)
+            | ty::Never
+            | ty::Error(_)
+            | ty::Foreign(..)
+            // If returned by `struct_tail_without_normalization` this is a unit struct
+            // without any fields, or not a struct, and therefore is Sized.
+            | ty::Adt(..)
+            // If returned by `struct_tail_without_normalization` this is the empty tuple,
+            // a.k.a. unit type, which is Sized
+            | ty::Tuple(..) => tcx.types.unit,
+
+            ty::Str | ty::Slice(_) => tcx.types.usize,
+            ty::Dynamic(..) => {
+                let dyn_metadata = tcx.lang_items().dyn_metadata().unwrap();
+                tcx.type_of(dyn_metadata).subst(tcx, &[tail.into()])
+            },
+
+            ty::Projection(_)
+            | ty::Param(_)
+            | ty::Opaque(..)
+            | ty::Infer(ty::TyVar(_))
+            | ty::Bound(..)
+            | ty::Placeholder(..)
+            | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+                bug!("`ptr_metadata_ty` applied to unexpected type: {:?}", tail)
+            }
+        }
+    }
+
     /// When we create a closure, we record its kind (i.e., what trait
     /// it implements) into its `ClosureSubsts` using a type
     /// parameter. This is kind of a phantom type, except that the
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index f4d7eac0ae2..ce17a724e25 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -4,9 +4,8 @@ use crate::ty::fast_reject;
 use crate::ty::fold::TypeFoldable;
 use crate::ty::{Ty, TyCtxt};
 use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_hir::definitions::DefPathHash;
-use rustc_hir::HirId;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -201,7 +200,7 @@ impl<'tcx> TyCtxt<'tcx> {
 pub(super) fn all_local_trait_impls<'tcx>(
     tcx: TyCtxt<'tcx>,
     krate: CrateNum,
-) -> &'tcx BTreeMap<DefId, Vec<HirId>> {
+) -> &'tcx BTreeMap<DefId, Vec<LocalDefId>> {
     &tcx.hir_crate(krate).trait_impls
 }
 
@@ -229,8 +228,8 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
         }
     }
 
-    for &hir_id in tcx.hir().trait_impls(trait_id) {
-        let impl_def_id = tcx.hir().local_def_id(hir_id).to_def_id();
+    for &impl_def_id in tcx.hir().trait_impls(trait_id) {
+        let impl_def_id = impl_def_id.to_def_id();
 
         let impl_self_ty = tcx.type_of(impl_def_id);
         if impl_self_ty.references_error() {
diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs
index e79adcdb545..791d5060fe5 100644
--- a/compiler/rustc_middle/src/util/bug.rs
+++ b/compiler/rustc_middle/src/util/bug.rs
@@ -3,7 +3,7 @@
 use crate::ty::{tls, TyCtxt};
 use rustc_span::{MultiSpan, Span};
 use std::fmt;
-use std::panic::Location;
+use std::panic::{panic_any, Location};
 
 #[cold]
 #[inline(never)]
@@ -32,7 +32,7 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
         match (tcx, span) {
             (Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, &msg),
             (Some(tcx), None) => tcx.sess.diagnostic().bug(&msg),
-            (None, _) => panic!(msg),
+            (None, _) => panic_any(msg),
         }
     });
     unreachable!();
diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_mir/Cargo.toml
index 10dbf35fedc..59a0c9a5dd5 100644
--- a/compiler/rustc_mir/Cargo.toml
+++ b/compiler/rustc_mir/Cargo.toml
@@ -31,7 +31,7 @@ rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
 rustc_apfloat = { path = "../rustc_apfloat" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 
 [dev-dependencies]
 coverage_test_macros = { path = "src/transform/coverage/test_macros" }
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 333ac0738d4..0400431a542 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
@@ -1,6 +1,7 @@
 use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_index::vec::Idx;
+use rustc_middle::hir::map::Map;
 use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{
@@ -376,15 +377,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                                     opt_assignment_rhs_span.and_then(|span| span.desugaring_kind());
                                 match opt_desugaring_kind {
                                     // on for loops, RHS points to the iterator part
-                                    Some(DesugaringKind::ForLoop(_)) => Some((
-                                        false,
-                                        opt_assignment_rhs_span.unwrap(),
-                                        format!(
-                                            "this iterator yields `{SIGIL}` {DESC}s",
-                                            SIGIL = pointer_sigil,
-                                            DESC = pointer_desc
-                                        ),
-                                    )),
+                                    Some(DesugaringKind::ForLoop(_)) => {
+                                        self.suggest_similar_mut_method_for_for_loop(&mut err);
+                                        Some((
+                                            false,
+                                            opt_assignment_rhs_span.unwrap(),
+                                            format!(
+                                                "this iterator yields `{SIGIL}` {DESC}s",
+                                                SIGIL = pointer_sigil,
+                                                DESC = pointer_desc
+                                            ),
+                                        ))
+                                    }
                                     // don't create labels for compiler-generated spans
                                     Some(_) => None,
                                     None => {
@@ -537,6 +541,90 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         );
     }
 
+    // Attempt to search similar mutable associated items for suggestion.
+    // In the future, attempt in all path but initially for RHS of for_loop
+    fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_>) {
+        use hir::{
+            BodyId, Expr,
+            ExprKind::{Block, Call, DropTemps, Match, MethodCall},
+            HirId, ImplItem, ImplItemKind, Item, ItemKind,
+        };
+
+        fn maybe_body_id_of_fn(hir_map: &Map<'tcx>, id: HirId) -> Option<BodyId> {
+            match hir_map.find(id) {
+                Some(Node::Item(Item { kind: ItemKind::Fn(_, _, body_id), .. }))
+                | Some(Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })) => {
+                    Some(*body_id)
+                }
+                _ => None,
+            }
+        }
+        let hir_map = self.infcx.tcx.hir();
+        let mir_body_hir_id = self.mir_hir_id();
+        if let Some(fn_body_id) = maybe_body_id_of_fn(&hir_map, mir_body_hir_id) {
+            if let Block(
+                hir::Block {
+                    expr:
+                        Some(Expr {
+                            kind:
+                                DropTemps(Expr {
+                                    kind:
+                                        Match(
+                                            Expr {
+                                                kind:
+                                                    Call(
+                                                        _,
+                                                        [Expr {
+                                                            kind: MethodCall(path_segment, ..),
+                                                            hir_id,
+                                                            ..
+                                                        }, ..],
+                                                    ),
+                                                ..
+                                            },
+                                            ..,
+                                        ),
+                                    ..
+                                }),
+                            ..
+                        }),
+                    ..
+                },
+                _,
+            ) = hir_map.body(fn_body_id).value.kind
+            {
+                let opt_suggestions = path_segment
+                    .hir_id
+                    .map(|path_hir_id| self.infcx.tcx.typeck(path_hir_id.owner))
+                    .and_then(|typeck| typeck.type_dependent_def_id(*hir_id))
+                    .and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
+                    .map(|def_id| self.infcx.tcx.associated_items(def_id))
+                    .map(|assoc_items| {
+                        assoc_items
+                            .in_definition_order()
+                            .map(|assoc_item_def| assoc_item_def.ident)
+                            .filter(|&ident| {
+                                let original_method_ident = path_segment.ident;
+                                original_method_ident != ident
+                                    && ident
+                                        .as_str()
+                                        .starts_with(&original_method_ident.name.to_string())
+                            })
+                            .map(|ident| format!("{}()", ident))
+                    });
+
+                if let Some(suggestions) = opt_suggestions {
+                    err.span_suggestions(
+                        path_segment.ident.span,
+                        &format!("use mutable method"),
+                        suggestions,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        };
+    }
+
     /// Targeted error when encountering an `FnMut` closure where an `Fn` closure was expected.
     fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Span, act: &str) {
         err.span_label(sp, format!("cannot {}", act));
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
index cbca012824f..03738f1b40a 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs
@@ -634,14 +634,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                     | GenericArgKind::Const(_),
                     _,
                 ) => {
-                    // I *think* that HIR lowering should ensure this
-                    // doesn't happen, even in erroneous
-                    // programs. Else we should use delay-span-bug.
-                    span_bug!(
+                    // HIR lowering sometimes doesn't catch this in erroneous
+                    // programs, so we need to use delay_span_bug here. See #82126.
+                    self.infcx.tcx.sess.delay_span_bug(
                         hir_arg.span(),
-                        "unmatched subst and hir arg: found {:?} vs {:?}",
-                        kind,
-                        hir_arg,
+                        &format!("unmatched subst and hir arg: found {:?} vs {:?}", kind, hir_arg),
                     );
                 }
             }
@@ -767,7 +764,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
         let hir = self.infcx.tcx.hir();
 
         if let hir::TyKind::OpaqueDef(id, _) = hir_ty.kind {
-            let opaque_ty = hir.item(id.id);
+            let opaque_ty = hir.item(id);
             if let hir::ItemKind::OpaqueTy(hir::OpaqueTy {
                 bounds:
                     [hir::GenericBound::LangItemTrait(
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index 5db52db70ac..375d4649171 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -243,7 +243,7 @@ fn do_mir_borrowck<'a, 'tcx>(
 
     let regioncx = Rc::new(regioncx);
 
-    let flow_borrows = Borrows::new(tcx, &body, regioncx.clone(), &borrow_set)
+    let flow_borrows = Borrows::new(tcx, &body, &regioncx, &borrow_set)
         .into_engine(tcx, &body)
         .pass_name("borrowck")
         .iterate_to_fixpoint();
@@ -266,7 +266,6 @@ fn do_mir_borrowck<'a, 'tcx>(
 
     for (idx, move_data_results) in promoted_errors {
         let promoted_body = &promoted[idx];
-        let dominators = promoted_body.dominators();
 
         if let Err((move_data, move_errors)) = move_data_results {
             let mut promoted_mbcx = MirBorrowckCtxt {
@@ -274,7 +273,7 @@ fn do_mir_borrowck<'a, 'tcx>(
                 param_env,
                 body: promoted_body,
                 move_data: &move_data,
-                location_table: &LocationTable::new(promoted_body),
+                location_table, // no need to create a real one for the promoted, it is not used
                 movable_generator,
                 fn_self_span_reported: Default::default(),
                 locals_are_invalidated_at_exit,
@@ -287,8 +286,8 @@ fn do_mir_borrowck<'a, 'tcx>(
                 regioncx: regioncx.clone(),
                 used_mut: Default::default(),
                 used_mut_upvars: SmallVec::new(),
-                borrow_set: borrow_set.clone(),
-                dominators,
+                borrow_set: Rc::clone(&borrow_set),
+                dominators: Dominators::dummy(), // not used
                 upvars: Vec::new(),
                 local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
                 region_names: RefCell::default(),
@@ -317,10 +316,10 @@ fn do_mir_borrowck<'a, 'tcx>(
         move_error_reported: BTreeMap::new(),
         uninitialized_error_reported: Default::default(),
         errors_buffer,
-        regioncx,
+        regioncx: Rc::clone(&regioncx),
         used_mut: Default::default(),
         used_mut_upvars: SmallVec::new(),
-        borrow_set,
+        borrow_set: Rc::clone(&borrow_set),
         dominators,
         upvars,
         local_names,
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 3ba06bdd6e0..f64848e694c 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs
@@ -43,6 +43,9 @@ use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations}
 use crate::dataflow::impls::MaybeInitializedPlaces;
 use crate::dataflow::move_paths::MoveData;
 use crate::dataflow::ResultsCursor;
+use crate::transform::{
+    check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
+};
 
 use crate::borrow_check::{
     borrow_set::BorrowSet,
@@ -1098,6 +1101,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
     ) -> Fallible<()> {
         relate_tys::relate_types(
             self.infcx,
+            self.param_env,
             a,
             v,
             b,
@@ -1988,18 +1992,24 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         Operand::Copy(..) | Operand::Constant(..) => {
                             // These are always okay: direct use of a const, or a value that can evidently be copied.
                         }
-                        Operand::Move(_) => {
+                        Operand::Move(place) => {
                             // Make sure that repeated elements implement `Copy`.
                             let span = body.source_info(location).span;
                             let ty = operand.ty(body, tcx);
                             if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
+                                let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env);
+                                let is_const_fn =
+                                    is_const_fn_in_array_repeat_expression(&ccx, &place, &body);
+
+                                debug!("check_rvalue: is_const_fn={:?}", is_const_fn);
+
                                 let def_id = body.source.def_id().expect_local();
                                 self.infcx.report_selection_error(
                                     &traits::Obligation::new(
                                         ObligationCause::new(
                                             span,
                                             self.tcx().hir().local_def_id_to_hir_id(def_id),
-                                            traits::ObligationCauseCode::RepeatVec,
+                                            traits::ObligationCauseCode::RepeatVec(is_const_fn),
                                         ),
                                         self.param_env,
                                         ty::Binder::bind(ty::TraitRef::new(
@@ -2191,19 +2201,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     CastKind::Pointer(PointerCast::ArrayToPointer) => {
                         let ty_from = op.ty(body, tcx);
 
-                        let opt_ty_elem = match ty_from.kind() {
-                            ty::RawPtr(ty::TypeAndMut {
-                                mutbl: hir::Mutability::Not,
-                                ty: array_ty,
-                            }) => match array_ty.kind() {
-                                ty::Array(ty_elem, _) => Some(ty_elem),
-                                _ => None,
-                            },
+                        let opt_ty_elem_mut = match ty_from.kind() {
+                            ty::RawPtr(ty::TypeAndMut { mutbl: array_mut, ty: array_ty }) => {
+                                match array_ty.kind() {
+                                    ty::Array(ty_elem, _) => Some((ty_elem, *array_mut)),
+                                    _ => None,
+                                }
+                            }
                             _ => None,
                         };
 
-                        let ty_elem = match opt_ty_elem {
-                            Some(ty_elem) => ty_elem,
+                        let (ty_elem, ty_mut) = match opt_ty_elem_mut {
+                            Some(ty_elem_mut) => ty_elem_mut,
                             None => {
                                 span_mirbug!(
                                     self,
@@ -2215,11 +2224,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             }
                         };
 
-                        let ty_to = match ty.kind() {
-                            ty::RawPtr(ty::TypeAndMut {
-                                mutbl: hir::Mutability::Not,
-                                ty: ty_to,
-                            }) => ty_to,
+                        let (ty_to, ty_to_mut) = match ty.kind() {
+                            ty::RawPtr(ty::TypeAndMut { mutbl: ty_to_mut, ty: ty_to }) => {
+                                (ty_to, *ty_to_mut)
+                            }
                             _ => {
                                 span_mirbug!(
                                     self,
@@ -2231,6 +2239,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                             }
                         };
 
+                        if ty_to_mut == Mutability::Mut && ty_mut == Mutability::Not {
+                            span_mirbug!(
+                                self,
+                                rvalue,
+                                "ArrayToPointer cast from const {:?} to mut {:?}",
+                                ty,
+                                ty_to
+                            );
+                            return;
+                        }
+
                         if let Err(terr) = self.sub_types(
                             ty_elem,
                             ty_to,
diff --git a/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
index 6665eb5ad5f..249945f04b7 100644
--- a/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
+++ b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs
@@ -18,6 +18,7 @@ use crate::borrow_check::type_check::{BorrowCheckContext, Locations};
 /// variables, but not the type `b`.
 pub(super) fn relate_types<'tcx>(
     infcx: &InferCtxt<'_, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
     a: Ty<'tcx>,
     v: ty::Variance,
     b: Ty<'tcx>,
@@ -28,7 +29,7 @@ pub(super) fn relate_types<'tcx>(
     debug!("relate_types(a={:?}, v={:?}, b={:?}, locations={:?})", a, v, b, locations);
     TypeRelating::new(
         infcx,
-        NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category),
+        NllTypeRelatingDelegate::new(infcx, borrowck_context, param_env, locations, category),
         v,
     )
     .relate(a, b)?;
@@ -39,6 +40,8 @@ struct NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
     infcx: &'me InferCtxt<'me, 'tcx>,
     borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
 
+    param_env: ty::ParamEnv<'tcx>,
+
     /// Where (and why) is this relation taking place?
     locations: Locations,
 
@@ -50,14 +53,19 @@ impl NllTypeRelatingDelegate<'me, 'bccx, 'tcx> {
     fn new(
         infcx: &'me InferCtxt<'me, 'tcx>,
         borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>,
+        param_env: ty::ParamEnv<'tcx>,
         locations: Locations,
         category: ConstraintCategory,
     ) -> Self {
-        Self { infcx, borrowck_context, locations, category }
+        Self { infcx, borrowck_context, param_env, locations, category }
     }
 }
 
 impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx> {
+    fn param_env(&self) -> ty::ParamEnv<'tcx> {
+        self.param_env
+    }
+
     fn create_next_universe(&mut self) -> ty::UniverseIndex {
         self.infcx.create_next_universe()
     }
diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs
index 0e610e37552..754ed0bea84 100644
--- a/compiler/rustc_mir/src/const_eval/error.rs
+++ b/compiler/rustc_mir/src/const_eval/error.rs
@@ -16,6 +16,7 @@ use crate::interpret::{
 #[derive(Clone, Debug)]
 pub enum ConstEvalErrKind {
     NeedsRfc(String),
+    PtrToIntCast,
     ConstAccessesStatic,
     ModifiedGlobal,
     AssertFailure(AssertKind<ConstInt>),
@@ -39,6 +40,12 @@ impl fmt::Display for ConstEvalErrKind {
             NeedsRfc(ref msg) => {
                 write!(f, "\"{}\" needs an rfc before being allowed inside constants", msg)
             }
+            PtrToIntCast => {
+                write!(
+                    f,
+                    "cannot cast pointer to integer because it was not created by cast from integer"
+                )
+            }
             ConstAccessesStatic => write!(f, "constant accesses static"),
             ModifiedGlobal => {
                 write!(f, "modifying a static's initial value from another static's initializer")
@@ -77,7 +84,11 @@ impl<'tcx> ConstEvalErr<'tcx> {
     {
         error.print_backtrace();
         let stacktrace = ecx.generate_stacktrace();
-        ConstEvalErr { error: error.kind, stacktrace, span: span.unwrap_or_else(|| ecx.cur_span()) }
+        ConstEvalErr {
+            error: error.into_kind(),
+            stacktrace,
+            span: span.unwrap_or_else(|| ecx.cur_span()),
+        }
     }
 
     pub fn struct_error(
diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs
index 252f5e7ef2f..de898460368 100644
--- a/compiler/rustc_mir/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs
@@ -56,7 +56,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
     ecx.push_stack_frame(
         cid.instance,
         body,
-        Some(ret.into()),
+        Some(&ret.into()),
         StackPopCleanup::None { cleanup: false },
     )?;
 
@@ -72,7 +72,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
             None => InternKind::Constant,
         }
     };
-    intern_const_alloc_recursive(ecx, intern_kind, ret)?;
+    intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
 
     debug!("eval_body_using_ecx done: {:?}", *ret);
     Ok(ret)
@@ -105,7 +105,7 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>(
 /// type system.
 pub(super) fn op_to_const<'tcx>(
     ecx: &CompileTimeEvalContext<'_, 'tcx>,
-    op: OpTy<'tcx>,
+    op: &OpTy<'tcx>,
 ) -> ConstValue<'tcx> {
     // We do not have value optimizations for everything.
     // Only scalars and slices, since they are very common.
@@ -137,7 +137,7 @@ pub(super) fn op_to_const<'tcx>(
         op.try_as_mplace(ecx)
     };
 
-    let to_const_value = |mplace: MPlaceTy<'_>| match mplace.ptr {
+    let to_const_value = |mplace: &MPlaceTy<'_>| match mplace.ptr {
         Scalar::Ptr(ptr) => {
             let alloc = ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory();
             ConstValue::ByRef { alloc, offset: ptr.offset }
@@ -155,12 +155,12 @@ pub(super) fn op_to_const<'tcx>(
         }
     };
     match immediate {
-        Ok(mplace) => to_const_value(mplace),
+        Ok(ref mplace) => to_const_value(mplace),
         // see comment on `let try_as_immediate` above
         Err(imm) => match *imm {
             Immediate::Scalar(x) => match x {
                 ScalarMaybeUninit::Scalar(s) => ConstValue::Scalar(s),
-                ScalarMaybeUninit::Uninit => to_const_value(op.assert_mem_place(ecx)),
+                ScalarMaybeUninit::Uninit => to_const_value(&op.assert_mem_place(ecx)),
             },
             Immediate::ScalarPair(a, b) => {
                 let (data, start) = match a.check_init().unwrap() {
@@ -201,14 +201,14 @@ fn turn_into_const_value<'tcx>(
         "the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead"
     );
     // Turn this into a proper constant.
-    op_to_const(&ecx, mplace.into())
+    op_to_const(&ecx, &mplace.into())
 }
 
 pub fn eval_to_const_value_raw_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
 ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
-    // see comment in const_eval_raw_provider for what we're doing here
+    // see comment in eval_to_allocation_raw_provider for what we're doing here
     if key.param_env.reveal() == Reveal::All {
         let mut key = key;
         key.param_env = key.param_env.with_user_facing();
@@ -230,7 +230,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
         };
         return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| {
             let span = tcx.def_span(def_id);
-            let error = ConstEvalErr { error: error.kind, stacktrace: vec![], span };
+            let error = ConstEvalErr { error: error.into_kind(), stacktrace: vec![], span };
             error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic")
         });
     }
@@ -348,7 +348,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
                         Some(_) => CtfeValidationMode::Regular, // a `static`
                         None => CtfeValidationMode::Const { inner, allow_static_ptrs: false },
                     };
-                    ecx.const_validate_operand(mplace.into(), path, &mut ref_tracking, mode)?;
+                    ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
                     inner = true;
                 }
             };
diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs
index 49126cfec6b..61785a52729 100644
--- a/compiler/rustc_mir/src/const_eval/machine.rs
+++ b/compiler/rustc_mir/src/const_eval/machine.rs
@@ -39,8 +39,8 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
             // &str
             assert!(args.len() == 1);
 
-            let msg_place = self.deref_operand(args[0])?;
-            let msg = Symbol::intern(self.read_str(msg_place)?);
+            let msg_place = self.deref_operand(&args[0])?;
+            let msg = Symbol::intern(self.read_str(&msg_place)?);
             let span = self.find_closest_untracked_caller_location();
             let (file, line, col) = self.location_triple_for_span(span);
             Err(ConstEvalErrKind::Panic { msg, file, line, col }.into())
@@ -222,7 +222,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         instance: ty::Instance<'tcx>,
         _abi: Abi,
         args: &[OpTy<'tcx>],
-        _ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
+        _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
         _unwind: Option<mir::BasicBlock>, // unwinding is not supported in consts
     ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
         debug!("find_mir_or_eval_fn: {:?}", instance);
@@ -245,8 +245,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         Ok(Some(match ecx.load_mir(instance.def, None) {
             Ok(body) => body,
             Err(err) => {
-                if let err_unsup!(NoMirFor(did)) = err.kind {
-                    let path = ecx.tcx.def_path_str(did);
+                if let err_unsup!(NoMirFor(did)) = err.kind() {
+                    let path = ecx.tcx.def_path_str(*did);
                     return Err(ConstEvalErrKind::NeedsRfc(format!(
                         "calling extern function `{}`",
                         path
@@ -262,7 +262,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
-        ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>,
+        ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
         _unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx> {
         // Shared intrinsics.
@@ -284,8 +284,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         };
         match intrinsic_name {
             sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => {
-                let a = ecx.read_immediate(args[0])?.to_scalar()?;
-                let b = ecx.read_immediate(args[1])?.to_scalar()?;
+                let a = ecx.read_immediate(&args[0])?.to_scalar()?;
+                let b = ecx.read_immediate(&args[1])?.to_scalar()?;
                 let cmp = if intrinsic_name == sym::ptr_guaranteed_eq {
                     ecx.guaranteed_eq(a, b)
                 } else {
@@ -294,8 +294,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
                 ecx.write_scalar(Scalar::from_bool(cmp), dest)?;
             }
             sym::const_allocate => {
-                let size = ecx.read_scalar(args[0])?.to_machine_usize(ecx)?;
-                let align = ecx.read_scalar(args[1])?.to_machine_usize(ecx)?;
+                let size = ecx.read_scalar(&args[0])?.to_machine_usize(ecx)?;
+                let align = ecx.read_scalar(&args[1])?.to_machine_usize(ecx)?;
 
                 let align = match Align::from_bytes(align) {
                     Ok(a) => a,
@@ -330,7 +330,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         use rustc_middle::mir::AssertKind::*;
         // Convert `AssertKind<Operand>` to `AssertKind<Scalar>`.
         let eval_to_int =
-            |op| ecx.read_immediate(ecx.eval_operand(op, None)?).map(|x| x.to_const_int());
+            |op| ecx.read_immediate(&ecx.eval_operand(op, None)?).map(|x| x.to_const_int());
         let err = match msg {
             BoundsCheck { ref len, ref index } => {
                 let len = eval_to_int(len)?;
@@ -352,21 +352,21 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
     }
 
     fn ptr_to_int(_mem: &Memory<'mir, 'tcx, Self>, _ptr: Pointer) -> InterpResult<'tcx, u64> {
-        Err(ConstEvalErrKind::NeedsRfc("pointer-to-integer cast".to_string()).into())
+        Err(ConstEvalErrKind::PtrToIntCast.into())
     }
 
     fn binary_ptr_op(
         _ecx: &InterpCx<'mir, 'tcx, Self>,
         _bin_op: mir::BinOp,
-        _left: ImmTy<'tcx>,
-        _right: ImmTy<'tcx>,
+        _left: &ImmTy<'tcx>,
+        _right: &ImmTy<'tcx>,
     ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
         Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into())
     }
 
     fn box_alloc(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _dest: PlaceTy<'tcx>,
+        _dest: &PlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into())
     }
diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs
index 9dd2a8592a7..a4e1cd2faa3 100644
--- a/compiler/rustc_mir/src/const_eval/mod.rs
+++ b/compiler/rustc_mir/src/const_eval/mod.rs
@@ -29,7 +29,7 @@ pub(crate) fn const_caller_location(
     let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all(), false);
 
     let loc_place = ecx.alloc_caller_location(file, line, col);
-    if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, loc_place).is_err() {
+    if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
         bug!("intern_const_alloc_recursive should not error in this case")
     }
     ConstValue::Scalar(loc_place.ptr)
@@ -55,8 +55,8 @@ pub(crate) fn destructure_const<'tcx>(
             return mir::DestructuredConst { variant: None, fields: &[] };
         }
         ty::Adt(def, _) => {
-            let variant = ecx.read_discriminant(op).unwrap().1;
-            let down = ecx.operand_downcast(op, variant).unwrap();
+            let variant = ecx.read_discriminant(&op).unwrap().1;
+            let down = ecx.operand_downcast(&op, variant).unwrap();
             (def.variants[variant].fields.len(), Some(variant), down)
         }
         ty::Tuple(substs) => (substs.len(), None, op),
@@ -64,8 +64,8 @@ pub(crate) fn destructure_const<'tcx>(
     };
 
     let fields_iter = (0..field_count).map(|i| {
-        let field_op = ecx.operand_field(down, i).unwrap();
-        let val = op_to_const(&ecx, field_op);
+        let field_op = ecx.operand_field(&down, i).unwrap();
+        let val = op_to_const(&ecx, &field_op);
         ty::Const::from_value(tcx, val, field_op.layout.ty)
     });
     let fields = tcx.arena.alloc_from_iter(fields_iter);
@@ -81,7 +81,7 @@ pub(crate) fn deref_const<'tcx>(
     trace!("deref_const: {:?}", val);
     let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
     let op = ecx.const_to_op(val, None).unwrap();
-    let mplace = ecx.deref_operand(op).unwrap();
+    let mplace = ecx.deref_operand(&op).unwrap();
     if let Scalar::Ptr(ptr) = mplace.ptr {
         assert_eq!(
             ecx.memory.get_raw(ptr.alloc_id).unwrap().mutability,
@@ -106,5 +106,5 @@ pub(crate) fn deref_const<'tcx>(
         },
     };
 
-    tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, mplace.into())), ty })
+    tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
 }
diff --git a/compiler/rustc_mir/src/dataflow/impls/borrows.rs b/compiler/rustc_mir/src/dataflow/impls/borrows.rs
index 6b7889c4d9e..b149ffa9667 100644
--- a/compiler/rustc_mir/src/dataflow/impls/borrows.rs
+++ b/compiler/rustc_mir/src/dataflow/impls/borrows.rs
@@ -11,7 +11,6 @@ use crate::borrow_check::{
 use crate::dataflow::{self, fmt::DebugWithContext, GenKill};
 
 use std::fmt;
-use std::rc::Rc;
 
 rustc_index::newtype_index! {
     pub struct BorrowIndex {
@@ -30,101 +29,113 @@ pub struct Borrows<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     body: &'a Body<'tcx>,
 
-    borrow_set: Rc<BorrowSet<'tcx>>,
+    borrow_set: &'a BorrowSet<'tcx>,
     borrows_out_of_scope_at_location: FxHashMap<Location, Vec<BorrowIndex>>,
-
-    /// NLL region inference context with which NLL queries should be resolved
-    _nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
 }
 
 struct StackEntry {
     bb: mir::BasicBlock,
     lo: usize,
     hi: usize,
-    first_part_only: bool,
 }
 
-fn precompute_borrows_out_of_scope<'tcx>(
-    body: &Body<'tcx>,
-    regioncx: &Rc<RegionInferenceContext<'tcx>>,
-    borrows_out_of_scope_at_location: &mut FxHashMap<Location, Vec<BorrowIndex>>,
-    borrow_index: BorrowIndex,
-    borrow_region: RegionVid,
-    location: Location,
-) {
-    // We visit one BB at a time. The complication is that we may start in the
-    // middle of the first BB visited (the one containing `location`), in which
-    // case we may have to later on process the first part of that BB if there
-    // is a path back to its start.
-
-    // For visited BBs, we record the index of the first statement processed.
-    // (In fully processed BBs this index is 0.) Note also that we add BBs to
-    // `visited` once they are added to `stack`, before they are actually
-    // processed, because this avoids the need to look them up again on
-    // completion.
-    let mut visited = FxHashMap::default();
-    visited.insert(location.block, location.statement_index);
-
-    let mut stack = vec![];
-    stack.push(StackEntry {
-        bb: location.block,
-        lo: location.statement_index,
-        hi: body[location.block].statements.len(),
-        first_part_only: false,
-    });
-
-    while let Some(StackEntry { bb, lo, hi, first_part_only }) = stack.pop() {
-        let mut finished_early = first_part_only;
-        for i in lo..=hi {
-            let location = Location { block: bb, statement_index: i };
-            // If region does not contain a point at the location, then add to list and skip
-            // successor locations.
-            if !regioncx.region_contains(borrow_region, location) {
-                debug!("borrow {:?} gets killed at {:?}", borrow_index, location);
-                borrows_out_of_scope_at_location.entry(location).or_default().push(borrow_index);
-                finished_early = true;
-                break;
-            }
+struct OutOfScopePrecomputer<'a, 'tcx> {
+    visited: BitSet<mir::BasicBlock>,
+    visit_stack: Vec<StackEntry>,
+    body: &'a Body<'tcx>,
+    regioncx: &'a RegionInferenceContext<'tcx>,
+    borrows_out_of_scope_at_location: FxHashMap<Location, Vec<BorrowIndex>>,
+}
+
+impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> {
+    fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
+        OutOfScopePrecomputer {
+            visited: BitSet::new_empty(body.basic_blocks().len()),
+            visit_stack: vec![],
+            body,
+            regioncx,
+            borrows_out_of_scope_at_location: FxHashMap::default(),
         }
+    }
+}
 
-        if !finished_early {
-            // Add successor BBs to the work list, if necessary.
-            let bb_data = &body[bb];
-            assert!(hi == bb_data.statements.len());
-            for &succ_bb in bb_data.terminator().successors() {
-                visited
-                    .entry(succ_bb)
-                    .and_modify(|lo| {
-                        // `succ_bb` has been seen before. If it wasn't
-                        // fully processed, add its first part to `stack`
-                        // for processing.
-                        if *lo > 0 {
-                            stack.push(StackEntry {
+impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
+    fn precompute_borrows_out_of_scope(
+        &mut self,
+        borrow_index: BorrowIndex,
+        borrow_region: RegionVid,
+        location: Location,
+    ) {
+        // We visit one BB at a time. The complication is that we may start in the
+        // middle of the first BB visited (the one containing `location`), in which
+        // case we may have to later on process the first part of that BB if there
+        // is a path back to its start.
+
+        // For visited BBs, we record the index of the first statement processed.
+        // (In fully processed BBs this index is 0.) Note also that we add BBs to
+        // `visited` once they are added to `stack`, before they are actually
+        // processed, because this avoids the need to look them up again on
+        // completion.
+        self.visited.insert(location.block);
+
+        let mut first_lo = location.statement_index;
+        let first_hi = self.body[location.block].statements.len();
+
+        self.visit_stack.push(StackEntry { bb: location.block, lo: first_lo, hi: first_hi });
+
+        while let Some(StackEntry { bb, lo, hi }) = self.visit_stack.pop() {
+            // If we process the first part of the first basic block (i.e. we encounter that block
+            // for the second time), we no longer have to visit its successors again.
+            let mut finished_early = bb == location.block && hi != first_hi;
+            for i in lo..=hi {
+                let location = Location { block: bb, statement_index: i };
+                // If region does not contain a point at the location, then add to list and skip
+                // successor locations.
+                if !self.regioncx.region_contains(borrow_region, location) {
+                    debug!("borrow {:?} gets killed at {:?}", borrow_index, location);
+                    self.borrows_out_of_scope_at_location
+                        .entry(location)
+                        .or_default()
+                        .push(borrow_index);
+                    finished_early = true;
+                    break;
+                }
+            }
+
+            if !finished_early {
+                // Add successor BBs to the work list, if necessary.
+                let bb_data = &self.body[bb];
+                debug_assert!(hi == bb_data.statements.len());
+                for &succ_bb in bb_data.terminator().successors() {
+                    if self.visited.insert(succ_bb) == false {
+                        if succ_bb == location.block && first_lo > 0 {
+                            // `succ_bb` has been seen before. If it wasn't
+                            // fully processed, add its first part to `stack`
+                            // for processing.
+                            self.visit_stack.push(StackEntry {
                                 bb: succ_bb,
                                 lo: 0,
-                                hi: *lo - 1,
-                                first_part_only: true,
+                                hi: first_lo - 1,
                             });
+
+                            // And update this entry with 0, to represent the
+                            // whole BB being processed.
+                            first_lo = 0;
                         }
-                        // And update this entry with 0, to represent the
-                        // whole BB being processed.
-                        *lo = 0;
-                    })
-                    .or_insert_with(|| {
+                    } else {
                         // succ_bb hasn't been seen before. Add it to
                         // `stack` for processing.
-                        stack.push(StackEntry {
+                        self.visit_stack.push(StackEntry {
                             bb: succ_bb,
                             lo: 0,
-                            hi: body[succ_bb].statements.len(),
-                            first_part_only: false,
+                            hi: self.body[succ_bb].statements.len(),
                         });
-                        // Insert 0 for this BB, to represent the whole BB
-                        // being processed.
-                        0
-                    });
+                    }
+                }
             }
         }
+
+        self.visited.clear();
     }
 }
 
@@ -132,30 +143,22 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
     crate fn new(
         tcx: TyCtxt<'tcx>,
         body: &'a Body<'tcx>,
-        nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
-        borrow_set: &Rc<BorrowSet<'tcx>>,
+        nonlexical_regioncx: &'a RegionInferenceContext<'tcx>,
+        borrow_set: &'a BorrowSet<'tcx>,
     ) -> Self {
-        let mut borrows_out_of_scope_at_location = FxHashMap::default();
+        let mut prec = OutOfScopePrecomputer::new(body, nonlexical_regioncx);
         for (borrow_index, borrow_data) in borrow_set.iter_enumerated() {
             let borrow_region = borrow_data.region.to_region_vid();
             let location = borrow_data.reserve_location;
 
-            precompute_borrows_out_of_scope(
-                body,
-                &nonlexical_regioncx,
-                &mut borrows_out_of_scope_at_location,
-                borrow_index,
-                borrow_region,
-                location,
-            );
+            prec.precompute_borrows_out_of_scope(borrow_index, borrow_region, location);
         }
 
         Borrows {
             tcx,
             body,
-            borrow_set: borrow_set.clone(),
-            borrows_out_of_scope_at_location,
-            _nonlexical_regioncx: nonlexical_regioncx,
+            borrow_set,
+            borrows_out_of_scope_at_location: prec.borrows_out_of_scope_at_location,
         }
     }
 
diff --git a/compiler/rustc_mir/src/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs
index 128d8cff95e..2d9e6df0ab8 100644
--- a/compiler/rustc_mir/src/interpret/cast.rs
+++ b/compiler/rustc_mir/src/interpret/cast.rs
@@ -17,10 +17,10 @@ use super::{
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn cast(
         &mut self,
-        src: OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
         cast_kind: CastKind,
         cast_ty: Ty<'tcx>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         use rustc_middle::mir::CastKind::*;
         // FIXME: In which cases should we trigger UB when the source is uninit?
@@ -32,7 +32,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
             Misc => {
                 let src = self.read_immediate(src)?;
-                let res = self.misc_cast(src, cast_ty)?;
+                let res = self.misc_cast(&src, cast_ty)?;
                 self.write_immediate(res, dest)?;
             }
 
@@ -107,7 +107,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     fn misc_cast(
         &self,
-        src: ImmTy<'tcx, M::PointerTag>,
+        src: &ImmTy<'tcx, M::PointerTag>,
         cast_ty: Ty<'tcx>,
     ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
         use rustc_middle::ty::TyKind::*;
@@ -158,13 +158,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             let dest_layout = self.layout_of(cast_ty)?;
             if dest_layout.size == src.layout.size {
                 // Thin or fat pointer that just hast the ptr kind of target type changed.
-                return Ok(*src);
+                return Ok(**src);
             } else {
                 // Casting the metadata away from a fat ptr.
                 assert_eq!(src.layout.size, 2 * self.memory.pointer_size());
                 assert_eq!(dest_layout.size, self.memory.pointer_size());
                 assert!(src.layout.ty.is_unsafe_ptr());
-                return match *src {
+                return match **src {
                     Immediate::ScalarPair(data, _) => Ok(data.into()),
                     Immediate::Scalar(..) => span_bug!(
                         self.cur_span(),
@@ -259,8 +259,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     fn unsize_into_ptr(
         &mut self,
-        src: OpTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
         // The pointee types
         source_ty: Ty<'tcx>,
         cast_ty: Ty<'tcx>,
@@ -300,9 +300,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     fn unsize_into(
         &mut self,
-        src: OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
         cast_ty: TyAndLayout<'tcx>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty);
         match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
@@ -340,9 +340,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     let src_field = self.operand_field(src, i)?;
                     let dst_field = self.place_field(dest, i)?;
                     if src_field.layout.ty == cast_ty_field.ty {
-                        self.copy_op(src_field, dst_field)?;
+                        self.copy_op(&src_field, &dst_field)?;
                     } else {
-                        self.unsize_into(src_field, cast_ty_field, dst_field)?;
+                        self.unsize_into(&src_field, cast_ty_field, &dst_field)?;
                     }
                 }
                 Ok(())
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index 7e9594dd6bf..1ba87358b1c 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -548,8 +548,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// This can fail to provide an answer for extern types.
     pub(super) fn size_and_align_of(
         &self,
-        metadata: MemPlaceMeta<M::PointerTag>,
-        layout: TyAndLayout<'tcx>,
+        metadata: &MemPlaceMeta<M::PointerTag>,
+        layout: &TyAndLayout<'tcx>,
     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
         if !layout.is_unsized() {
             return Ok(Some((layout.size, layout.align.abi)));
@@ -577,24 +577,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // the last field).  Can't have foreign types here, how would we
                 // adjust alignment and size for them?
                 let field = layout.field(self, layout.fields.count() - 1)?;
-                let (unsized_size, unsized_align) = match self.size_and_align_of(metadata, field)? {
-                    Some(size_and_align) => size_and_align,
-                    None => {
-                        // A field with extern type.  If this field is at offset 0, we behave
-                        // like the underlying extern type.
-                        // FIXME: Once we have made decisions for how to handle size and alignment
-                        // of `extern type`, this should be adapted.  It is just a temporary hack
-                        // to get some code to work that probably ought to work.
-                        if sized_size == Size::ZERO {
-                            return Ok(None);
-                        } else {
-                            span_bug!(
-                                self.cur_span(),
-                                "Fields cannot be extern types, unless they are at offset 0"
-                            )
+                let (unsized_size, unsized_align) =
+                    match self.size_and_align_of(metadata, &field)? {
+                        Some(size_and_align) => size_and_align,
+                        None => {
+                            // A field with extern type.  If this field is at offset 0, we behave
+                            // like the underlying extern type.
+                            // FIXME: Once we have made decisions for how to handle size and alignment
+                            // of `extern type`, this should be adapted.  It is just a temporary hack
+                            // to get some code to work that probably ought to work.
+                            if sized_size == Size::ZERO {
+                                return Ok(None);
+                            } else {
+                                span_bug!(
+                                    self.cur_span(),
+                                    "Fields cannot be extern types, unless they are at offset 0"
+                                )
+                            }
                         }
-                    }
-                };
+                    };
 
                 // FIXME (#26403, #27023): We should be adding padding
                 // to `sized_size` (to accommodate the `unsized_align`
@@ -645,16 +646,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline]
     pub fn size_and_align_of_mplace(
         &self,
-        mplace: MPlaceTy<'tcx, M::PointerTag>,
+        mplace: &MPlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, Option<(Size, Align)>> {
-        self.size_and_align_of(mplace.meta, mplace.layout)
+        self.size_and_align_of(&mplace.meta, &mplace.layout)
     }
 
     pub fn push_stack_frame(
         &mut self,
         instance: ty::Instance<'tcx>,
         body: &'mir mir::Body<'tcx>,
-        return_place: Option<PlaceTy<'tcx, M::PointerTag>>,
+        return_place: Option<&PlaceTy<'tcx, M::PointerTag>>,
         return_to_block: StackPopCleanup,
     ) -> InterpResult<'tcx> {
         // first push a stack frame so we have access to the local substs
@@ -662,7 +663,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             body,
             loc: Err(body.span), // Span used for errors caused during preamble.
             return_to_block,
-            return_place,
+            return_place: return_place.copied(),
             // empty local array, we fill it in below, after we are inside the stack frame and
             // all methods actually know about the frame
             locals: IndexVec::new(),
@@ -777,10 +778,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         if !unwinding {
             // Copy the return value to the caller's stack frame.
-            if let Some(return_place) = frame.return_place {
+            if let Some(ref return_place) = frame.return_place {
                 let op = self.access_local(&frame, mir::RETURN_PLACE, None)?;
-                self.copy_op_transmute(op, return_place)?;
-                trace!("{:?}", self.dump_place(*return_place));
+                self.copy_op_transmute(&op, return_place)?;
+                trace!("{:?}", self.dump_place(**return_place));
             } else {
                 throw_ub!(Unreachable);
             }
diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs
index 01d58c47e3a..59438661cac 100644
--- a/compiler/rustc_mir/src/interpret/intern.rs
+++ b/compiler/rustc_mir/src/interpret/intern.rs
@@ -167,7 +167,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
 
     fn visit_aggregate(
         &mut self,
-        mplace: MPlaceTy<'tcx>,
+        mplace: &MPlaceTy<'tcx>,
         fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>,
     ) -> InterpResult<'tcx> {
         // ZSTs cannot contain pointers, so we can skip them.
@@ -191,14 +191,14 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
         self.walk_aggregate(mplace, fields)
     }
 
-    fn visit_value(&mut self, mplace: MPlaceTy<'tcx>) -> InterpResult<'tcx> {
+    fn visit_value(&mut self, mplace: &MPlaceTy<'tcx>) -> InterpResult<'tcx> {
         // Handle Reference types, as these are the only relocations supported by const eval.
         // Raw pointers (and boxes) are handled by the `leftover_relocations` logic.
         let tcx = self.ecx.tcx;
         let ty = mplace.layout.ty;
         if let ty::Ref(_, referenced_ty, ref_mutability) = *ty.kind() {
-            let value = self.ecx.read_immediate(mplace.into())?;
-            let mplace = self.ecx.ref_to_mplace(value)?;
+            let value = self.ecx.read_immediate(&(*mplace).into())?;
+            let mplace = self.ecx.ref_to_mplace(&value)?;
             assert_eq!(mplace.layout.ty, referenced_ty);
             // Handle trait object vtables.
             if let ty::Dynamic(..) =
@@ -292,11 +292,11 @@ pub enum InternKind {
 /// tracks where in the value we are and thus can show much better error messages.
 /// Any errors here would anyway be turned into `const_err` lints, whereas validation failures
 /// are hard errors.
-#[tracing::instrument(skip(ecx))]
+#[tracing::instrument(level = "debug", skip(ecx))]
 pub fn intern_const_alloc_recursive<M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>(
     ecx: &mut InterpCx<'mir, 'tcx, M>,
     intern_kind: InternKind,
-    ret: MPlaceTy<'tcx>,
+    ret: &MPlaceTy<'tcx>,
 ) -> Result<(), ErrorReported>
 where
     'tcx: 'mir,
@@ -328,7 +328,7 @@ where
         Some(ret.layout.ty),
     );
 
-    ref_tracking.track((ret, base_intern_mode), || ());
+    ref_tracking.track((*ret, base_intern_mode), || ());
 
     while let Some(((mplace, mode), _)) = ref_tracking.todo.pop() {
         let res = InternVisitor {
@@ -338,7 +338,7 @@ where
             leftover_allocations,
             inside_unsafe_cell: false,
         }
-        .visit_value(mplace);
+        .visit_value(&mplace);
         // We deliberately *ignore* interpreter errors here.  When there is a problem, the remaining
         // references are "leftover"-interned, and later validation will show a proper error
         // and point at the right part of the value causing the problem.
@@ -356,7 +356,7 @@ where
                 // an allocation, which we should avoid. When that happens,
                 // dedicated error variants should be introduced instead.
                 assert!(
-                    !error.kind.allocates(),
+                    !error.kind().allocates(),
                     "interning encountered allocating error: {}",
                     error
                 );
@@ -435,11 +435,11 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
         layout: TyAndLayout<'tcx>,
         f: impl FnOnce(
             &mut InterpCx<'mir, 'tcx, M>,
-            MPlaceTy<'tcx, M::PointerTag>,
+            &MPlaceTy<'tcx, M::PointerTag>,
         ) -> InterpResult<'tcx, ()>,
     ) -> InterpResult<'tcx, &'tcx Allocation> {
         let dest = self.allocate(layout, MemoryKind::Stack);
-        f(self, dest)?;
+        f(self, &dest)?;
         let ptr = dest.ptr.assert_ptr();
         assert_eq!(ptr.offset, Size::ZERO);
         let mut alloc = self.memory.alloc_map.remove(&ptr.alloc_id).unwrap().1;
diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs
index f4309c9cd95..c4039f2f15e 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics.rs
@@ -115,7 +115,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &mut self,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, M::PointerTag>],
-        ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
+        ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
     ) -> InterpResult<'tcx, bool> {
         let substs = instance.substs;
         let intrinsic_name = self.tcx.item_name(instance.def_id());
@@ -143,9 +143,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             sym::min_align_of_val | sym::size_of_val => {
                 // Avoid `deref_operand` -- this is not a deref, the ptr does not have to be
                 // dereferencable!
-                let place = self.ref_to_mplace(self.read_immediate(args[0])?)?;
+                let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
                 let (size, align) = self
-                    .size_and_align_of_mplace(place)?
+                    .size_and_align_of_mplace(&place)?
                     .ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?;
 
                 let result = match intrinsic_name {
@@ -177,7 +177,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?;
                 let const_ = ty::Const { val: ty::ConstKind::Value(val), ty };
                 let val = self.const_to_op(&const_, None)?;
-                self.copy_op(val, dest)?;
+                self.copy_op(&val, dest)?;
             }
 
             sym::ctpop
@@ -189,7 +189,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             | sym::bitreverse => {
                 let ty = substs.type_at(0);
                 let layout_of = self.layout_of(ty)?;
-                let val = self.read_scalar(args[0])?.check_init()?;
+                let val = self.read_scalar(&args[0])?.check_init()?;
                 let bits = self.force_bits(val, layout_of.size)?;
                 let kind = match layout_of.abi {
                     Abi::Scalar(ref scalar) => scalar.value,
@@ -212,22 +212,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.write_scalar(out_val, dest)?;
             }
             sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
-                let lhs = self.read_immediate(args[0])?;
-                let rhs = self.read_immediate(args[1])?;
+                let lhs = self.read_immediate(&args[0])?;
+                let rhs = self.read_immediate(&args[1])?;
                 let bin_op = match intrinsic_name {
                     sym::add_with_overflow => BinOp::Add,
                     sym::sub_with_overflow => BinOp::Sub,
                     sym::mul_with_overflow => BinOp::Mul,
                     _ => bug!("Already checked for int ops"),
                 };
-                self.binop_with_overflow(bin_op, lhs, rhs, dest)?;
+                self.binop_with_overflow(bin_op, &lhs, &rhs, dest)?;
             }
             sym::saturating_add | sym::saturating_sub => {
-                let l = self.read_immediate(args[0])?;
-                let r = self.read_immediate(args[1])?;
+                let l = self.read_immediate(&args[0])?;
+                let r = self.read_immediate(&args[1])?;
                 let is_add = intrinsic_name == sym::saturating_add;
-                let (val, overflowed, _ty) =
-                    self.overflowing_binary_op(if is_add { BinOp::Add } else { BinOp::Sub }, l, r)?;
+                let (val, overflowed, _ty) = self.overflowing_binary_op(
+                    if is_add { BinOp::Add } else { BinOp::Sub },
+                    &l,
+                    &r,
+                )?;
                 let val = if overflowed {
                     let num_bits = l.layout.size.bits();
                     if l.layout.abi.is_signed() {
@@ -269,8 +272,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.write_scalar(val, dest)?;
             }
             sym::discriminant_value => {
-                let place = self.deref_operand(args[0])?;
-                let discr_val = self.read_discriminant(place.into())?.0;
+                let place = self.deref_operand(&args[0])?;
+                let discr_val = self.read_discriminant(&place.into())?.0;
                 self.write_scalar(discr_val, dest)?;
             }
             sym::unchecked_shl
@@ -280,8 +283,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             | sym::unchecked_mul
             | sym::unchecked_div
             | sym::unchecked_rem => {
-                let l = self.read_immediate(args[0])?;
-                let r = self.read_immediate(args[1])?;
+                let l = self.read_immediate(&args[0])?;
+                let r = self.read_immediate(&args[1])?;
                 let bin_op = match intrinsic_name {
                     sym::unchecked_shl => BinOp::Shl,
                     sym::unchecked_shr => BinOp::Shr,
@@ -292,7 +295,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     sym::unchecked_rem => BinOp::Rem,
                     _ => bug!("Already checked for int ops"),
                 };
-                let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, l, r)?;
+                let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?;
                 if overflowed {
                     let layout = self.layout_of(substs.type_at(0))?;
                     let r_val = self.force_bits(r.to_scalar()?, layout.size)?;
@@ -308,9 +311,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
                 // rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
                 let layout = self.layout_of(substs.type_at(0))?;
-                let val = self.read_scalar(args[0])?.check_init()?;
+                let val = self.read_scalar(&args[0])?.check_init()?;
                 let val_bits = self.force_bits(val, layout.size)?;
-                let raw_shift = self.read_scalar(args[1])?.check_init()?;
+                let raw_shift = self.read_scalar(&args[1])?.check_init()?;
                 let raw_shift_bits = self.force_bits(raw_shift, layout.size)?;
                 let width_bits = u128::from(layout.size.bits());
                 let shift_bits = raw_shift_bits % width_bits;
@@ -327,15 +330,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             sym::copy | sym::copy_nonoverlapping => {
                 let elem_ty = instance.substs.type_at(0);
                 let elem_layout = self.layout_of(elem_ty)?;
-                let count = self.read_scalar(args[2])?.to_machine_usize(self)?;
+                let count = self.read_scalar(&args[2])?.to_machine_usize(self)?;
                 let elem_align = elem_layout.align.abi;
 
                 let size = elem_layout.size.checked_mul(count, self).ok_or_else(|| {
                     err_ub_format!("overflow computing total size of `{}`", intrinsic_name)
                 })?;
-                let src = self.read_scalar(args[0])?.check_init()?;
+                let src = self.read_scalar(&args[0])?.check_init()?;
                 let src = self.memory.check_ptr_access(src, size, elem_align)?;
-                let dest = self.read_scalar(args[1])?.check_init()?;
+                let dest = self.read_scalar(&args[1])?.check_init()?;
                 let dest = self.memory.check_ptr_access(dest, size, elem_align)?;
 
                 if let (Some(src), Some(dest)) = (src, dest) {
@@ -348,16 +351,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 }
             }
             sym::offset => {
-                let ptr = self.read_scalar(args[0])?.check_init()?;
-                let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
+                let ptr = self.read_scalar(&args[0])?.check_init()?;
+                let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?;
                 let pointee_ty = substs.type_at(0);
 
                 let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?;
                 self.write_scalar(offset_ptr, dest)?;
             }
             sym::arith_offset => {
-                let ptr = self.read_scalar(args[0])?.check_init()?;
-                let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
+                let ptr = self.read_scalar(&args[0])?.check_init()?;
+                let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?;
                 let pointee_ty = substs.type_at(0);
 
                 let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
@@ -366,8 +369,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 self.write_scalar(offset_ptr, dest)?;
             }
             sym::ptr_offset_from => {
-                let a = self.read_immediate(args[0])?.to_scalar()?;
-                let b = self.read_immediate(args[1])?.to_scalar()?;
+                let a = self.read_immediate(&args[0])?.to_scalar()?;
+                let b = self.read_immediate(&args[1])?.to_scalar()?;
 
                 // Special case: if both scalars are *equal integers*
                 // and not NULL, we pretend there is an allocation of size 0 right there,
@@ -406,16 +409,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     let a_offset = ImmTy::from_uint(a.offset.bytes(), usize_layout);
                     let b_offset = ImmTy::from_uint(b.offset.bytes(), usize_layout);
                     let (val, _overflowed, _ty) =
-                        self.overflowing_binary_op(BinOp::Sub, a_offset, b_offset)?;
+                        self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?;
                     let pointee_layout = self.layout_of(substs.type_at(0))?;
                     let val = ImmTy::from_scalar(val, isize_layout);
                     let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
-                    self.exact_div(val, size, dest)?;
+                    self.exact_div(&val, &size, dest)?;
                 }
             }
 
             sym::transmute => {
-                self.copy_op_transmute(args[0], dest)?;
+                self.copy_op_transmute(&args[0], dest)?;
             }
             sym::assert_inhabited => {
                 let ty = instance.substs.type_at(0);
@@ -434,9 +437,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 }
             }
             sym::simd_insert => {
-                let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
-                let elem = args[2];
-                let input = args[0];
+                let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
+                let elem = &args[2];
+                let input = &args[0];
                 let (len, e_ty) = input.layout.ty.simd_size_and_type(*self.tcx);
                 assert!(
                     index < len,
@@ -458,12 +461,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
                 for i in 0..len {
                     let place = self.place_index(dest, i)?;
-                    let value = if i == index { elem } else { self.operand_index(input, i)? };
-                    self.copy_op(value, place)?;
+                    let value = if i == index { *elem } else { self.operand_index(input, i)? };
+                    self.copy_op(&value, &place)?;
                 }
             }
             sym::simd_extract => {
-                let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
+                let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
                 let (len, e_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx);
                 assert!(
                     index < len,
@@ -477,14 +480,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     "Return type `{}` must match vector element type `{}`",
                     dest.layout.ty, e_ty
                 );
-                self.copy_op(self.operand_index(args[0], index)?, dest)?;
+                self.copy_op(&self.operand_index(&args[0], index)?, dest)?;
             }
             sym::likely | sym::unlikely => {
                 // These just return their argument
-                self.copy_op(args[0], dest)?;
+                self.copy_op(&args[0], dest)?;
             }
             sym::assume => {
-                let cond = self.read_scalar(args[0])?.check_init()?.to_bool()?;
+                let cond = self.read_scalar(&args[0])?.check_init()?.to_bool()?;
                 if !cond {
                     throw_ub_format!("`assume` intrinsic called with `false`");
                 }
@@ -492,21 +495,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             _ => return Ok(false),
         }
 
-        trace!("{:?}", self.dump_place(*dest));
+        trace!("{:?}", self.dump_place(**dest));
         self.go_to_block(ret);
         Ok(true)
     }
 
     pub fn exact_div(
         &mut self,
-        a: ImmTy<'tcx, M::PointerTag>,
-        b: ImmTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        a: &ImmTy<'tcx, M::PointerTag>,
+        b: &ImmTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         // Performs an exact division, resulting in undefined behavior where
         // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`.
         // First, check x % y != 0 (or if that computation overflows).
-        let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, a, b)?;
+        let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?;
         if overflow || res.assert_bits(a.layout.size) != 0 {
             // Then, check if `b` is -1, which is the "MIN / -1" case.
             let minus1 = Scalar::from_int(-1, dest.layout.size);
@@ -518,7 +521,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
         }
         // `Rem` says this is all right, so we can let `Div` do its job.
-        self.binop_ignore_overflow(BinOp::Div, a, b, dest)
+        self.binop_ignore_overflow(BinOp::Div, &a, &b, dest)
     }
 
     /// Offsets a pointer by some multiple of its type, returning an error if the pointer leaves its
diff --git a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
index 5c917f00d15..4dfdc08b875 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
@@ -92,11 +92,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let location = self.allocate(loc_layout, MemoryKind::CallerLocation);
 
         // Initialize fields.
-        self.write_immediate(file.to_ref(), self.mplace_field(location, 0).unwrap().into())
+        self.write_immediate(file.to_ref(), &self.mplace_field(&location, 0).unwrap().into())
             .expect("writing to memory we just allocated cannot fail");
-        self.write_scalar(line, self.mplace_field(location, 1).unwrap().into())
+        self.write_scalar(line, &self.mplace_field(&location, 1).unwrap().into())
             .expect("writing to memory we just allocated cannot fail");
-        self.write_scalar(col, self.mplace_field(location, 2).unwrap().into())
+        self.write_scalar(col, &self.mplace_field(&location, 2).unwrap().into())
             .expect("writing to memory we just allocated cannot fail");
 
         location
diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs
index 53ac62d4351..65869f95639 100644
--- a/compiler/rustc_mir/src/interpret/machine.rs
+++ b/compiler/rustc_mir/src/interpret/machine.rs
@@ -157,7 +157,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         instance: ty::Instance<'tcx>,
         abi: Abi,
         args: &[OpTy<'tcx, Self::PointerTag>],
-        ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
+        ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;
 
@@ -168,7 +168,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         fn_val: Self::ExtraFnVal,
         abi: Abi,
         args: &[OpTy<'tcx, Self::PointerTag>],
-        ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
+        ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx>;
 
@@ -178,7 +178,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Self::PointerTag>],
-        ret: Option<(PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
+        ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx>;
 
@@ -200,14 +200,14 @@ pub trait Machine<'mir, 'tcx>: Sized {
     fn binary_ptr_op(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         bin_op: mir::BinOp,
-        left: ImmTy<'tcx, Self::PointerTag>,
-        right: ImmTy<'tcx, Self::PointerTag>,
+        left: &ImmTy<'tcx, Self::PointerTag>,
+        right: &ImmTy<'tcx, Self::PointerTag>,
     ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>;
 
     /// Heap allocations via the `box` keyword.
     fn box_alloc(
         ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        dest: PlaceTy<'tcx, Self::PointerTag>,
+        dest: &PlaceTy<'tcx, Self::PointerTag>,
     ) -> InterpResult<'tcx>;
 
     /// Called to read the specified `local` from the `frame`.
@@ -327,7 +327,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     fn retag(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _kind: mir::RetagKind,
-        _place: PlaceTy<'tcx, Self::PointerTag>,
+        _place: &PlaceTy<'tcx, Self::PointerTag>,
     ) -> InterpResult<'tcx> {
         Ok(())
     }
@@ -420,7 +420,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
         fn_val: !,
         _abi: Abi,
         _args: &[OpTy<$tcx>],
-        _ret: Option<(PlaceTy<$tcx>, mir::BasicBlock)>,
+        _ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>,
         _unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<$tcx> {
         match fn_val {}
diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs
index 88236458a21..46ecd33cc5b 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_mir/src/interpret/operand.rs
@@ -32,6 +32,9 @@ pub enum Immediate<Tag = ()> {
     ScalarPair(ScalarMaybeUninit<Tag>, ScalarMaybeUninit<Tag>),
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(Immediate, 56);
+
 impl<Tag> From<ScalarMaybeUninit<Tag>> for Immediate<Tag> {
     #[inline(always)]
     fn from(val: ScalarMaybeUninit<Tag>) -> Self {
@@ -92,6 +95,9 @@ pub struct ImmTy<'tcx, Tag = ()> {
     pub layout: TyAndLayout<'tcx>,
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(ImmTy<'_>, 72);
+
 impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         /// Helper function for printing a scalar to a FmtPrinter
@@ -106,7 +112,7 @@ impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> {
                 }
                 ScalarMaybeUninit::Uninit => cx.typed_value(
                     |mut this| {
-                        this.write_str("{uninit ")?;
+                        this.write_str("uninit ")?;
                         Ok(this)
                     },
                     |this| this.print_type(ty),
@@ -156,6 +162,9 @@ pub struct OpTy<'tcx, Tag = ()> {
     pub layout: TyAndLayout<'tcx>,
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(OpTy<'_, ()>, 80);
+
 impl<'tcx, Tag> std::ops::Deref for OpTy<'tcx, Tag> {
     type Target = Operand<Tag>;
     #[inline(always)]
@@ -171,6 +180,13 @@ impl<'tcx, Tag: Copy> From<MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
     }
 }
 
+impl<'tcx, Tag: Copy> From<&'_ MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
+    #[inline(always)]
+    fn from(mplace: &MPlaceTy<'tcx, Tag>) -> Self {
+        OpTy { op: Operand::Indirect(**mplace), layout: mplace.layout }
+    }
+}
+
 impl<'tcx, Tag> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
     #[inline(always)]
     fn from(val: ImmTy<'tcx, Tag>) -> Self {
@@ -222,7 +238,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline]
     pub fn force_op_ptr(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         match op.try_as_mplace(self) {
             Ok(mplace) => Ok(self.force_mplace_ptr(mplace)?.into()),
@@ -234,7 +250,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Returns `None` if the layout does not permit loading this as a value.
     fn try_read_immediate_from_mplace(
         &self,
-        mplace: MPlaceTy<'tcx, M::PointerTag>,
+        mplace: &MPlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, Option<ImmTy<'tcx, M::PointerTag>>> {
         if mplace.layout.is_unsized() {
             // Don't touch unsized
@@ -295,14 +311,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// in a `Immediate`, not on which data is stored there currently.
     pub(crate) fn try_read_immediate(
         &self,
-        src: OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::PointerTag>, MPlaceTy<'tcx, M::PointerTag>>> {
         Ok(match src.try_as_mplace(self) {
-            Ok(mplace) => {
+            Ok(ref mplace) => {
                 if let Some(val) = self.try_read_immediate_from_mplace(mplace)? {
                     Ok(val)
                 } else {
-                    Err(mplace)
+                    Err(*mplace)
                 }
             }
             Err(val) => Ok(val),
@@ -313,7 +329,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline(always)]
     pub fn read_immediate(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
         if let Ok(imm) = self.try_read_immediate(op)? {
             Ok(imm)
@@ -325,13 +341,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Read a scalar from a place
     pub fn read_scalar(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, ScalarMaybeUninit<M::PointerTag>> {
         Ok(self.read_immediate(op)?.to_scalar_or_uninit())
     }
 
     // Turn the wide MPlace into a string (must already be dereferenced!)
-    pub fn read_str(&self, mplace: MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> {
+    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)))?;
@@ -341,11 +357,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Projection functions
     pub fn operand_field(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         field: usize,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         let base = match op.try_as_mplace(self) {
-            Ok(mplace) => {
+            Ok(ref mplace) => {
                 // We can reuse the mplace field computation logic for indirect operands.
                 let field = self.mplace_field(mplace, field)?;
                 return Ok(field.into());
@@ -379,7 +395,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     pub fn operand_index(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         index: u64,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         if let Ok(index) = usize::try_from(index) {
@@ -388,28 +404,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         } else {
             // Indexing into a big array. This must be an mplace.
             let mplace = op.assert_mem_place(self);
-            Ok(self.mplace_index(mplace, index)?.into())
+            Ok(self.mplace_index(&mplace, index)?.into())
         }
     }
 
     pub fn operand_downcast(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         // Downcasts only change the layout
         Ok(match op.try_as_mplace(self) {
-            Ok(mplace) => self.mplace_downcast(mplace, variant)?.into(),
+            Ok(ref mplace) => self.mplace_downcast(mplace, variant)?.into(),
             Err(..) => {
                 let layout = op.layout.for_variant(self, variant);
-                OpTy { layout, ..op }
+                OpTy { layout, ..*op }
             }
         })
     }
 
     pub fn operand_projection(
         &self,
-        base: OpTy<'tcx, M::PointerTag>,
+        base: &OpTy<'tcx, M::PointerTag>,
         proj_elem: mir::PlaceElem<'tcx>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         use rustc_middle::mir::ProjectionElem::*;
@@ -421,7 +437,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // The rest should only occur as mplace, we do not use Immediates for types
                 // allowing such operations.  This matches place_projection forcing an allocation.
                 let mplace = base.assert_mem_place(self);
-                self.mplace_projection(mplace, proj_elem)?.into()
+                self.mplace_projection(&mplace, proj_elem)?.into()
             }
         })
     }
@@ -453,9 +469,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline(always)]
     pub fn place_to_op(
         &self,
-        place: PlaceTy<'tcx, M::PointerTag>,
+        place: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        let op = match *place {
+        let op = match **place {
             Place::Ptr(mplace) => Operand::Indirect(mplace),
             Place::Local { frame, local } => {
                 *self.access_local(&self.stack()[frame], local, None)?
@@ -480,7 +496,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let op = place
             .projection
             .iter()
-            .try_fold(base_op, |op, elem| self.operand_projection(op, elem))?;
+            .try_fold(base_op, |op, elem| self.operand_projection(&op, elem))?;
 
         trace!("eval_place_to_op: got {:?}", *op);
         // Sanity-check the type we ended up with.
@@ -590,7 +606,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Read discriminant, return the runtime value as well as the variant index.
     pub fn read_discriminant(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, VariantIdx)> {
         trace!("read_discriminant_value {:#?}", op.layout);
         // Get type and layout of the discriminant.
@@ -636,7 +652,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let tag_layout = self.layout_of(tag_scalar_layout.value.to_int_ty(*self.tcx))?;
 
         // Read tag and sanity-check `tag_layout`.
-        let tag_val = self.read_immediate(self.operand_field(op, tag_field)?)?;
+        let tag_val = self.read_immediate(&self.operand_field(op, tag_field)?)?;
         assert_eq!(tag_layout.size, tag_val.layout.size);
         assert_eq!(tag_layout.abi.is_signed(), tag_val.layout.abi.is_signed());
         let tag_val = tag_val.to_scalar()?;
@@ -690,7 +706,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
                         let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
                         let variant_index_relative_val =
-                            self.binary_op(mir::BinOp::Sub, tag_val, niche_start_val)?;
+                            self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
                         let variant_index_relative = variant_index_relative_val
                             .to_scalar()?
                             .assert_bits(tag_val.layout.size);
diff --git a/compiler/rustc_mir/src/interpret/operator.rs b/compiler/rustc_mir/src/interpret/operator.rs
index f5081655015..3737f8781c7 100644
--- a/compiler/rustc_mir/src/interpret/operator.rs
+++ b/compiler/rustc_mir/src/interpret/operator.rs
@@ -14,11 +14,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn binop_with_overflow(
         &mut self,
         op: mir::BinOp,
-        left: ImmTy<'tcx, M::PointerTag>,
-        right: ImmTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        left: &ImmTy<'tcx, M::PointerTag>,
+        right: &ImmTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
-        let (val, overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
+        let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?;
         debug_assert_eq!(
             self.tcx.intern_tup(&[ty, self.tcx.types.bool]),
             dest.layout.ty,
@@ -34,9 +34,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn binop_ignore_overflow(
         &mut self,
         op: mir::BinOp,
-        left: ImmTy<'tcx, M::PointerTag>,
-        right: ImmTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        left: &ImmTy<'tcx, M::PointerTag>,
+        right: &ImmTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
         assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op);
@@ -269,8 +269,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn overflowing_binary_op(
         &self,
         bin_op: mir::BinOp,
-        left: ImmTy<'tcx, M::PointerTag>,
-        right: ImmTy<'tcx, M::PointerTag>,
+        left: &ImmTy<'tcx, M::PointerTag>,
+        right: &ImmTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
         trace!(
             "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
@@ -347,8 +347,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn binary_op(
         &self,
         bin_op: mir::BinOp,
-        left: ImmTy<'tcx, M::PointerTag>,
-        right: ImmTy<'tcx, M::PointerTag>,
+        left: &ImmTy<'tcx, M::PointerTag>,
+        right: &ImmTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
         let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?;
         Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
@@ -359,7 +359,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn overflowing_unary_op(
         &self,
         un_op: mir::UnOp,
-        val: ImmTy<'tcx, M::PointerTag>,
+        val: &ImmTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
         use rustc_middle::mir::UnOp::*;
 
@@ -409,7 +409,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     pub fn unary_op(
         &self,
         un_op: mir::UnOp,
-        val: ImmTy<'tcx, M::PointerTag>,
+        val: &ImmTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
         let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?;
         Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs
index efde7fe6948..392f739e84f 100644
--- a/compiler/rustc_mir/src/interpret/place.rs
+++ b/compiler/rustc_mir/src/interpret/place.rs
@@ -33,6 +33,9 @@ pub enum MemPlaceMeta<Tag = ()> {
     Poison,
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(MemPlaceMeta, 24);
+
 impl<Tag> MemPlaceMeta<Tag> {
     pub fn unwrap_meta(self) -> Scalar<Tag> {
         match self {
@@ -71,6 +74,9 @@ pub struct MemPlace<Tag = ()> {
     pub meta: MemPlaceMeta<Tag>,
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(MemPlace, 56);
+
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)]
 pub enum Place<Tag = ()> {
     /// A place referring to a value allocated in the `Memory` system.
@@ -81,12 +87,18 @@ pub enum Place<Tag = ()> {
     Local { frame: usize, local: mir::Local },
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(Place, 64);
+
 #[derive(Copy, Clone, Debug)]
 pub struct PlaceTy<'tcx, Tag = ()> {
     place: Place<Tag>, // Keep this private; it helps enforce invariants.
     pub layout: TyAndLayout<'tcx>,
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(PlaceTy<'_>, 80);
+
 impl<'tcx, Tag> std::ops::Deref for PlaceTy<'tcx, Tag> {
     type Target = Place<Tag>;
     #[inline(always)]
@@ -102,6 +114,9 @@ pub struct MPlaceTy<'tcx, Tag = ()> {
     pub layout: TyAndLayout<'tcx>,
 }
 
+#[cfg(target_arch = "x86_64")]
+rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 72);
+
 impl<'tcx, Tag> std::ops::Deref for MPlaceTy<'tcx, Tag> {
     type Target = MemPlace<Tag>;
     #[inline(always)]
@@ -168,7 +183,7 @@ impl<Tag> MemPlace<Tag> {
     }
 }
 
-impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
+impl<'tcx, Tag: Copy> MPlaceTy<'tcx, Tag> {
     /// Produces a MemPlace that works for ZST but nothing else
     #[inline]
     pub fn dangling(layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
@@ -180,13 +195,13 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
 
     /// Replace ptr tag, maintain vtable tag (if any)
     #[inline]
-    pub fn replace_tag(self, new_tag: Tag) -> Self {
+    pub fn replace_tag(&self, new_tag: Tag) -> Self {
         MPlaceTy { mplace: self.mplace.replace_tag(new_tag), layout: self.layout }
     }
 
     #[inline]
     pub fn offset(
-        self,
+        &self,
         offset: Size,
         meta: MemPlaceMeta<Tag>,
         layout: TyAndLayout<'tcx>,
@@ -201,7 +216,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
     }
 
     #[inline]
-    pub(super) fn len(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
+    pub(super) fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
         if self.layout.is_unsized() {
             // We need to consult `meta` metadata
             match self.layout.ty.kind() {
@@ -219,7 +234,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
     }
 
     #[inline]
-    pub(super) fn vtable(self) -> Scalar<Tag> {
+    pub(super) fn vtable(&self) -> Scalar<Tag> {
         match self.layout.ty.kind() {
             ty::Dynamic(..) => self.mplace.meta.unwrap_meta(),
             _ => bug!("vtable not supported on type {:?}", self.layout.ty),
@@ -233,10 +248,10 @@ impl<'tcx, Tag: Debug + Copy> OpTy<'tcx, Tag> {
     /// 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.
     pub fn try_as_mplace(
-        self,
+        &self,
         cx: &impl HasDataLayout,
     ) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
-        match *self {
+        match **self {
             Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
             Operand::Immediate(_) if self.layout.is_zst() => {
                 Ok(MPlaceTy::dangling(self.layout, cx))
@@ -248,7 +263,7 @@ 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.
-    pub fn assert_mem_place(self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> {
+    pub fn assert_mem_place(&self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> {
         self.try_as_mplace(cx).unwrap()
     }
 }
@@ -288,12 +303,12 @@ where
     /// Generally prefer `deref_operand`.
     pub fn ref_to_mplace(
         &self,
-        val: ImmTy<'tcx, M::PointerTag>,
+        val: &ImmTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let pointee_type =
             val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty;
         let layout = self.layout_of(pointee_type)?;
-        let (ptr, meta) = match *val {
+        let (ptr, meta) = match **val {
             Immediate::Scalar(ptr) => (ptr.check_init()?, MemPlaceMeta::None),
             Immediate::ScalarPair(ptr, meta) => {
                 (ptr.check_init()?, MemPlaceMeta::Meta(meta.check_init()?))
@@ -316,11 +331,11 @@ where
     /// will always be a MemPlace.  Lives in `place.rs` because it creates a place.
     pub fn deref_operand(
         &self,
-        src: OpTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let val = self.read_immediate(src)?;
         trace!("deref to {} on {:?}", val.layout.ty, *val);
-        let place = self.ref_to_mplace(val)?;
+        let place = self.ref_to_mplace(&val)?;
         self.mplace_access_checked(place, None)
     }
 
@@ -333,7 +348,7 @@ where
     #[inline]
     pub(super) fn check_mplace_access(
         &self,
-        place: MPlaceTy<'tcx, M::PointerTag>,
+        place: &MPlaceTy<'tcx, M::PointerTag>,
         size: Option<Size>,
     ) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
         let size = size.unwrap_or_else(|| {
@@ -355,13 +370,13 @@ where
         force_align: Option<Align>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let (size, align) = self
-            .size_and_align_of_mplace(place)?
+            .size_and_align_of_mplace(&place)?
             .unwrap_or((place.layout.size, place.layout.align.abi));
         assert!(place.mplace.align <= align, "dynamic alignment less strict than static one?");
         // Check (stricter) dynamic alignment, unless forced otherwise.
         place.mplace.align = force_align.unwrap_or(align);
         // When dereferencing a pointer, it must be non-NULL, aligned, and live.
-        if let Some(ptr) = self.check_mplace_access(place, Some(size))? {
+        if let Some(ptr) = self.check_mplace_access(&place, Some(size))? {
             place.mplace.ptr = ptr.into();
         }
         Ok(place)
@@ -386,7 +401,7 @@ where
     #[inline(always)]
     pub fn mplace_field(
         &self,
-        base: MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::PointerTag>,
         field: usize,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let offset = base.layout.fields.offset(field);
@@ -397,7 +412,7 @@ where
             // Re-use parent metadata to determine dynamic field layout.
             // With custom DSTS, this *will* execute user-defined code, but the same
             // happens at run-time so that's okay.
-            let align = match self.size_and_align_of(base.meta, field_layout)? {
+            let align = match self.size_and_align_of(&base.meta, &field_layout)? {
                 Some((_, align)) => align,
                 None if offset == Size::ZERO => {
                     // An extern type at offset 0, we fall back to its static alignment.
@@ -427,7 +442,7 @@ where
     #[inline(always)]
     pub fn mplace_index(
         &self,
-        base: MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::PointerTag>,
         index: u64,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         // Not using the layout method because we want to compute on u64
@@ -457,8 +472,8 @@ where
     // same by repeatedly calling `mplace_array`.
     pub(super) fn mplace_array_fields(
         &self,
-        base: MPlaceTy<'tcx, Tag>,
-    ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'tcx>
+        base: &'a MPlaceTy<'tcx, Tag>,
+    ) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
     {
         let len = base.len(self)?; // also asserts that we have a type where this makes sense
         let stride = match base.layout.fields {
@@ -473,7 +488,7 @@ where
 
     fn mplace_subslice(
         &self,
-        base: MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::PointerTag>,
         from: u64,
         to: u64,
         from_end: bool,
@@ -518,30 +533,30 @@ where
 
     pub(super) fn mplace_downcast(
         &self,
-        base: MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::PointerTag>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         // Downcasts only change the layout
         assert!(!base.meta.has_meta());
-        Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
+        Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..*base })
     }
 
     /// Project into an mplace
     pub(super) fn mplace_projection(
         &self,
-        base: MPlaceTy<'tcx, M::PointerTag>,
+        base: &MPlaceTy<'tcx, M::PointerTag>,
         proj_elem: mir::PlaceElem<'tcx>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         use rustc_middle::mir::ProjectionElem::*;
         Ok(match proj_elem {
             Field(field, _) => self.mplace_field(base, field.index())?,
             Downcast(_, variant) => self.mplace_downcast(base, variant)?,
-            Deref => self.deref_operand(base.into())?,
+            Deref => self.deref_operand(&base.into())?,
 
             Index(local) => {
                 let layout = self.layout_of(self.tcx.types.usize)?;
                 let n = self.access_local(self.frame(), local, Some(layout))?;
-                let n = self.read_scalar(n)?;
+                let n = self.read_scalar(&n)?;
                 let n = u64::try_from(
                     self.force_bits(n.check_init()?, self.tcx.data_layout.pointer_size)?,
                 )
@@ -577,37 +592,37 @@ where
     /// into the field of a local `ScalarPair`, we have to first allocate it.
     pub fn place_field(
         &mut self,
-        base: PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::PointerTag>,
         field: usize,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         // FIXME: We could try to be smarter and avoid allocation for fields that span the
         // entire place.
         let mplace = self.force_allocation(base)?;
-        Ok(self.mplace_field(mplace, field)?.into())
+        Ok(self.mplace_field(&mplace, field)?.into())
     }
 
     pub fn place_index(
         &mut self,
-        base: PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::PointerTag>,
         index: u64,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         let mplace = self.force_allocation(base)?;
-        Ok(self.mplace_index(mplace, index)?.into())
+        Ok(self.mplace_index(&mplace, index)?.into())
     }
 
     pub fn place_downcast(
         &self,
-        base: PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::PointerTag>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         // Downcast just changes the layout
         Ok(match base.place {
             Place::Ptr(mplace) => {
-                self.mplace_downcast(MPlaceTy { mplace, layout: base.layout }, variant)?.into()
+                self.mplace_downcast(&MPlaceTy { mplace, layout: base.layout }, variant)?.into()
             }
             Place::Local { .. } => {
                 let layout = base.layout.for_variant(self, variant);
-                PlaceTy { layout, ..base }
+                PlaceTy { layout, ..*base }
             }
         })
     }
@@ -615,19 +630,19 @@ where
     /// Projects into a place.
     pub fn place_projection(
         &mut self,
-        base: PlaceTy<'tcx, M::PointerTag>,
+        base: &PlaceTy<'tcx, M::PointerTag>,
         &proj_elem: &mir::ProjectionElem<mir::Local, Ty<'tcx>>,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         use rustc_middle::mir::ProjectionElem::*;
         Ok(match proj_elem {
             Field(field, _) => self.place_field(base, field.index())?,
             Downcast(_, variant) => self.place_downcast(base, variant)?,
-            Deref => self.deref_operand(self.place_to_op(base)?)?.into(),
+            Deref => self.deref_operand(&self.place_to_op(base)?)?.into(),
             // For the other variants, we have to force an allocation.
             // This matches `operand_projection`.
             Subslice { .. } | ConstantIndex { .. } | Index(_) => {
                 let mplace = self.force_allocation(base)?;
-                self.mplace_projection(mplace, proj_elem)?.into()
+                self.mplace_projection(&mplace, proj_elem)?.into()
             }
         })
     }
@@ -645,7 +660,7 @@ where
         };
 
         for elem in place.projection.iter() {
-            place_ty = self.place_projection(place_ty, &elem)?
+            place_ty = self.place_projection(&place_ty, &elem)?
         }
 
         trace!("{:?}", self.dump_place(place_ty.place));
@@ -666,7 +681,7 @@ where
     pub fn write_scalar(
         &mut self,
         val: impl Into<ScalarMaybeUninit<M::PointerTag>>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         self.write_immediate(Immediate::Scalar(val.into()), dest)
     }
@@ -676,13 +691,13 @@ where
     pub fn write_immediate(
         &mut self,
         src: Immediate<M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         self.write_immediate_no_validate(src, dest)?;
 
         if M::enforce_validity(self) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(self.place_to_op(dest)?)?;
+            self.validate_operand(&self.place_to_op(dest)?)?;
         }
 
         Ok(())
@@ -693,13 +708,13 @@ where
     pub fn write_immediate_to_mplace(
         &mut self,
         src: Immediate<M::PointerTag>,
-        dest: MPlaceTy<'tcx, M::PointerTag>,
+        dest: &MPlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         self.write_immediate_to_mplace_no_validate(src, dest)?;
 
         if M::enforce_validity(self) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(dest.into())?;
+            self.validate_operand(&dest.into())?;
         }
 
         Ok(())
@@ -711,7 +726,7 @@ where
     fn write_immediate_no_validate(
         &mut self,
         src: Immediate<M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         if cfg!(debug_assertions) {
             // This is a very common path, avoid some checks in release mode
@@ -754,7 +769,7 @@ where
         let dest = MPlaceTy { mplace, layout: dest.layout };
 
         // This is already in memory, write there.
-        self.write_immediate_to_mplace_no_validate(src, dest)
+        self.write_immediate_to_mplace_no_validate(src, &dest)
     }
 
     /// Write an immediate to memory.
@@ -763,7 +778,7 @@ where
     fn write_immediate_to_mplace_no_validate(
         &mut self,
         value: Immediate<M::PointerTag>,
-        dest: MPlaceTy<'tcx, M::PointerTag>,
+        dest: &MPlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         // Note that it is really important that the type here is the right one, and matches the
         // type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here
@@ -828,14 +843,14 @@ where
     #[inline(always)]
     pub fn copy_op(
         &mut self,
-        src: OpTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         self.copy_op_no_validate(src, dest)?;
 
         if M::enforce_validity(self) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(self.place_to_op(dest)?)?;
+            self.validate_operand(&self.place_to_op(dest)?)?;
         }
 
         Ok(())
@@ -847,8 +862,8 @@ where
     /// right type.
     fn copy_op_no_validate(
         &mut self,
-        src: OpTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         // We do NOT compare the types for equality, because well-typed code can
         // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
@@ -888,10 +903,10 @@ where
         assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances");
 
         let src = self
-            .check_mplace_access(src, Some(size))
+            .check_mplace_access(&src, Some(size))
             .expect("places should be checked on creation");
         let dest = self
-            .check_mplace_access(dest, Some(size))
+            .check_mplace_access(&dest, Some(size))
             .expect("places should be checked on creation");
         let (src_ptr, dest_ptr) = match (src, dest) {
             (Some(src_ptr), Some(dest_ptr)) => (src_ptr, dest_ptr),
@@ -906,8 +921,8 @@ where
     /// have the same size.
     pub fn copy_op_transmute(
         &mut self,
-        src: OpTy<'tcx, M::PointerTag>,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        src: &OpTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         if mir_assign_valid_types(*self.tcx, self.param_env, src.layout, dest.layout) {
             // Fast path: Just use normal `copy_op`
@@ -944,12 +959,12 @@ where
         let dest = self.force_allocation(dest)?;
         self.copy_op_no_validate(
             src,
-            PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }),
+            &PlaceTy::from(MPlaceTy { mplace: *dest, layout: src.layout }),
         )?;
 
         if M::enforce_validity(self) {
             // Data got changed, better make sure it matches the type!
-            self.validate_operand(dest.into())?;
+            self.validate_operand(&dest.into())?;
         }
 
         Ok(())
@@ -965,7 +980,7 @@ where
     /// version.
     pub fn force_allocation_maybe_sized(
         &mut self,
-        place: PlaceTy<'tcx, M::PointerTag>,
+        place: &PlaceTy<'tcx, M::PointerTag>,
         meta: MemPlaceMeta<M::PointerTag>,
     ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> {
         let (mplace, size) = match place.place {
@@ -981,7 +996,7 @@ where
                             self.layout_of_local(&self.stack()[frame], local, None)?;
                         // We also need to support unsized types, and hence cannot use `allocate`.
                         let (size, align) = self
-                            .size_and_align_of(meta, local_layout)?
+                            .size_and_align_of(&meta, &local_layout)?
                             .expect("Cannot allocate for non-dyn-sized type");
                         let ptr = self.memory.allocate(size, align, MemoryKind::Stack);
                         let mplace = MemPlace { ptr: ptr.into(), align, meta };
@@ -990,7 +1005,7 @@ where
                             // We don't have to validate as we can assume the local
                             // was already valid for its type.
                             let mplace = MPlaceTy { mplace, layout: local_layout };
-                            self.write_immediate_to_mplace_no_validate(value, mplace)?;
+                            self.write_immediate_to_mplace_no_validate(value, &mplace)?;
                         }
                         // Now we can call `access_mut` again, asserting it goes well,
                         // and actually overwrite things.
@@ -1010,7 +1025,7 @@ where
     #[inline(always)]
     pub fn force_allocation(
         &mut self,
-        place: PlaceTy<'tcx, M::PointerTag>,
+        place: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         Ok(self.force_allocation_maybe_sized(place, MemPlaceMeta::None)?.0)
     }
@@ -1046,7 +1061,7 @@ where
     pub fn write_discriminant(
         &mut self,
         variant_index: VariantIdx,
-        dest: PlaceTy<'tcx, M::PointerTag>,
+        dest: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         // Layout computation excludes uninhabited variants from consideration
         // therefore there's no way to represent those variants in the given layout.
@@ -1077,7 +1092,7 @@ where
                 let tag_val = size.truncate(discr_val);
 
                 let tag_dest = self.place_field(dest, tag_field)?;
-                self.write_scalar(Scalar::from_uint(tag_val, size), tag_dest)?;
+                self.write_scalar(Scalar::from_uint(tag_val, size), &tag_dest)?;
             }
             Variants::Multiple {
                 tag_encoding:
@@ -1103,12 +1118,12 @@ where
                         ImmTy::from_uint(variant_index_relative, tag_layout);
                     let tag_val = self.binary_op(
                         mir::BinOp::Add,
-                        variant_index_relative_val,
-                        niche_start_val,
+                        &variant_index_relative_val,
+                        &niche_start_val,
                     )?;
                     // Write result.
                     let niche_dest = self.place_field(dest, tag_field)?;
-                    self.write_immediate(*tag_val, niche_dest)?;
+                    self.write_immediate(*tag_val, &niche_dest)?;
                 }
             }
         }
@@ -1131,7 +1146,7 @@ where
     /// Also return some more information so drop doesn't have to run the same code twice.
     pub(super) fn unpack_dyn_trait(
         &self,
-        mplace: MPlaceTy<'tcx, M::PointerTag>,
+        mplace: &MPlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
         let vtable = mplace.vtable(); // also sanity checks the type
         let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
@@ -1145,7 +1160,7 @@ where
             assert_eq!(align, layout.align.abi);
         }
 
-        let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..*mplace }, layout };
+        let mplace = MPlaceTy { mplace: MemPlace { meta: MemPlaceMeta::None, ..**mplace }, layout };
         Ok((instance, mplace))
     }
 }
diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs
index fbc72ad8adc..64d7c8ef2c7 100644
--- a/compiler/rustc_mir/src/interpret/step.rs
+++ b/compiler/rustc_mir/src/interpret/step.rs
@@ -90,7 +90,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
             SetDiscriminant { place, variant_index } => {
                 let dest = self.eval_place(**place)?;
-                self.write_discriminant(*variant_index, dest)?;
+                self.write_discriminant(*variant_index, &dest)?;
             }
 
             // Mark locals as alive
@@ -110,7 +110,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             // Stacked Borrows.
             Retag(kind, place) => {
                 let dest = self.eval_place(**place)?;
-                M::retag(self, *kind, dest)?;
+                M::retag(self, *kind, &dest)?;
             }
 
             // Statements we do not track.
@@ -156,45 +156,45 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             ThreadLocalRef(did) => {
                 let id = M::thread_local_static_alloc_id(self, did)?;
                 let val = self.global_base_pointer(id.into())?;
-                self.write_scalar(val, dest)?;
+                self.write_scalar(val, &dest)?;
             }
 
             Use(ref operand) => {
                 // Avoid recomputing the layout
                 let op = self.eval_operand(operand, Some(dest.layout))?;
-                self.copy_op(op, dest)?;
+                self.copy_op(&op, &dest)?;
             }
 
             BinaryOp(bin_op, ref left, ref right) => {
                 let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
-                let left = self.read_immediate(self.eval_operand(left, layout)?)?;
+                let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
                 let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
-                let right = self.read_immediate(self.eval_operand(right, layout)?)?;
-                self.binop_ignore_overflow(bin_op, left, right, dest)?;
+                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
+                self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
             }
 
             CheckedBinaryOp(bin_op, ref left, ref right) => {
                 // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
-                let left = self.read_immediate(self.eval_operand(left, None)?)?;
+                let left = self.read_immediate(&self.eval_operand(left, None)?)?;
                 let layout = binop_right_homogeneous(bin_op).then_some(left.layout);
-                let right = self.read_immediate(self.eval_operand(right, layout)?)?;
-                self.binop_with_overflow(bin_op, left, right, dest)?;
+                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
+                self.binop_with_overflow(bin_op, &left, &right, &dest)?;
             }
 
             UnaryOp(un_op, ref operand) => {
                 // The operand always has the same type as the result.
-                let val = self.read_immediate(self.eval_operand(operand, Some(dest.layout))?)?;
-                let val = self.unary_op(un_op, val)?;
+                let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?;
+                let val = self.unary_op(un_op, &val)?;
                 assert_eq!(val.layout, dest.layout, "layout mismatch for result of {:?}", un_op);
-                self.write_immediate(*val, dest)?;
+                self.write_immediate(*val, &dest)?;
             }
 
             Aggregate(ref kind, ref operands) => {
                 let (dest, active_field_index) = match **kind {
                     mir::AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
-                        self.write_discriminant(variant_index, dest)?;
+                        self.write_discriminant(variant_index, &dest)?;
                         if adt_def.is_enum() {
-                            (self.place_downcast(dest, variant_index)?, active_field_index)
+                            (self.place_downcast(&dest, variant_index)?, active_field_index)
                         } else {
                             (dest, active_field_index)
                         }
@@ -207,21 +207,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     // Ignore zero-sized fields.
                     if !op.layout.is_zst() {
                         let field_index = active_field_index.unwrap_or(i);
-                        let field_dest = self.place_field(dest, field_index)?;
-                        self.copy_op(op, field_dest)?;
+                        let field_dest = self.place_field(&dest, field_index)?;
+                        self.copy_op(&op, &field_dest)?;
                     }
                 }
             }
 
             Repeat(ref operand, _) => {
                 let op = self.eval_operand(operand, None)?;
-                let dest = self.force_allocation(dest)?;
+                let dest = self.force_allocation(&dest)?;
                 let length = dest.len(self)?;
 
-                if let Some(first_ptr) = self.check_mplace_access(dest, None)? {
+                if let Some(first_ptr) = self.check_mplace_access(&dest, None)? {
                     // Write the first.
-                    let first = self.mplace_field(dest, 0)?;
-                    self.copy_op(op, first.into())?;
+                    let first = self.mplace_field(&dest, 0)?;
+                    self.copy_op(&op, &first.into())?;
 
                     if length > 1 {
                         let elem_size = first.layout.size;
@@ -242,23 +242,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Len(place) => {
                 // FIXME(CTFE): don't allow computing the length of arrays in const eval
                 let src = self.eval_place(place)?;
-                let mplace = self.force_allocation(src)?;
+                let mplace = self.force_allocation(&src)?;
                 let len = mplace.len(self)?;
-                self.write_scalar(Scalar::from_machine_usize(len, self), dest)?;
+                self.write_scalar(Scalar::from_machine_usize(len, self), &dest)?;
             }
 
             AddressOf(_, place) | Ref(_, _, place) => {
                 let src = self.eval_place(place)?;
-                let place = self.force_allocation(src)?;
+                let place = self.force_allocation(&src)?;
                 if place.layout.size.bytes() > 0 {
                     // definitely not a ZST
                     assert!(place.ptr.is_ptr(), "non-ZST places should be normalized to `Pointer`");
                 }
-                self.write_immediate(place.to_ref(), dest)?;
+                self.write_immediate(place.to_ref(), &dest)?;
             }
 
             NullaryOp(mir::NullOp::Box, _) => {
-                M::box_alloc(self, dest)?;
+                M::box_alloc(self, &dest)?;
             }
 
             NullaryOp(mir::NullOp::SizeOf, ty) => {
@@ -272,19 +272,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     );
                     throw_inval!(SizeOfUnsizedType(ty));
                 }
-                self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), dest)?;
+                self.write_scalar(Scalar::from_machine_usize(layout.size.bytes(), self), &dest)?;
             }
 
             Cast(cast_kind, ref operand, cast_ty) => {
                 let src = self.eval_operand(operand, None)?;
                 let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty);
-                self.cast(src, cast_kind, cast_ty, dest)?;
+                self.cast(&src, cast_kind, cast_ty, &dest)?;
             }
 
             Discriminant(place) => {
                 let op = self.eval_place_to_op(place, None)?;
-                let discr_val = self.read_discriminant(op)?.0;
-                self.write_scalar(discr_val, dest)?;
+                let discr_val = self.read_discriminant(&op)?.0;
+                self.write_scalar(discr_val, &dest)?;
             }
         }
 
diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs
index 575667f9a95..0807949a2d9 100644
--- a/compiler/rustc_mir/src/interpret/terminator.rs
+++ b/compiler/rustc_mir/src/interpret/terminator.rs
@@ -25,7 +25,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Goto { target } => self.go_to_block(target),
 
             SwitchInt { ref discr, ref targets, switch_ty } => {
-                let discr = self.read_immediate(self.eval_operand(discr, None)?)?;
+                let discr = self.read_immediate(&self.eval_operand(discr, None)?)?;
                 trace!("SwitchInt({:?})", *discr);
                 assert_eq!(discr.layout.ty, switch_ty);
 
@@ -38,8 +38,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     let res = self
                         .overflowing_binary_op(
                             mir::BinOp::Eq,
-                            discr,
-                            ImmTy::from_uint(const_int, discr.layout),
+                            &discr,
+                            &ImmTy::from_uint(const_int, discr.layout),
                         )?
                         .0;
                     if res.to_bool()? {
@@ -58,7 +58,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let (fn_val, abi) = match *func.layout.ty.kind() {
                     ty::FnPtr(sig) => {
                         let caller_abi = sig.abi();
-                        let fn_ptr = self.read_scalar(func)?.check_init()?;
+                        let fn_ptr = self.read_scalar(&func)?.check_init()?;
                         let fn_val = self.memory.get_fn(fn_ptr)?;
                         (fn_val, caller_abi)
                     }
@@ -78,8 +78,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     ),
                 };
                 let args = self.eval_operands(args)?;
+                let dest_place;
                 let ret = match destination {
-                    Some((dest, ret)) => Some((self.eval_place(dest)?, ret)),
+                    Some((dest, ret)) => {
+                        dest_place = self.eval_place(dest)?;
+                        Some((&dest_place, ret))
+                    }
                     None => None,
                 };
                 self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?;
@@ -96,12 +100,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 trace!("TerminatorKind::drop: {:?}, type {}", place, ty);
 
                 let instance = Instance::resolve_drop_in_place(*self.tcx, ty);
-                self.drop_in_place(place, instance, target, unwind)?;
+                self.drop_in_place(&place, instance, target, unwind)?;
             }
 
             Assert { ref cond, expected, ref msg, target, cleanup } => {
                 let cond_val =
-                    self.read_immediate(self.eval_operand(cond, None)?)?.to_scalar()?.to_bool()?;
+                    self.read_immediate(&self.eval_operand(cond, None)?)?.to_scalar()?.to_bool()?;
                 if expected == cond_val {
                     self.go_to_block(target);
                 } else {
@@ -180,7 +184,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         &mut self,
         rust_abi: bool,
         caller_arg: &mut impl Iterator<Item = OpTy<'tcx, M::PointerTag>>,
-        callee_arg: PlaceTy<'tcx, M::PointerTag>,
+        callee_arg: &PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         if rust_abi && callee_arg.layout.is_zst() {
             // Nothing to do.
@@ -202,7 +206,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             )
         }
         // We allow some transmutes here
-        self.copy_op_transmute(caller_arg, callee_arg)
+        self.copy_op_transmute(&caller_arg, callee_arg)
     }
 
     /// Call this function -- pushing the stack frame and initializing the arguments.
@@ -211,7 +215,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         fn_val: FnVal<'tcx, M::ExtraFnVal>,
         caller_abi: Abi,
         args: &[OpTy<'tcx, M::PointerTag>],
-        ret: Option<(PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
+        ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
         unwind: Option<mir::BasicBlock>,
     ) -> InterpResult<'tcx> {
         trace!("eval_fn_call: {:#?}", fn_val);
@@ -314,7 +318,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     let caller_args: Cow<'_, [OpTy<'tcx, M::PointerTag>]> =
                         if caller_abi == Abi::RustCall && !args.is_empty() {
                             // Untuple
-                            let (&untuple_arg, args) = args.split_last().unwrap();
+                            let (untuple_arg, args) = args.split_last().unwrap();
                             trace!("eval_fn_call: Will pass last argument by untupling");
                             Cow::from(
                                 args.iter()
@@ -344,12 +348,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         if Some(local) == body.spread_arg {
                             // Must be a tuple
                             for i in 0..dest.layout.fields.count() {
-                                let dest = self.place_field(dest, i)?;
-                                self.pass_argument(rust_abi, &mut caller_iter, dest)?;
+                                let dest = self.place_field(&dest, i)?;
+                                self.pass_argument(rust_abi, &mut caller_iter, &dest)?;
                             }
                         } else {
                             // Normal argument
-                            self.pass_argument(rust_abi, &mut caller_iter, dest)?;
+                            self.pass_argument(rust_abi, &mut caller_iter, &dest)?;
                         }
                     }
                     // Now we should have no more caller args
@@ -397,7 +401,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let receiver_place = match args[0].layout.ty.builtin_deref(true) {
                     Some(_) => {
                         // Built-in pointer.
-                        self.deref_operand(args[0])?
+                        self.deref_operand(&args[0])?
                     }
                     None => {
                         // Unsized self.
@@ -426,7 +430,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     fn drop_in_place(
         &mut self,
-        place: PlaceTy<'tcx, M::PointerTag>,
+        place: &PlaceTy<'tcx, M::PointerTag>,
         instance: ty::Instance<'tcx>,
         target: mir::BasicBlock,
         unwind: Option<mir::BasicBlock>,
@@ -440,7 +444,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let (instance, place) = match place.layout.ty.kind() {
             ty::Dynamic(..) => {
                 // Dropping a trait object.
-                self.unpack_dyn_trait(place)?
+                self.unpack_dyn_trait(&place)?
             }
             _ => (instance, place),
         };
@@ -457,7 +461,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             FnVal::Instance(instance),
             Abi::Rust,
             &[arg.into()],
-            Some((dest.into(), target)),
+            Some((&dest.into(), target)),
             unwind,
         )
     }
diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs
index 09ce6bc0fb7..50603bdd45b 100644
--- a/compiler/rustc_mir/src/interpret/traits.rs
+++ b/compiler/rustc_mir/src/interpret/traits.rs
@@ -118,7 +118,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             .get_raw(vtable_slot.alloc_id)?
             .read_ptr_sized(self, vtable_slot)?
             .check_init()?;
-        Ok(self.memory.get_fn(fn_ptr)?)
+        self.memory.get_fn(fn_ptr)
     }
 
     /// Returns the drop fn instance as well as the actual dynamic type.
diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs
index 0b7492631c4..2d2799f81e3 100644
--- a/compiler/rustc_mir/src/interpret/validity.rs
+++ b/compiler/rustc_mir/src/interpret/validity.rs
@@ -11,7 +11,7 @@ use std::ops::RangeInclusive;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_middle::mir::interpret::{InterpError, InterpErrorInfo};
+use rustc_middle::mir::interpret::InterpError;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_span::symbol::{sym, Symbol};
@@ -21,7 +21,7 @@ use std::hash::Hash;
 
 use super::{
     CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
-    ValueVisitor,
+    ScalarMaybeUninit, ValueVisitor,
 };
 
 macro_rules! throw_validation_failure {
@@ -83,14 +83,17 @@ macro_rules! try_validation {
             Ok(x) => x,
             // We catch the error and turn it into a validation failure. We are okay with
             // allocation here as this can only slow down builds that fail anyway.
-            $( $( Err(InterpErrorInfo { kind: $p, .. }) )|+ =>
-                throw_validation_failure!(
-                    $where,
-                    { $( $what_fmt ),+ } $( expected { $( $expected_fmt ),+ } )?
-                ),
-            )+
-            #[allow(unreachable_patterns)]
-            Err(e) => Err::<!, _>(e)?,
+            Err(e) => match e.kind() {
+                $(
+                    $($p)|+ =>
+                       throw_validation_failure!(
+                            $where,
+                            { $( $what_fmt ),+ } $( expected { $( $expected_fmt ),+ } )?
+                        )
+                ),+,
+                #[allow(unreachable_patterns)]
+                _ => Err::<!, _>(e)?,
+            }
         }
     }};
 }
@@ -375,14 +378,18 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
     /// Check a reference or `Box`.
     fn check_safe_pointer(
         &mut self,
-        value: OpTy<'tcx, M::PointerTag>,
+        value: &OpTy<'tcx, M::PointerTag>,
         kind: &str,
     ) -> InterpResult<'tcx> {
-        let value = self.ecx.read_immediate(value)?;
+        let value = try_validation!(
+            self.ecx.read_immediate(value),
+            self.path,
+            err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
+        );
         // Handle wide pointers.
         // Check metadata early, for better diagnostics
         let place = try_validation!(
-            self.ecx.ref_to_mplace(value),
+            self.ecx.ref_to_mplace(&value),
             self.path,
             err_ub!(InvalidUninitBytes(None)) => { "uninitialized {}", kind },
         );
@@ -391,7 +398,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
         }
         // Make sure this is dereferenceable and all.
         let size_and_align = try_validation!(
-            self.ecx.size_and_align_of_mplace(place),
+            self.ecx.size_and_align_of_mplace(&place),
             self.path,
             err_ub!(InvalidMeta(msg)) => { "invalid {} metadata: {}", kind, msg },
         );
@@ -485,17 +492,28 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
         Ok(())
     }
 
+    fn read_scalar(
+        &self,
+        op: &OpTy<'tcx, M::PointerTag>,
+    ) -> InterpResult<'tcx, ScalarMaybeUninit<M::PointerTag>> {
+        Ok(try_validation!(
+            self.ecx.read_scalar(op),
+            self.path,
+            err_unsup!(ReadPointerAsBytes) => { "(potentially part of) a pointer" } expected { "plain (non-pointer) bytes" },
+        ))
+    }
+
     /// Check if this is a value of primitive type, and if yes check the validity of the value
     /// at that type.  Return `true` if the type is indeed primitive.
     fn try_visit_primitive(
         &mut self,
-        value: OpTy<'tcx, M::PointerTag>,
+        value: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, bool> {
         // Go over all the primitive types
         let ty = value.layout.ty;
         match ty.kind() {
             ty::Bool => {
-                let value = self.ecx.read_scalar(value)?;
+                let value = self.read_scalar(value)?;
                 try_validation!(
                     value.to_bool(),
                     self.path,
@@ -505,7 +523,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 Ok(true)
             }
             ty::Char => {
-                let value = self.ecx.read_scalar(value)?;
+                let value = self.read_scalar(value)?;
                 try_validation!(
                     value.to_char(),
                     self.path,
@@ -515,11 +533,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 Ok(true)
             }
             ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
-                let value = try_validation!(
-                    self.ecx.read_scalar(value),
-                    self.path,
-                    err_unsup!(ReadPointerAsBytes) => { "read of part of a pointer" },
-                );
+                let value = self.read_scalar(value)?;
                 // NOTE: Keep this in sync with the array optimization for int/float
                 // types below!
                 if self.ctfe_mode.is_some() {
@@ -541,9 +555,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 // actually enforce the strict rules for raw pointers (mostly because
                 // that lets us re-use `ref_to_mplace`).
                 let place = try_validation!(
-                    self.ecx.ref_to_mplace(self.ecx.read_immediate(value)?),
+                    self.ecx.read_immediate(value).and_then(|ref i| self.ecx.ref_to_mplace(i)),
                     self.path,
                     err_ub!(InvalidUninitBytes(None)) => { "uninitialized raw pointer" },
+                    err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
                 );
                 if place.layout.is_unsized() {
                     self.check_wide_ptr_meta(place.meta, place.layout)?;
@@ -569,7 +584,14 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                 Ok(true)
             }
             ty::FnPtr(_sig) => {
-                let value = self.ecx.read_scalar(value)?;
+                let value = try_validation!(
+                    self.ecx.read_immediate(value),
+                    self.path,
+                    err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
+                );
+                // Make sure we print a `ScalarMaybeUninit` (and not an `ImmTy`) in the error
+                // message below.
+                let value = value.to_scalar_or_uninit();
                 let _fn = try_validation!(
                     value.check_init().and_then(|ptr| self.ecx.memory.get_fn(ptr)),
                     self.path,
@@ -612,10 +634,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
 
     fn visit_scalar(
         &mut self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         scalar_layout: &Scalar,
     ) -> InterpResult<'tcx> {
-        let value = self.ecx.read_scalar(op)?;
+        let value = self.read_scalar(op)?;
         let valid_range = &scalar_layout.valid_range;
         let (lo, hi) = valid_range.clone().into_inner();
         // Determine the allowed range
@@ -686,7 +708,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
 
     fn read_discriminant(
         &mut self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, VariantIdx> {
         self.with_elem(PathElem::EnumTag, move |this| {
             Ok(try_validation!(
@@ -706,9 +728,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     #[inline]
     fn visit_field(
         &mut self,
-        old_op: OpTy<'tcx, M::PointerTag>,
+        old_op: &OpTy<'tcx, M::PointerTag>,
         field: usize,
-        new_op: OpTy<'tcx, M::PointerTag>,
+        new_op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         let elem = self.aggregate_field_path_elem(old_op.layout, field);
         self.with_elem(elem, move |this| this.visit_value(new_op))
@@ -717,9 +739,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     #[inline]
     fn visit_variant(
         &mut self,
-        old_op: OpTy<'tcx, M::PointerTag>,
+        old_op: &OpTy<'tcx, M::PointerTag>,
         variant_id: VariantIdx,
-        new_op: OpTy<'tcx, M::PointerTag>,
+        new_op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         let name = match old_op.layout.ty.kind() {
             ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name),
@@ -733,14 +755,14 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
     #[inline(always)]
     fn visit_union(
         &mut self,
-        _op: OpTy<'tcx, M::PointerTag>,
+        _op: &OpTy<'tcx, M::PointerTag>,
         _fields: NonZeroUsize,
     ) -> InterpResult<'tcx> {
         Ok(())
     }
 
     #[inline]
-    fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
+    fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
         trace!("visit_value: {:?}, {:?}", *op, op.layout);
 
         // Check primitive types -- the leafs of our recursive descend.
@@ -797,7 +819,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
 
     fn visit_aggregate(
         &mut self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         fields: impl Iterator<Item = InterpResult<'tcx, Self::V>>,
     ) -> InterpResult<'tcx> {
         match op.layout.ty.kind() {
@@ -858,7 +880,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                     Err(err) => {
                         // For some errors we might be able to provide extra information.
                         // (This custom logic does not fit the `try_validation!` macro.)
-                        match err.kind {
+                        match err.kind() {
                             err_ub!(InvalidUninitBytes(Some(access))) => {
                                 // Some byte was uninitialized, determine which
                                 // element that byte belongs to so we can
@@ -899,7 +921,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     fn validate_operand_internal(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         path: Vec<PathElem>,
         ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>>,
         ctfe_mode: Option<CtfeValidationMode>,
@@ -910,16 +932,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let mut visitor = ValidityVisitor { path, ref_tracking, ctfe_mode, ecx: self };
 
         // Try to cast to ptr *once* instead of all the time.
-        let op = self.force_op_ptr(op).unwrap_or(op);
+        let op = self.force_op_ptr(&op).unwrap_or(*op);
 
         // Run it.
-        match visitor.visit_value(op) {
+        match visitor.visit_value(&op) {
             Ok(()) => Ok(()),
             // Pass through validation failures.
-            Err(err) if matches!(err.kind, err_ub!(ValidationFailure { .. })) => Err(err),
+            Err(err) if matches!(err.kind(), err_ub!(ValidationFailure { .. })) => Err(err),
             // Also pass through InvalidProgram, those just indicate that we could not
             // validate and each caller will know best what to do with them.
-            Err(err) if matches!(err.kind, InterpError::InvalidProgram(_)) => Err(err),
+            Err(err) if matches!(err.kind(), InterpError::InvalidProgram(_)) => Err(err),
             // Avoid other errors as those do not show *where* in the value the issue lies.
             Err(err) => {
                 err.print_backtrace();
@@ -941,7 +963,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     #[inline(always)]
     pub fn const_validate_operand(
         &self,
-        op: OpTy<'tcx, M::PointerTag>,
+        op: &OpTy<'tcx, M::PointerTag>,
         path: Vec<PathElem>,
         ref_tracking: &mut RefTracking<MPlaceTy<'tcx, M::PointerTag>, Vec<PathElem>>,
         ctfe_mode: CtfeValidationMode,
@@ -953,7 +975,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// `op` is assumed to cover valid memory if it is an indirect operand.
     /// It will error if the bits at the destination do not match the ones described by the layout.
     #[inline(always)]
-    pub fn validate_operand(&self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
+    pub fn validate_operand(&self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
         self.validate_operand_internal(op, vec![], None, None)
     }
 }
diff --git a/compiler/rustc_mir/src/interpret/visitor.rs b/compiler/rustc_mir/src/interpret/visitor.rs
index 097b9ae6ca1..32edca6f3df 100644
--- a/compiler/rustc_mir/src/interpret/visitor.rs
+++ b/compiler/rustc_mir/src/interpret/visitor.rs
@@ -18,21 +18,25 @@ pub trait Value<'mir, 'tcx, M: Machine<'mir, 'tcx>>: Copy {
     fn layout(&self) -> TyAndLayout<'tcx>;
 
     /// Makes this into an `OpTy`.
-    fn to_op(self, ecx: &InterpCx<'mir, 'tcx, M>) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>;
+    fn to_op(&self, ecx: &InterpCx<'mir, 'tcx, M>)
+    -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>>;
 
     /// Creates this from an `MPlaceTy`.
     fn from_mem_place(mplace: MPlaceTy<'tcx, M::PointerTag>) -> Self;
 
     /// Projects to the given enum variant.
     fn project_downcast(
-        self,
+        &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, Self>;
 
     /// Projects to the n-th field.
-    fn project_field(self, ecx: &InterpCx<'mir, 'tcx, M>, field: usize)
-    -> InterpResult<'tcx, Self>;
+    fn project_field(
+        &self,
+        ecx: &InterpCx<'mir, 'tcx, M>,
+        field: usize,
+    ) -> InterpResult<'tcx, Self>;
 }
 
 // Operands and memory-places are both values.
@@ -45,10 +49,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc
 
     #[inline(always)]
     fn to_op(
-        self,
+        &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        Ok(self)
+        Ok(*self)
     }
 
     #[inline(always)]
@@ -58,7 +62,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc
 
     #[inline(always)]
     fn project_downcast(
-        self,
+        &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, Self> {
@@ -67,7 +71,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M> for OpTy<'tc
 
     #[inline(always)]
     fn project_field(
-        self,
+        &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
         field: usize,
     ) -> InterpResult<'tcx, Self> {
@@ -85,10 +89,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M>
 
     #[inline(always)]
     fn to_op(
-        self,
+        &self,
         _ecx: &InterpCx<'mir, 'tcx, M>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        Ok(self.into())
+        Ok((*self).into())
     }
 
     #[inline(always)]
@@ -98,7 +102,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M>
 
     #[inline(always)]
     fn project_downcast(
-        self,
+        &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
         variant: VariantIdx,
     ) -> InterpResult<'tcx, Self> {
@@ -107,7 +111,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> Value<'mir, 'tcx, M>
 
     #[inline(always)]
     fn project_field(
-        self,
+        &self,
         ecx: &InterpCx<'mir, 'tcx, M>,
         field: usize,
     ) -> InterpResult<'tcx, Self> {
@@ -129,7 +133,7 @@ macro_rules! make_value_visitor {
             #[inline(always)]
             fn read_discriminant(
                 &mut self,
-                op: OpTy<'tcx, M::PointerTag>,
+                op: &OpTy<'tcx, M::PointerTag>,
             ) -> InterpResult<'tcx, VariantIdx> {
                 Ok(self.ecx().read_discriminant(op)?.1)
             }
@@ -137,13 +141,13 @@ macro_rules! make_value_visitor {
             // Recursive actions, ready to be overloaded.
             /// Visits the given value, dispatching as appropriate to more specialized visitors.
             #[inline(always)]
-            fn visit_value(&mut self, v: Self::V) -> InterpResult<'tcx>
+            fn visit_value(&mut self, v: &Self::V) -> InterpResult<'tcx>
             {
                 self.walk_value(v)
             }
             /// Visits the given value as a union. No automatic recursion can happen here.
             #[inline(always)]
-            fn visit_union(&mut self, _v: Self::V, _fields: NonZeroUsize) -> InterpResult<'tcx>
+            fn visit_union(&mut self, _v: &Self::V, _fields: NonZeroUsize) -> InterpResult<'tcx>
             {
                 Ok(())
             }
@@ -153,7 +157,7 @@ macro_rules! make_value_visitor {
             #[inline(always)]
             fn visit_aggregate(
                 &mut self,
-                v: Self::V,
+                v: &Self::V,
                 fields: impl Iterator<Item=InterpResult<'tcx, Self::V>>,
             ) -> InterpResult<'tcx> {
                 self.walk_aggregate(v, fields)
@@ -167,9 +171,9 @@ macro_rules! make_value_visitor {
             #[inline(always)]
             fn visit_field(
                 &mut self,
-                _old_val: Self::V,
+                _old_val: &Self::V,
                 _field: usize,
-                new_val: Self::V,
+                new_val: &Self::V,
             ) -> InterpResult<'tcx> {
                 self.visit_value(new_val)
             }
@@ -179,9 +183,9 @@ macro_rules! make_value_visitor {
             #[inline(always)]
             fn visit_variant(
                 &mut self,
-                _old_val: Self::V,
+                _old_val: &Self::V,
                 _variant: VariantIdx,
-                new_val: Self::V,
+                new_val: &Self::V,
             ) -> InterpResult<'tcx> {
                 self.visit_value(new_val)
             }
@@ -189,16 +193,16 @@ macro_rules! make_value_visitor {
             // Default recursors. Not meant to be overloaded.
             fn walk_aggregate(
                 &mut self,
-                v: Self::V,
+                v: &Self::V,
                 fields: impl Iterator<Item=InterpResult<'tcx, Self::V>>,
             ) -> InterpResult<'tcx> {
                 // Now iterate over it.
                 for (idx, field_val) in fields.enumerate() {
-                    self.visit_field(v, idx, field_val?)?;
+                    self.visit_field(v, idx, &field_val?)?;
                 }
                 Ok(())
             }
-            fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx>
+            fn walk_value(&mut self, v: &Self::V) -> InterpResult<'tcx>
             {
                 trace!("walk_value: type: {}", v.layout().ty);
 
@@ -208,10 +212,10 @@ macro_rules! make_value_visitor {
                     ty::Dynamic(..) => {
                         // immediate trait objects are not a thing
                         let dest = v.to_op(self.ecx())?.assert_mem_place(self.ecx());
-                        let inner = self.ecx().unpack_dyn_trait(dest)?.1;
+                        let inner = self.ecx().unpack_dyn_trait(&dest)?.1;
                         trace!("walk_value: dyn object layout: {:#?}", inner.layout);
                         // recurse with the inner type
-                        return self.visit_field(v, 0, Value::from_mem_place(inner));
+                        return self.visit_field(&v, 0, &Value::from_mem_place(inner));
                     },
                     // Slices do not need special handling here: they have `Array` field
                     // placement with length 0, so we enter the `Array` case below which
@@ -241,7 +245,7 @@ macro_rules! make_value_visitor {
                         // Now we can go over all the fields.
                         // This uses the *run-time length*, i.e., if we are a slice,
                         // the dynamic info from the metadata is used.
-                        let iter = self.ecx().mplace_array_fields(mplace)?
+                        let iter = self.ecx().mplace_array_fields(&mplace)?
                             .map(|f| f.and_then(|f| {
                                 Ok(Value::from_mem_place(f))
                             }));
@@ -254,11 +258,11 @@ macro_rules! make_value_visitor {
                     // with *its* fields.
                     Variants::Multiple { .. } => {
                         let op = v.to_op(self.ecx())?;
-                        let idx = self.read_discriminant(op)?;
+                        let idx = self.read_discriminant(&op)?;
                         let inner = v.project_downcast(self.ecx(), idx)?;
                         trace!("walk_value: variant layout: {:#?}", inner.layout());
                         // recurse with the inner type
-                        self.visit_variant(v, idx, inner)
+                        self.visit_variant(v, idx, &inner)
                     }
                     // For single-variant layouts, we already did anything there is to do.
                     Variants::Single { .. } => Ok(())
diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs
index 75f80f69bea..20cb989196a 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -1013,13 +1013,12 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> {
             | hir::ItemKind::Union(_, ref generics) => {
                 if generics.params.is_empty() {
                     if self.mode == MonoItemCollectionMode::Eager {
-                        let def_id = self.tcx.hir().local_def_id(item.hir_id);
                         debug!(
                             "RootCollector: ADT drop-glue for {}",
-                            self.tcx.def_path_str(def_id.to_def_id())
+                            self.tcx.def_path_str(item.def_id.to_def_id())
                         );
 
-                        let ty = Instance::new(def_id.to_def_id(), InternalSubsts::empty())
+                        let ty = Instance::new(item.def_id.to_def_id(), InternalSubsts::empty())
                             .ty(self.tcx, ty::ParamEnv::reveal_all());
                         visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
                     }
@@ -1028,29 +1027,28 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> {
             hir::ItemKind::GlobalAsm(..) => {
                 debug!(
                     "RootCollector: ItemKind::GlobalAsm({})",
-                    self.tcx.def_path_str(self.tcx.hir().local_def_id(item.hir_id).to_def_id())
+                    self.tcx.def_path_str(item.def_id.to_def_id())
                 );
-                self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.hir_id)));
+                self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.item_id())));
             }
             hir::ItemKind::Static(..) => {
-                let def_id = self.tcx.hir().local_def_id(item.hir_id).to_def_id();
-                debug!("RootCollector: ItemKind::Static({})", self.tcx.def_path_str(def_id));
-                self.output.push(dummy_spanned(MonoItem::Static(def_id)));
+                debug!(
+                    "RootCollector: ItemKind::Static({})",
+                    self.tcx.def_path_str(item.def_id.to_def_id())
+                );
+                self.output.push(dummy_spanned(MonoItem::Static(item.def_id.to_def_id())));
             }
             hir::ItemKind::Const(..) => {
                 // const items only generate mono items if they are
                 // actually used somewhere. Just declaring them is insufficient.
 
                 // but even just declaring them must collect the items they refer to
-                let def_id = self.tcx.hir().local_def_id(item.hir_id);
-
-                if let Ok(val) = self.tcx.const_eval_poly(def_id.to_def_id()) {
+                if let Ok(val) = self.tcx.const_eval_poly(item.def_id.to_def_id()) {
                     collect_const_value(self.tcx, val, &mut self.output);
                 }
             }
             hir::ItemKind::Fn(..) => {
-                let def_id = self.tcx.hir().local_def_id(item.hir_id);
-                self.push_if_root(def_id);
+                self.push_if_root(item.def_id);
             }
         }
     }
@@ -1062,8 +1060,7 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> {
 
     fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) {
         if let hir::ImplItemKind::Fn(hir::FnSig { .. }, _) = ii.kind {
-            let def_id = self.tcx.hir().local_def_id(ii.hir_id);
-            self.push_if_root(def_id);
+            self.push_if_root(ii.def_id);
         }
     }
 
@@ -1156,14 +1153,12 @@ fn create_mono_items_for_default_impls<'tcx>(
                 }
             }
 
-            let impl_def_id = tcx.hir().local_def_id(item.hir_id);
-
             debug!(
                 "create_mono_items_for_default_impls(item={})",
-                tcx.def_path_str(impl_def_id.to_def_id())
+                tcx.def_path_str(item.def_id.to_def_id())
             );
 
-            if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) {
+            if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
                 let param_env = ty::ParamEnv::reveal_all();
                 let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
                 let overridden_methods: FxHashSet<_> =
diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
index d5a845dd76f..edd46310f20 100644
--- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
+++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs
@@ -314,7 +314,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
             Some(def_id)
         }
         MonoItem::Static(def_id) => Some(def_id),
-        MonoItem::GlobalAsm(hir_id) => Some(tcx.hir().local_def_id(hir_id).to_def_id()),
+        MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.to_def_id()),
     }
 }
 
@@ -405,11 +405,10 @@ fn mono_item_visibility(
                 Visibility::Hidden
             };
         }
-        MonoItem::GlobalAsm(hir_id) => {
-            let def_id = tcx.hir().local_def_id(*hir_id);
-            return if tcx.is_reachable_non_generic(def_id) {
+        MonoItem::GlobalAsm(item_id) => {
+            return if tcx.is_reachable_non_generic(item_id.def_id) {
                 *can_be_internalized = false;
-                default_visibility(tcx, def_id.to_def_id(), false)
+                default_visibility(tcx, item_id.def_id.to_def_id(), false)
             } else {
                 Visibility::Hidden
             };
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index a92997dddac..4973450ca83 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -812,7 +812,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
         }
     }
 
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
         use rustc_target::spec::abi::Abi::RustIntrinsic;
 
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
index fd5c2236902..5384dbcb8a6 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir/src/transform/const_prop.rs
@@ -197,7 +197,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         _instance: ty::Instance<'tcx>,
         _abi: Abi,
         _args: &[OpTy<'tcx>],
-        _ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
+        _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
         _unwind: Option<BasicBlock>,
     ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> {
         Ok(None)
@@ -207,7 +207,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
         _instance: ty::Instance<'tcx>,
         _args: &[OpTy<'tcx>],
-        _ret: Option<(PlaceTy<'tcx>, BasicBlock)>,
+        _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
         _unwind: Option<BasicBlock>,
     ) -> InterpResult<'tcx> {
         throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
@@ -228,8 +228,8 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
     fn binary_ptr_op(
         _ecx: &InterpCx<'mir, 'tcx, Self>,
         _bin_op: BinOp,
-        _left: ImmTy<'tcx>,
-        _right: ImmTy<'tcx>,
+        _left: &ImmTy<'tcx>,
+        _right: &ImmTy<'tcx>,
     ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
         // We can't do this because aliasing of memory can differ between const eval and llvm
         throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
@@ -237,7 +237,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
 
     fn box_alloc(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _dest: PlaceTy<'tcx>,
+        _dest: &PlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
         throw_machine_stop_str!("can't const prop heap allocations")
     }
@@ -392,12 +392,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             .filter(|ret_layout| {
                 !ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
             })
-            .map(|ret_layout| ecx.allocate(ret_layout, MemoryKind::Stack));
+            .map(|ret_layout| ecx.allocate(ret_layout, MemoryKind::Stack).into());
 
         ecx.push_stack_frame(
             Instance::new(def_id, substs),
             dummy_body,
-            ret.map(Into::into),
+            ret.as_ref(),
             StackPopCleanup::None { cleanup: false },
         )
         .expect("failed to push initial stack frame");
@@ -426,7 +426,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
 
         // Try to read the local as an immediate so that if it is representable as a scalar, we can
         // handle it as such, but otherwise, just return the value as is.
-        Some(match self.ecx.try_read_immediate(op) {
+        Some(match self.ecx.try_read_immediate(&op) {
             Ok(Ok(imm)) => imm.into(),
             _ => op,
         })
@@ -466,7 +466,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                 // an allocation, which we should avoid. When that happens,
                 // dedicated error variants should be introduced instead.
                 assert!(
-                    !error.kind.allocates(),
+                    !error.kind().allocates(),
                     "const-prop encountered allocating error: {}",
                     error
                 );
@@ -548,8 +548,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         source_info: SourceInfo,
     ) -> Option<()> {
         if let (val, true) = self.use_ecx(|this| {
-            let val = this.ecx.read_immediate(this.ecx.eval_operand(arg, None)?)?;
-            let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, val)?;
+            let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?;
+            let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, &val)?;
             Ok((val, overflow))
         })? {
             // `AssertKind` only has an `OverflowNeg` variant, so make sure that is
@@ -573,8 +573,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         right: &Operand<'tcx>,
         source_info: SourceInfo,
     ) -> Option<()> {
-        let r = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?));
-        let l = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(left, None)?));
+        let r = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?));
+        let l = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?));
         // Check for exceeding shifts *even if* we cannot evaluate the LHS.
         if op == BinOp::Shr || op == BinOp::Shl {
             let r = r?;
@@ -609,7 +609,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             }
         }
 
-        if let (Some(l), Some(r)) = (l, r) {
+        if let (Some(l), Some(r)) = (&l, &r) {
             // The remaining operators are handled through `overflowing_binary_op`.
             if self.use_ecx(|this| {
                 let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
@@ -630,7 +630,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         match *operand {
             Operand::Copy(l) | Operand::Move(l) => {
                 if let Some(value) = self.get_const(l) {
-                    if self.should_const_prop(value) {
+                    if self.should_const_prop(&value) {
                         // FIXME(felix91gr): this code only handles `Scalar` cases.
                         // For now, we're not handling `ScalarPair` cases because
                         // doing so here would require a lot of code duplication.
@@ -745,7 +745,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     let r = this.ecx.eval_operand(right, None);
 
                     let const_arg = match (l, r) {
-                        (Ok(x), Err(_)) | (Err(_), Ok(x)) => this.ecx.read_immediate(x)?,
+                        (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
                         (Err(e), Err(_)) => return Err(e),
                         (Ok(_), Ok(_)) => {
                             this.ecx.eval_rvalue_into_place(rvalue, place)?;
@@ -760,14 +760,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                     match op {
                         BinOp::BitAnd => {
                             if arg_value == 0 {
-                                this.ecx.write_immediate(*const_arg, dest)?;
+                                this.ecx.write_immediate(*const_arg, &dest)?;
                             }
                         }
                         BinOp::BitOr => {
                             if arg_value == const_arg.layout.size.truncate(u128::MAX)
                                 || (const_arg.layout.ty.is_bool() && arg_value == 1)
                             {
-                                this.ecx.write_immediate(*const_arg, dest)?;
+                                this.ecx.write_immediate(*const_arg, &dest)?;
                             }
                         }
                         BinOp::Mul => {
@@ -777,9 +777,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
                                         const_arg.to_scalar()?.into(),
                                         Scalar::from_bool(false).into(),
                                     );
-                                    this.ecx.write_immediate(val, dest)?;
+                                    this.ecx.write_immediate(val, &dest)?;
                                 } else {
-                                    this.ecx.write_immediate(*const_arg, dest)?;
+                                    this.ecx.write_immediate(*const_arg, &dest)?;
                                 }
                             }
                         }
@@ -809,7 +809,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     fn replace_with_const(
         &mut self,
         rval: &mut Rvalue<'tcx>,
-        value: OpTy<'tcx>,
+        value: &OpTy<'tcx>,
         source_info: SourceInfo,
     ) {
         if let Rvalue::Use(Operand::Constant(c)) = rval {
@@ -902,7 +902,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
     }
 
     /// Returns `true` if and only if this `op` should be const-propagated into.
-    fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool {
+    fn should_const_prop(&mut self, op: &OpTy<'tcx>) -> bool {
         let mir_opt_level = self.tcx.sess.opts.debugging_opts.mir_opt_level;
 
         if mir_opt_level == 0 {
@@ -913,7 +913,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             return false;
         }
 
-        match *op {
+        match **op {
             interpret::Operand::Immediate(Immediate::Scalar(ScalarMaybeUninit::Scalar(s))) => {
                 s.is_bits()
             }
@@ -1094,7 +1094,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                 // This will return None if the above `const_prop` invocation only "wrote" a
                 // type whose creation requires no write. E.g. a generator whose initial state
                 // consists solely of uninitialized memory (so it doesn't capture any locals).
-                if let Some(value) = self.get_const(place) {
+                if let Some(ref value) = self.get_const(place) {
                     if self.should_const_prop(value) {
                         trace!("replacing {:?} with {:?}", rval, value);
                         self.replace_with_const(rval, value, source_info);
@@ -1177,10 +1177,10 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
         self.super_terminator(terminator, location);
         match &mut terminator.kind {
             TerminatorKind::Assert { expected, ref msg, ref mut cond, .. } => {
-                if let Some(value) = self.eval_operand(&cond, source_info) {
+                if let Some(ref value) = self.eval_operand(&cond, source_info) {
                     trace!("assertion on {:?} should be {:?}", value, expected);
                     let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected));
-                    let value_const = self.ecx.read_scalar(value).unwrap();
+                    let value_const = self.ecx.read_scalar(&value).unwrap();
                     if expected != value_const {
                         enum DbgVal<T> {
                             Val(T),
@@ -1198,9 +1198,9 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                             // This can be `None` if the lhs wasn't const propagated and we just
                             // triggered the assert on the value of the rhs.
                             match self.eval_operand(op, source_info) {
-                                Some(op) => {
-                                    DbgVal::Val(self.ecx.read_immediate(op).unwrap().to_const_int())
-                                }
+                                Some(op) => DbgVal::Val(
+                                    self.ecx.read_immediate(&op).unwrap().to_const_int(),
+                                ),
                                 None => DbgVal::Underscore,
                             }
                         };
diff --git a/compiler/rustc_mir/src/transform/coverage/tests.rs b/compiler/rustc_mir/src/transform/coverage/tests.rs
index d36f1b8e5f6..7a9bfaad883 100644
--- a/compiler/rustc_mir/src/transform/coverage/tests.rs
+++ b/compiler/rustc_mir/src/transform/coverage/tests.rs
@@ -327,7 +327,7 @@ macro_rules! assert_successors {
 fn test_covgraph_goto_switchint() {
     let mir_body = goto_switchint();
     if false {
-        println!("basic_blocks = {}", debug_basic_blocks(&mir_body));
+        eprintln!("basic_blocks = {}", debug_basic_blocks(&mir_body));
     }
     let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
     print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &basic_coverage_blocks);
@@ -583,11 +583,11 @@ fn test_find_loop_backedges_none() {
     let mir_body = goto_switchint();
     let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
     if false {
-        println!(
+        eprintln!(
             "basic_coverage_blocks = {:?}",
             basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
         );
-        println!("successors = {:?}", basic_coverage_blocks.successors);
+        eprintln!("successors = {:?}", basic_coverage_blocks.successors);
     }
     let backedges = graph::find_loop_backedges(&basic_coverage_blocks);
     assert_eq!(
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index dd9a514466d..f4f69fc8ac6 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -159,7 +159,7 @@ impl Inliner<'tcx> {
         }
     }
 
-    #[instrument(skip(self, caller_body))]
+    #[instrument(level = "debug", skip(self, caller_body))]
     fn is_mir_available(&self, callee: Instance<'tcx>, caller_body: &Body<'tcx>) -> bool {
         match callee.def {
             InstanceDef::Item(_) => {
@@ -258,7 +258,7 @@ impl Inliner<'tcx> {
         None
     }
 
-    #[instrument(skip(self, callee_body))]
+    #[instrument(level = "debug", skip(self, callee_body))]
     fn should_inline(&self, callsite: CallSite<'tcx>, callee_body: &Body<'tcx>) -> bool {
         let tcx = self.tcx;
 
@@ -281,6 +281,11 @@ impl Inliner<'tcx> {
             return false;
         }
 
+        if self.codegen_fn_attrs.instruction_set != codegen_fn_attrs.instruction_set {
+            debug!("`callee has incompatible instruction set - not inlining");
+            return false;
+        }
+
         let hinted = match codegen_fn_attrs.inline {
             // Just treat inline(always) as a hint for now,
             // there are cases that prevent inlining that we
diff --git a/compiler/rustc_mir/src/transform/inline/cycle.rs b/compiler/rustc_mir/src/transform/inline/cycle.rs
index e4d403fbf60..4c24bec0ce3 100644
--- a/compiler/rustc_mir/src/transform/inline/cycle.rs
+++ b/compiler/rustc_mir/src/transform/inline/cycle.rs
@@ -7,7 +7,7 @@ use rustc_middle::ty::{self, subst::SubstsRef, InstanceDef, TyCtxt};
 
 // FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking
 // this query riddiculously often.
-#[instrument(skip(tcx, root, target))]
+#[instrument(level = "debug", skip(tcx, root, target))]
 crate fn mir_callgraph_reachable(
     tcx: TyCtxt<'tcx>,
     (root, target): (ty::Instance<'tcx>, LocalDefId),
@@ -27,7 +27,10 @@ crate fn mir_callgraph_reachable(
         !tcx.is_constructor(root.def_id()),
         "you should not call `mir_callgraph_reachable` on enum/struct constructor functions"
     );
-    #[instrument(skip(tcx, param_env, target, stack, seen, recursion_limiter, caller))]
+    #[instrument(
+        level = "debug",
+        skip(tcx, param_env, target, stack, seen, recursion_limiter, caller)
+    )]
     fn process(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index b4504a0e223..1d4438d80c9 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -1231,3 +1231,38 @@ pub fn promote_candidates<'tcx>(
 
     promotions
 }
+
+/// This function returns `true` if the function being called in the array
+/// repeat expression is a `const` function.
+crate fn is_const_fn_in_array_repeat_expression<'tcx>(
+    ccx: &ConstCx<'_, 'tcx>,
+    place: &Place<'tcx>,
+    body: &Body<'tcx>,
+) -> bool {
+    match place.as_local() {
+        // rule out cases such as: `let my_var = some_fn(); [my_var; N]`
+        Some(local) if body.local_decls[local].is_user_variable() => return false,
+        None => return false,
+        _ => {}
+    }
+
+    for block in body.basic_blocks() {
+        if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) =
+            &block.terminator
+        {
+            if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
+                if let ty::FnDef(def_id, _) = *ty.kind() {
+                    if let Some((destination_place, _)) = destination {
+                        if destination_place == place {
+                            if is_const_fn(ccx.tcx, def_id) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    false
+}
diff --git a/compiler/rustc_mir/src/util/generic_graphviz.rs b/compiler/rustc_mir/src/util/generic_graphviz.rs
index fd55a4dfc4c..fd41e282266 100644
--- a/compiler/rustc_mir/src/util/generic_graphviz.rs
+++ b/compiler/rustc_mir/src/util/generic_graphviz.rs
@@ -6,8 +6,8 @@ use std::io::{self, Write};
 pub struct GraphvizWriter<
     'a,
     G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes,
-    NodeContentFn: Fn(<G as rustc_data_structures::graph::DirectedGraph>::Node) -> Vec<String>,
-    EdgeLabelsFn: Fn(<G as rustc_data_structures::graph::DirectedGraph>::Node) -> Vec<String>,
+    NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
+    EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
 > {
     graph: &'a G,
     is_subgraph: bool,
@@ -20,8 +20,8 @@ pub struct GraphvizWriter<
 impl<
     'a,
     G: graph::DirectedGraph + graph::WithSuccessors + graph::WithStartNode + graph::WithNumNodes,
-    NodeContentFn: Fn(<G as rustc_data_structures::graph::DirectedGraph>::Node) -> Vec<String>,
-    EdgeLabelsFn: Fn(<G as rustc_data_structures::graph::DirectedGraph>::Node) -> Vec<String>,
+    NodeContentFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
+    EdgeLabelsFn: Fn(<G as graph::DirectedGraph>::Node) -> Vec<String>,
 > GraphvizWriter<'a, G, NodeContentFn, EdgeLabelsFn>
 {
     pub fn new(
diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs
index 7fc1c3a73af..f46e94eea96 100644
--- a/compiler/rustc_mir/src/util/pretty.rs
+++ b/compiler/rustc_mir/src/util/pretty.rs
@@ -289,19 +289,19 @@ pub fn write_mir_pretty<'tcx>(
             }
             Ok(())
         };
-        match tcx.hir().body_const_context(def_id.expect_local()) {
-            None => render_body(w, tcx.optimized_mir(def_id))?,
-            // For `const fn` we want to render the optimized MIR. If you want the mir used in
-            // ctfe, you can dump the MIR after the `Deaggregator` optimization pass.
-            Some(rustc_hir::ConstContext::ConstFn) => {
-                render_body(w, tcx.optimized_mir(def_id))?;
-                writeln!(w)?;
-                writeln!(w, "// MIR FOR CTFE")?;
-                // Do not use `render_body`, as that would render the promoteds again, but these
-                // are shared between mir_for_ctfe and optimized_mir
-                write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?;
-            }
-            Some(_) => render_body(w, tcx.mir_for_ctfe(def_id))?,
+
+        // For `const fn` we want to render both the optimized MIR and the MIR for ctfe.
+        if tcx.is_const_fn_raw(def_id) {
+            render_body(w, tcx.optimized_mir(def_id))?;
+            writeln!(w)?;
+            writeln!(w, "// MIR FOR CTFE")?;
+            // Do not use `render_body`, as that would render the promoteds again, but these
+            // are shared between mir_for_ctfe and optimized_mir
+            write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?;
+        } else {
+            let instance_mir =
+                tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)));
+            render_body(w, instance_mir)?;
         }
     }
     Ok(())
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index 2dd894a67a6..b75221bb5d5 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -24,4 +24,4 @@ rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_ast = { path = "../rustc_ast" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 82f38ac0e76..d5f72e6f22d 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -3,7 +3,6 @@ use crate::build::ForGuard::OutsideGuard;
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use crate::thir::*;
 use rustc_hir as hir;
-use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
 use rustc_session::lint::Level;
@@ -13,7 +12,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn ast_block(
         &mut self,
         destination: Place<'tcx>,
-        scope: Option<region::Scope>,
         block: BasicBlock,
         ast_block: &'tcx hir::Block<'tcx>,
         source_info: SourceInfo,
@@ -30,10 +28,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| {
             this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
                 if targeted_by_break {
-                    this.in_breakable_scope(None, destination, scope, span, |this| {
+                    this.in_breakable_scope(None, destination, span, |this| {
                         Some(this.ast_block_stmts(
                             destination,
-                            scope,
                             block,
                             span,
                             stmts,
@@ -42,7 +39,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         ))
                     })
                 } else {
-                    this.ast_block_stmts(destination, scope, block, span, stmts, expr, safety_mode)
+                    this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode)
                 }
             })
         })
@@ -51,7 +48,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn ast_block_stmts(
         &mut self,
         destination: Place<'tcx>,
-        scope: Option<region::Scope>,
         mut block: BasicBlock,
         span: Span,
         stmts: Vec<StmtRef<'tcx>>,
@@ -186,7 +182,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             };
             this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored, span });
 
-            unpack!(block = this.into(destination, scope, block, expr));
+            unpack!(block = this.into(destination, block, expr));
             let popped = this.block_context.pop();
 
             assert!(popped.map_or(false, |bf| bf.is_tail_expr()));
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index c95fc969797..e602f4dd71d 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -12,8 +12,6 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, UpvarSubsts};
 use rustc_span::Span;
 
-use std::slice;
-
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Returns an rvalue suitable for use until the end of the current
     /// scope expression.
@@ -115,19 +113,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
                 this.cfg.push_assign(block, source_info, Place::from(result), box_);
 
-                // Initialize the box contents. No scope is needed since the
-                // `Box` is already scheduled to be dropped.
+                // initialize the box contents:
                 unpack!(
-                    block = this.into(
-                        this.hir.tcx().mk_place_deref(Place::from(result)),
-                        None,
-                        block,
-                        value,
-                    )
+                    block =
+                        this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value)
                 );
-                let result_operand = Operand::Move(Place::from(result));
-                this.record_operands_moved(slice::from_ref(&result_operand));
-                block.and(Rvalue::Use(result_operand))
+                block.and(Rvalue::Use(Operand::Move(Place::from(result))))
             }
             ExprKind::Cast { source } => {
                 let source = unpack!(block = this.as_operand(block, scope, source));
@@ -171,7 +162,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     .map(|f| unpack!(block = this.as_operand(block, scope, f)))
                     .collect();
 
-                this.record_operands_moved(&fields);
                 block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
             }
             ExprKind::Tuple { fields } => {
@@ -182,7 +172,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     .map(|f| unpack!(block = this.as_operand(block, scope, f)))
                     .collect();
 
-                this.record_operands_moved(&fields);
                 block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
             }
             ExprKind::Closure { closure_id, substs, upvars, movability } => {
@@ -234,7 +223,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     }
                     UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs),
                 };
-                this.record_operands_moved(&operands);
                 block.and(Rvalue::Aggregate(result, operands))
             }
             ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
index 241330d96e7..9984b527ffd 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -114,7 +114,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
         }
 
-        unpack!(block = this.into(temp_place, temp_lifetime, block, expr));
+        unpack!(block = this.into(temp_place, block, expr));
+
+        if let Some(temp_lifetime) = temp_lifetime {
+            this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
+        }
 
         block.and(temp)
     }
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 18ebf334404..235fe14cbf9 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -1,35 +1,25 @@
 //! See docs in build/expr/mod.rs
 
 use crate::build::expr::category::{Category, RvalueFunc};
-use crate::build::scope::DropKind;
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use crate::thir::*;
 use rustc_ast::InlineAsmOptions;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
-use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::ty::CanonicalUserTypeAnnotation;
 
-use std::slice;
-
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, storing the result into `destination`, which
     /// is assumed to be uninitialized.
-    /// If a `drop_scope` is provided, `destination` is scheduled to be dropped
-    /// in `scope` once it has been initialized.
     crate fn into_expr(
         &mut self,
         destination: Place<'tcx>,
-        scope: Option<region::Scope>,
         mut block: BasicBlock,
         expr: Expr<'tcx>,
     ) -> BlockAnd<()> {
-        debug!(
-            "into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})",
-            destination, scope, block, expr
-        );
+        debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
 
         // since we frequently have to reference `self` from within a
         // closure, where `self` would be shadowed, it's easier to
@@ -41,14 +31,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let expr_is_block_or_scope =
             matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. });
 
-        let schedule_drop = move |this: &mut Self| {
-            if let Some(drop_scope) = scope {
-                let local =
-                    destination.as_local().expect("cannot schedule drop of non-Local place");
-                this.schedule_drop(expr_span, drop_scope, local, DropKind::Value);
-            }
-        };
-
         if !expr_is_block_or_scope {
             this.block_context.push(BlockFrame::SubExpr);
         }
@@ -58,15 +40,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let region_scope = (region_scope, source_info);
                 ensure_sufficient_stack(|| {
                     this.in_scope(region_scope, lint_level, |this| {
-                        this.into(destination, scope, block, value)
+                        this.into(destination, block, value)
                     })
                 })
             }
             ExprKind::Block { body: ast_block } => {
-                this.ast_block(destination, scope, block, ast_block, source_info)
+                this.ast_block(destination, block, ast_block, source_info)
             }
             ExprKind::Match { scrutinee, arms } => {
-                this.match_expr(destination, scope, expr_span, block, scrutinee, arms)
+                this.match_expr(destination, expr_span, block, scrutinee, arms)
             }
             ExprKind::If { cond, then, else_opt } => {
                 let place = unpack!(
@@ -79,9 +61,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block);
                 this.cfg.terminate(block, source_info, term);
 
-                unpack!(then_block = this.into(destination, scope, then_block, then));
+                unpack!(then_block = this.into(destination, then_block, then));
                 else_block = if let Some(else_opt) = else_opt {
-                    unpack!(this.into(destination, None, else_block, else_opt))
+                    unpack!(this.into(destination, else_block, else_opt))
                 } else {
                     // Body of the `if` expression without an `else` clause must return `()`, thus
                     // we implicitly generate a `else {}` if it is not specified.
@@ -117,7 +99,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 // This is an optimization. If the expression was a call then we already have an
                 // unreachable block. Don't bother to terminate it and create a new one.
-                schedule_drop(this);
                 if is_call {
                     block.unit()
                 } else {
@@ -193,35 +174,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // Start the loop.
                 this.cfg.goto(block, source_info, loop_block);
 
-                this.in_breakable_scope(
-                    Some(loop_block),
-                    destination,
-                    scope,
-                    expr_span,
-                    move |this| {
-                        // conduct the test, if necessary
-                        let body_block = this.cfg.start_new_block();
-                        this.cfg.terminate(
-                            loop_block,
-                            source_info,
-                            TerminatorKind::FalseUnwind { real_target: body_block, unwind: None },
-                        );
-                        this.diverge_from(loop_block);
-
-                        // The “return” value of the loop body must always be an unit. We therefore
-                        // introduce a unit temporary as the destination for the loop body.
-                        let tmp = this.get_unit_temp();
-                        // Execute the body, branching back to the test.
-                        // We don't need to provide a drop scope because `tmp`
-                        // has type `()`.
-                        let body_block_end = unpack!(this.into(tmp, None, body_block, body));
-                        this.cfg.goto(body_block_end, source_info, loop_block);
-                        schedule_drop(this);
-
-                        // Loops are only exited by `break` expressions.
-                        None
-                    },
-                )
+                this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| {
+                    // conduct the test, if necessary
+                    let body_block = this.cfg.start_new_block();
+                    this.cfg.terminate(
+                        loop_block,
+                        source_info,
+                        TerminatorKind::FalseUnwind { real_target: body_block, unwind: None },
+                    );
+                    this.diverge_from(loop_block);
+
+                    // The “return” value of the loop body must always be an unit. We therefore
+                    // introduce a unit temporary as the destination for the loop body.
+                    let tmp = this.get_unit_temp();
+                    // Execute the body, branching back to the test.
+                    let body_block_end = unpack!(this.into(tmp, body_block, body));
+                    this.cfg.goto(body_block_end, source_info, loop_block);
+
+                    // Loops are only exited by `break` expressions.
+                    None
+                })
             }
             ExprKind::Call { ty: _, fun, args, from_hir_call, fn_span } => {
                 let fun = unpack!(block = this.as_local_operand(block, fun));
@@ -256,10 +228,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     },
                 );
                 this.diverge_from(block);
-                schedule_drop(this);
                 success.unit()
             }
-            ExprKind::Use { source } => this.into(destination, scope, block, source),
+            ExprKind::Use { source } => this.into(destination, block, source),
             ExprKind::Borrow { arg, borrow_kind } => {
                 // We don't do this in `as_rvalue` because we use `as_place`
                 // for borrow expressions, so we cannot create an `RValue` that
@@ -341,14 +312,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     user_ty,
                     active_field_index,
                 );
-                this.record_operands_moved(&fields);
                 this.cfg.push_assign(
                     block,
                     source_info,
                     destination,
                     Rvalue::Aggregate(adt, fields),
                 );
-                schedule_drop(this);
                 block.unit()
             }
             ExprKind::InlineAsm { template, operands, options, line_spans } => {
@@ -445,7 +414,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let place = unpack!(block = this.as_place(block, expr));
                 let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
                 this.cfg.push_assign(block, source_info, destination, rvalue);
-                schedule_drop(this);
                 block.unit()
             }
             ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
@@ -463,7 +431,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let place = unpack!(block = this.as_place(block, expr));
                 let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
                 this.cfg.push_assign(block, source_info, destination, rvalue);
-                schedule_drop(this);
                 block.unit()
             }
 
@@ -471,14 +438,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let scope = this.local_scope();
                 let value = unpack!(block = this.as_operand(block, Some(scope), value));
                 let resume = this.cfg.start_new_block();
-                this.record_operands_moved(slice::from_ref(&value));
                 this.cfg.terminate(
                     block,
                     source_info,
                     TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None },
                 );
                 this.generator_drop_cleanup(block);
-                schedule_drop(this);
                 resume.unit()
             }
 
@@ -510,7 +475,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
                 this.cfg.push_assign(block, source_info, destination, rvalue);
-                schedule_drop(this);
                 block.unit()
             }
         };
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index a974ea0db5f..f117689d940 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -3,7 +3,6 @@ use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use crate::thir::*;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
-use std::slice;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Builds a block of MIR statements to evaluate the THIR `expr`.
@@ -47,7 +46,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 if this.hir.needs_drop(lhs.ty) {
                     let rhs = unpack!(block = this.as_local_operand(block, rhs));
                     let lhs = unpack!(block = this.as_place(block, lhs));
-                    this.record_operands_moved(slice::from_ref(&rhs));
                     unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
                 } else {
                     let rhs = unpack!(block = this.as_local_rvalue(block, rhs));
diff --git a/compiler/rustc_mir_build/src/build/into.rs b/compiler/rustc_mir_build/src/build/into.rs
index ee1838ddea6..7264e495b84 100644
--- a/compiler/rustc_mir_build/src/build/into.rs
+++ b/compiler/rustc_mir_build/src/build/into.rs
@@ -6,7 +6,6 @@
 
 use crate::build::{BlockAnd, Builder};
 use crate::thir::*;
-use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 
 pub(in crate::build) trait EvalInto<'tcx> {
@@ -14,7 +13,6 @@ pub(in crate::build) trait EvalInto<'tcx> {
         self,
         builder: &mut Builder<'_, 'tcx>,
         destination: Place<'tcx>,
-        scope: Option<region::Scope>,
         block: BasicBlock,
     ) -> BlockAnd<()>;
 }
@@ -23,14 +21,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn into<E>(
         &mut self,
         destination: Place<'tcx>,
-        scope: Option<region::Scope>,
         block: BasicBlock,
         expr: E,
     ) -> BlockAnd<()>
     where
         E: EvalInto<'tcx>,
     {
-        expr.eval_into(self, destination, scope, block)
+        expr.eval_into(self, destination, block)
     }
 }
 
@@ -39,11 +36,10 @@ impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
         self,
         builder: &mut Builder<'_, 'tcx>,
         destination: Place<'tcx>,
-        scope: Option<region::Scope>,
         block: BasicBlock,
     ) -> BlockAnd<()> {
         let expr = builder.hir.mirror(self);
-        builder.into_expr(destination, scope, block, expr)
+        builder.into_expr(destination, block, expr)
     }
 }
 
@@ -52,9 +48,8 @@ impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
         self,
         builder: &mut Builder<'_, 'tcx>,
         destination: Place<'tcx>,
-        scope: Option<region::Scope>,
         block: BasicBlock,
     ) -> BlockAnd<()> {
-        builder.into_expr(destination, scope, block, self)
+        builder.into_expr(destination, block, self)
     }
 }
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 205ba0d2579..fde007ec011 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -87,7 +87,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn match_expr(
         &mut self,
         destination: Place<'tcx>,
-        destination_scope: Option<region::Scope>,
         span: Span,
         mut block: BasicBlock,
         scrutinee: ExprRef<'tcx>,
@@ -108,7 +107,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         self.lower_match_arms(
             destination,
-            destination_scope,
             scrutinee_place,
             scrutinee_span,
             arm_candidates,
@@ -215,13 +213,76 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
+    /// Lower the bindings, guards and arm bodies of a `match` expression.
+    ///
+    /// The decision tree should have already been created
+    /// (by [Builder::lower_match_tree]).
+    ///
+    /// `outer_source_info` is the SourceInfo for the whole match.
+    fn lower_match_arms(
+        &mut self,
+        destination: Place<'tcx>,
+        scrutinee_place: Place<'tcx>,
+        scrutinee_span: Span,
+        arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
+        outer_source_info: SourceInfo,
+        fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
+    ) -> BlockAnd<()> {
+        let arm_end_blocks: Vec<_> = arm_candidates
+            .into_iter()
+            .map(|(arm, candidate)| {
+                debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate);
+
+                let arm_source_info = self.source_info(arm.span);
+                let arm_scope = (arm.scope, arm_source_info);
+                self.in_scope(arm_scope, arm.lint_level, |this| {
+                    let body = this.hir.mirror(arm.body.clone());
+                    let scope = this.declare_bindings(
+                        None,
+                        arm.span,
+                        &arm.pattern,
+                        ArmHasGuard(arm.guard.is_some()),
+                        Some((Some(&scrutinee_place), scrutinee_span)),
+                    );
+
+                    let arm_block = this.bind_pattern(
+                        outer_source_info,
+                        candidate,
+                        arm.guard.as_ref(),
+                        &fake_borrow_temps,
+                        scrutinee_span,
+                        Some(arm.span),
+                        Some(arm.scope),
+                    );
+
+                    if let Some(source_scope) = scope {
+                        this.source_scope = source_scope;
+                    }
+
+                    this.into(destination, arm_block, body)
+                })
+            })
+            .collect();
+
+        // all the arm blocks will rejoin here
+        let end_block = self.cfg.start_new_block();
+
+        for arm_block in arm_end_blocks {
+            self.cfg.goto(unpack!(arm_block), outer_source_info, end_block);
+        }
+
+        self.source_scope = outer_source_info.scope;
+
+        end_block.unit()
+    }
+
     /// Binds the variables and ascribes types for a given `match` arm or
     /// `let` binding.
     ///
     /// Also check if the guard matches, if it's provided.
     /// `arm_scope` should be `Some` if and only if this is called for a
     /// `match` arm.
-    crate fn bind_pattern(
+    fn bind_pattern(
         &mut self,
         outer_source_info: SourceInfo,
         candidate: Candidate<'_, 'tcx>,
@@ -308,14 +369,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
                 let place =
                     self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
-                let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
-
-                unpack!(block = self.into(place, Some(region_scope), block, initializer));
+                unpack!(block = self.into(place, block, initializer));
 
                 // Inject a fake read, see comments on `FakeReadCause::ForLet`.
                 let source_info = self.source_info(irrefutable_pat.span);
                 self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet, place);
 
+                self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
                 block.unit()
             }
 
@@ -342,10 +402,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 ascription:
                     thir::pattern::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
             } => {
-                let region_scope = self.hir.region_scope_tree.var_scope(var.local_id);
                 let place =
                     self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
-                unpack!(block = self.into(place, Some(region_scope), block, initializer));
+                unpack!(block = self.into(place, block, initializer));
 
                 // Inject a fake read, see comments on `FakeReadCause::ForLet`.
                 let pattern_source_info = self.source_info(irrefutable_pat.span);
@@ -383,6 +442,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     },
                 );
 
+                self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);
                 block.unit()
             }
 
@@ -629,7 +689,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 }
 
 #[derive(Debug)]
-pub(super) struct Candidate<'pat, 'tcx> {
+struct Candidate<'pat, 'tcx> {
     /// [`Span`] of the original pattern that gave rise to this candidate.
     span: Span,
 
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 8c1f73f4235..5f6c8d26402 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -618,12 +618,8 @@ where
         let arg_scope_s = (arg_scope, source_info);
         // Attribute epilogue to function's closing brace
         let fn_end = span_with_body.shrink_to_hi();
-        let return_block = unpack!(builder.in_breakable_scope(
-            None,
-            Place::return_place(),
-            Some(call_site_scope),
-            fn_end,
-            |builder| {
+        let return_block =
+            unpack!(builder.in_breakable_scope(None, Place::return_place(), fn_end, |builder| {
                 Some(builder.in_scope(arg_scope_s, LintLevel::Inherited, |builder| {
                     builder.args_and_body(
                         START_BLOCK,
@@ -633,13 +629,11 @@ where
                         &body.value,
                     )
                 }))
-            },
-        ));
+            }));
         let source_info = builder.source_info(fn_end);
         builder.cfg.terminate(return_block, source_info, TerminatorKind::Return);
         let should_abort = should_abort_on_panic(tcx, fn_def_id, abi);
         builder.build_drop_trees(should_abort);
-        builder.unschedule_return_place_drop();
         return_block.unit()
     }));
 
@@ -672,9 +666,7 @@ fn construct_const<'a, 'tcx>(
     let mut block = START_BLOCK;
     let ast_expr = &tcx.hir().body(body_id).value;
     let expr = builder.hir.mirror(ast_expr);
-    // We don't provide a scope because we can't unwind in constants, so won't
-    // need to drop the return place.
-    unpack!(block = builder.into_expr(Place::return_place(), None, block, expr));
+    unpack!(block = builder.into_expr(Place::return_place(), block, expr));
 
     let source_info = builder.source_info(span);
     builder.cfg.terminate(block, source_info, TerminatorKind::Return);
@@ -953,9 +945,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
 
         let body = self.hir.mirror(ast_body);
-        let call_site =
-            region::Scope { id: ast_body.hir_id.local_id, data: region::ScopeData::CallSite };
-        self.into(Place::return_place(), Some(call_site), block, body)
+        self.into(Place::return_place(), block, body)
     }
 
     fn set_correct_source_scope_for_arg(
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index cbc20c6153a..5e9d780d179 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -81,10 +81,9 @@ that contains only loops and breakable blocks. It tracks where a `break`,
 
 */
 
-use crate::build::matches::{ArmHasGuard, Candidate};
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
-use crate::thir::{Arm, Expr, ExprRef, LintLevel};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use crate::thir::{Expr, ExprRef, LintLevel};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_index::vec::IndexVec;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
@@ -121,6 +120,8 @@ struct Scope {
     /// end of the vector (top of the stack) first.
     drops: Vec<DropData>,
 
+    moved_locals: Vec<Local>,
+
     /// The drop index that will drop everything in and below this scope on an
     /// unwind path.
     cached_unwind_block: Option<DropIdx>,
@@ -156,8 +157,6 @@ struct BreakableScope<'tcx> {
     /// The destination of the loop/block expression itself (i.e., where to put
     /// the result of a `break` or `return` expression)
     break_destination: Place<'tcx>,
-    /// The scope that the destination should have its drop scheduled in.
-    destination_scope: Option<region::Scope>,
     /// Drops that happen on the `break`/`return` path.
     break_drops: DropTree,
     /// Drops that happen on the `continue` path.
@@ -406,6 +405,7 @@ impl<'tcx> Scopes<'tcx> {
             region_scope: region_scope.0,
             region_scope_span: region_scope.1.span,
             drops: vec![],
+            moved_locals: vec![],
             cached_unwind_block: None,
             cached_generator_drop_block: None,
         });
@@ -440,7 +440,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         loop_block: Option<BasicBlock>,
         break_destination: Place<'tcx>,
-        destination_scope: Option<region::Scope>,
         span: Span,
         f: F,
     ) -> BlockAnd<()>
@@ -451,19 +450,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let scope = BreakableScope {
             region_scope,
             break_destination,
-            destination_scope,
             break_drops: DropTree::new(),
             continue_drops: loop_block.map(|_| DropTree::new()),
         };
-        let continue_block = loop_block.map(|block| (block, self.diverge_cleanup()));
         self.scopes.breakable_scopes.push(scope);
         let normal_exit_block = f(self);
         let breakable_scope = self.scopes.breakable_scopes.pop().unwrap();
         assert!(breakable_scope.region_scope == region_scope);
+        let break_block = self.build_exit_tree(breakable_scope.break_drops, None);
         if let Some(drops) = breakable_scope.continue_drops {
-            self.build_exit_tree(drops, continue_block);
+            self.build_exit_tree(drops, loop_block);
         }
-        let break_block = self.build_exit_tree(breakable_scope.break_drops, None);
         match (normal_exit_block, break_block) {
             (Some(block), None) | (None, Some(block)) => block,
             (None, None) => self.cfg.start_new_block().unit(),
@@ -592,22 +589,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 .rposition(|breakable_scope| breakable_scope.region_scope == scope)
                 .unwrap_or_else(|| span_bug!(span, "no enclosing breakable scope found"))
         };
-        let (break_index, destination, dest_scope) = match target {
+        let (break_index, destination) = match target {
             BreakableTarget::Return => {
                 let scope = &self.scopes.breakable_scopes[0];
                 if scope.break_destination != Place::return_place() {
                     span_bug!(span, "`return` in item with no return scope");
                 }
-                (0, Some(scope.break_destination), scope.destination_scope)
+                (0, Some(scope.break_destination))
             }
             BreakableTarget::Break(scope) => {
                 let break_index = get_scope_index(scope);
                 let scope = &self.scopes.breakable_scopes[break_index];
-                (break_index, Some(scope.break_destination), scope.destination_scope)
+                (break_index, Some(scope.break_destination))
             }
             BreakableTarget::Continue(scope) => {
                 let break_index = get_scope_index(scope);
-                (break_index, None, None)
+                (break_index, None)
             }
         };
 
@@ -615,10 +612,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             if let Some(value) = value {
                 debug!("stmt_expr Break val block_context.push(SubExpr)");
                 self.block_context.push(BlockFrame::SubExpr);
-                unpack!(block = self.into(destination, dest_scope, block, value));
-                if let Some(scope) = dest_scope {
-                    self.unschedule_drop(scope, destination.as_local().unwrap())
-                };
+                unpack!(block = self.into(destination, block, value));
                 self.block_context.pop();
             } else {
                 self.cfg.push_assign_unit(block, source_info, destination, self.hir.tcx())
@@ -858,47 +852,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         span_bug!(span, "region scope {:?} not in scope to drop {:?}", region_scope, local);
     }
 
-    /// Unschedule a drop. Used for `break`, `return` and `match` expressions,
-    /// where `record_operands_moved` is not powerful enough.
-    ///
-    /// The given local is expected to have a value drop scheduled in the given
-    /// scope and for that drop to be the most recent thing scheduled in that
-    /// scope.
-    fn unschedule_drop(&mut self, region_scope: region::Scope, local: Local) {
-        if !self.hir.needs_drop(self.local_decls[local].ty) {
-            return;
-        }
-        for scope in self.scopes.scopes.iter_mut().rev() {
-            scope.invalidate_cache();
-
-            if scope.region_scope == region_scope {
-                let drop = scope.drops.pop();
-
-                match drop {
-                    Some(DropData { local: removed_local, kind: DropKind::Value, .. })
-                        if removed_local == local =>
-                    {
-                        return;
-                    }
-                    _ => bug!(
-                        "found wrong drop, expected value drop of {:?}, found {:?}",
-                        local,
-                        drop,
-                    ),
-                }
-            }
-        }
-
-        bug!("region scope {:?} not in scope to unschedule drop of {:?}", region_scope, local);
-    }
-
-    /// Indicates that the "local operands" stored in `local` is
+    /// Indicates that the "local operand" stored in `local` is
     /// *moved* at some point during execution (see `local_scope` for
     /// more information about what a "local operand" is -- in short,
     /// it's an intermediate operand created as part of preparing some
     /// MIR instruction). We use this information to suppress
-    /// redundant drops. This results in less MIR, but also avoids spurious
-    /// borrow check errors (c.f. #64391).
+    /// redundant drops on the non-unwind paths. This results in less
+    /// MIR, but also avoids spurious borrow check errors
+    /// (c.f. #64391).
     ///
     /// Example: when compiling the call to `foo` here:
     ///
@@ -934,19 +895,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         assert_eq!(scope.region_scope, local_scope, "local scope is not the topmost scope!",);
 
         // look for moves of a local variable, like `MOVE(_X)`
-        let locals_moved = operands
-            .iter()
-            .filter_map(|operand| match operand {
-                Operand::Copy(_) | Operand::Constant(_) => None,
-                Operand::Move(place) => place.as_local(),
-            })
-            .collect::<FxHashSet<_>>();
+        let locals_moved = operands.iter().flat_map(|operand| match operand {
+            Operand::Copy(_) | Operand::Constant(_) => None,
+            Operand::Move(place) => place.as_local(),
+        });
 
-        // Remove the drops for the moved operands.
-        scope
-            .drops
-            .retain(|drop| drop.kind == DropKind::Storage || !locals_moved.contains(&drop.local));
-        scope.invalidate_cache();
+        for local in locals_moved {
+            // check if we have a Drop for this operand and -- if so
+            // -- add it to the list of moved operands. Note that this
+            // local might not have been an operand created for this
+            // call, it could come from other places too.
+            if scope.drops.iter().any(|drop| drop.local == local && drop.kind == DropKind::Value) {
+                scope.moved_locals.push(local);
+            }
+        }
     }
 
     // Other
@@ -1133,97 +1095,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         success_block
     }
 
-    /// Lower the arms and guards of a match.
-    ///
-    /// The decision tree should have already been created (by
-    /// [Builder::lower_match_tree]).
-    ///
-    /// This is this module, and not in `build::matches` because we have to do
-    /// some careful scope manipulation to have the drop of the destination be
-    /// scheduled at the end of each arm and then cleared for the next arm.
-    crate fn lower_match_arms(
-        &mut self,
-        destination: Place<'tcx>,
-        destination_scope: Option<region::Scope>,
-        scrutinee_place: Place<'tcx>,
-        scrutinee_span: Span,
-        arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
-        outer_source_info: SourceInfo,
-        fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
-    ) -> BlockAnd<()> {
-        if arm_candidates.is_empty() {
-            // If there are no arms to schedule drops, then we have to do it
-            // manually.
-            if let Some(scope) = destination_scope {
-                self.schedule_drop(
-                    outer_source_info.span,
-                    scope,
-                    destination.as_local().unwrap(),
-                    DropKind::Value,
-                );
-            }
-            return self.cfg.start_new_block().unit();
-        }
-        let mut first_arm = true;
-        let arm_end_blocks: Vec<_> = arm_candidates
-            .into_iter()
-            .map(|(arm, candidate)| {
-                debug!("lowering arm {:?}\ncandidate = {:?}", arm, candidate);
-
-                if first_arm {
-                    first_arm = false;
-                } else if let Some(scope) = destination_scope {
-                    self.unschedule_drop(scope, destination.as_local().unwrap());
-                }
-
-                let arm_source_info = self.source_info(arm.span);
-                let arm_scope = (arm.scope, arm_source_info);
-                self.in_scope(arm_scope, arm.lint_level, |this| {
-                    let body = this.hir.mirror(arm.body.clone());
-                    let scope = this.declare_bindings(
-                        None,
-                        arm.span,
-                        &arm.pattern,
-                        ArmHasGuard(arm.guard.is_some()),
-                        Some((Some(&scrutinee_place), scrutinee_span)),
-                    );
-
-                    let arm_block = this.bind_pattern(
-                        outer_source_info,
-                        candidate,
-                        arm.guard.as_ref(),
-                        &fake_borrow_temps,
-                        scrutinee_span,
-                        Some(arm.span),
-                        Some(arm.scope),
-                    );
-
-                    if let Some(source_scope) = scope {
-                        this.source_scope = source_scope;
-                    }
-
-                    this.into(destination, destination_scope, arm_block, body)
-                })
-            })
-            .collect();
-
-        // all the arm blocks will rejoin here
-        let end_block = self.cfg.start_new_block();
-
-        for arm_block in arm_end_blocks {
-            self.cfg.goto(unpack!(arm_block), outer_source_info, end_block);
-        }
-
-        self.source_scope = outer_source_info.scope;
-
-        end_block.unit()
-    }
-
     /// Unschedules any drops in the top scope.
     ///
     /// This is only needed for `match` arm scopes, because they have one
     /// entrance per pattern, but only one exit.
-    pub(super) fn clear_top_scope(&mut self, region_scope: region::Scope) {
+    crate fn clear_top_scope(&mut self, region_scope: region::Scope) {
         let top_scope = self.scopes.scopes.last_mut().unwrap();
 
         assert_eq!(top_scope.region_scope, region_scope);
@@ -1231,18 +1107,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         top_scope.drops.clear();
         top_scope.invalidate_cache();
     }
-
-    /// Unschedules the drop of the return place.
-    ///
-    /// If the return type of a function requires drop, then we schedule it
-    /// in the outermost scope so that it's dropped if there's a panic while
-    /// we drop any local variables. But we don't want to drop it if we
-    /// return normally.
-    crate fn unschedule_return_place_drop(&mut self) {
-        assert_eq!(self.scopes.scopes.len(), 1);
-        assert!(self.scopes.scopes[0].drops.len() <= 1);
-        self.scopes.scopes[0].drops.clear();
-    }
 }
 
 /// Builds drops for `pop_scope` and `leave_top_scope`.
@@ -1289,6 +1153,14 @@ fn build_scope_drops<'tcx>(
                 debug_assert_eq!(unwind_drops.drops[unwind_to].0.kind, drop_data.kind);
                 unwind_to = unwind_drops.drops[unwind_to].1;
 
+                // If the operand has been moved, and we are not on an unwind
+                // path, then don't generate the drop. (We only take this into
+                // account for non-unwind paths so as not to disturb the
+                // caching mechanism.)
+                if scope.moved_locals.iter().any(|&o| o == local) {
+                    continue;
+                }
+
                 unwind_drops.add_entry(block, unwind_to);
 
                 let next = cfg.start_new_block();
@@ -1318,24 +1190,20 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
     /// Build a drop tree for a breakable scope.
     ///
     /// If `continue_block` is `Some`, then the tree is for `continue` inside a
-    /// loop. Otherwise this is for `break` or `return`. The `DropIdx` is the
-    /// next drop in the case that the drop tree unwinds. This is needed
-    /// because the drop of the break destination has already been scheduled
-    /// but it hasn't been initialized on the `continue` paths.
+    /// loop. Otherwise this is for `break` or `return`.
     fn build_exit_tree(
         &mut self,
         mut drops: DropTree,
-        continue_block: Option<(BasicBlock, DropIdx)>,
+        continue_block: Option<BasicBlock>,
     ) -> Option<BlockAnd<()>> {
         let mut blocks = IndexVec::from_elem(None, &drops.drops);
-        blocks[ROOT_NODE] = continue_block.map(|(block, _)| block);
+        blocks[ROOT_NODE] = continue_block;
 
         drops.build_mir::<ExitScopes>(&mut self.cfg, &mut blocks);
 
         // Link the exit drop tree to unwind drop tree.
         if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) {
-            let unwind_target = continue_block
-                .map_or_else(|| self.diverge_cleanup(), |(_, unwind_target)| unwind_target);
+            let unwind_target = self.diverge_cleanup();
             let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1);
             for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) {
                 match drop_data.0.kind {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 2962cbe8157..620ce360e7d 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -299,7 +299,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
             }
         }
 
-        hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => {
+        hir::ExprKind::Unary(hir::UnOp::Deref, ref arg) => {
             if cx.typeck_results().is_method_call(expr) {
                 overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()], expr.span)
             } else {
@@ -307,7 +307,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
             }
         }
 
-        hir::ExprKind::Unary(hir::UnOp::UnNot, ref arg) => {
+        hir::ExprKind::Unary(hir::UnOp::Not, ref arg) => {
             if cx.typeck_results().is_method_call(expr) {
                 overloaded_operator(cx, expr, vec![arg.to_ref()])
             } else {
@@ -315,7 +315,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
             }
         }
 
-        hir::ExprKind::Unary(hir::UnOp::UnNeg, ref arg) => {
+        hir::ExprKind::Unary(hir::UnOp::Neg, ref arg) => {
             if cx.typeck_results().is_method_call(expr) {
                 overloaded_operator(cx, expr, vec![arg.to_ref()])
             } else if let hir::ExprKind::Lit(ref lit) = arg.kind {
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 397706851cb..fdecbb94788 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1,6 +1,6 @@
-use super::usefulness::Usefulness::*;
 use super::usefulness::{
-    compute_match_usefulness, expand_pattern, MatchArm, MatchCheckCtxt, UsefulnessReport,
+    compute_match_usefulness, expand_pattern, MatchArm, MatchCheckCtxt, Reachability,
+    UsefulnessReport,
 };
 use super::{PatCtxt, PatKind, PatternError};
 
@@ -366,14 +366,31 @@ fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<
 }
 
 fn irrefutable_let_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, source: hir::MatchSource) {
-    tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| {
-        let msg = match source {
-            hir::MatchSource::IfLetDesugar { .. } => "irrefutable if-let pattern",
-            hir::MatchSource::WhileLetDesugar => "irrefutable while-let pattern",
-            hir::MatchSource::IfLetGuardDesugar => "irrefutable if-let guard",
-            _ => bug!(),
-        };
-        lint.build(msg).emit()
+    tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source {
+        hir::MatchSource::IfLetDesugar { .. } => {
+            let mut diag = lint.build("irrefutable `if let` pattern");
+            diag.note("this pattern will always match, so the `if let` is useless");
+            diag.help("consider replacing the `if let` with a `let`");
+            diag.emit()
+        }
+        hir::MatchSource::WhileLetDesugar => {
+            let mut diag = lint.build("irrefutable `while let` pattern");
+            diag.note("this pattern will always match, so the loop will never exit");
+            diag.help("consider instead using a `loop { ... }` with a `let` inside it");
+            diag.emit()
+        }
+        hir::MatchSource::IfLetGuardDesugar => {
+            let mut diag = lint.build("irrefutable `if let` guard pattern");
+            diag.note("this pattern will always match, so the guard is useless");
+            diag.help("consider removing the guard and adding a `let` inside the match arm");
+            diag.emit()
+        }
+        _ => {
+            bug!(
+                "expected `if let`, `while let`, or `if let` guard HIR match source, found {:?}",
+                source,
+            )
+        }
     });
 }
 
@@ -387,7 +404,7 @@ fn check_if_let_guard<'p, 'tcx>(
     report_arm_reachability(&cx, &report, hir::MatchSource::IfLetGuardDesugar);
 
     if report.non_exhaustiveness_witnesses.is_empty() {
-        // The match is exhaustive, i.e. the if let pattern is irrefutable.
+        // The match is exhaustive, i.e. the `if let` pattern is irrefutable.
         irrefutable_let_pattern(cx.tcx, pat.span, pat_id, hir::MatchSource::IfLetGuardDesugar)
     }
 }
@@ -398,10 +415,11 @@ fn report_arm_reachability<'p, 'tcx>(
     report: &UsefulnessReport<'p, 'tcx>,
     source: hir::MatchSource,
 ) {
+    use Reachability::*;
     let mut catchall = None;
     for (arm_index, (arm, is_useful)) in report.arm_usefulness.iter().enumerate() {
         match is_useful {
-            NotUseful => {
+            Unreachable => {
                 match source {
                     hir::MatchSource::WhileDesugar => bug!(),
 
@@ -430,17 +448,16 @@ fn report_arm_reachability<'p, 'tcx>(
                     hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
                 }
             }
-            Useful(unreachables) if unreachables.is_empty() => {}
+            Reachable(unreachables) if unreachables.is_empty() => {}
             // The arm is reachable, but contains unreachable subpatterns (from or-patterns).
-            Useful(unreachables) => {
-                let mut unreachables: Vec<_> = unreachables.iter().collect();
+            Reachable(unreachables) => {
+                let mut unreachables = unreachables.clone();
                 // Emit lints in the order in which they occur in the file.
                 unreachables.sort_unstable();
                 for span in unreachables {
                     unreachable_pattern(cx.tcx, span, arm.hir_id, None);
                 }
             }
-            UsefulWithWitness(_) => bug!(),
         }
         if !arm.has_guard && catchall.is_none() && pat_is_catchall(arm.pat) {
             catchall = Some(arm.pat.span);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 32fc0f008e9..ef1419b5b74 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -18,7 +18,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     /// Converts an evaluated constant to a pattern (if possible).
     /// This means aggregate values (like structs and enums) are converted
     /// to a pattern that matches the value (as if you'd compared via structural equality).
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     pub(super) fn const_to_pat(
         &self,
         cv: &'tcx ty::Const<'tcx>,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index e67166c99c8..3a67eeff92c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -723,8 +723,6 @@ impl<'tcx> Constructor<'tcx> {
     where
         'tcx: 'a,
     {
-        debug!("Constructor::split({:#?})", self);
-
         match self {
             Wildcard => {
                 let mut split_wildcard = SplitWildcard::new(pcx);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 7186e26be80..6e29e60b303 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -866,7 +866,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     return *self.const_to_pat(value, expr.hir_id, expr.span, false).kind;
                 }
                 hir::ExprKind::Lit(ref lit) => (lit, false),
-                hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => {
+                hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => {
                     let lit = match expr.kind {
                         hir::ExprKind::Lit(ref lit) => lit,
                         _ => span_bug!(expr.span, "not a literal: {:?}", expr),
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index d7c08a2d1af..38b7e50d786 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -288,7 +288,7 @@ use super::{Pat, PatKind};
 use super::{PatternFoldable, PatternFolder};
 
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::sync::OnceCell;
+use rustc_data_structures::fx::FxHashMap;
 
 use rustc_arena::TypedArena;
 use rustc_hir::def_id::DefId;
@@ -299,6 +299,7 @@ use rustc_span::Span;
 use smallvec::{smallvec, SmallVec};
 use std::fmt;
 use std::iter::{FromIterator, IntoIterator};
+use std::lazy::OnceCell;
 
 crate struct MatchCheckCtxt<'a, 'tcx> {
     crate tcx: TyCtxt<'tcx>,
@@ -344,6 +345,12 @@ pub(super) struct PatCtxt<'a, 'p, 'tcx> {
     pub(super) is_top_level: bool,
 }
 
+impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("PatCtxt").field("ty", &self.ty).finish()
+    }
+}
+
 crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> {
     LiteralExpander.fold_pattern(&pat)
 }
@@ -379,11 +386,32 @@ impl<'tcx> Pat<'tcx> {
     pub(super) fn is_wildcard(&self) -> bool {
         matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
     }
+
+    fn is_or_pat(&self) -> bool {
+        matches!(*self.kind, PatKind::Or { .. })
+    }
+
+    /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
+    fn expand_or_pat(&self) -> Vec<&Self> {
+        fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) {
+            if let PatKind::Or { pats } = pat.kind.as_ref() {
+                for pat in pats {
+                    expand(pat, vec);
+                }
+            } else {
+                vec.push(pat)
+            }
+        }
+
+        let mut pats = Vec::new();
+        expand(self, &mut pats);
+        pats
+    }
 }
 
 /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
 /// works well.
-#[derive(Debug, Clone)]
+#[derive(Clone)]
 struct PatStack<'p, 'tcx> {
     pats: SmallVec<[&'p Pat<'tcx>; 2]>,
     /// Cache for the constructor of the head
@@ -419,23 +447,14 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
         self.pats.iter().copied()
     }
 
-    // If the first pattern is an or-pattern, expand this pattern. Otherwise, return `None`.
-    fn expand_or_pat(&self) -> Option<Vec<Self>> {
-        if self.is_empty() {
-            None
-        } else if let PatKind::Or { pats } = &*self.head().kind {
-            Some(
-                pats.iter()
-                    .map(|pat| {
-                        let mut new_patstack = PatStack::from_pattern(pat);
-                        new_patstack.pats.extend_from_slice(&self.pats[1..]);
-                        new_patstack
-                    })
-                    .collect(),
-            )
-        } else {
-            None
-        }
+    // Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an
+    // or-pattern. Panics if `self` is empty.
+    fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = PatStack<'p, 'tcx>> + Captures<'a> {
+        self.head().expand_or_pat().into_iter().map(move |pat| {
+            let mut new_patstack = PatStack::from_pattern(pat);
+            new_patstack.pats.extend_from_slice(&self.pats[1..]);
+            new_patstack
+        })
     }
 
     /// This computes `S(self.head_ctor(), self)`. See top of the file for explanations.
@@ -475,6 +494,17 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> {
     }
 }
 
+/// Pretty-printing for matrix row.
+impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "+")?;
+        for pat in self.iter() {
+            write!(f, " {} +", pat)?;
+        }
+        Ok(())
+    }
+}
+
 /// A 2D matrix.
 #[derive(Clone, PartialEq)]
 pub(super) struct Matrix<'p, 'tcx> {
@@ -491,13 +521,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
         self.patterns.get(0).map(|r| r.len())
     }
 
-    /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it.
+    /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively
+    /// expands it.
     fn push(&mut self, row: PatStack<'p, 'tcx>) {
-        if let Some(rows) = row.expand_or_pat() {
-            for row in rows {
-                // We recursively expand the or-patterns of the new rows.
-                // This is necessary as we might have `0 | (1 | 2)` or e.g., `x @ 0 | x @ (1 | 2)`.
-                self.push(row)
+        if !row.is_empty() && row.head().is_or_pat() {
+            for row in row.expand_or_pat() {
+                self.patterns.push(row);
             }
         } else {
             self.patterns.push(row);
@@ -543,17 +572,11 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
 /// Pretty-printer for matrices of patterns, example:
 ///
 /// ```text
-/// +++++++++++++++++++++++++++++
 /// + _     + []                +
-/// +++++++++++++++++++++++++++++
 /// + true  + [First]           +
-/// +++++++++++++++++++++++++++++
 /// + true  + [Second(true)]    +
-/// +++++++++++++++++++++++++++++
 /// + false + [_]               +
-/// +++++++++++++++++++++++++++++
 /// + _     + [_, _, tail @ ..] +
-/// +++++++++++++++++++++++++++++
 /// ```
 impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -561,17 +584,14 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
 
         let Matrix { patterns: m, .. } = self;
         let pretty_printed_matrix: Vec<Vec<String>> =
-            m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect();
+            m.iter().map(|row| row.iter().map(|pat| format!("{}", pat)).collect()).collect();
 
-        let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0);
+        let column_count = m.iter().map(|row| row.len()).next().unwrap_or(0);
         assert!(m.iter().all(|row| row.len() == column_count));
         let column_widths: Vec<usize> = (0..column_count)
             .map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0))
             .collect();
 
-        let total_width = column_widths.iter().cloned().sum::<usize>() + column_count * 3 + 1;
-        let br = "+".repeat(total_width);
-        write!(f, "{}\n", br)?;
         for row in pretty_printed_matrix {
             write!(f, "+")?;
             for (column, pat_str) in row.into_iter().enumerate() {
@@ -580,7 +600,6 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> {
                 write!(f, " +")?;
             }
             write!(f, "\n")?;
-            write!(f, "{}\n", br)?;
         }
         Ok(())
     }
@@ -600,183 +619,318 @@ impl<'p, 'tcx> FromIterator<PatStack<'p, 'tcx>> for Matrix<'p, 'tcx> {
     }
 }
 
-/// Represents a set of `Span`s closed under the containment relation. That is, if a `Span` is
-/// contained in the set then all `Span`s contained in it are also implicitly contained in the set.
-/// In particular this means that when intersecting two sets, taking the intersection of some span
-/// and one of its subspans returns the subspan, whereas a simple `HashSet` would have returned an
-/// empty intersection.
-/// It is assumed that two spans don't overlap without one being contained in the other; in other
-/// words, that the inclusion structure forms a tree and not a DAG.
-/// Intersection is not very efficient. It compares everything pairwise. If needed it could be made
-/// faster by sorting the `Span`s and merging cleverly.
-#[derive(Debug, Clone, Default)]
-pub(crate) struct SpanSet {
-    /// The minimal set of `Span`s required to represent the whole set. If A and B are `Span`s in
-    /// the `SpanSet`, and A is a descendant of B, then only B will be in `root_spans`.
-    /// Invariant: the spans are disjoint.
-    root_spans: Vec<Span>,
+/// Given a pattern or a pattern-stack, this struct captures a set of its subpatterns. We use that
+/// to track reachable sub-patterns arising from or-patterns. In the absence of or-patterns this
+/// will always be either `Empty` (the whole pattern is unreachable) or `Full` (the whole pattern
+/// is reachable). When there are or-patterns, some subpatterns may be reachable while others
+/// aren't. In this case the whole pattern still counts as reachable, but we will lint the
+/// unreachable subpatterns.
+///
+/// This supports a limited set of operations, so not all possible sets of subpatterns can be
+/// represented. That's ok, we only want the ones that make sense for our usage.
+///
+/// What we're doing is illustrated by this:
+/// ```
+/// match (true, 0) {
+///     (true, 0) => {}
+///     (_, 1) => {}
+///     (true | false, 0 | 1) => {}
+/// }
+/// ```
+/// When we try the alternatives of the `true | false` or-pattern, the last `0` is reachable in the
+/// `false` alternative but not the `true`. So overall it is reachable. By contrast, the last `1`
+/// is not reachable in either alternative, so we want to signal this to the user.
+/// Therefore we take the union of sets of reachable patterns coming from different alternatives in
+/// order to figure out which subpatterns are overall reachable.
+///
+/// Invariant: we try to construct the smallest representation we can. In particular if
+/// `self.is_empty()` we ensure that `self` is `Empty`, and same with `Full`. This is not important
+/// for correctness currently.
+#[derive(Debug, Clone)]
+enum SubPatSet<'p, 'tcx> {
+    /// The empty set. This means the pattern is unreachable.
+    Empty,
+    /// The set containing the full pattern.
+    Full,
+    /// If the pattern is a pattern with a constructor or a pattern-stack, we store a set for each
+    /// of its subpatterns. Missing entries in the map are implicitly full, because that's the
+    /// common case.
+    Seq { subpats: FxHashMap<usize, SubPatSet<'p, 'tcx>> },
+    /// If the pattern is an or-pattern, we store a set for each of its alternatives. Missing
+    /// entries in the map are implicitly empty. Note: we always flatten nested or-patterns.
+    Alt {
+        subpats: FxHashMap<usize, SubPatSet<'p, 'tcx>>,
+        /// Counts the total number of alternatives in the pattern
+        alt_count: usize,
+        /// We keep the pattern around to retrieve spans.
+        pat: &'p Pat<'tcx>,
+    },
 }
 
-impl SpanSet {
-    /// Creates an empty set.
-    fn new() -> Self {
-        Self::default()
-    }
-
-    /// Tests whether the set is empty.
-    pub(crate) fn is_empty(&self) -> bool {
-        self.root_spans.is_empty()
+impl<'p, 'tcx> SubPatSet<'p, 'tcx> {
+    fn full() -> Self {
+        SubPatSet::Full
     }
-
-    /// Iterate over the disjoint list of spans at the roots of this set.
-    pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = Span> + Captures<'a> {
-        self.root_spans.iter().copied()
+    fn empty() -> Self {
+        SubPatSet::Empty
     }
 
-    /// Tests whether the set contains a given Span.
-    fn contains(&self, span: Span) -> bool {
-        self.iter().any(|root_span| root_span.contains(span))
+    fn is_empty(&self) -> bool {
+        match self {
+            SubPatSet::Empty => true,
+            SubPatSet::Full => false,
+            // If any subpattern in a sequence is unreachable, the whole pattern is unreachable.
+            SubPatSet::Seq { subpats } => subpats.values().any(|set| set.is_empty()),
+            // An or-pattern is reachable if any of its alternatives is.
+            SubPatSet::Alt { subpats, .. } => subpats.values().all(|set| set.is_empty()),
+        }
     }
 
-    /// Add a span to the set if we know the span has no intersection in this set.
-    fn push_nonintersecting(&mut self, new_span: Span) {
-        self.root_spans.push(new_span);
+    fn is_full(&self) -> bool {
+        match self {
+            SubPatSet::Empty => false,
+            SubPatSet::Full => true,
+            // The whole pattern is reachable only when all its alternatives are.
+            SubPatSet::Seq { subpats } => subpats.values().all(|sub_set| sub_set.is_full()),
+            // The whole or-pattern is reachable only when all its alternatives are.
+            SubPatSet::Alt { subpats, alt_count, .. } => {
+                subpats.len() == *alt_count && subpats.values().all(|set| set.is_full())
+            }
+        }
     }
 
-    fn intersection_mut(&mut self, other: &Self) {
-        if self.is_empty() || other.is_empty() {
-            *self = Self::new();
+    /// Union `self` with `other`, mutating `self`.
+    fn union(&mut self, other: Self) {
+        use SubPatSet::*;
+        // Union with full stays full; union with empty changes nothing.
+        if self.is_full() || other.is_empty() {
+            return;
+        } else if self.is_empty() {
+            *self = other;
+            return;
+        } else if other.is_full() {
+            *self = Full;
             return;
         }
-        // Those that were in `self` but not contained in `other`
-        let mut leftover = SpanSet::new();
-        // We keep the elements in `self` that are also in `other`.
-        self.root_spans.retain(|span| {
-            let retain = other.contains(*span);
-            if !retain {
-                leftover.root_spans.push(*span);
+
+        match (&mut *self, other) {
+            (Seq { subpats: s_set }, Seq { subpats: mut o_set }) => {
+                s_set.retain(|i, s_sub_set| {
+                    // Missing entries count as full.
+                    let o_sub_set = o_set.remove(&i).unwrap_or(Full);
+                    s_sub_set.union(o_sub_set);
+                    // We drop full entries.
+                    !s_sub_set.is_full()
+                });
+                // Everything left in `o_set` is missing from `s_set`, i.e. counts as full. Since
+                // unioning with full returns full, we can drop those entries.
             }
-            retain
-        });
-        // We keep the elements in `other` that are also in the original `self`. You might think
-        // this is not needed because `self` already contains the intersection. But those aren't
-        // just sets of things. If `self = [a]`, `other = [b]` and `a` contains `b`, then `b`
-        // belongs in the intersection but we didn't catch it in the filtering above. We look at
-        // `leftover` instead of the full original `self` to avoid duplicates.
-        for span in other.iter() {
-            if leftover.contains(span) {
-                self.root_spans.push(span);
+            (Alt { subpats: s_set, .. }, Alt { subpats: mut o_set, .. }) => {
+                s_set.retain(|i, s_sub_set| {
+                    // Missing entries count as empty.
+                    let o_sub_set = o_set.remove(&i).unwrap_or(Empty);
+                    s_sub_set.union(o_sub_set);
+                    // We drop empty entries.
+                    !s_sub_set.is_empty()
+                });
+                // Everything left in `o_set` is missing from `s_set`, i.e. counts as empty. Since
+                // unioning with empty changes nothing, we can take those entries as is.
+                s_set.extend(o_set);
+            }
+            _ => bug!(),
+        }
+
+        if self.is_full() {
+            *self = Full;
+        }
+    }
+
+    /// Returns a list of the spans of the unreachable subpatterns. If `self` is empty (i.e. the
+    /// whole pattern is unreachable) we return `None`.
+    fn list_unreachable_spans(&self) -> Option<Vec<Span>> {
+        /// Panics if `set.is_empty()`.
+        fn fill_spans(set: &SubPatSet<'_, '_>, spans: &mut Vec<Span>) {
+            match set {
+                SubPatSet::Empty => bug!(),
+                SubPatSet::Full => {}
+                SubPatSet::Seq { subpats } => {
+                    for (_, sub_set) in subpats {
+                        fill_spans(sub_set, spans);
+                    }
+                }
+                SubPatSet::Alt { subpats, pat, alt_count, .. } => {
+                    let expanded = pat.expand_or_pat();
+                    for i in 0..*alt_count {
+                        let sub_set = subpats.get(&i).unwrap_or(&SubPatSet::Empty);
+                        if sub_set.is_empty() {
+                            // Found a unreachable subpattern.
+                            spans.push(expanded[i].span);
+                        } else {
+                            fill_spans(sub_set, spans);
+                        }
+                    }
+                }
             }
         }
+
+        if self.is_empty() {
+            return None;
+        }
+        if self.is_full() {
+            // No subpatterns are unreachable.
+            return Some(Vec::new());
+        }
+        let mut spans = Vec::new();
+        fill_spans(self, &mut spans);
+        Some(spans)
+    }
+
+    /// When `self` refers to a patstack that was obtained from specialization, after running
+    /// `unspecialize` it will refer to the original patstack before specialization.
+    fn unspecialize(self, arity: usize) -> Self {
+        use SubPatSet::*;
+        match self {
+            Full => Full,
+            Empty => Empty,
+            Seq { subpats } => {
+                // We gather the first `arity` subpatterns together and shift the remaining ones.
+                let mut new_subpats = FxHashMap::default();
+                let mut new_subpats_first_col = FxHashMap::default();
+                for (i, sub_set) in subpats {
+                    if i < arity {
+                        // The first `arity` indices are now part of the pattern in the first
+                        // column.
+                        new_subpats_first_col.insert(i, sub_set);
+                    } else {
+                        // Indices after `arity` are simply shifted
+                        new_subpats.insert(i - arity + 1, sub_set);
+                    }
+                }
+                // If `new_subpats_first_col` has no entries it counts as full, so we can omit it.
+                if !new_subpats_first_col.is_empty() {
+                    new_subpats.insert(0, Seq { subpats: new_subpats_first_col });
+                }
+                Seq { subpats: new_subpats }
+            }
+            Alt { .. } => bug!(), // `self` is a patstack
+        }
+    }
+
+    /// When `self` refers to a patstack that was obtained from splitting an or-pattern, after
+    /// running `unspecialize` it will refer to the original patstack before splitting.
+    ///
+    /// For example:
+    /// ```
+    /// match Some(true) {
+    ///     Some(true) => {}
+    ///     None | Some(true | false) => {}
+    /// }
+    /// ```
+    /// Here `None` would return the full set and `Some(true | false)` would return the set
+    /// containing `false`. After `unsplit_or_pat`, we want the set to contain `None` and `false`.
+    /// This is what this function does.
+    fn unsplit_or_pat(mut self, alt_id: usize, alt_count: usize, pat: &'p Pat<'tcx>) -> Self {
+        use SubPatSet::*;
+        if self.is_empty() {
+            return Empty;
+        }
+
+        // Subpatterns coming from inside the or-pattern alternative itself, e.g. in `None | Some(0
+        // | 1)`.
+        let set_first_col = match &mut self {
+            Full => Full,
+            Seq { subpats } => subpats.remove(&0).unwrap_or(Full),
+            Empty => unreachable!(),
+            Alt { .. } => bug!(), // `self` is a patstack
+        };
+        let mut subpats_first_col = FxHashMap::default();
+        subpats_first_col.insert(alt_id, set_first_col);
+        let set_first_col = Alt { subpats: subpats_first_col, pat, alt_count };
+
+        let mut subpats = match self {
+            Full => FxHashMap::default(),
+            Seq { subpats } => subpats,
+            Empty => unreachable!(),
+            Alt { .. } => bug!(), // `self` is a patstack
+        };
+        subpats.insert(0, set_first_col);
+        Seq { subpats }
     }
 }
 
+/// This carries the results of computing usefulness, as described at the top of the file. When
+/// checking usefulness of a match branch, we use the `NoWitnesses` variant, which also keeps track
+/// of potential unreachable sub-patterns (in the presence of or-patterns). When checking
+/// exhaustiveness of a whole match, we use the `WithWitnesses` variant, which carries a list of
+/// witnesses of non-exhaustiveness when there are any.
+/// Which variant to use is dictated by `WitnessPreference`.
 #[derive(Clone, Debug)]
-crate enum Usefulness<'tcx> {
-    /// Pontentially carries a set of sub-branches that have been found to be unreachable. Used
-    /// only in the presence of or-patterns, otherwise it stays empty.
-    Useful(SpanSet),
-    /// Carries a list of witnesses of non-exhaustiveness.
-    UsefulWithWitness(Vec<Witness<'tcx>>),
-    NotUseful,
+enum Usefulness<'p, 'tcx> {
+    /// Carries a set of subpatterns that have been found to be reachable. If empty, this indicates
+    /// the whole pattern is unreachable. If not, this indicates that the pattern is reachable but
+    /// that some sub-patterns may be unreachable (due to or-patterns). In the absence of
+    /// or-patterns this will always be either `Empty` (the whole pattern is unreachable) or `Full`
+    /// (the whole pattern is reachable).
+    NoWitnesses(SubPatSet<'p, 'tcx>),
+    /// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole
+    /// pattern is unreachable.
+    WithWitnesses(Vec<Witness<'tcx>>),
 }
 
-impl<'tcx> Usefulness<'tcx> {
+impl<'p, 'tcx> Usefulness<'p, 'tcx> {
     fn new_useful(preference: WitnessPreference) -> Self {
         match preference {
-            ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
-            LeaveOutWitness => Useful(Default::default()),
+            ConstructWitness => WithWitnesses(vec![Witness(vec![])]),
+            LeaveOutWitness => NoWitnesses(SubPatSet::full()),
+        }
+    }
+    fn new_not_useful(preference: WitnessPreference) -> Self {
+        match preference {
+            ConstructWitness => WithWitnesses(vec![]),
+            LeaveOutWitness => NoWitnesses(SubPatSet::empty()),
+        }
+    }
+
+    /// Combine usefulnesses from two branches. This is an associative operation.
+    fn extend(&mut self, other: Self) {
+        match (&mut *self, other) {
+            (WithWitnesses(_), WithWitnesses(o)) if o.is_empty() => {}
+            (WithWitnesses(s), WithWitnesses(o)) if s.is_empty() => *self = WithWitnesses(o),
+            (WithWitnesses(s), WithWitnesses(o)) => s.extend(o),
+            (NoWitnesses(s), NoWitnesses(o)) => s.union(o),
+            _ => unreachable!(),
         }
     }
 
     /// When trying several branches and each returns a `Usefulness`, we need to combine the
     /// results together.
-    fn merge(usefulnesses: impl Iterator<Item = Self>) -> Self {
-        // If we have detected some unreachable sub-branches, we only want to keep them when they
-        // were unreachable in _all_ branches. Eg. in the following, the last `true` is unreachable
-        // in the second branch of the first or-pattern, but not otherwise. Therefore we don't want
-        // to lint that it is unreachable.
-        // ```
-        // match (true, true) {
-        //     (true, true) => {}
-        //     (false | true, false | true) => {}
-        // }
-        // ```
-        // Here however we _do_ want to lint that the last `false` is unreachable. So we don't want
-        // to intersect the spans that come directly from the or-pattern, since each branch of the
-        // or-pattern brings a new disjoint pattern.
-        // ```
-        // match None {
-        //     Some(false) => {}
-        //     None | Some(true | false) => {}
-        // }
-        // ```
-
-        // Is `None` when no branch was useful. Will often be `Some(Spanset::new())` because the
-        // sets are only non-empty in the presence of or-patterns.
-        let mut unreachables: Option<SpanSet> = None;
-        // Witnesses of usefulness, if any.
-        let mut witnesses = Vec::new();
-
+    fn merge(pref: WitnessPreference, usefulnesses: impl Iterator<Item = Self>) -> Self {
+        let mut ret = Self::new_not_useful(pref);
         for u in usefulnesses {
-            match u {
-                Useful(spans) if spans.is_empty() => {
-                    // Once we reach the empty set, more intersections won't change the result.
-                    return Useful(SpanSet::new());
-                }
-                Useful(spans) => {
-                    if let Some(unreachables) = &mut unreachables {
-                        if !unreachables.is_empty() {
-                            unreachables.intersection_mut(&spans);
-                        }
-                        if unreachables.is_empty() {
-                            return Useful(SpanSet::new());
-                        }
-                    } else {
-                        unreachables = Some(spans);
-                    }
-                }
-                NotUseful => {}
-                UsefulWithWitness(wits) => {
-                    witnesses.extend(wits);
+            ret.extend(u);
+            if let NoWitnesses(subpats) = &ret {
+                if subpats.is_full() {
+                    // Once we reach the full set, more unions won't change the result.
+                    return ret;
                 }
             }
         }
-
-        if !witnesses.is_empty() {
-            UsefulWithWitness(witnesses)
-        } else if let Some(unreachables) = unreachables {
-            Useful(unreachables)
-        } else {
-            NotUseful
-        }
+        ret
     }
 
     /// After calculating the usefulness for a branch of an or-pattern, call this to make this
     /// usefulness mergeable with those from the other branches.
-    fn unsplit_or_pat(self, this_span: Span, or_pat_spans: &[Span]) -> Self {
+    fn unsplit_or_pat(self, alt_id: usize, alt_count: usize, pat: &'p Pat<'tcx>) -> Self {
         match self {
-            Useful(mut spans) => {
-                // We register the spans of the other branches of this or-pattern as being
-                // unreachable from this one. This ensures that intersecting together the sets of
-                // spans returns what we want.
-                // Until we optimize `SpanSet` however, intersecting this entails a number of
-                // comparisons quadratic in the number of branches.
-                for &span in or_pat_spans {
-                    if span != this_span {
-                        spans.push_nonintersecting(span);
-                    }
-                }
-                Useful(spans)
-            }
-            x => x,
+            NoWitnesses(subpats) => NoWitnesses(subpats.unsplit_or_pat(alt_id, alt_count, pat)),
+            WithWitnesses(_) => bug!(),
         }
     }
 
     /// After calculating usefulness after a specialization, call this to recontruct a usefulness
     /// that makes sense for the matrix pre-specialization. This new usefulness can then be merged
     /// with the results of specializing with the other constructors.
-    fn apply_constructor<'p>(
+    fn apply_constructor(
         self,
         pcx: PatCtxt<'_, 'p, 'tcx>,
         matrix: &Matrix<'p, 'tcx>, // used to compute missing ctors
@@ -784,7 +938,8 @@ impl<'tcx> Usefulness<'tcx> {
         ctor_wild_subpatterns: &Fields<'p, 'tcx>,
     ) -> Self {
         match self {
-            UsefulWithWitness(witnesses) => {
+            WithWitnesses(witnesses) if witnesses.is_empty() => WithWitnesses(witnesses),
+            WithWitnesses(witnesses) => {
                 let new_witnesses = if matches!(ctor, Constructor::Missing) {
                     let mut split_wildcard = SplitWildcard::new(pcx);
                     split_wildcard.split(pcx, matrix.head_ctors(pcx.cx));
@@ -814,9 +969,9 @@ impl<'tcx> Usefulness<'tcx> {
                         .map(|witness| witness.apply_constructor(pcx, &ctor, ctor_wild_subpatterns))
                         .collect()
                 };
-                UsefulWithWitness(new_witnesses)
+                WithWitnesses(new_witnesses)
             }
-            x => x,
+            NoWitnesses(subpats) => NoWitnesses(subpats.unspecialize(ctor_wild_subpatterns.len())),
         }
     }
 }
@@ -924,6 +1079,10 @@ impl<'tcx> Witness<'tcx> {
 /// `is_under_guard` is used to inform if the pattern has a guard. If it
 /// has one it must not be inserted into the matrix. This shouldn't be
 /// relied on for soundness.
+#[instrument(
+    level = "debug",
+    skip(cx, matrix, witness_preference, hir_id, is_under_guard, is_top_level)
+)]
 fn is_useful<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     matrix: &Matrix<'p, 'tcx>,
@@ -932,9 +1091,9 @@ fn is_useful<'p, 'tcx>(
     hir_id: HirId,
     is_under_guard: bool,
     is_top_level: bool,
-) -> Usefulness<'tcx> {
+) -> Usefulness<'p, 'tcx> {
+    debug!("matrix,v={:?}{:?}", matrix, v);
     let Matrix { patterns: rows, .. } = matrix;
-    debug!("is_useful({:#?}, {:#?})", matrix, v);
 
     // The base case. We are pattern-matching on () and the return value is
     // based on whether our matrix has a row or not.
@@ -942,12 +1101,14 @@ fn is_useful<'p, 'tcx>(
     // first and then, if v is non-empty, the return value is based on whether
     // the type of the tuple we're checking is inhabited or not.
     if v.is_empty() {
-        return if rows.is_empty() {
+        let ret = if rows.is_empty() {
             Usefulness::new_useful(witness_preference)
         } else {
-            NotUseful
+            Usefulness::new_not_useful(witness_preference)
         };
-    };
+        debug!(?ret);
+        return ret;
+    }
 
     assert!(rows.iter().all(|r| r.len() == v.len()));
 
@@ -955,16 +1116,15 @@ fn is_useful<'p, 'tcx>(
     let ty = matrix.heads().next().map_or(v.head().ty, |r| r.ty);
     let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level };
 
-    debug!("is_useful_expand_first_col: ty={:#?}, expanding {:#?}", pcx.ty, v.head());
-
     // If the first pattern is an or-pattern, expand it.
-    let ret = if let Some(vs) = v.expand_or_pat() {
-        let subspans: Vec<_> = vs.iter().map(|v| v.head().span).collect();
-        // We expand the or pattern, trying each of its branches in turn and keeping careful track
-        // of possible unreachable sub-branches.
+    let ret = if v.head().is_or_pat() {
+        debug!("expanding or-pattern");
+        let v_head = v.head();
+        let vs: Vec<_> = v.expand_or_pat().collect();
+        let alt_count = vs.len();
+        // We try each or-pattern branch in turn.
         let mut matrix = matrix.clone();
-        let usefulnesses = vs.into_iter().map(|v| {
-            let v_span = v.head().span;
+        let usefulnesses = vs.into_iter().enumerate().map(|(i, v)| {
             let usefulness =
                 is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false);
             // If pattern has a guard don't add it to the matrix.
@@ -973,9 +1133,9 @@ fn is_useful<'p, 'tcx>(
                 // branches like `Some(_) | Some(0)`.
                 matrix.push(v);
             }
-            usefulness.unsplit_or_pat(v_span, &subspans)
+            usefulness.unsplit_or_pat(i, alt_count, v_head)
         });
-        Usefulness::merge(usefulnesses)
+        Usefulness::merge(witness_preference, usefulnesses)
     } else {
         let v_ctor = v.head_ctor(cx);
         if let Constructor::IntRange(ctor_range) = &v_ctor {
@@ -993,6 +1153,7 @@ fn is_useful<'p, 'tcx>(
         // witness the usefulness of `v`.
         let start_matrix = &matrix;
         let usefulnesses = split_ctors.into_iter().map(|ctor| {
+            debug!("specialize({:?})", ctor);
             // We cache the result of `Fields::wildcards` because it is used a lot.
             let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
             let spec_matrix =
@@ -1002,9 +1163,9 @@ fn is_useful<'p, 'tcx>(
                 is_useful(cx, &spec_matrix, &v, witness_preference, hir_id, is_under_guard, false);
             usefulness.apply_constructor(pcx, start_matrix, &ctor, &ctor_wild_subpatterns)
         });
-        Usefulness::merge(usefulnesses)
+        Usefulness::merge(witness_preference, usefulnesses)
     };
-    debug!("is_useful::returns({:#?}, {:#?}) = {:?}", matrix, v, ret);
+    debug!(?ret);
     ret
 }
 
@@ -1017,10 +1178,21 @@ crate struct MatchArm<'p, 'tcx> {
     crate has_guard: bool,
 }
 
+/// Indicates whether or not a given arm is reachable.
+#[derive(Clone, Debug)]
+crate enum Reachability {
+    /// The arm is reachable. This additionally carries a set of or-pattern branches that have been
+    /// found to be unreachable despite the overall arm being reachable. Used only in the presence
+    /// of or-patterns, otherwise it stays empty.
+    Reachable(Vec<Span>),
+    /// The arm is unreachable.
+    Unreachable,
+}
+
 /// The output of checking a match for exhaustiveness and arm reachability.
 crate struct UsefulnessReport<'p, 'tcx> {
     /// For each arm of the input, whether that arm is reachable after the arms above it.
-    crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Usefulness<'tcx>)>,
+    crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Reachability)>,
     /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
     /// exhaustiveness.
     crate non_exhaustiveness_witnesses: Vec<super::Pat<'tcx>>,
@@ -1048,7 +1220,14 @@ crate fn compute_match_usefulness<'p, 'tcx>(
             if !arm.has_guard {
                 matrix.push(v);
             }
-            (arm, usefulness)
+            let reachability = match usefulness {
+                NoWitnesses(subpats) if subpats.is_empty() => Reachability::Unreachable,
+                NoWitnesses(subpats) => {
+                    Reachability::Reachable(subpats.list_unreachable_spans().unwrap())
+                }
+                WithWitnesses(..) => bug!(),
+            };
+            (arm, reachability)
         })
         .collect();
 
@@ -1056,15 +1235,8 @@ crate fn compute_match_usefulness<'p, 'tcx>(
     let v = PatStack::from_pattern(wild_pattern);
     let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, scrut_hir_id, false, true);
     let non_exhaustiveness_witnesses = match usefulness {
-        NotUseful => vec![], // Wildcard pattern isn't useful, so the match is exhaustive.
-        UsefulWithWitness(pats) => {
-            if pats.is_empty() {
-                bug!("Exhaustiveness check returned no witnesses")
-            } else {
-                pats.into_iter().map(|w| w.single_pattern()).collect()
-            }
-        }
-        Useful(_) => bug!(),
+        WithWitnesses(pats) => pats.into_iter().map(|w| w.single_pattern()).collect(),
+        NoWitnesses(_) => bug!(),
     };
     UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
 }
diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml
index 52835e5c8a9..c887729c355 100644
--- a/compiler/rustc_parse/Cargo.toml
+++ b/compiler/rustc_parse/Cargo.toml
@@ -19,4 +19,4 @@ rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_ast = { path = "../rustc_ast" }
 unicode-normalization = "0.1.11"
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index b5b34c7338d..4a638ec3f80 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -14,7 +14,7 @@ mod tokentrees;
 mod unescape_error_reporting;
 mod unicode_chars;
 
-use unescape_error_reporting::{emit_unescape_error, push_escaped_char};
+use unescape_error_reporting::{emit_unescape_error, escaped_char};
 
 #[derive(Clone, Debug)]
 pub struct UnmatchedBrace {
@@ -122,11 +122,9 @@ impl<'a> StringReader<'a> {
         m: &str,
         c: char,
     ) -> DiagnosticBuilder<'a> {
-        let mut m = m.to_string();
-        m.push_str(": ");
-        push_escaped_char(&mut m, c);
-
-        self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..])
+        self.sess
+            .span_diagnostic
+            .struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
     }
 
     /// Turns simple `rustc_lexer::TokenKind` enum into a rich
@@ -421,7 +419,7 @@ impl<'a> StringReader<'a> {
         let content_start = start + BytePos(prefix_len);
         let content_end = suffix_start - BytePos(postfix_len);
         let id = self.symbol_from_to(content_start, content_end);
-        self.validate_literal_escape(mode, content_start, content_end);
+        self.validate_literal_escape(mode, content_start, content_end, prefix_len, postfix_len);
         (lit_kind, id)
     }
 
@@ -525,17 +523,29 @@ impl<'a> StringReader<'a> {
         .raise();
     }
 
-    fn validate_literal_escape(&self, mode: Mode, content_start: BytePos, content_end: BytePos) {
+    fn validate_literal_escape(
+        &self,
+        mode: Mode,
+        content_start: BytePos,
+        content_end: BytePos,
+        prefix_len: u32,
+        postfix_len: u32,
+    ) {
         let lit_content = self.str_from_to(content_start, content_end);
         unescape::unescape_literal(lit_content, mode, &mut |range, result| {
             // Here we only check for errors. The actual unescaping is done later.
             if let Err(err) = result {
-                let span_with_quotes =
-                    self.mk_sp(content_start - BytePos(1), content_end + BytePos(1));
+                let span_with_quotes = self
+                    .mk_sp(content_start - BytePos(prefix_len), content_end + BytePos(postfix_len));
+                let (start, end) = (range.start as u32, range.end as u32);
+                let lo = content_start + BytePos(start);
+                let hi = lo + BytePos(end - start);
+                let span = self.mk_sp(lo, hi);
                 emit_unescape_error(
                     &self.sess.span_diagnostic,
                     lit_content,
                     span_with_quotes,
+                    span,
                     mode,
                     range,
                     err,
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 47d317f9188..a580f0c55d0 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -13,6 +13,8 @@ pub(crate) fn emit_unescape_error(
     lit: &str,
     // full span of the literal, including quotes
     span_with_quotes: Span,
+    // interior span of the literal, without quotes
+    span: Span,
     mode: Mode,
     // range of the error inside `lit`
     range: Range<usize>,
@@ -26,13 +28,6 @@ pub(crate) fn emit_unescape_error(
         range,
         error
     );
-    let span = {
-        let Range { start, end } = range;
-        let (start, end) = (start as u32, end as u32);
-        let lo = span_with_quotes.lo() + BytePos(start + 1);
-        let hi = lo + BytePos(end - start);
-        span_with_quotes.with_lo(lo).with_hi(hi)
-    };
     let last_char = || {
         let c = lit[range.clone()].chars().rev().next().unwrap();
         let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32));
@@ -42,20 +37,22 @@ pub(crate) fn emit_unescape_error(
         EscapeError::LoneSurrogateUnicodeEscape => {
             handler
                 .struct_span_err(span, "invalid unicode character escape")
+                .span_label(span, "invalid escape")
                 .help("unicode escape must not be a surrogate")
                 .emit();
         }
         EscapeError::OutOfRangeUnicodeEscape => {
             handler
                 .struct_span_err(span, "invalid unicode character escape")
+                .span_label(span, "invalid escape")
                 .help("unicode escape must be at most 10FFFF")
                 .emit();
         }
         EscapeError::MoreThanOneChar => {
-            let msg = if mode.is_bytes() {
-                "if you meant to write a byte string literal, use double quotes"
+            let (prefix, msg) = if mode.is_bytes() {
+                ("b", "if you meant to write a byte string literal, use double quotes")
             } else {
-                "if you meant to write a `str` literal, use double quotes"
+                ("", "if you meant to write a `str` literal, use double quotes")
             };
 
             handler
@@ -66,31 +63,44 @@ pub(crate) fn emit_unescape_error(
                 .span_suggestion(
                     span_with_quotes,
                     msg,
-                    format!("\"{}\"", lit),
+                    format!("{}\"{}\"", prefix, lit),
                     Applicability::MachineApplicable,
                 )
                 .emit();
         }
         EscapeError::EscapeOnlyChar => {
-            let (c, _span) = last_char();
+            let (c, char_span) = last_char();
 
-            let mut msg = if mode.is_bytes() {
-                "byte constant must be escaped: "
+            let msg = if mode.is_bytes() {
+                "byte constant must be escaped"
             } else {
-                "character constant must be escaped: "
-            }
-            .to_string();
-            push_escaped_char(&mut msg, c);
-
-            handler.span_err(span, msg.as_str())
+                "character constant must be escaped"
+            };
+            handler
+                .struct_span_err(span, &format!("{}: `{}`", msg, escaped_char(c)))
+                .span_suggestion(
+                    char_span,
+                    "escape the character",
+                    c.escape_default().to_string(),
+                    Applicability::MachineApplicable,
+                )
+                .emit()
         }
         EscapeError::BareCarriageReturn => {
             let msg = if mode.in_double_quotes() {
-                "bare CR not allowed in string, use \\r instead"
+                "bare CR not allowed in string, use `\\r` instead"
             } else {
-                "character constant must be escaped: \\r"
+                "character constant must be escaped: `\\r`"
             };
-            handler.span_err(span, msg);
+            handler
+                .struct_span_err(span, msg)
+                .span_suggestion(
+                    span,
+                    "escape the character",
+                    "\\r".to_string(),
+                    Applicability::MachineApplicable,
+                )
+                .emit();
         }
         EscapeError::BareCarriageReturnInRawString => {
             assert!(mode.in_double_quotes());
@@ -102,21 +112,22 @@ pub(crate) fn emit_unescape_error(
 
             let label =
                 if mode.is_bytes() { "unknown byte escape" } else { "unknown character escape" };
-            let mut msg = label.to_string();
-            msg.push_str(": ");
-            push_escaped_char(&mut msg, c);
-
-            let mut diag = handler.struct_span_err(span, msg.as_str());
+            let ec = escaped_char(c);
+            let mut diag = handler.struct_span_err(span, &format!("{}: `{}`", label, ec));
             diag.span_label(span, label);
             if c == '{' || c == '}' && !mode.is_bytes() {
                 diag.help(
-                    "if used in a formatting string, \
-                           curly braces are escaped with `{{` and `}}`",
+                    "if used in a formatting string, curly braces are escaped with `{{` and `}}`",
                 );
             } else if c == '\r' {
                 diag.help(
-                    "this is an isolated carriage return; \
-                           consider checking your editor and version control settings",
+                    "this is an isolated carriage return; consider checking your editor and \
+                     version control settings",
+                );
+            } else {
+                diag.help(
+                    "for more information, visit \
+                     <https://static.rust-lang.org/doc/master/reference.html#literals>",
                 );
             }
             diag.emit();
@@ -127,45 +138,70 @@ pub(crate) fn emit_unescape_error(
         EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => {
             let (c, span) = last_char();
 
-            let mut msg = if error == EscapeError::InvalidCharInHexEscape {
-                "invalid character in numeric character escape: "
+            let msg = if error == EscapeError::InvalidCharInHexEscape {
+                "invalid character in numeric character escape"
             } else {
-                "invalid character in unicode escape: "
-            }
-            .to_string();
-            push_escaped_char(&mut msg, c);
+                "invalid character in unicode escape"
+            };
+            let c = escaped_char(c);
 
-            handler.span_err(span, msg.as_str())
+            handler
+                .struct_span_err(span, &format!("{}: `{}`", msg, c))
+                .span_label(span, msg)
+                .emit();
         }
         EscapeError::NonAsciiCharInByte => {
             assert!(mode.is_bytes());
-            let (_c, span) = last_char();
-            handler.span_err(
-                span,
-                "byte constant must be ASCII. \
-                                    Use a \\xHH escape for a non-ASCII byte",
-            )
+            let (c, span) = last_char();
+            handler
+                .struct_span_err(span, "non-ASCII character in byte constant")
+                .span_label(span, "byte constant must be ASCII")
+                .span_suggestion(
+                    span,
+                    "use a \\xHH escape for a non-ASCII byte",
+                    format!("\\x{:X}", c as u32),
+                    Applicability::MachineApplicable,
+                )
+                .emit();
         }
         EscapeError::NonAsciiCharInByteString => {
             assert!(mode.is_bytes());
             let (_c, span) = last_char();
-            handler.span_err(span, "raw byte string must be ASCII")
+            handler
+                .struct_span_err(span, "raw byte string must be ASCII")
+                .span_label(span, "must be ASCII")
+                .emit();
+        }
+        EscapeError::OutOfRangeHexEscape => {
+            handler
+                .struct_span_err(span, "out of range hex escape")
+                .span_label(span, "must be a character in the range [\\x00-\\x7f]")
+                .emit();
         }
-        EscapeError::OutOfRangeHexEscape => handler.span_err(
-            span,
-            "this form of character escape may only be used \
-                                    with characters in the range [\\x00-\\x7f]",
-        ),
         EscapeError::LeadingUnderscoreUnicodeEscape => {
-            let (_c, span) = last_char();
-            handler.span_err(span, "invalid start of unicode escape")
+            let (c, span) = last_char();
+            let msg = "invalid start of unicode escape";
+            handler
+                .struct_span_err(span, &format!("{}: `{}`", msg, c))
+                .span_label(span, msg)
+                .emit();
         }
         EscapeError::OverlongUnicodeEscape => {
-            handler.span_err(span, "overlong unicode escape (must have at most 6 hex digits)")
-        }
-        EscapeError::UnclosedUnicodeEscape => {
-            handler.span_err(span, "unterminated unicode escape (needed a `}`)")
+            handler
+                .struct_span_err(span, "overlong unicode escape")
+                .span_label(span, "must have at most 6 hex digits")
+                .emit();
         }
+        EscapeError::UnclosedUnicodeEscape => handler
+            .struct_span_err(span, "unterminated unicode escape")
+            .span_label(span, "missing a closing `}`")
+            .span_suggestion_verbose(
+                span.shrink_to_hi(),
+                "terminate the unicode escape",
+                "}".to_string(),
+                Applicability::MaybeIncorrect,
+            )
+            .emit(),
         EscapeError::NoBraceInUnicodeEscape => {
             let msg = "incorrect unicode escape sequence";
             let mut diag = handler.struct_span_err(span, msg);
@@ -195,28 +231,38 @@ pub(crate) fn emit_unescape_error(
 
             diag.emit();
         }
-        EscapeError::UnicodeEscapeInByte => handler.span_err(
-            span,
-            "unicode escape sequences cannot be used \
-                                    as a byte or in a byte string",
-        ),
+        EscapeError::UnicodeEscapeInByte => {
+            let msg = "unicode escape in byte string";
+            handler
+                .struct_span_err(span, msg)
+                .span_label(span, msg)
+                .help("unicode escape sequences cannot be used as a byte or in a byte string")
+                .emit();
+        }
         EscapeError::EmptyUnicodeEscape => {
-            handler.span_err(span, "empty unicode escape (must have at least 1 hex digit)")
+            handler
+                .struct_span_err(span, "empty unicode escape")
+                .span_label(span, "this escape must have at least 1 hex digit")
+                .emit();
+        }
+        EscapeError::ZeroChars => {
+            let msg = "empty character literal";
+            handler.struct_span_err(span, msg).span_label(span, msg).emit()
+        }
+        EscapeError::LoneSlash => {
+            let msg = "invalid trailing slash in literal";
+            handler.struct_span_err(span, msg).span_label(span, msg).emit();
         }
-        EscapeError::ZeroChars => handler.span_err(span, "empty character literal"),
-        EscapeError::LoneSlash => handler.span_err(span, "invalid trailing slash in literal"),
     }
 }
 
 /// Pushes a character to a message string for error reporting
-pub(crate) fn push_escaped_char(msg: &mut String, c: char) {
+pub(crate) fn escaped_char(c: char) -> String {
     match c {
         '\u{20}'..='\u{7e}' => {
             // Don't escape \, ' or " for user-facing messages
-            msg.push(c);
-        }
-        _ => {
-            msg.extend(c.escape_default());
+            c.to_string()
         }
+        _ => c.escape_default().to_string(),
     }
 }
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 1b26fb33370..95d4a48b845 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,4 +1,4 @@
-use super::{Parser, PathStyle};
+use super::{AttrWrapper, Parser, PathStyle};
 use rustc_ast as ast;
 use rustc_ast::attr;
 use rustc_ast::token::{self, Nonterminal};
@@ -26,7 +26,7 @@ pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPo
 
 impl<'a> Parser<'a> {
     /// Parses attributes that appear before an item.
-    pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> {
+    pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> {
         let mut attrs: Vec<ast::Attribute> = Vec::new();
         let mut just_parsed_doc_comment = false;
         loop {
@@ -74,7 +74,7 @@ impl<'a> Parser<'a> {
                 break;
             }
         }
-        Ok(attrs)
+        Ok(AttrWrapper::new(attrs))
     }
 
     /// Matches `attribute = # ! [ meta_item ]`.
@@ -89,7 +89,8 @@ impl<'a> Parser<'a> {
             inner_parse_policy, self.token
         );
         let lo = self.token.span;
-        self.collect_tokens(|this| {
+        // Attributse can't have attributes of their own
+        self.collect_tokens_no_attrs(|this| {
             if this.eat(&token::Pound) {
                 let style = if this.eat(&token::Not) {
                     ast::AttrStyle::Inner
@@ -163,7 +164,8 @@ impl<'a> Parser<'a> {
                 let args = this.parse_attr_args()?;
                 Ok(ast::AttrItem { path, args, tokens: None })
             };
-            if capture_tokens { self.collect_tokens(do_parse) } else { do_parse(self) }?
+            // Attr items don't have attributes
+            if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) }?
         })
     }
 
@@ -306,13 +308,11 @@ impl<'a> Parser<'a> {
 }
 
 pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool {
-    // One of the attributes may either itself be a macro, or apply derive macros (`derive`),
+    // One of the attributes may either itself be a macro,
     // or expand to macro attributes (`cfg_attr`).
     attrs.iter().any(|attr| {
         attr.ident().map_or(true, |ident| {
-            ident.name == sym::derive
-                || ident.name == sym::cfg_attr
-                || !rustc_feature::is_builtin_attr_name(ident.name)
+            ident.name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(ident.name)
         })
     })
 }
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
new file mode 100644
index 00000000000..aea7c6b42cf
--- /dev/null
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -0,0 +1,185 @@
+use super::attr;
+use super::{ForceCollect, Parser, TokenCursor, TrailingToken};
+use rustc_ast::token::{self, Token, TokenKind};
+use rustc_ast::tokenstream::{CreateTokenStream, TokenStream, TokenTree, TreeAndSpacing};
+use rustc_ast::tokenstream::{DelimSpan, LazyTokenStream, Spacing};
+use rustc_ast::HasTokens;
+use rustc_ast::{self as ast};
+use rustc_errors::PResult;
+use rustc_span::{Span, DUMMY_SP};
+
+/// A wrapper type to ensure that the parser handles outer attributes correctly.
+/// When we parse outer attributes, we need to ensure that we capture tokens
+/// for the attribute target. This allows us to perform cfg-expansion on
+/// a token stream before we invoke a derive proc-macro.
+///
+/// This wrapper prevents direct access to the underlying `Vec<ast::Attribute>`.
+/// Parsing code can only get access to the underlying attributes
+/// by passing an `AttrWrapper` to `collect_tokens_trailing_tokens`.
+/// This makes it difficult to accidentally construct an AST node
+/// (which stores a `Vec<ast::Attribute>`) without first collecting tokens.
+///
+/// This struct has its own module, to ensure that the parser code
+/// cannot directly access the `attrs` field
+#[derive(Debug, Clone)]
+pub struct AttrWrapper {
+    attrs: Vec<ast::Attribute>,
+}
+
+impl AttrWrapper {
+    pub fn empty() -> AttrWrapper {
+        AttrWrapper { attrs: vec![] }
+    }
+    pub fn new(attrs: Vec<ast::Attribute>) -> AttrWrapper {
+        AttrWrapper { attrs }
+    }
+    // FIXME: Delay span bug here?
+    pub(crate) fn take_for_recovery(self) -> Vec<ast::Attribute> {
+        self.attrs
+    }
+    pub fn is_empty(&self) -> bool {
+        self.attrs.is_empty()
+    }
+}
+
+impl<'a> Parser<'a> {
+    /// Records all tokens consumed by the provided callback,
+    /// including the current token. These tokens are collected
+    /// into a `LazyTokenStream`, and returned along with the result
+    /// of the callback.
+    ///
+    /// Note: If your callback consumes an opening delimiter
+    /// (including the case where you call `collect_tokens`
+    /// when the current token is an opening delimeter),
+    /// you must also consume the corresponding closing delimiter.
+    ///
+    /// That is, you can consume
+    /// `something ([{ }])` or `([{}])`, but not `([{}]`
+    ///
+    /// This restriction shouldn't be an issue in practice,
+    /// since this function is used to record the tokens for
+    /// a parsed AST item, which always has matching delimiters.
+    pub fn collect_tokens_trailing_token<R: HasTokens>(
+        &mut self,
+        attrs: AttrWrapper,
+        force_collect: ForceCollect,
+        f: impl FnOnce(&mut Self, Vec<ast::Attribute>) -> PResult<'a, (R, TrailingToken)>,
+    ) -> PResult<'a, R> {
+        if matches!(force_collect, ForceCollect::No) && !attr::maybe_needs_tokens(&attrs.attrs) {
+            return Ok(f(self, attrs.attrs)?.0);
+        }
+        let start_token = (self.token.clone(), self.token_spacing);
+        let cursor_snapshot = self.token_cursor.clone();
+
+        let (mut ret, trailing_token) = f(self, attrs.attrs)?;
+
+        // Produces a `TokenStream` on-demand. Using `cursor_snapshot`
+        // and `num_calls`, we can reconstruct the `TokenStream` seen
+        // by the callback. This allows us to avoid producing a `TokenStream`
+        // if it is never needed - for example, a captured `macro_rules!`
+        // argument that is never passed to a proc macro.
+        // In practice token stream creation happens rarely compared to
+        // calls to `collect_tokens` (see some statistics in #78736),
+        // so we are doing as little up-front work as possible.
+        //
+        // This also makes `Parser` very cheap to clone, since
+        // there is no intermediate collection buffer to clone.
+        #[derive(Clone)]
+        struct LazyTokenStreamImpl {
+            start_token: (Token, Spacing),
+            cursor_snapshot: TokenCursor,
+            num_calls: usize,
+            desugar_doc_comments: bool,
+            append_unglued_token: Option<TreeAndSpacing>,
+        }
+        impl CreateTokenStream for LazyTokenStreamImpl {
+            fn create_token_stream(&self) -> TokenStream {
+                // The token produced by the final call to `next` or `next_desugared`
+                // was not actually consumed by the callback. The combination
+                // of chaining the initial token and using `take` produces the desired
+                // result - we produce an empty `TokenStream` if no calls were made,
+                // and omit the final token otherwise.
+                let mut cursor_snapshot = self.cursor_snapshot.clone();
+                let tokens = std::iter::once(self.start_token.clone())
+                    .chain((0..self.num_calls).map(|_| {
+                        if self.desugar_doc_comments {
+                            cursor_snapshot.next_desugared()
+                        } else {
+                            cursor_snapshot.next()
+                        }
+                    }))
+                    .take(self.num_calls);
+
+                make_token_stream(tokens, self.append_unglued_token.clone())
+            }
+        }
+
+        let mut num_calls = self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls;
+        match trailing_token {
+            TrailingToken::None => {}
+            TrailingToken::Semi => {
+                assert_eq!(self.token.kind, token::Semi);
+                num_calls += 1;
+            }
+            TrailingToken::MaybeComma => {
+                if self.token.kind == token::Comma {
+                    num_calls += 1;
+                }
+            }
+        }
+
+        let lazy_impl = LazyTokenStreamImpl {
+            start_token,
+            num_calls,
+            cursor_snapshot,
+            desugar_doc_comments: self.desugar_doc_comments,
+            append_unglued_token: self.token_cursor.append_unglued_token.clone(),
+        };
+        ret.finalize_tokens(LazyTokenStream::new(lazy_impl));
+        Ok(ret)
+    }
+}
+
+/// Converts a flattened iterator of tokens (including open and close delimiter tokens)
+/// into a `TokenStream`, creating a `TokenTree::Delimited` for each matching pair
+/// of open and close delims.
+fn make_token_stream(
+    tokens: impl Iterator<Item = (Token, Spacing)>,
+    append_unglued_token: Option<TreeAndSpacing>,
+) -> TokenStream {
+    #[derive(Debug)]
+    struct FrameData {
+        open: Span,
+        inner: Vec<(TokenTree, Spacing)>,
+    }
+    let mut stack = vec![FrameData { open: DUMMY_SP, inner: vec![] }];
+    for (token, spacing) in tokens {
+        match token {
+            Token { kind: TokenKind::OpenDelim(_), span } => {
+                stack.push(FrameData { open: span, inner: vec![] });
+            }
+            Token { kind: TokenKind::CloseDelim(delim), span } => {
+                let frame_data = stack.pop().expect("Token stack was empty!");
+                let dspan = DelimSpan::from_pair(frame_data.open, span);
+                let stream = TokenStream::new(frame_data.inner);
+                let delimited = TokenTree::Delimited(dspan, delim, stream);
+                stack
+                    .last_mut()
+                    .unwrap_or_else(|| panic!("Bottom token frame is missing for tokens!"))
+                    .inner
+                    .push((delimited, Spacing::Alone));
+            }
+            token => {
+                stack
+                    .last_mut()
+                    .expect("Bottom token frame is missing!")
+                    .inner
+                    .push((TokenTree::Token(token), spacing));
+            }
+        }
+    }
+    let mut final_buf = stack.pop().expect("Missing final buf!");
+    final_buf.inner.extend(append_unglued_token);
+    assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack);
+    TokenStream::new(final_buf.inner)
+}
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 5512e849c45..0f49386dec0 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -1654,7 +1654,7 @@ impl<'a> Parser<'a> {
     }
 
     pub(super) fn recover_arg_parse(&mut self) -> PResult<'a, (P<ast::Pat>, P<ast::Ty>)> {
-        let pat = self.parse_pat(Some("argument name"))?;
+        let pat = self.parse_pat_no_top_alt(Some("argument name"))?;
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
 
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index cfd7ad48222..fa05df6805f 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1,7 +1,7 @@
 use super::pat::{GateOr, RecoverComma, PARAM_EXPECTED};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
-use super::{BlockMode, Parser, PathStyle, Restrictions, TokenType};
-use super::{SemiColonMode, SeqSep, TokenExpectType};
+use super::{AttrWrapper, BlockMode, ForceCollect, Parser, PathStyle, Restrictions, TokenType};
+use super::{SemiColonMode, SeqSep, TokenExpectType, TrailingToken};
 use crate::maybe_recover_from_interpolated_ty_qpath;
 
 use rustc_ast::ptr::P;
@@ -62,16 +62,16 @@ macro_rules! maybe_whole_expr {
 #[derive(Debug)]
 pub(super) enum LhsExpr {
     NotYetParsed,
-    AttributesParsed(AttrVec),
+    AttributesParsed(AttrWrapper),
     AlreadyParsed(P<Expr>),
 }
 
-impl From<Option<AttrVec>> for LhsExpr {
+impl From<Option<AttrWrapper>> for LhsExpr {
     /// Converts `Some(attrs)` into `LhsExpr::AttributesParsed(attrs)`
     /// and `None` into `LhsExpr::NotYetParsed`.
     ///
     /// This conversion does not allocate.
-    fn from(o: Option<AttrVec>) -> Self {
+    fn from(o: Option<AttrWrapper>) -> Self {
         if let Some(attrs) = o { LhsExpr::AttributesParsed(attrs) } else { LhsExpr::NotYetParsed }
     }
 }
@@ -123,7 +123,7 @@ impl<'a> Parser<'a> {
     pub(super) fn parse_expr_res(
         &mut self,
         r: Restrictions,
-        already_parsed_attrs: Option<AttrVec>,
+        already_parsed_attrs: Option<AttrWrapper>,
     ) -> PResult<'a, P<Expr>> {
         self.with_res(r, |this| this.parse_assoc_expr(already_parsed_attrs))
     }
@@ -133,7 +133,10 @@ impl<'a> Parser<'a> {
     /// This parses an expression accounting for associativity and precedence of the operators in
     /// the expression.
     #[inline]
-    fn parse_assoc_expr(&mut self, already_parsed_attrs: Option<AttrVec>) -> PResult<'a, P<Expr>> {
+    fn parse_assoc_expr(
+        &mut self,
+        already_parsed_attrs: Option<AttrWrapper>,
+    ) -> PResult<'a, P<Expr>> {
         self.parse_assoc_expr_with(0, already_parsed_attrs.into())
     }
 
@@ -439,7 +442,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses prefix-forms of range notation: `..expr`, `..`, `..=expr`.
-    fn parse_prefix_range_expr(&mut self, attrs: Option<AttrVec>) -> PResult<'a, P<Expr>> {
+    fn parse_prefix_range_expr(&mut self, attrs: Option<AttrWrapper>) -> PResult<'a, P<Expr>> {
         // Check for deprecated `...` syntax.
         if self.token == token::DotDotDot {
             self.err_dotdotdot_syntax(self.token.span);
@@ -456,45 +459,62 @@ impl<'a> Parser<'a> {
             _ => RangeLimits::Closed,
         };
         let op = AssocOp::from_token(&self.token);
+        // FIXME: `parse_prefix_range_expr` is called when the current
+        // token is `DotDot`, `DotDotDot`, or `DotDotEq`. If we haven't already
+        // parsed attributes, then trying to parse them here will always fail.
+        // We should figure out how we want attributes on range expressions to work.
         let attrs = self.parse_or_use_outer_attributes(attrs)?;
-        let lo = self.token.span;
-        self.bump();
-        let (span, opt_end) = if self.is_at_start_of_range_notation_rhs() {
-            // RHS must be parsed with more associativity than the dots.
-            self.parse_assoc_expr_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed)
-                .map(|x| (lo.to(x.span), Some(x)))?
-        } else {
-            (lo, None)
-        };
-        Ok(self.mk_expr(span, self.mk_range(None, opt_end, limits)?, attrs))
+        self.collect_tokens_for_expr(attrs, |this, attrs| {
+            let lo = this.token.span;
+            this.bump();
+            let (span, opt_end) = if this.is_at_start_of_range_notation_rhs() {
+                // RHS must be parsed with more associativity than the dots.
+                this.parse_assoc_expr_with(op.unwrap().precedence() + 1, LhsExpr::NotYetParsed)
+                    .map(|x| (lo.to(x.span), Some(x)))?
+            } else {
+                (lo, None)
+            };
+            Ok(this.mk_expr(span, this.mk_range(None, opt_end, limits)?, attrs.into()))
+        })
     }
 
     /// Parses a prefix-unary-operator expr.
-    fn parse_prefix_expr(&mut self, attrs: Option<AttrVec>) -> PResult<'a, P<Expr>> {
+    fn parse_prefix_expr(&mut self, attrs: Option<AttrWrapper>) -> PResult<'a, P<Expr>> {
         let attrs = self.parse_or_use_outer_attributes(attrs)?;
-        // FIXME: Use super::attr::maybe_needs_tokens(&attrs) once we come up
-        // with a good way of passing `force_tokens` through from `parse_nonterminal`.
-        // Checking !attrs.is_empty() is correct, but will cause us to unnecessarily
-        // capture tokens in some circumstances.
-        let needs_tokens = !attrs.is_empty();
-        let do_parse = |this: &mut Parser<'a>| {
-            let lo = this.token.span;
-            // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
-            let (hi, ex) = match this.token.uninterpolate().kind {
-                token::Not => this.parse_unary_expr(lo, UnOp::Not), // `!expr`
-                token::Tilde => this.recover_tilde_expr(lo),        // `~expr`
-                token::BinOp(token::Minus) => this.parse_unary_expr(lo, UnOp::Neg), // `-expr`
-                token::BinOp(token::Star) => this.parse_unary_expr(lo, UnOp::Deref), // `*expr`
-                token::BinOp(token::And) | token::AndAnd => this.parse_borrow_expr(lo),
-                token::Ident(..) if this.token.is_keyword(kw::Box) => this.parse_box_expr(lo),
-                token::Ident(..) if this.is_mistaken_not_ident_negation() => {
-                    this.recover_not_expr(lo)
-                }
-                _ => return this.parse_dot_or_call_expr(Some(attrs)),
-            }?;
-            Ok(this.mk_expr(lo.to(hi), ex, attrs))
-        };
-        if needs_tokens { self.collect_tokens(do_parse) } else { do_parse(self) }
+        let lo = self.token.span;
+
+        macro_rules! make_it {
+            ($this:ident, $attrs:expr, |this, _| $body:expr) => {
+                $this.collect_tokens_for_expr($attrs, |$this, attrs| {
+                    let (hi, ex) = $body?;
+                    Ok($this.mk_expr(lo.to(hi), ex, attrs.into()))
+                })
+            };
+        }
+
+        let this = self;
+
+        // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr()
+        match this.token.uninterpolate().kind {
+            token::Not => make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Not)), // `!expr`
+            token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)), // `~expr`
+            token::BinOp(token::Minus) => {
+                make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Neg))
+            } // `-expr`
+            token::BinOp(token::Star) => {
+                make_it!(this, attrs, |this, _| this.parse_unary_expr(lo, UnOp::Deref))
+            } // `*expr`
+            token::BinOp(token::And) | token::AndAnd => {
+                make_it!(this, attrs, |this, _| this.parse_borrow_expr(lo))
+            }
+            token::Ident(..) if this.token.is_keyword(kw::Box) => {
+                make_it!(this, attrs, |this, _| this.parse_box_expr(lo))
+            }
+            token::Ident(..) if this.is_mistaken_not_ident_negation() => {
+                make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
+            }
+            _ => return this.parse_dot_or_call_expr(Some(attrs)),
+        }
     }
 
     fn parse_prefix_expr_common(&mut self, lo: Span) -> PResult<'a, (Span, P<Expr>)> {
@@ -805,18 +825,20 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses `a.b` or `a(13)` or `a[4]` or just `a`.
-    fn parse_dot_or_call_expr(&mut self, attrs: Option<AttrVec>) -> PResult<'a, P<Expr>> {
+    fn parse_dot_or_call_expr(&mut self, attrs: Option<AttrWrapper>) -> PResult<'a, P<Expr>> {
         let attrs = self.parse_or_use_outer_attributes(attrs)?;
-        let base = self.parse_bottom_expr();
-        let (span, base) = self.interpolated_or_expr_span(base)?;
-        self.parse_dot_or_call_expr_with(base, span, attrs)
+        self.collect_tokens_for_expr(attrs, |this, attrs| {
+            let base = this.parse_bottom_expr();
+            let (span, base) = this.interpolated_or_expr_span(base)?;
+            this.parse_dot_or_call_expr_with(base, span, attrs)
+        })
     }
 
     pub(super) fn parse_dot_or_call_expr_with(
         &mut self,
         e0: P<Expr>,
         lo: Span,
-        mut attrs: AttrVec,
+        mut attrs: Vec<ast::Attribute>,
     ) -> PResult<'a, P<Expr>> {
         // Stitch the list of outer attributes onto the return value.
         // A little bit ugly, but the best way given the current code
@@ -824,7 +846,7 @@ impl<'a> Parser<'a> {
         self.parse_dot_or_call_expr_with_(e0, lo).map(|expr| {
             expr.map(|mut expr| {
                 attrs.extend::<Vec<_>>(expr.attrs.into());
-                expr.attrs = attrs;
+                expr.attrs = attrs.into();
                 expr
             })
         })
@@ -1703,19 +1725,25 @@ impl<'a> Parser<'a> {
     fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
         let lo = self.token.span;
         let attrs = self.parse_outer_attributes()?;
-        let pat = self.parse_pat(PARAM_EXPECTED)?;
-        let ty = if self.eat(&token::Colon) {
-            self.parse_ty()?
-        } else {
-            self.mk_ty(self.prev_token.span, TyKind::Infer)
-        };
-        Ok(Param {
-            attrs: attrs.into(),
-            ty,
-            pat,
-            span: lo.to(self.token.span),
-            id: DUMMY_NODE_ID,
-            is_placeholder: false,
+        self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+            let pat = this.parse_pat_no_top_alt(PARAM_EXPECTED)?;
+            let ty = if this.eat(&token::Colon) {
+                this.parse_ty()?
+            } else {
+                this.mk_ty(this.prev_token.span, TyKind::Infer)
+            };
+
+            Ok((
+                Param {
+                    attrs: attrs.into(),
+                    ty,
+                    pat,
+                    span: lo.to(this.token.span),
+                    id: DUMMY_NODE_ID,
+                    is_placeholder: false,
+                },
+                TrailingToken::MaybeComma,
+            ))
         })
     }
 
@@ -1731,7 +1759,7 @@ impl<'a> Parser<'a> {
         let thn = if self.eat_keyword(kw::Else) || !cond.returns() {
             self.error_missing_if_cond(lo, cond.span)
         } else {
-            let attrs = self.parse_outer_attributes()?; // For recovery.
+            let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
             let not_block = self.token != token::OpenDelim(token::Brace);
             let block = self.parse_block().map_err(|mut err| {
                 if not_block {
@@ -1775,7 +1803,7 @@ impl<'a> Parser<'a> {
     /// The `let` token has already been eaten.
     fn parse_let_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> {
         let lo = self.prev_token.span;
-        let pat = self.parse_top_pat(GateOr::No, RecoverComma::Yes)?;
+        let pat = self.parse_pat_allow_top_alt(None, GateOr::No, RecoverComma::Yes)?;
         self.expect(&token::Eq)?;
         let expr = self.with_res(self.restrictions | Restrictions::NO_STRUCT_LITERAL, |this| {
             this.parse_assoc_expr_with(1 + prec_let_scrutinee_needs_par(), None.into())
@@ -1788,7 +1816,7 @@ impl<'a> Parser<'a> {
     /// Parses an `else { ... }` expression (`else` token already eaten).
     fn parse_else_expr(&mut self) -> PResult<'a, P<Expr>> {
         let ctx_span = self.prev_token.span; // `else`
-        let attrs = self.parse_outer_attributes()?; // For recovery.
+        let attrs = self.parse_outer_attributes()?.take_for_recovery(); // For recovery.
         let expr = if self.eat_keyword(kw::If) {
             self.parse_if_expr(AttrVec::new())?
         } else {
@@ -1838,7 +1866,7 @@ impl<'a> Parser<'a> {
             _ => None,
         };
 
-        let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?;
+        let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::Yes)?;
         if !self.eat_keyword(kw::In) {
             self.error_missing_in_for_loop();
         }
@@ -1947,85 +1975,91 @@ impl<'a> Parser<'a> {
 
     pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
         let attrs = self.parse_outer_attributes()?;
-        let lo = self.token.span;
-        let pat = self.parse_top_pat(GateOr::No, RecoverComma::Yes)?;
-        let guard = if self.eat_keyword(kw::If) {
-            let if_span = self.prev_token.span;
-            let cond = self.parse_expr()?;
-            if let ExprKind::Let(..) = cond.kind {
-                // Remove the last feature gating of a `let` expression since it's stable.
-                self.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
-                let span = if_span.to(cond.span);
-                self.sess.gated_spans.gate(sym::if_let_guard, span);
-            }
-            Some(cond)
-        } else {
-            None
-        };
-        let arrow_span = self.token.span;
-        self.expect(&token::FatArrow)?;
-        let arm_start_span = self.token.span;
+        self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+            let lo = this.token.span;
+            let pat = this.parse_pat_allow_top_alt(None, GateOr::No, RecoverComma::Yes)?;
+            let guard = if this.eat_keyword(kw::If) {
+                let if_span = this.prev_token.span;
+                let cond = this.parse_expr()?;
+                if let ExprKind::Let(..) = cond.kind {
+                    // Remove the last feature gating of a `let` expression since it's stable.
+                    this.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
+                    let span = if_span.to(cond.span);
+                    this.sess.gated_spans.gate(sym::if_let_guard, span);
+                }
+                Some(cond)
+            } else {
+                None
+            };
+            let arrow_span = this.token.span;
+            this.expect(&token::FatArrow)?;
+            let arm_start_span = this.token.span;
 
-        let expr = self.parse_expr_res(Restrictions::STMT_EXPR, None).map_err(|mut err| {
-            err.span_label(arrow_span, "while parsing the `match` arm starting here");
-            err
-        })?;
+            let expr = this.parse_expr_res(Restrictions::STMT_EXPR, None).map_err(|mut err| {
+                err.span_label(arrow_span, "while parsing the `match` arm starting here");
+                err
+            })?;
 
-        let require_comma = classify::expr_requires_semi_to_be_stmt(&expr)
-            && self.token != token::CloseDelim(token::Brace);
-
-        let hi = self.prev_token.span;
-
-        if require_comma {
-            let sm = self.sess.source_map();
-            self.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)]).map_err(
-                |mut err| {
-                    match (sm.span_to_lines(expr.span), sm.span_to_lines(arm_start_span)) {
-                        (Ok(ref expr_lines), Ok(ref arm_start_lines))
-                            if arm_start_lines.lines[0].end_col == expr_lines.lines[0].end_col
-                                && expr_lines.lines.len() == 2
-                                && self.token == token::FatArrow =>
-                        {
-                            // We check whether there's any trailing code in the parse span,
-                            // if there isn't, we very likely have the following:
-                            //
-                            // X |     &Y => "y"
-                            //   |        --    - missing comma
-                            //   |        |
-                            //   |        arrow_span
-                            // X |     &X => "x"
-                            //   |      - ^^ self.token.span
-                            //   |      |
-                            //   |      parsed until here as `"y" & X`
-                            err.span_suggestion_short(
-                                arm_start_span.shrink_to_hi(),
-                                "missing a comma here to end this `match` arm",
-                                ",".to_owned(),
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                        _ => {
-                            err.span_label(
-                                arrow_span,
-                                "while parsing the `match` arm starting here",
-                            );
+            let require_comma = classify::expr_requires_semi_to_be_stmt(&expr)
+                && this.token != token::CloseDelim(token::Brace);
+
+            let hi = this.prev_token.span;
+
+            if require_comma {
+                let sm = this.sess.source_map();
+                this.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Brace)]).map_err(
+                    |mut err| {
+                        match (sm.span_to_lines(expr.span), sm.span_to_lines(arm_start_span)) {
+                            (Ok(ref expr_lines), Ok(ref arm_start_lines))
+                                if arm_start_lines.lines[0].end_col
+                                    == expr_lines.lines[0].end_col
+                                    && expr_lines.lines.len() == 2
+                                    && this.token == token::FatArrow =>
+                            {
+                                // We check whether there's any trailing code in the parse span,
+                                // if there isn't, we very likely have the following:
+                                //
+                                // X |     &Y => "y"
+                                //   |        --    - missing comma
+                                //   |        |
+                                //   |        arrow_span
+                                // X |     &X => "x"
+                                //   |      - ^^ self.token.span
+                                //   |      |
+                                //   |      parsed until here as `"y" & X`
+                                err.span_suggestion_short(
+                                    arm_start_span.shrink_to_hi(),
+                                    "missing a comma here to end this `match` arm",
+                                    ",".to_owned(),
+                                    Applicability::MachineApplicable,
+                                );
+                            }
+                            _ => {
+                                err.span_label(
+                                    arrow_span,
+                                    "while parsing the `match` arm starting here",
+                                );
+                            }
                         }
-                    }
-                    err
-                },
-            )?;
-        } else {
-            self.eat(&token::Comma);
-        }
+                        err
+                    },
+                )?;
+            } else {
+                this.eat(&token::Comma);
+            }
 
-        Ok(ast::Arm {
-            attrs,
-            pat,
-            guard,
-            body: expr,
-            span: lo.to(hi),
-            id: DUMMY_NODE_ID,
-            is_placeholder: false,
+            Ok((
+                ast::Arm {
+                    attrs,
+                    pat,
+                    guard,
+                    body: expr,
+                    span: lo.to(hi),
+                    id: DUMMY_NODE_ID,
+                    is_placeholder: false,
+                },
+                TrailingToken::None,
+            ))
         })
     }
 
@@ -2274,30 +2308,36 @@ impl<'a> Parser<'a> {
 
     /// Parses `ident (COLON expr)?`.
     fn parse_field(&mut self) -> PResult<'a, Field> {
-        let attrs = self.parse_outer_attributes()?.into();
-        let lo = self.token.span;
+        let attrs = self.parse_outer_attributes()?;
+        self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+            let lo = this.token.span;
 
-        // Check if a colon exists one ahead. This means we're parsing a fieldname.
-        let is_shorthand = !self.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
-        let (ident, expr) = if is_shorthand {
-            // Mimic `x: x` for the `x` field shorthand.
-            let ident = self.parse_ident_common(false)?;
-            let path = ast::Path::from_ident(ident);
-            (ident, self.mk_expr(ident.span, ExprKind::Path(None, path), AttrVec::new()))
-        } else {
-            let ident = self.parse_field_name()?;
-            self.error_on_eq_field_init(ident);
-            self.bump(); // `:`
-            (ident, self.parse_expr()?)
-        };
-        Ok(ast::Field {
-            ident,
-            span: lo.to(expr.span),
-            expr,
-            is_shorthand,
-            attrs,
-            id: DUMMY_NODE_ID,
-            is_placeholder: false,
+            // Check if a colon exists one ahead. This means we're parsing a fieldname.
+            let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq);
+            let (ident, expr) = if is_shorthand {
+                // Mimic `x: x` for the `x` field shorthand.
+                let ident = this.parse_ident_common(false)?;
+                let path = ast::Path::from_ident(ident);
+                (ident, this.mk_expr(ident.span, ExprKind::Path(None, path), AttrVec::new()))
+            } else {
+                let ident = this.parse_field_name()?;
+                this.error_on_eq_field_init(ident);
+                this.bump(); // `:`
+                (ident, this.parse_expr()?)
+            };
+
+            Ok((
+                ast::Field {
+                    ident,
+                    span: lo.to(expr.span),
+                    expr,
+                    is_shorthand,
+                    attrs: attrs.into(),
+                    id: DUMMY_NODE_ID,
+                    is_placeholder: false,
+                },
+                TrailingToken::MaybeComma,
+            ))
         })
     }
 
@@ -2405,4 +2445,27 @@ impl<'a> Parser<'a> {
             .map_or(lhs_span, |a| a.span)
             .to(rhs_span)
     }
+
+    fn collect_tokens_for_expr(
+        &mut self,
+        attrs: AttrWrapper,
+        f: impl FnOnce(&mut Self, Vec<ast::Attribute>) -> PResult<'a, P<Expr>>,
+    ) -> PResult<'a, P<Expr>> {
+        // FIXME - come up with a nice way to properly forward `ForceCollect`from
+        // the nonterminal parsing code. TThis approach iscorrect, but will cause
+        // us to unnecessarily capture tokens for exprs that have only builtin
+        // attributes. Revisit this before #![feature(stmt_expr_attributes)] is stabilized
+        let force_collect = if attrs.is_empty() { ForceCollect::No } else { ForceCollect::Yes };
+        self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
+            let res = f(this, attrs)?;
+            let trailing = if this.restrictions.contains(Restrictions::STMT_EXPR)
+                && this.token.kind == token::Semi
+            {
+                TrailingToken::Semi
+            } else {
+                TrailingToken::None
+            };
+            Ok((res, trailing))
+        })
+    }
 }
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 42a13376863..f175c5b50b3 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -1,4 +1,4 @@
-use super::Parser;
+use super::{ForceCollect, Parser, TrailingToken};
 
 use rustc_ast::token;
 use rustc_ast::{
@@ -84,68 +84,89 @@ impl<'a> Parser<'a> {
     /// a trailing comma and erroneous trailing attributes.
     pub(super) fn parse_generic_params(&mut self) -> PResult<'a, Vec<ast::GenericParam>> {
         let mut params = Vec::new();
-        loop {
+        let mut done = false;
+        while !done {
             let attrs = self.parse_outer_attributes()?;
-            if self.check_lifetime() {
-                let lifetime = self.expect_lifetime();
-                // Parse lifetime parameter.
-                let bounds =
-                    if self.eat(&token::Colon) { self.parse_lt_param_bounds() } else { Vec::new() };
-                params.push(ast::GenericParam {
-                    ident: lifetime.ident,
-                    id: lifetime.id,
-                    attrs: attrs.into(),
-                    bounds,
-                    kind: ast::GenericParamKind::Lifetime,
-                    is_placeholder: false,
-                });
-            } else if self.check_keyword(kw::Const) {
-                // Parse const parameter.
-                params.push(self.parse_const_param(attrs)?);
-            } else if self.check_ident() {
-                // Parse type parameter.
-                params.push(self.parse_ty_param(attrs)?);
-            } else if self.token.can_begin_type() {
-                // Trying to write an associated type bound? (#26271)
-                let snapshot = self.clone();
-                match self.parse_ty_where_predicate() {
-                    Ok(where_predicate) => {
-                        self.struct_span_err(
-                            where_predicate.span(),
-                            "bounds on associated types do not belong here",
-                        )
-                        .span_label(where_predicate.span(), "belongs in `where` clause")
-                        .emit();
-                    }
-                    Err(mut err) => {
-                        err.cancel();
-                        *self = snapshot;
-                        break;
-                    }
-                }
-            } else {
-                // Check for trailing attributes and stop parsing.
-                if !attrs.is_empty() {
-                    if !params.is_empty() {
-                        self.struct_span_err(
-                            attrs[0].span,
-                            "trailing attribute after generic parameter",
-                        )
-                        .span_label(attrs[0].span, "attributes must go before parameters")
-                        .emit();
+            let param =
+                self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+                    let param = if this.check_lifetime() {
+                        let lifetime = this.expect_lifetime();
+                        // Parse lifetime parameter.
+                        let bounds = if this.eat(&token::Colon) {
+                            this.parse_lt_param_bounds()
+                        } else {
+                            Vec::new()
+                        };
+                        Some(ast::GenericParam {
+                            ident: lifetime.ident,
+                            id: lifetime.id,
+                            attrs: attrs.into(),
+                            bounds,
+                            kind: ast::GenericParamKind::Lifetime,
+                            is_placeholder: false,
+                        })
+                    } else if this.check_keyword(kw::Const) {
+                        // Parse const parameter.
+                        Some(this.parse_const_param(attrs)?)
+                    } else if this.check_ident() {
+                        // Parse type parameter.
+                        Some(this.parse_ty_param(attrs)?)
+                    } else if this.token.can_begin_type() {
+                        // Trying to write an associated type bound? (#26271)
+                        let snapshot = this.clone();
+                        match this.parse_ty_where_predicate() {
+                            Ok(where_predicate) => {
+                                this.struct_span_err(
+                                    where_predicate.span(),
+                                    "bounds on associated types do not belong here",
+                                )
+                                .span_label(where_predicate.span(), "belongs in `where` clause")
+                                .emit();
+                                // FIXME - try to continue parsing other generics?
+                                return Ok((None, TrailingToken::None));
+                            }
+                            Err(mut err) => {
+                                err.cancel();
+                                // FIXME - maybe we should overwrite 'self' outside of `collect_tokens`?
+                                *this = snapshot;
+                                return Ok((None, TrailingToken::None));
+                            }
+                        }
                     } else {
-                        self.struct_span_err(attrs[0].span, "attribute without generic parameters")
-                            .span_label(
-                                attrs[0].span,
-                                "attributes are only permitted when preceding parameters",
-                            )
-                            .emit();
+                        // Check for trailing attributes and stop parsing.
+                        if !attrs.is_empty() {
+                            if !params.is_empty() {
+                                this.struct_span_err(
+                                    attrs[0].span,
+                                    "trailing attribute after generic parameter",
+                                )
+                                .span_label(attrs[0].span, "attributes must go before parameters")
+                                .emit();
+                            } else {
+                                this.struct_span_err(
+                                    attrs[0].span,
+                                    "attribute without generic parameters",
+                                )
+                                .span_label(
+                                    attrs[0].span,
+                                    "attributes are only permitted when preceding parameters",
+                                )
+                                .emit();
+                            }
+                        }
+                        return Ok((None, TrailingToken::None));
+                    };
+
+                    if !this.eat(&token::Comma) {
+                        done = true;
                     }
-                }
-                break;
-            }
+                    // We just ate the comma, so no need to use `TrailingToken`
+                    Ok((param, TrailingToken::None))
+                })?;
 
-            if !self.eat(&token::Comma) {
+            if let Some(param) = param {
+                params.push(param);
+            } else {
                 break;
             }
         }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index c44ccfadda5..0f907859a19 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1,8 +1,6 @@
 use super::diagnostics::{dummy_arg, ConsumeClosingDelim, Error};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
-use super::{FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
-
-use crate::{maybe_collect_tokens, maybe_whole};
+use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken};
 
 use rustc_ast::ast::*;
 use rustc_ast::ptr::P;
@@ -27,11 +25,9 @@ use tracing::debug;
 impl<'a> Parser<'a> {
     /// Parses a source module as a crate. This is the main entry point for the parser.
     pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
-        let lo = self.token.span;
-        let (module, attrs) = self.parse_mod(&token::Eof, Unsafe::No)?;
-        let span = lo.to(self.token.span);
+        let (attrs, items, span) = self.parse_mod(&token::Eof)?;
         let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`.
-        Ok(ast::Crate { attrs, module, span, proc_macros })
+        Ok(ast::Crate { attrs, items, span, proc_macros })
     }
 
     /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
@@ -39,35 +35,26 @@ impl<'a> Parser<'a> {
         let unsafety = self.parse_unsafety();
         self.expect_keyword(kw::Mod)?;
         let id = self.parse_ident()?;
-        let (module, mut inner_attrs) = if self.eat(&token::Semi) {
-            (Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }, Vec::new())
+        let mod_kind = if self.eat(&token::Semi) {
+            ModKind::Unloaded
         } else {
             self.expect(&token::OpenDelim(token::Brace))?;
-            self.parse_mod(&token::CloseDelim(token::Brace), unsafety)?
+            let (mut inner_attrs, items, inner_span) =
+                self.parse_mod(&token::CloseDelim(token::Brace))?;
+            attrs.append(&mut inner_attrs);
+            ModKind::Loaded(items, Inline::Yes, inner_span)
         };
-        attrs.append(&mut inner_attrs);
-        Ok((id, ItemKind::Mod(module)))
+        Ok((id, ItemKind::Mod(unsafety, mod_kind)))
     }
 
     /// Parses the contents of a module (inner attributes followed by module items).
     pub fn parse_mod(
         &mut self,
         term: &TokenKind,
-        unsafety: Unsafe,
-    ) -> PResult<'a, (Mod, Vec<Attribute>)> {
+    ) -> PResult<'a, (Vec<Attribute>, Vec<P<Item>>, Span)> {
         let lo = self.token.span;
         let attrs = self.parse_inner_attributes()?;
-        let module = self.parse_mod_items(term, lo, unsafety)?;
-        Ok((module, attrs))
-    }
 
-    /// Given a termination token, parses all of the items in a module.
-    fn parse_mod_items(
-        &mut self,
-        term: &TokenKind,
-        inner_lo: Span,
-        unsafety: Unsafe,
-    ) -> PResult<'a, Mod> {
         let mut items = vec![];
         while let Some(item) = self.parse_item(ForceCollect::No)? {
             items.push(item);
@@ -84,9 +71,7 @@ impl<'a> Parser<'a> {
             }
         }
 
-        let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span };
-
-        Ok(Mod { inner: inner_lo.to(hi), unsafety, items, inline: true })
+        Ok((attrs, items, lo.to(self.prev_token.span)))
     }
 }
 
@@ -108,25 +93,40 @@ impl<'a> Parser<'a> {
 
     pub(super) fn parse_item_common(
         &mut self,
-        mut attrs: Vec<Attribute>,
+        attrs: AttrWrapper,
         mac_allowed: bool,
         attrs_allowed: bool,
         req_name: ReqName,
         force_collect: ForceCollect,
     ) -> PResult<'a, Option<Item>> {
-        maybe_whole!(self, NtItem, |item| {
-            let mut item = item;
-            mem::swap(&mut item.attrs, &mut attrs);
-            item.attrs.extend(attrs);
-            Some(item.into_inner())
-        });
+        // Don't use `maybe_whole` so that we have precise control
+        // over when we bump the parser
+        if let token::Interpolated(nt) = &self.token.kind {
+            if let token::NtItem(item) = &**nt {
+                let item = item.clone();
+
+                return self.collect_tokens_trailing_token(
+                    attrs,
+                    force_collect,
+                    |this, mut attrs| {
+                        let mut item = item;
+                        mem::swap(&mut item.attrs, &mut attrs);
+                        item.attrs.extend(attrs);
+                        // Bump the parser so the we capture the token::Interpolated
+                        this.bump();
+                        Ok((Some(item.into_inner()), TrailingToken::None))
+                    },
+                );
+            }
+        };
 
         let mut unclosed_delims = vec![];
-        let item = maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Self| {
-            let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
-            unclosed_delims.append(&mut this.unclosed_delims);
-            Ok((item?, TrailingToken::None))
-        })?;
+        let item =
+            self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| {
+                let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, req_name);
+                unclosed_delims.append(&mut this.unclosed_delims);
+                Ok((item?, TrailingToken::None))
+            })?;
 
         self.unclosed_delims.append(&mut unclosed_delims);
         Ok(item)
@@ -1010,9 +1010,18 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, ItemInfo> {
         let impl_span = self.token.span;
         let mut err = self.expected_ident_found();
-        let mut impl_info = self.parse_item_impl(attrs, defaultness)?;
+
+        // Only try to recover if this is implementing a trait for a type
+        let mut impl_info = match self.parse_item_impl(attrs, defaultness) {
+            Ok(impl_info) => impl_info,
+            Err(mut recovery_error) => {
+                // Recovery failed, raise the "expected identifier" error
+                recovery_error.cancel();
+                return Err(err);
+            }
+        };
+
         match impl_info.1 {
-            // only try to recover if this is implementing a trait for a type
             ItemKind::Impl(box ImplKind {
                 of_trait: Some(ref trai), ref mut constness, ..
             }) => {
@@ -1030,6 +1039,7 @@ impl<'a> Parser<'a> {
             ItemKind::Impl { .. } => return Err(err),
             _ => unreachable!(),
         }
+
         Ok(impl_info)
     }
 
@@ -1099,39 +1109,45 @@ impl<'a> Parser<'a> {
 
     fn parse_enum_variant(&mut self) -> PResult<'a, Option<Variant>> {
         let variant_attrs = self.parse_outer_attributes()?;
-        let vlo = self.token.span;
-
-        let vis = self.parse_visibility(FollowedByType::No)?;
-        if !self.recover_nested_adt_item(kw::Enum)? {
-            return Ok(None);
-        }
-        let ident = self.parse_ident()?;
-
-        let struct_def = if self.check(&token::OpenDelim(token::Brace)) {
-            // Parse a struct variant.
-            let (fields, recovered) = self.parse_record_struct_body()?;
-            VariantData::Struct(fields, recovered)
-        } else if self.check(&token::OpenDelim(token::Paren)) {
-            VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID)
-        } else {
-            VariantData::Unit(DUMMY_NODE_ID)
-        };
-
-        let disr_expr =
-            if self.eat(&token::Eq) { Some(self.parse_anon_const_expr()?) } else { None };
+        self.collect_tokens_trailing_token(
+            variant_attrs,
+            ForceCollect::No,
+            |this, variant_attrs| {
+                let vlo = this.token.span;
+
+                let vis = this.parse_visibility(FollowedByType::No)?;
+                if !this.recover_nested_adt_item(kw::Enum)? {
+                    return Ok((None, TrailingToken::None));
+                }
+                let ident = this.parse_ident()?;
+
+                let struct_def = if this.check(&token::OpenDelim(token::Brace)) {
+                    // Parse a struct variant.
+                    let (fields, recovered) = this.parse_record_struct_body()?;
+                    VariantData::Struct(fields, recovered)
+                } else if this.check(&token::OpenDelim(token::Paren)) {
+                    VariantData::Tuple(this.parse_tuple_struct_body()?, DUMMY_NODE_ID)
+                } else {
+                    VariantData::Unit(DUMMY_NODE_ID)
+                };
 
-        let vr = ast::Variant {
-            ident,
-            vis,
-            id: DUMMY_NODE_ID,
-            attrs: variant_attrs,
-            data: struct_def,
-            disr_expr,
-            span: vlo.to(self.prev_token.span),
-            is_placeholder: false,
-        };
+                let disr_expr =
+                    if this.eat(&token::Eq) { Some(this.parse_anon_const_expr()?) } else { None };
+
+                let vr = ast::Variant {
+                    ident,
+                    vis,
+                    id: DUMMY_NODE_ID,
+                    attrs: variant_attrs,
+                    data: struct_def,
+                    disr_expr,
+                    span: vlo.to(this.prev_token.span),
+                    is_placeholder: false,
+                };
 
-        Ok(Some(vr))
+                Ok((Some(vr), TrailingToken::MaybeComma))
+            },
+        )
     }
 
     /// Parses `struct Foo { ... }`.
@@ -1252,17 +1268,23 @@ impl<'a> Parser<'a> {
         // Unit like structs are handled in parse_item_struct function
         self.parse_paren_comma_seq(|p| {
             let attrs = p.parse_outer_attributes()?;
-            let lo = p.token.span;
-            let vis = p.parse_visibility(FollowedByType::Yes)?;
-            let ty = p.parse_ty()?;
-            Ok(StructField {
-                span: lo.to(ty.span),
-                vis,
-                ident: None,
-                id: DUMMY_NODE_ID,
-                ty,
-                attrs,
-                is_placeholder: false,
+            p.collect_tokens_trailing_token(attrs, ForceCollect::No, |p, attrs| {
+                let lo = p.token.span;
+                let vis = p.parse_visibility(FollowedByType::Yes)?;
+                let ty = p.parse_ty()?;
+
+                Ok((
+                    StructField {
+                        span: lo.to(ty.span),
+                        vis,
+                        ident: None,
+                        id: DUMMY_NODE_ID,
+                        ty,
+                        attrs,
+                        is_placeholder: false,
+                    },
+                    TrailingToken::MaybeComma,
+                ))
             })
         })
         .map(|(r, _)| r)
@@ -1271,9 +1293,11 @@ impl<'a> Parser<'a> {
     /// Parses an element of a struct declaration.
     fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> {
         let attrs = self.parse_outer_attributes()?;
-        let lo = self.token.span;
-        let vis = self.parse_visibility(FollowedByType::No)?;
-        self.parse_single_struct_field(lo, vis, attrs)
+        self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+            let lo = this.token.span;
+            let vis = this.parse_visibility(FollowedByType::No)?;
+            Ok((this.parse_single_struct_field(lo, vis, attrs)?, TrailingToken::None))
+        })
     }
 
     /// Parses a structure field declaration.
@@ -1726,74 +1750,79 @@ impl<'a> Parser<'a> {
     fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResult<'a, Param> {
         let lo = self.token.span;
         let attrs = self.parse_outer_attributes()?;
+        self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+            // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
+            if let Some(mut param) = this.parse_self_param()? {
+                param.attrs = attrs.into();
+                let res = if first_param { Ok(param) } else { this.recover_bad_self_param(param) };
+                return Ok((res?, TrailingToken::None));
+            }
 
-        // Possibly parse `self`. Recover if we parsed it and it wasn't allowed here.
-        if let Some(mut param) = self.parse_self_param()? {
-            param.attrs = attrs.into();
-            return if first_param { Ok(param) } else { self.recover_bad_self_param(param) };
-        }
-
-        let is_name_required = match self.token.kind {
-            token::DotDotDot => false,
-            _ => req_name(self.token.span.edition()),
-        };
-        let (pat, ty) = if is_name_required || self.is_named_param() {
-            debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
+            let is_name_required = match this.token.kind {
+                token::DotDotDot => false,
+                _ => req_name(this.token.span.edition()),
+            };
+            let (pat, ty) = if is_name_required || this.is_named_param() {
+                debug!("parse_param_general parse_pat (is_name_required:{})", is_name_required);
+
+                let pat = this.parse_fn_param_pat()?;
+                if let Err(mut err) = this.expect(&token::Colon) {
+                    return if let Some(ident) =
+                        this.parameter_without_type(&mut err, pat, is_name_required, first_param)
+                    {
+                        err.emit();
+                        Ok((dummy_arg(ident), TrailingToken::None))
+                    } else {
+                        Err(err)
+                    };
+                }
 
-            let pat = self.parse_fn_param_pat()?;
-            if let Err(mut err) = self.expect(&token::Colon) {
-                return if let Some(ident) =
-                    self.parameter_without_type(&mut err, pat, is_name_required, first_param)
+                this.eat_incorrect_doc_comment_for_param_type();
+                (pat, this.parse_ty_for_param()?)
+            } else {
+                debug!("parse_param_general ident_to_pat");
+                let parser_snapshot_before_ty = this.clone();
+                this.eat_incorrect_doc_comment_for_param_type();
+                let mut ty = this.parse_ty_for_param();
+                if ty.is_ok()
+                    && this.token != token::Comma
+                    && this.token != token::CloseDelim(token::Paren)
                 {
-                    err.emit();
-                    Ok(dummy_arg(ident))
-                } else {
-                    Err(err)
-                };
-            }
-
-            self.eat_incorrect_doc_comment_for_param_type();
-            (pat, self.parse_ty_for_param()?)
-        } else {
-            debug!("parse_param_general ident_to_pat");
-            let parser_snapshot_before_ty = self.clone();
-            self.eat_incorrect_doc_comment_for_param_type();
-            let mut ty = self.parse_ty_for_param();
-            if ty.is_ok()
-                && self.token != token::Comma
-                && self.token != token::CloseDelim(token::Paren)
-            {
-                // This wasn't actually a type, but a pattern looking like a type,
-                // so we are going to rollback and re-parse for recovery.
-                ty = self.unexpected();
-            }
-            match ty {
-                Ok(ty) => {
-                    let ident = Ident::new(kw::Empty, self.prev_token.span);
-                    let bm = BindingMode::ByValue(Mutability::Not);
-                    let pat = self.mk_pat_ident(ty.span, bm, ident);
-                    (pat, ty)
+                    // This wasn't actually a type, but a pattern looking like a type,
+                    // so we are going to rollback and re-parse for recovery.
+                    ty = this.unexpected();
                 }
-                // If this is a C-variadic argument and we hit an error, return the error.
-                Err(err) if self.token == token::DotDotDot => return Err(err),
-                // Recover from attempting to parse the argument as a type without pattern.
-                Err(mut err) => {
-                    err.cancel();
-                    *self = parser_snapshot_before_ty;
-                    self.recover_arg_parse()?
+                match ty {
+                    Ok(ty) => {
+                        let ident = Ident::new(kw::Empty, this.prev_token.span);
+                        let bm = BindingMode::ByValue(Mutability::Not);
+                        let pat = this.mk_pat_ident(ty.span, bm, ident);
+                        (pat, ty)
+                    }
+                    // If this is a C-variadic argument and we hit an error, return the error.
+                    Err(err) if this.token == token::DotDotDot => return Err(err),
+                    // Recover from attempting to parse the argument as a type without pattern.
+                    Err(mut err) => {
+                        err.cancel();
+                        *this = parser_snapshot_before_ty;
+                        this.recover_arg_parse()?
+                    }
                 }
-            }
-        };
-
-        let span = lo.until(self.token.span);
+            };
 
-        Ok(Param {
-            attrs: attrs.into(),
-            id: ast::DUMMY_NODE_ID,
-            is_placeholder: false,
-            pat,
-            span,
-            ty,
+            let span = lo.until(this.token.span);
+
+            Ok((
+                Param {
+                    attrs: attrs.into(),
+                    id: ast::DUMMY_NODE_ID,
+                    is_placeholder: false,
+                    pat,
+                    span,
+                    ty,
+                },
+                TrailingToken::None,
+            ))
         })
     }
 
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index e2af63d1744..ace4134b1f6 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1,4 +1,5 @@
 pub mod attr;
+mod attr_wrapper;
 mod diagnostics;
 mod expr;
 mod generics;
@@ -10,14 +11,16 @@ mod stmt;
 mod ty;
 
 use crate::lexer::UnmatchedBrace;
+pub use attr_wrapper::AttrWrapper;
 pub use diagnostics::AttemptLocalParseRecovery;
 use diagnostics::Error;
+pub use pat::{GateOr, RecoverComma};
 pub use path::PathStyle;
 
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, DelimToken, Token, TokenKind};
-use rustc_ast::tokenstream::{self, DelimSpan, LazyTokenStream, Spacing};
-use rustc_ast::tokenstream::{CreateTokenStream, TokenStream, TokenTree, TreeAndSpacing};
+use rustc_ast::tokenstream::{self, DelimSpan, Spacing};
+use rustc_ast::tokenstream::{TokenStream, TokenTree, TreeAndSpacing};
 use rustc_ast::DUMMY_NODE_ID;
 use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern, HasTokens};
 use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit, Unsafe};
@@ -64,6 +67,9 @@ pub enum ForceCollect {
 pub enum TrailingToken {
     None,
     Semi,
+    /// If the trailing token is a comma, then capture it
+    /// Otherwise, ignore the trailing token
+    MaybeComma,
 }
 
 /// Like `maybe_whole_expr`, but for things other than expressions.
@@ -981,7 +987,7 @@ impl<'a> Parser<'a> {
                     }
 
                     // Collect tokens because they are used during lowering to HIR.
-                    let expr = self.collect_tokens(|this| this.parse_expr())?;
+                    let expr = self.collect_tokens_no_attrs(|this| this.parse_expr())?;
                     let span = expr.span;
 
                     match &expr.kind {
@@ -1004,12 +1010,12 @@ impl<'a> Parser<'a> {
 
     fn parse_or_use_outer_attributes(
         &mut self,
-        already_parsed_attrs: Option<AttrVec>,
-    ) -> PResult<'a, AttrVec> {
+        already_parsed_attrs: Option<AttrWrapper>,
+    ) -> PResult<'a, AttrWrapper> {
         if let Some(attrs) = already_parsed_attrs {
             Ok(attrs)
         } else {
-            self.parse_outer_attributes().map(|a| a.into())
+            self.parse_outer_attributes()
         }
     }
 
@@ -1226,97 +1232,17 @@ impl<'a> Parser<'a> {
         }
     }
 
-    pub fn collect_tokens<R: HasTokens>(
+    pub fn collect_tokens_no_attrs<R: HasTokens>(
         &mut self,
         f: impl FnOnce(&mut Self) -> PResult<'a, R>,
     ) -> PResult<'a, R> {
-        self.collect_tokens_trailing_token(|this| Ok((f(this)?, TrailingToken::None)))
-    }
-
-    /// Records all tokens consumed by the provided callback,
-    /// including the current token. These tokens are collected
-    /// into a `LazyTokenStream`, and returned along with the result
-    /// of the callback.
-    ///
-    /// Note: If your callback consumes an opening delimiter
-    /// (including the case where you call `collect_tokens`
-    /// when the current token is an opening delimeter),
-    /// you must also consume the corresponding closing delimiter.
-    ///
-    /// That is, you can consume
-    /// `something ([{ }])` or `([{}])`, but not `([{}]`
-    ///
-    /// This restriction shouldn't be an issue in practice,
-    /// since this function is used to record the tokens for
-    /// a parsed AST item, which always has matching delimiters.
-    pub fn collect_tokens_trailing_token<R: HasTokens>(
-        &mut self,
-        f: impl FnOnce(&mut Self) -> PResult<'a, (R, TrailingToken)>,
-    ) -> PResult<'a, R> {
-        let start_token = (self.token.clone(), self.token_spacing);
-        let cursor_snapshot = self.token_cursor.clone();
-
-        let (mut ret, trailing_token) = f(self)?;
-
-        // Produces a `TokenStream` on-demand. Using `cursor_snapshot`
-        // and `num_calls`, we can reconstruct the `TokenStream` seen
-        // by the callback. This allows us to avoid producing a `TokenStream`
-        // if it is never needed - for example, a captured `macro_rules!`
-        // argument that is never passed to a proc macro.
-        // In practice token stream creation happens rarely compared to
-        // calls to `collect_tokens` (see some statistics in #78736),
-        // so we are doing as little up-front work as possible.
-        //
-        // This also makes `Parser` very cheap to clone, since
-        // there is no intermediate collection buffer to clone.
-        #[derive(Clone)]
-        struct LazyTokenStreamImpl {
-            start_token: (Token, Spacing),
-            cursor_snapshot: TokenCursor,
-            num_calls: usize,
-            desugar_doc_comments: bool,
-            append_unglued_token: Option<TreeAndSpacing>,
-        }
-        impl CreateTokenStream for LazyTokenStreamImpl {
-            fn create_token_stream(&self) -> TokenStream {
-                // The token produced by the final call to `next` or `next_desugared`
-                // was not actually consumed by the callback. The combination
-                // of chaining the initial token and using `take` produces the desired
-                // result - we produce an empty `TokenStream` if no calls were made,
-                // and omit the final token otherwise.
-                let mut cursor_snapshot = self.cursor_snapshot.clone();
-                let tokens = std::iter::once(self.start_token.clone())
-                    .chain((0..self.num_calls).map(|_| {
-                        if self.desugar_doc_comments {
-                            cursor_snapshot.next_desugared()
-                        } else {
-                            cursor_snapshot.next()
-                        }
-                    }))
-                    .take(self.num_calls);
-
-                make_token_stream(tokens, self.append_unglued_token.clone())
-            }
-        }
-
-        let mut num_calls = self.token_cursor.num_next_calls - cursor_snapshot.num_next_calls;
-        match trailing_token {
-            TrailingToken::None => {}
-            TrailingToken::Semi => {
-                assert_eq!(self.token.kind, token::Semi);
-                num_calls += 1;
-            }
-        }
-
-        let lazy_impl = LazyTokenStreamImpl {
-            start_token,
-            num_calls,
-            cursor_snapshot,
-            desugar_doc_comments: self.desugar_doc_comments,
-            append_unglued_token: self.token_cursor.append_unglued_token.clone(),
-        };
-        ret.finalize_tokens(LazyTokenStream::new(lazy_impl));
-        Ok(ret)
+        // The only reason to call `collect_tokens_no_attrs` is if you want tokens, so use
+        // `ForceCollect::Yes`
+        self.collect_tokens_trailing_token(
+            AttrWrapper::empty(),
+            ForceCollect::Yes,
+            |this, _attrs| Ok((f(this)?, TrailingToken::None)),
+        )
     }
 
     /// `::{` or `::*`
@@ -1365,60 +1291,3 @@ pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedBrace>, sess: &Pa
         }
     }
 }
-
-/// Converts a flattened iterator of tokens (including open and close delimiter tokens)
-/// into a `TokenStream`, creating a `TokenTree::Delimited` for each matching pair
-/// of open and close delims.
-fn make_token_stream(
-    tokens: impl Iterator<Item = (Token, Spacing)>,
-    append_unglued_token: Option<TreeAndSpacing>,
-) -> TokenStream {
-    #[derive(Debug)]
-    struct FrameData {
-        open: Span,
-        inner: Vec<(TokenTree, Spacing)>,
-    }
-    let mut stack = vec![FrameData { open: DUMMY_SP, inner: vec![] }];
-    for (token, spacing) in tokens {
-        match token {
-            Token { kind: TokenKind::OpenDelim(_), span } => {
-                stack.push(FrameData { open: span, inner: vec![] });
-            }
-            Token { kind: TokenKind::CloseDelim(delim), span } => {
-                let frame_data = stack.pop().expect("Token stack was empty!");
-                let dspan = DelimSpan::from_pair(frame_data.open, span);
-                let stream = TokenStream::new(frame_data.inner);
-                let delimited = TokenTree::Delimited(dspan, delim, stream);
-                stack
-                    .last_mut()
-                    .unwrap_or_else(|| panic!("Bottom token frame is missing for tokens!"))
-                    .inner
-                    .push((delimited, Spacing::Alone));
-            }
-            token => {
-                stack
-                    .last_mut()
-                    .expect("Bottom token frame is missing!")
-                    .inner
-                    .push((TokenTree::Token(token), spacing));
-            }
-        }
-    }
-    let mut final_buf = stack.pop().expect("Missing final buf!");
-    final_buf.inner.extend(append_unglued_token);
-    assert!(stack.is_empty(), "Stack should be empty: final_buf={:?} stack={:?}", final_buf, stack);
-    TokenStream::new(final_buf.inner)
-}
-
-#[macro_export]
-macro_rules! maybe_collect_tokens {
-    ($self:ident, $force_collect:expr, $attrs:expr, $f:expr) => {
-        if matches!($force_collect, ForceCollect::Yes)
-            || $crate::parser::attr::maybe_needs_tokens($attrs)
-        {
-            $self.collect_tokens_trailing_token($f)
-        } else {
-            Ok($f($self)?.0)
-        }
-    };
-}
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 6e25209f090..a84ae515144 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -108,7 +108,9 @@ impl<'a> Parser<'a> {
                 }
             },
             NonterminalKind::Block => {
-                token::NtBlock(self.collect_tokens(|this| this.parse_block())?)
+                // While a block *expression* may have attributes (e.g. `#[my_attr] { ... }`),
+                // the ':block' matcher does not support them
+                token::NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?)
             }
             NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? {
                 Some(s) => token::NtStmt(s),
@@ -117,19 +119,41 @@ impl<'a> Parser<'a> {
                 }
             },
             NonterminalKind::Pat2018 { .. } | NonterminalKind::Pat2021 { .. } => {
-                token::NtPat(self.collect_tokens(|this| match kind {
-                    NonterminalKind::Pat2018 { .. } => this.parse_pat(None),
+                token::NtPat(self.collect_tokens_no_attrs(|this| match kind {
+                    NonterminalKind::Pat2018 { .. } => this.parse_pat_no_top_alt(None),
                     NonterminalKind::Pat2021 { .. } => {
-                        this.parse_top_pat(GateOr::Yes, RecoverComma::No)
+                        this.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)
                     }
                     _ => unreachable!(),
                 })?)
             }
-            NonterminalKind::Expr => token::NtExpr(self.collect_tokens(|this| this.parse_expr())?),
+
+            // If there are attributes present, then `parse_expr` will end up collecting tokens,
+            // turning the outer `collect_tokens_no_attrs` into a no-op due to the already present
+            // tokens. If there are *not* attributes present, then the outer
+            // `collect_tokens_no_attrs` will ensure that we will end up collecting tokens for the
+            // expressions.
+            //
+            // This is less efficient than it could be, since the outer `collect_tokens_no_attrs`
+            // still needs to snapshot the `TokenCursor` before calling `parse_expr`, even when
+            // `parse_expr` will end up collecting tokens. Ideally, this would work more like
+            // `parse_item`, and take in a `ForceCollect` parameter. However, this would require
+            // adding a `ForceCollect` parameter in a bunch of places in expression parsing
+            // for little gain. If the perf impact from this turns out to be noticeable, we should
+            // revisit this apporach.
+            NonterminalKind::Expr => {
+                token::NtExpr(self.collect_tokens_no_attrs(|this| this.parse_expr())?)
+            }
             NonterminalKind::Literal => {
-                token::NtLiteral(self.collect_tokens(|this| this.parse_literal_maybe_minus())?)
+                // The `:literal` matcher does not support attributes
+                token::NtLiteral(
+                    self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?,
+                )
+            }
+
+            NonterminalKind::Ty => {
+                token::NtTy(self.collect_tokens_no_attrs(|this| this.parse_ty())?)
             }
-            NonterminalKind::Ty => token::NtTy(self.collect_tokens(|this| this.parse_ty())?),
             // this could be handled like a token, since it is one
             NonterminalKind::Ident => {
                 if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
@@ -141,15 +165,15 @@ impl<'a> Parser<'a> {
                     return Err(self.struct_span_err(self.token.span, msg));
                 }
             }
-            NonterminalKind::Path => {
-                token::NtPath(self.collect_tokens(|this| this.parse_path(PathStyle::Type))?)
-            }
+            NonterminalKind::Path => token::NtPath(
+                self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?,
+            ),
             NonterminalKind::Meta => {
-                token::NtMeta(P(self.collect_tokens(|this| this.parse_attr_item(false))?))
+                token::NtMeta(P(self.collect_tokens_no_attrs(|this| this.parse_attr_item(false))?))
             }
             NonterminalKind::TT => token::NtTT(self.parse_token_tree()),
             NonterminalKind::Vis => token::NtVis(
-                self.collect_tokens(|this| this.parse_visibility(FollowedByType::Yes))?,
+                self.collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?,
             ),
             NonterminalKind::Lifetime => {
                 if self.check_lifetime() {
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index d888514cf56..8874548da78 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,4 +1,4 @@
-use super::{Parser, PathStyle};
+use super::{ForceCollect, Parser, PathStyle, TrailingToken};
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
 use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor};
 use rustc_ast::ptr::P;
@@ -19,14 +19,14 @@ const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here"
 
 /// Whether or not an or-pattern should be gated when occurring in the current context.
 #[derive(PartialEq, Clone, Copy)]
-pub(super) enum GateOr {
+pub enum GateOr {
     Yes,
     No,
 }
 
 /// Whether or not to recover a `,` when parsing or-patterns.
 #[derive(PartialEq, Copy, Clone)]
-pub(super) enum RecoverComma {
+pub enum RecoverComma {
     Yes,
     No,
 }
@@ -37,80 +37,57 @@ impl<'a> Parser<'a> {
     /// Corresponds to `pat<no_top_alt>` in RFC 2535 and does not admit or-patterns
     /// at the top level. Used when parsing the parameters of lambda expressions,
     /// functions, function pointers, and `pat` macro fragments.
-    pub fn parse_pat(&mut self, expected: Expected) -> PResult<'a, P<Pat>> {
+    pub fn parse_pat_no_top_alt(&mut self, expected: Expected) -> PResult<'a, P<Pat>> {
         self.parse_pat_with_range_pat(true, expected)
     }
 
-    /// Entry point to the main pattern parser.
+    /// Parses a pattern.
+    ///
     /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level.
-    pub(super) fn parse_top_pat(
+    /// Used for parsing patterns in all cases when `pat<no_top_alt>` is not used.
+    ///
+    /// Note that after the FCP in <https://github.com/rust-lang/rust/issues/81415>,
+    /// a leading vert is allowed in nested or-patterns, too. This allows us to
+    /// simplify the grammar somewhat.
+    pub fn parse_pat_allow_top_alt(
         &mut self,
+        expected: Expected,
         gate_or: GateOr,
         rc: RecoverComma,
     ) -> PResult<'a, P<Pat>> {
         // Allow a '|' before the pats (RFCs 1925, 2530, and 2535).
-        let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes;
-        let leading_vert_span = self.prev_token.span;
-
-        // Parse the possibly-or-pattern.
-        let pat = self.parse_pat_with_or(None, gate_or, rc)?;
-
-        // If we parsed a leading `|` which should be gated,
-        // and no other gated or-pattern has been parsed thus far,
-        // then we should really gate the leading `|`.
-        // This complicated procedure is done purely for diagnostics UX.
-        if gated_leading_vert && self.sess.gated_spans.is_ungated(sym::or_patterns) {
-            self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span);
-        }
-
-        Ok(pat)
-    }
-
-    /// Parse the pattern for a function or function pointer parameter.
-    /// Special recovery is provided for or-patterns and leading `|`.
-    pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P<Pat>> {
-        self.recover_leading_vert(None, "not allowed in a parameter pattern");
-        let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?;
-
-        if let PatKind::Or(..) = &pat.kind {
-            self.ban_illegal_fn_param_or_pat(&pat);
-        }
-
-        Ok(pat)
-    }
-
-    /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens.
-    fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) {
-        let msg = "wrap the pattern in parenthesis";
-        let fix = format!("({})", pprust::pat_to_string(pat));
-        self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parenthesis")
-            .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable)
-            .emit();
-    }
+        let leading_vert_span =
+            if self.eat_or_separator(None) { Some(self.prev_token.span) } else { None };
 
-    /// Parses a pattern, that may be a or-pattern (e.g. `Foo | Bar` in `Some(Foo | Bar)`).
-    /// Corresponds to `pat<allow_top_alt>` in RFC 2535.
-    fn parse_pat_with_or(
-        &mut self,
-        expected: Expected,
-        gate_or: GateOr,
-        rc: RecoverComma,
-    ) -> PResult<'a, P<Pat>> {
         // Parse the first pattern (`p_0`).
-        let first_pat = self.parse_pat(expected)?;
+        let first_pat = self.parse_pat_no_top_alt(expected)?;
         self.maybe_recover_unexpected_comma(first_pat.span, rc, gate_or)?;
 
         // If the next token is not a `|`,
         // this is not an or-pattern and we should exit here.
         if !self.check(&token::BinOp(token::Or)) && self.token != token::OrOr {
+            // If we parsed a leading `|` which should be gated,
+            // then we should really gate the leading `|`.
+            // This complicated procedure is done purely for diagnostics UX.
+            if let Some(leading_vert_span) = leading_vert_span {
+                if gate_or == GateOr::Yes && self.sess.gated_spans.is_ungated(sym::or_patterns) {
+                    self.sess.gated_spans.gate(sym::or_patterns, leading_vert_span);
+                }
+
+                // If there was a leading vert, treat this as an or-pattern. This improves
+                // diagnostics.
+                let span = leading_vert_span.to(self.prev_token.span);
+                return Ok(self.mk_pat(span, PatKind::Or(vec![first_pat])));
+            }
+
             return Ok(first_pat);
         }
 
         // Parse the patterns `p_1 | ... | p_n` where `n > 0`.
-        let lo = first_pat.span;
+        let lo = leading_vert_span.unwrap_or(first_pat.span);
         let mut pats = vec![first_pat];
         while self.eat_or_separator(Some(lo)) {
-            let pat = self.parse_pat(expected).map_err(|mut err| {
+            let pat = self.parse_pat_no_top_alt(expected).map_err(|mut err| {
                 err.span_label(lo, WHILE_PARSING_OR_MSG);
                 err
             })?;
@@ -127,6 +104,62 @@ impl<'a> Parser<'a> {
         Ok(self.mk_pat(or_pattern_span, PatKind::Or(pats)))
     }
 
+    /// Parse the pattern for a function or function pointer parameter.
+    pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P<Pat>> {
+        // We actually do _not_ allow top-level or-patterns in function params, but we use
+        // `parse_pat_allow_top_alt` anyway so that we can detect when a user tries to use it. This
+        // allows us to print a better error message.
+        //
+        // In order to get good UX, we first recover in the case of a leading vert for an illegal
+        // top-level or-pat. Normally, this means recovering both `|` and `||`, but in this case,
+        // a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that
+        // separately.
+        if let token::OrOr = self.token.kind {
+            let span = self.token.span;
+            let mut err = self.struct_span_err(span, "unexpected `||` before function parameter");
+            err.span_suggestion(
+                span,
+                "remove the `||`",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+            err.note("alternatives in or-patterns are separated with `|`, not `||`");
+            err.emit();
+            self.bump();
+        }
+
+        let pat = self.parse_pat_allow_top_alt(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?;
+
+        if let PatKind::Or(..) = &pat.kind {
+            self.ban_illegal_fn_param_or_pat(&pat);
+        }
+
+        Ok(pat)
+    }
+
+    /// Ban `A | B` immediately in a parameter pattern and suggest wrapping in parens.
+    fn ban_illegal_fn_param_or_pat(&self, pat: &Pat) {
+        // If all we have a leading vert, then print a special message. This is the case if
+        // `parse_pat_allow_top_alt` returns an or-pattern with one variant.
+        let (msg, fix) = match &pat.kind {
+            PatKind::Or(pats) if pats.len() == 1 => {
+                let msg = "remove the leading `|`";
+                let fix = pprust::pat_to_string(pat);
+                (msg, fix)
+            }
+
+            _ => {
+                let msg = "wrap the pattern in parentheses";
+                let fix = format!("({})", pprust::pat_to_string(pat));
+                (msg, fix)
+            }
+        };
+
+        self.struct_span_err(pat.span, "an or-pattern parameter must be wrapped in parentheses")
+            .span_suggestion(pat.span, msg, fix, Applicability::MachineApplicable)
+            .emit();
+    }
+
     /// Eat the or-pattern `|` separator.
     /// If instead a `||` token is encountered, recover and pretend we parsed `|`.
     fn eat_or_separator(&mut self, lo: Option<Span>) -> bool {
@@ -179,7 +212,7 @@ impl<'a> Parser<'a> {
 
     /// We have parsed `||` instead of `|`. Error and suggest `|` instead.
     fn ban_unexpected_or_or(&mut self, lo: Option<Span>) {
-        let mut err = self.struct_span_err(self.token.span, "unexpected token `||` after pattern");
+        let mut err = self.struct_span_err(self.token.span, "unexpected token `||` in pattern");
         err.span_suggestion(
             self.token.span,
             "use a single `|` to separate multiple alternative patterns",
@@ -244,7 +277,7 @@ impl<'a> Parser<'a> {
     /// sequence of patterns until `)` is reached.
     fn skip_pat_list(&mut self) -> PResult<'a, ()> {
         while !self.check(&token::CloseDelim(token::Paren)) {
-            self.parse_pat(None)?;
+            self.parse_pat_no_top_alt(None)?;
             if !self.eat(&token::Comma) {
                 return Ok(());
             }
@@ -252,22 +285,6 @@ impl<'a> Parser<'a> {
         Ok(())
     }
 
-    /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`.
-    /// See `parse_pat_with_or` for details on parsing or-patterns.
-    fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P<Pat>> {
-        self.recover_leading_vert(None, "only allowed in a top-level pattern");
-        self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No)
-    }
-
-    /// Recover if `|` or `||` is here.
-    /// The user is thinking that a leading `|` is allowed in this position.
-    fn recover_leading_vert(&mut self, lo: Option<Span>, ctx: &str) {
-        if let token::BinOp(token::Or) | token::OrOr = self.token.kind {
-            self.ban_illegal_vert(lo, "leading", ctx);
-            self.bump();
-        }
-    }
-
     /// A `|` or possibly `||` token shouldn't be here. Ban it.
     fn ban_illegal_vert(&mut self, lo: Option<Span>, pos: &str, ctx: &str) {
         let span = self.token.span;
@@ -305,8 +322,9 @@ impl<'a> Parser<'a> {
             self.parse_pat_tuple_or_parens()?
         } else if self.check(&token::OpenDelim(token::Bracket)) {
             // Parse `[pat, pat,...]` as a slice pattern.
-            let (pats, _) =
-                self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat_with_or_inner())?;
+            let (pats, _) = self.parse_delim_comma_seq(token::Bracket, |p| {
+                p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)
+            })?;
             PatKind::Slice(pats)
         } else if self.check(&token::DotDot) && !self.is_pat_range_end_start(1) {
             // A rest pattern `..`.
@@ -429,7 +447,7 @@ impl<'a> Parser<'a> {
 
         // At this point we attempt to parse `@ $pat_rhs` and emit an error.
         self.bump(); // `@`
-        let mut rhs = self.parse_pat(None)?;
+        let mut rhs = self.parse_pat_no_top_alt(None)?;
         let sp = lhs.span.to(rhs.span);
 
         if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind {
@@ -518,8 +536,9 @@ impl<'a> Parser<'a> {
 
     /// Parse a tuple or parenthesis pattern.
     fn parse_pat_tuple_or_parens(&mut self) -> PResult<'a, PatKind> {
-        let (fields, trailing_comma) =
-            self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?;
+        let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| {
+            p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)
+        })?;
 
         // Here, `(pat,)` is a tuple pattern.
         // For backward compatibility, `(..)` is a tuple pattern as well.
@@ -548,7 +567,7 @@ impl<'a> Parser<'a> {
         }
 
         // Parse the pattern we hope to be an identifier.
-        let mut pat = self.parse_pat(Some("identifier"))?;
+        let mut pat = self.parse_pat_no_top_alt(Some("identifier"))?;
 
         // If we don't have `mut $ident (@ pat)?`, error.
         if let PatKind::Ident(BindingMode::ByValue(m @ Mutability::Not), ..) = &mut pat.kind {
@@ -793,7 +812,7 @@ impl<'a> Parser<'a> {
     fn parse_pat_ident(&mut self, binding_mode: BindingMode) -> PResult<'a, PatKind> {
         let ident = self.parse_ident()?;
         let sub = if self.eat(&token::At) {
-            Some(self.parse_pat(Some("binding pattern"))?)
+            Some(self.parse_pat_no_top_alt(Some("binding pattern"))?)
         } else {
             None
         };
@@ -832,7 +851,9 @@ impl<'a> Parser<'a> {
         if qself.is_some() {
             return self.error_qpath_before_pat(&path, "(");
         }
-        let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat_with_or_inner())?;
+        let (fields, _) = self.parse_paren_comma_seq(|p| {
+            p.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)
+        })?;
         Ok(PatKind::TupleStruct(path, fields))
     }
 
@@ -938,16 +959,24 @@ impl<'a> Parser<'a> {
                 }
             }
 
-            fields.push(match self.parse_pat_field(lo, attrs) {
-                Ok(field) => field,
-                Err(err) => {
-                    if let Some(mut delayed_err) = delayed_err {
-                        delayed_err.emit();
-                    }
-                    return Err(err);
-                }
-            });
-            ate_comma = self.eat(&token::Comma);
+            let field =
+                self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
+                    let field = match this.parse_pat_field(lo, attrs) {
+                        Ok(field) => Ok(field),
+                        Err(err) => {
+                            if let Some(mut delayed_err) = delayed_err.take() {
+                                delayed_err.emit();
+                            }
+                            return Err(err);
+                        }
+                    }?;
+                    ate_comma = this.eat(&token::Comma);
+                    // We just ate a comma, so there's no need to use
+                    // `TrailingToken::Comma`
+                    Ok((field, TrailingToken::None))
+                })?;
+
+            fields.push(field)
         }
 
         if let Some(mut err) = delayed_err {
@@ -990,7 +1019,7 @@ impl<'a> Parser<'a> {
             // Parsing a pattern of the form `fieldname: pat`.
             let fieldname = self.parse_field_name()?;
             self.bump();
-            let pat = self.parse_pat_with_or_inner()?;
+            let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::No)?;
             hi = pat.span;
             (pat, fieldname, false)
         } else {
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 8373f6acd7e..bb2c7e98861 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -3,8 +3,9 @@ use super::diagnostics::{AttemptLocalParseRecovery, Error};
 use super::expr::LhsExpr;
 use super::pat::{GateOr, RecoverComma};
 use super::path::PathStyle;
-use super::{BlockMode, ForceCollect, Parser, Restrictions, SemiColonMode, TrailingToken};
-use crate::{maybe_collect_tokens, maybe_whole};
+use super::TrailingToken;
+use super::{AttrWrapper, BlockMode, ForceCollect, Parser, Restrictions, SemiColonMode};
+use crate::maybe_whole;
 
 use rustc_ast as ast;
 use rustc_ast::attr::HasAttrs;
@@ -38,30 +39,47 @@ impl<'a> Parser<'a> {
         capture_semi: bool,
         force_collect: ForceCollect,
     ) -> PResult<'a, Option<Stmt>> {
-        let mut attrs = self.parse_outer_attributes()?;
+        let attrs = self.parse_outer_attributes()?;
         let lo = self.token.span;
 
-        maybe_whole!(self, NtStmt, |stmt| {
-            let mut stmt = stmt;
-            stmt.visit_attrs(|stmt_attrs| {
-                mem::swap(stmt_attrs, &mut attrs);
-                stmt_attrs.extend(attrs);
-            });
-            Some(stmt)
-        });
+        // Don't use `maybe_whole` so that we have precise control
+        // over when we bump the parser
+        if let token::Interpolated(nt) = &self.token.kind {
+            if let token::NtStmt(stmt) = &**nt {
+                let mut stmt = stmt.clone();
+                return self.collect_tokens_trailing_token(
+                    attrs,
+                    force_collect,
+                    |this, mut attrs| {
+                        stmt.visit_attrs(|stmt_attrs| {
+                            mem::swap(stmt_attrs, &mut attrs);
+                            stmt_attrs.extend(attrs);
+                        });
+                        // Make sure we capture the token::Interpolated
+                        this.bump();
+                        Ok((Some(stmt), TrailingToken::None))
+                    },
+                );
+            }
+        }
 
         Ok(Some(if self.token.is_keyword(kw::Let) {
-            self.parse_local_mk(lo, attrs.into(), capture_semi, force_collect)?
+            self.parse_local_mk(lo, attrs, capture_semi, force_collect)?
         } else if self.is_kw_followed_by_ident(kw::Mut) {
-            self.recover_stmt_local(lo, attrs.into(), "missing keyword", "let mut")?
+            self.recover_stmt_local(
+                lo,
+                attrs.take_for_recovery().into(),
+                "missing keyword",
+                "let mut",
+            )?
         } else if self.is_kw_followed_by_ident(kw::Auto) {
             self.bump(); // `auto`
             let msg = "write `let` instead of `auto` to introduce a new variable";
-            self.recover_stmt_local(lo, attrs.into(), msg, "let")?
+            self.recover_stmt_local(lo, attrs.take_for_recovery().into(), msg, "let")?
         } else if self.is_kw_followed_by_ident(sym::var) {
             self.bump(); // `var`
             let msg = "write `let` instead of `var` to introduce a new variable";
-            self.recover_stmt_local(lo, attrs.into(), msg, "let")?
+            self.recover_stmt_local(lo, attrs.take_for_recovery().into(), msg, "let")?
         } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
             // We have avoided contextual keywords like `union`, items with `crate` visibility,
             // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
@@ -75,14 +93,14 @@ impl<'a> Parser<'a> {
             self.mk_stmt(lo.to(item.span), StmtKind::Item(P(item)))
         } else if self.eat(&token::Semi) {
             // Do not attempt to parse an expression if we're done here.
-            self.error_outer_attrs(&attrs);
+            self.error_outer_attrs(&attrs.take_for_recovery());
             self.mk_stmt(lo, StmtKind::Empty)
         } else if self.token != token::CloseDelim(token::Brace) {
             // Remainder are line-expr stmts.
-            let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs.into()))?;
+            let e = self.parse_expr_res(Restrictions::STMT_EXPR, Some(attrs))?;
             self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
         } else {
-            self.error_outer_attrs(&attrs);
+            self.error_outer_attrs(&attrs.take_for_recovery());
             return Ok(None);
         }))
     }
@@ -90,10 +108,10 @@ impl<'a> Parser<'a> {
     fn parse_stmt_path_start(
         &mut self,
         lo: Span,
-        attrs: Vec<Attribute>,
+        attrs: AttrWrapper,
         force_collect: ForceCollect,
     ) -> PResult<'a, Stmt> {
-        maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Parser<'a>| {
+        self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
             let path = this.parse_path(PathStyle::Expr)?;
 
             if this.eat(&token::Not) {
@@ -113,7 +131,7 @@ impl<'a> Parser<'a> {
             };
 
             let expr = this.with_res(Restrictions::STMT_EXPR, |this| {
-                let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
+                let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs)?;
                 this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
             })?;
             Ok((
@@ -142,7 +160,7 @@ impl<'a> Parser<'a> {
             // Since none of the above applied, this is an expression statement macro.
             let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new());
             let e = self.maybe_recover_from_bad_qpath(e, true)?;
-            let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
+            let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?;
             let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
             StmtKind::Expr(e)
         };
@@ -178,11 +196,11 @@ impl<'a> Parser<'a> {
     fn parse_local_mk(
         &mut self,
         lo: Span,
-        attrs: AttrVec,
+        attrs: AttrWrapper,
         capture_semi: bool,
         force_collect: ForceCollect,
     ) -> PResult<'a, Stmt> {
-        maybe_collect_tokens!(self, force_collect, &attrs, |this: &mut Parser<'a>| {
+        self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
             this.expect_keyword(kw::Let)?;
             let local = this.parse_local(attrs.into())?;
             let trailing = if capture_semi && this.token.kind == token::Semi {
@@ -195,14 +213,14 @@ impl<'a> Parser<'a> {
     }
 
     fn recover_local_after_let(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, Stmt> {
-        let local = self.parse_local(attrs.into())?;
+        let local = self.parse_local(attrs)?;
         Ok(self.mk_stmt(lo.to(self.prev_token.span), StmtKind::Local(local)))
     }
 
     /// Parses a local variable declaration.
     fn parse_local(&mut self, attrs: AttrVec) -> PResult<'a, P<Local>> {
         let lo = self.prev_token.span;
-        let pat = self.parse_top_pat(GateOr::Yes, RecoverComma::Yes)?;
+        let pat = self.parse_pat_allow_top_alt(None, GateOr::Yes, RecoverComma::Yes)?;
 
         let (err, ty) = if self.eat(&token::Colon) {
             // Save the state of the parser before parsing type normally, in case there is a `:`
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index f150f7a41ae..92d974690b5 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -730,7 +730,7 @@ fn find_skips_from_snippet(
     str_style: Option<usize>,
 ) -> (Vec<usize>, bool) {
     let snippet = match snippet {
-        Some(ref s) if s.starts_with('"') || s.starts_with("r#") => s,
+        Some(ref s) if s.starts_with('"') || s.starts_with("r\"") || s.starts_with("r#") => s,
         _ => return (vec![], false),
     };
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 0e3a722e082..bf9b7e588bd 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -29,7 +29,7 @@ pub(crate) fn target_from_impl_item<'tcx>(
     match impl_item.kind {
         hir::ImplItemKind::Const(..) => Target::AssocConst,
         hir::ImplItemKind::Fn(..) => {
-            let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id);
+            let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id());
             let containing_item = tcx.hir().expect_item(parent_hir_id);
             let containing_impl_is_for_trait = match &containing_item.kind {
                 hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
@@ -1058,7 +1058,7 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
     fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
         let target = Target::from_item(item);
         self.check_attributes(
-            item.hir_id,
+            item.hir_id(),
             item.attrs,
             &item.span,
             target,
@@ -1081,7 +1081,13 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
 
     fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) {
         let target = Target::from_trait_item(trait_item);
-        self.check_attributes(trait_item.hir_id, &trait_item.attrs, &trait_item.span, target, None);
+        self.check_attributes(
+            trait_item.hir_id(),
+            &trait_item.attrs,
+            &trait_item.span,
+            target,
+            None,
+        );
         intravisit::walk_trait_item(self, trait_item)
     }
 
@@ -1101,21 +1107,10 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
         intravisit::walk_arm(self, arm);
     }
 
-    fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef<'tcx>) {
-        self.check_attributes(
-            macro_def.hir_id,
-            &macro_def.attrs,
-            &macro_def.span,
-            Target::MacroDef,
-            None,
-        );
-        intravisit::walk_macro_def(self, macro_def);
-    }
-
     fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
         let target = Target::from_foreign_item(f_item);
         self.check_attributes(
-            f_item.hir_id,
+            f_item.hir_id(),
             &f_item.attrs,
             &f_item.span,
             target,
@@ -1126,7 +1121,7 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         let target = target_from_impl_item(self.tcx, impl_item);
-        self.check_attributes(impl_item.hir_id, &impl_item.attrs, &impl_item.span, target, None);
+        self.check_attributes(impl_item.hir_id(), &impl_item.attrs, &impl_item.span, target, None);
         intravisit::walk_impl_item(self, impl_item)
     }
 
@@ -1157,6 +1152,23 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
         self.check_attributes(variant.id, variant.attrs, &variant.span, Target::Variant, None);
         intravisit::walk_variant(self, variant, generics, item_id)
     }
+
+    fn visit_macro_def(&mut self, macro_def: &'tcx hir::MacroDef<'tcx>) {
+        self.check_attributes(
+            macro_def.hir_id(),
+            macro_def.attrs,
+            &macro_def.span,
+            Target::MacroDef,
+            None,
+        );
+        intravisit::walk_macro_def(self, macro_def);
+    }
+
+    fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
+        self.check_attributes(param.hir_id, param.attrs, &param.span, Target::Param, None);
+
+        intravisit::walk_param(self, param);
+    }
 }
 
 fn is_c_like_enum(item: &Item<'_>) -> bool {
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 8950f9b33b6..9328f7cd9ec 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -45,7 +45,7 @@ impl NonConstExpr {
                 return None;
             }
 
-            Self::Match(IfLetGuardDesugar) => bug!("if-let guard outside a `match` expression"),
+            Self::Match(IfLetGuardDesugar) => bug!("`if let` guard outside a `match` expression"),
 
             // All other expressions are allowed.
             Self::Loop(Loop | While | WhileLet)
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 0d096a0556b..d51b501f7ae 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -188,8 +188,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         match node {
             Node::Item(item) => match item.kind {
                 hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
-                    let def_id = self.tcx.hir().local_def_id(item.hir_id);
-                    let def = self.tcx.adt_def(def_id);
+                    let def = self.tcx.adt_def(item.def_id);
                     self.repr_has_repr_c = def.repr.c();
 
                     intravisit::walk_item(self, &item);
@@ -329,7 +328,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
 
     fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
         if let TyKind::OpaqueDef(item_id, _) = ty.kind {
-            let item = self.tcx.hir().expect_item(item_id.id);
+            let item = self.tcx.hir().item(item_id);
             intravisit::walk_item(self, item);
         }
         intravisit::walk_ty(self, ty);
@@ -395,9 +394,10 @@ struct LifeSeeder<'k, 'tcx> {
 
 impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        let allow_dead_code = has_allow_dead_code_or_lang_attr(self.tcx, item.hir_id, &item.attrs);
+        let allow_dead_code =
+            has_allow_dead_code_or_lang_attr(self.tcx, item.hir_id(), &item.attrs);
         if allow_dead_code {
-            self.worklist.push(item.hir_id);
+            self.worklist.push(item.hir_id());
         }
         match item.kind {
             hir::ItemKind::Enum(ref enum_def, _) => {
@@ -413,24 +413,24 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
             }
             hir::ItemKind::Impl(hir::Impl { ref of_trait, items, .. }) => {
                 if of_trait.is_some() {
-                    self.worklist.push(item.hir_id);
+                    self.worklist.push(item.hir_id());
                 }
                 for impl_item_ref in items {
                     let impl_item = self.krate.impl_item(impl_item_ref.id);
                     if of_trait.is_some()
                         || has_allow_dead_code_or_lang_attr(
                             self.tcx,
-                            impl_item.hir_id,
+                            impl_item.hir_id(),
                             &impl_item.attrs,
                         )
                     {
-                        self.worklist.push(impl_item_ref.id.hir_id);
+                        self.worklist.push(impl_item_ref.id.hir_id());
                     }
                 }
             }
             hir::ItemKind::Struct(ref variant_data, _) => {
                 if let Some(ctor_hir_id) = variant_data.ctor_hir_id() {
-                    self.struct_constructors.insert(ctor_hir_id, item.hir_id);
+                    self.struct_constructors.insert(ctor_hir_id, item.hir_id());
                 }
             }
             _ => (),
@@ -440,9 +440,9 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
     fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
         use hir::TraitItemKind::{Const, Fn};
         if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
-            && has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id, &trait_item.attrs)
+            && has_allow_dead_code_or_lang_attr(self.tcx, trait_item.hir_id(), &trait_item.attrs)
         {
-            self.worklist.push(trait_item.hir_id);
+            self.worklist.push(trait_item.hir_id());
         }
     }
 
@@ -453,9 +453,13 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> {
     fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
         use hir::ForeignItemKind::{Fn, Static};
         if matches!(foreign_item.kind, Static(..) | Fn(..))
-            && has_allow_dead_code_or_lang_attr(self.tcx, foreign_item.hir_id, &foreign_item.attrs)
+            && has_allow_dead_code_or_lang_attr(
+                self.tcx,
+                foreign_item.hir_id(),
+                &foreign_item.attrs,
+            )
         {
-            self.worklist.push(foreign_item.hir_id);
+            self.worklist.push(foreign_item.hir_id());
         }
     }
 }
@@ -525,7 +529,7 @@ impl DeadVisitor<'tcx> {
                 | hir::ItemKind::Struct(..)
                 | hir::ItemKind::Union(..)
         );
-        should_warn && !self.symbol_is_live(item.hir_id)
+        should_warn && !self.symbol_is_live(item.hir_id())
     }
 
     fn should_warn_about_field(&mut self, field: &hir::StructField<'_>) -> bool {
@@ -542,8 +546,8 @@ impl DeadVisitor<'tcx> {
     }
 
     fn should_warn_about_foreign_item(&mut self, fi: &hir::ForeignItem<'_>) -> bool {
-        !self.symbol_is_live(fi.hir_id)
-            && !has_allow_dead_code_or_lang_attr(self.tcx, fi.hir_id, &fi.attrs)
+        !self.symbol_is_live(fi.hir_id())
+            && !has_allow_dead_code_or_lang_attr(self.tcx, fi.hir_id(), &fi.attrs)
     }
 
     // id := HIR id of an item's definition.
@@ -627,7 +631,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
                 hir::ItemKind::Struct(..) => "constructed", // Issue #52325
                 _ => "used",
             };
-            self.warn_dead_code(item.hir_id, span, item.ident.name, participle);
+            self.warn_dead_code(item.hir_id(), span, item.ident.name, participle);
         } else {
             // Only continue if we didn't warn
             intravisit::walk_item(self, item);
@@ -649,7 +653,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
 
     fn visit_foreign_item(&mut self, fi: &'tcx hir::ForeignItem<'tcx>) {
         if self.should_warn_about_foreign_item(fi) {
-            self.warn_dead_code(fi.hir_id, fi.span, fi.ident.name, "used");
+            self.warn_dead_code(fi.hir_id(), fi.span, fi.ident.name, "used");
         }
         intravisit::walk_foreign_item(self, fi);
     }
@@ -664,9 +668,9 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         match impl_item.kind {
             hir::ImplItemKind::Const(_, body_id) => {
-                if !self.symbol_is_live(impl_item.hir_id) {
+                if !self.symbol_is_live(impl_item.hir_id()) {
                     self.warn_dead_code(
-                        impl_item.hir_id,
+                        impl_item.hir_id(),
                         impl_item.span,
                         impl_item.ident.name,
                         "used",
@@ -675,7 +679,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
                 self.visit_nested_body(body_id)
             }
             hir::ImplItemKind::Fn(_, body_id) => {
-                if !self.symbol_is_live(impl_item.hir_id) {
+                if !self.symbol_is_live(impl_item.hir_id()) {
                     // FIXME(66095): Because impl_item.span is annotated with things
                     // like expansion data, and ident.span isn't, we use the
                     // def_span method if it's part of a macro invocation
@@ -687,7 +691,7 @@ impl Visitor<'tcx> for DeadVisitor<'tcx> {
                     } else {
                         impl_item.ident.span
                     };
-                    self.warn_dead_code(impl_item.hir_id, span, impl_item.ident.name, "used");
+                    self.warn_dead_code(impl_item.hir_id(), span, impl_item.ident.name, "used");
                 }
                 self.visit_nested_body(body_id)
             }
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index 699c96bc49d..3ec7ea39248 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -16,7 +16,7 @@ use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
-use rustc_span::def_id::{DefId, LOCAL_CRATE};
+use rustc_span::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_span::symbol::{sym, Symbol};
 
 struct DiagnosticItemCollector<'tcx> {
@@ -27,19 +27,19 @@ struct DiagnosticItemCollector<'tcx> {
 
 impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        self.observe_item(&item.attrs, item.hir_id);
+        self.observe_item(&item.attrs, item.def_id);
     }
 
     fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
-        self.observe_item(&trait_item.attrs, trait_item.hir_id);
+        self.observe_item(&trait_item.attrs, trait_item.def_id);
     }
 
     fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
-        self.observe_item(&impl_item.attrs, impl_item.hir_id);
+        self.observe_item(&impl_item.attrs, impl_item.def_id);
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
-        self.observe_item(foreign_item.attrs, foreign_item.hir_id);
+        self.observe_item(foreign_item.attrs, foreign_item.def_id);
     }
 }
 
@@ -48,9 +48,8 @@ impl<'tcx> DiagnosticItemCollector<'tcx> {
         DiagnosticItemCollector { tcx, items: Default::default() }
     }
 
-    fn observe_item(&mut self, attrs: &[ast::Attribute], hir_id: hir::HirId) {
+    fn observe_item(&mut self, attrs: &[ast::Attribute], def_id: LocalDefId) {
         if let Some(name) = extract(&self.tcx.sess, attrs) {
-            let def_id = self.tcx.hir().local_def_id(hir_id);
             // insert into our table
             collect_item(self.tcx, &mut self.items, name, def_id.to_def_id());
         }
@@ -106,7 +105,7 @@ fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> FxHashMap<Symbol, DefId> {
     tcx.hir().krate().visit_all_item_likes(&mut collector);
 
     for m in tcx.hir().krate().exported_macros {
-        collector.observe_item(m.attrs, m.hir_id);
+        collector.observe_item(m.attrs, m.def_id);
     }
 
     collector.items
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 5ff631a2457..0d3a7ea3a8a 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -32,8 +32,7 @@ struct EntryContext<'a, 'tcx> {
 
 impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
-        let def_id = self.map.local_def_id(item.hir_id);
-        let def_key = self.map.def_key(def_id);
+        let def_key = self.map.def_key(item.def_id);
         let at_root = def_key.parent == Some(CRATE_DEF_INDEX);
         find_item(item, self, at_root);
     }
@@ -116,18 +115,18 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
         }
         EntryPointType::MainNamed => {
             if ctxt.main_fn.is_none() {
-                ctxt.main_fn = Some((item.hir_id, item.span));
+                ctxt.main_fn = Some((item.hir_id(), item.span));
             } else {
                 struct_span_err!(ctxt.session, item.span, E0136, "multiple `main` functions")
                     .emit();
             }
         }
         EntryPointType::OtherMain => {
-            ctxt.non_main_fns.push((item.hir_id, item.span));
+            ctxt.non_main_fns.push((item.hir_id(), item.span));
         }
         EntryPointType::MainAttr => {
             if ctxt.attr_main_fn.is_none() {
-                ctxt.attr_main_fn = Some((item.hir_id, item.span));
+                ctxt.attr_main_fn = Some((item.hir_id(), item.span));
             } else {
                 struct_span_err!(
                     ctxt.session,
@@ -142,7 +141,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
         }
         EntryPointType::Start => {
             if ctxt.start_fn.is_none() {
-                ctxt.start_fn = Some((item.hir_id, item.span));
+                ctxt.start_fn = Some((item.hir_id(), item.span));
             } else {
                 struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions")
                     .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index fdd6c238055..79e3b5952ac 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -14,12 +14,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
     let errors = Lock::new(Vec::new());
     let hir_map = tcx.hir();
 
-    par_iter(&hir_map.krate().modules).for_each(|(module_id, _)| {
-        let local_def_id = hir_map.local_def_id(*module_id);
-        hir_map.visit_item_likes_in_module(
-            local_def_id,
-            &mut OuterVisitor { hir_map, errors: &errors },
-        );
+    par_iter(&hir_map.krate().modules).for_each(|(&module_id, _)| {
+        hir_map
+            .visit_item_likes_in_module(module_id, &mut OuterVisitor { hir_map, errors: &errors });
     });
 
     let errors = errors.into_inner();
@@ -56,22 +53,22 @@ impl<'a, 'hir> OuterVisitor<'a, 'hir> {
 impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> {
     fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
         let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.hir_id, |this| intravisit::walk_item(this, i));
+        inner_visitor.check(i.hir_id(), |this| intravisit::walk_item(this, i));
     }
 
     fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
         let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.hir_id, |this| intravisit::walk_trait_item(this, i));
+        inner_visitor.check(i.hir_id(), |this| intravisit::walk_trait_item(this, i));
     }
 
     fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
         let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.hir_id, |this| intravisit::walk_impl_item(this, i));
+        inner_visitor.check(i.hir_id(), |this| intravisit::walk_impl_item(this, i));
     }
 
     fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
         let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.hir_id, |this| intravisit::walk_foreign_item(this, i));
+        inner_visitor.check(i.hir_id(), |this| intravisit::walk_foreign_item(this, i));
     }
 }
 
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 1d02c9aa637..fac28281593 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -66,13 +66,13 @@ impl<'k> StatCollector<'k> {
 
         let mut total_size = 0;
 
-        println!("\n{}\n", title);
+        eprintln!("\n{}\n", title);
 
-        println!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
-        println!("----------------------------------------------------------------");
+        eprintln!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
+        eprintln!("----------------------------------------------------------------");
 
         for (label, data) in stats {
-            println!(
+            eprintln!(
                 "{:<18}{:>18}{:>14}{:>14}",
                 label,
                 to_readable_str(data.count * data.size),
@@ -82,8 +82,8 @@ impl<'k> StatCollector<'k> {
 
             total_size += data.count * data.size;
         }
-        println!("----------------------------------------------------------------");
-        println!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
+        eprintln!("----------------------------------------------------------------");
+        eprintln!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
     }
 }
 
@@ -100,7 +100,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
     }
 
     fn visit_nested_item(&mut self, id: hir::ItemId) {
-        let nested_item = self.krate.unwrap().item(id.id);
+        let nested_item = self.krate.unwrap().item(id);
         self.visit_item(nested_item)
     }
 
@@ -120,17 +120,12 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
     }
 
     fn visit_item(&mut self, i: &'v hir::Item<'v>) {
-        self.record("Item", Id::Node(i.hir_id), i);
+        self.record("Item", Id::Node(i.hir_id()), i);
         hir_visit::walk_item(self, i)
     }
 
-    fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: hir::HirId) {
-        self.record("Mod", Id::None, m);
-        hir_visit::walk_mod(self, m, n)
-    }
-
     fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) {
-        self.record("ForeignItem", Id::Node(i.hir_id), i);
+        self.record("ForeignItem", Id::Node(i.hir_id()), i);
         hir_visit::walk_foreign_item(self, i)
     }
 
@@ -187,12 +182,12 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
     }
 
     fn visit_trait_item(&mut self, ti: &'v hir::TraitItem<'v>) {
-        self.record("TraitItem", Id::Node(ti.hir_id), ti);
+        self.record("TraitItem", Id::Node(ti.hir_id()), ti);
         hir_visit::walk_trait_item(self, ti)
     }
 
     fn visit_impl_item(&mut self, ii: &'v hir::ImplItem<'v>) {
-        self.record("ImplItem", Id::Node(ii.hir_id), ii);
+        self.record("ImplItem", Id::Node(ii.hir_id()), ii);
         hir_visit::walk_impl_item(self, ii)
     }
 
@@ -246,17 +241,12 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
     }
 
     fn visit_macro_def(&mut self, macro_def: &'v hir::MacroDef<'v>) {
-        self.record("MacroDef", Id::Node(macro_def.hir_id), macro_def);
+        self.record("MacroDef", Id::Node(macro_def.hir_id()), macro_def);
         hir_visit::walk_macro_def(self, macro_def)
     }
 }
 
 impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
-    fn visit_mod(&mut self, m: &'v ast::Mod, _s: Span, _a: &[ast::Attribute], _n: NodeId) {
-        self.record("Mod", Id::None, m);
-        ast_visit::walk_mod(self, m)
-    }
-
     fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
         self.record("ForeignItem", Id::None, i);
         ast_visit::walk_foreign_item(self, i)
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 3132661e5f5..8e2ad7f783e 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -30,7 +30,7 @@ struct LanguageItemCollector<'tcx> {
 
 impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        self.check_for_lang(Target::from_item(item), item.hir_id, item.attrs);
+        self.check_for_lang(Target::from_item(item), item.hir_id(), item.attrs);
 
         if let hir::ItemKind::Enum(def, ..) = &item.kind {
             for variant in def.variants {
@@ -42,7 +42,7 @@ impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
     fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
         self.check_for_lang(
             Target::from_trait_item(trait_item),
-            trait_item.hir_id,
+            trait_item.hir_id(),
             trait_item.attrs,
         )
     }
@@ -50,7 +50,7 @@ impl ItemLikeVisitor<'v> for LanguageItemCollector<'tcx> {
     fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
         self.check_for_lang(
             target_from_impl_item(self.tcx, impl_item),
-            impl_item.hir_id,
+            impl_item.hir_id(),
             impl_item.attrs,
         )
     }
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 9e83cbd6680..18c1d647060 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -21,16 +21,14 @@ struct LayoutTest<'tcx> {
 
 impl ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let item_def_id = self.tcx.hir().local_def_id(item.hir_id);
-
         match item.kind {
             ItemKind::TyAlias(..)
             | ItemKind::Enum(..)
             | ItemKind::Struct(..)
             | ItemKind::Union(..) => {
-                for attr in self.tcx.get_attrs(item_def_id.to_def_id()).iter() {
+                for attr in self.tcx.get_attrs(item.def_id.to_def_id()).iter() {
                     if self.tcx.sess.check_name(attr, sym::rustc_layout) {
-                        self.dump_layout_of(item_def_id, item, attr);
+                        self.dump_layout_of(item.def_id, item, attr);
                     }
                 }
             }
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index eb24c51c54c..20aaaea5b98 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -31,7 +31,7 @@ fn item_might_be_inlined(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>, attrs: &Codege
     match item.kind {
         hir::ItemKind::Fn(ref sig, ..) if sig.header.is_const() => true,
         hir::ItemKind::Impl { .. } | hir::ItemKind::Fn(..) => {
-            let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id));
+            let generics = tcx.generics_of(item.def_id);
             generics.requires_monomorphization(tcx)
         }
         _ => false,
@@ -43,8 +43,8 @@ fn method_might_be_inlined(
     impl_item: &hir::ImplItem<'_>,
     impl_src: LocalDefId,
 ) -> bool {
-    let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id.owner.to_def_id());
-    let generics = tcx.generics_of(tcx.hir().local_def_id(impl_item.hir_id));
+    let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id().owner.to_def_id());
+    let generics = tcx.generics_of(impl_item.def_id);
     if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) {
         return true;
     }
@@ -218,8 +218,7 @@ impl<'tcx> ReachableContext<'tcx> {
                 } else {
                     false
                 };
-                let def_id = self.tcx.hir().local_def_id(item.hir_id);
-                let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
+                let codegen_attrs = self.tcx.codegen_fn_attrs(item.def_id);
                 let is_extern = codegen_attrs.contains_extern_indicator();
                 let std_internal =
                     codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
@@ -239,9 +238,11 @@ impl<'tcx> ReachableContext<'tcx> {
             Node::Item(item) => {
                 match item.kind {
                     hir::ItemKind::Fn(.., body) => {
-                        let def_id = self.tcx.hir().local_def_id(item.hir_id);
-                        if item_might_be_inlined(self.tcx, &item, self.tcx.codegen_fn_attrs(def_id))
-                        {
+                        if item_might_be_inlined(
+                            self.tcx,
+                            &item,
+                            self.tcx.codegen_fn_attrs(item.def_id),
+                        ) {
                             self.visit_nested_body(body);
                         }
                     }
@@ -341,23 +342,21 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx
         // Anything which has custom linkage gets thrown on the worklist no
         // matter where it is in the crate, along with "special std symbols"
         // which are currently akin to allocator symbols.
-        let def_id = self.tcx.hir().local_def_id(item.hir_id);
-        let codegen_attrs = self.tcx.codegen_fn_attrs(def_id);
+        let codegen_attrs = self.tcx.codegen_fn_attrs(item.def_id);
         if codegen_attrs.contains_extern_indicator()
             || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
         {
-            self.worklist.push(def_id);
+            self.worklist.push(item.def_id);
         }
 
         // We need only trait impls here, not inherent impls, and only non-exported ones
         if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
             item.kind
         {
-            if !self.access_levels.is_reachable(item.hir_id) {
+            if !self.access_levels.is_reachable(item.hir_id()) {
                 // FIXME(#53488) remove `let`
                 let tcx = self.tcx;
-                self.worklist
-                    .extend(items.iter().map(|ii_ref| tcx.hir().local_def_id(ii_ref.id.hir_id)));
+                self.worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id));
 
                 let trait_def_id = match trait_ref.path.res {
                     Res::Def(DefKind::Trait, def_id) => def_id,
diff --git a/compiler/rustc_passes/src/region.rs b/compiler/rustc_passes/src/region.rs
index 64356f73f6c..b532021bed2 100644
--- a/compiler/rustc_passes/src/region.rs
+++ b/compiler/rustc_passes/src/region.rs
@@ -664,7 +664,7 @@ fn resolve_local<'tcx>(
 
             match expr.kind {
                 hir::ExprKind::AddrOf(_, _, ref subexpr)
-                | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref subexpr)
+                | hir::ExprKind::Unary(hir::UnOp::Deref, ref subexpr)
                 | hir::ExprKind::Field(ref subexpr, _)
                 | hir::ExprKind::Index(ref subexpr, _) => {
                     expr = &subexpr;
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index e1d03e35048..f538427efd9 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -376,7 +376,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         }
 
         self.annotate(
-            i.hir_id,
+            i.hir_id(),
             &i.attrs,
             i.span,
             kind,
@@ -389,7 +389,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
 
     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
         self.annotate(
-            ti.hir_id,
+            ti.hir_id(),
             &ti.attrs,
             ti.span,
             AnnotationKind::Required,
@@ -405,7 +405,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         let kind =
             if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required };
         self.annotate(
-            ii.hir_id,
+            ii.hir_id(),
             &ii.attrs,
             ii.span,
             kind,
@@ -459,7 +459,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
 
     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
         self.annotate(
-            i.hir_id,
+            i.hir_id(),
             &i.attrs,
             i.span,
             AnnotationKind::Required,
@@ -473,7 +473,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
 
     fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
         self.annotate(
-            md.hir_id,
+            md.hir_id(),
             &md.attrs,
             md.span,
             AnnotationKind::Required,
@@ -556,7 +556,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
             hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
                 | hir::ItemKind::ForeignMod { .. }
         ) {
-            self.check_missing_stability(i.hir_id, i.span);
+            self.check_missing_stability(i.hir_id(), i.span);
         }
 
         // Ensure `const fn` that are `stable` have one of `rustc_const_unstable` or
@@ -564,21 +564,21 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
         if self.tcx.features().staged_api
             && matches!(&i.kind, hir::ItemKind::Fn(sig, ..) if sig.header.is_const())
         {
-            self.check_missing_const_stability(i.hir_id, i.span);
+            self.check_missing_const_stability(i.hir_id(), i.span);
         }
 
         intravisit::walk_item(self, i)
     }
 
     fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
-        self.check_missing_stability(ti.hir_id, ti.span);
+        self.check_missing_stability(ti.hir_id(), ti.span);
         intravisit::walk_trait_item(self, ti);
     }
 
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
-        let impl_def_id = self.tcx.hir().local_def_id(self.tcx.hir().get_parent_item(ii.hir_id));
+        let impl_def_id = self.tcx.hir().local_def_id(self.tcx.hir().get_parent_item(ii.hir_id()));
         if self.tcx.impl_trait_ref(impl_def_id).is_none() {
-            self.check_missing_stability(ii.hir_id, ii.span);
+            self.check_missing_stability(ii.hir_id(), ii.span);
         }
         intravisit::walk_impl_item(self, ii);
     }
@@ -594,12 +594,12 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
     }
 
     fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
-        self.check_missing_stability(i.hir_id, i.span);
+        self.check_missing_stability(i.hir_id(), i.span);
         intravisit::walk_foreign_item(self, i);
     }
 
     fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
-        self.check_missing_stability(md.hir_id, md.span);
+        self.check_missing_stability(md.hir_id(), md.span);
     }
 
     // Note that we don't need to `check_missing_stability` for default generic parameters,
@@ -712,13 +712,12 @@ impl Visitor<'tcx> for Checker<'tcx> {
                     return;
                 }
 
-                let def_id = self.tcx.hir().local_def_id(item.hir_id);
-                let cnum = match self.tcx.extern_mod_stmt_cnum(def_id) {
+                let cnum = match self.tcx.extern_mod_stmt_cnum(item.def_id) {
                     Some(cnum) => cnum,
                     None => return,
                 };
                 let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
-                self.tcx.check_stability(def_id, Some(item.hir_id), item.span);
+                self.tcx.check_stability(def_id, Some(item.hir_id()), item.span);
             }
 
             // For implementations of traits, check the stability of each item
@@ -744,7 +743,7 @@ impl Visitor<'tcx> for Checker<'tcx> {
                                 .map_or(item.span, |a| a.span);
                             self.tcx.struct_span_lint_hir(
                                 INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
-                                item.hir_id,
+                                item.hir_id(),
                                 span,
                                 |lint| lint
                                     .build("an `#[unstable]` annotation here has no effect")
@@ -775,15 +774,14 @@ impl Visitor<'tcx> for Checker<'tcx> {
             // There's no good place to insert stability check for non-Copy unions,
             // so semi-randomly perform it here in stability.rs
             hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => {
-                let def_id = self.tcx.hir().local_def_id(item.hir_id);
-                let ty = self.tcx.type_of(def_id);
+                let ty = self.tcx.type_of(item.def_id);
                 let (adt_def, substs) = match ty.kind() {
                     ty::Adt(adt_def, substs) => (adt_def, substs),
                     _ => bug!(),
                 };
 
                 // Non-`Copy` fields are unstable, except for `ManuallyDrop`.
-                let param_env = self.tcx.param_env(def_id);
+                let param_env = self.tcx.param_env(item.def_id);
                 for field in &adt_def.non_enum_variant().fields {
                     let field_ty = field.ty(self.tcx, substs);
                     if !field_ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop())
diff --git a/compiler/rustc_plugin_impl/src/build.rs b/compiler/rustc_plugin_impl/src/build.rs
index 4796d9a80b6..d5c287fb3bc 100644
--- a/compiler/rustc_plugin_impl/src/build.rs
+++ b/compiler/rustc_plugin_impl/src/build.rs
@@ -1,7 +1,7 @@
 //! Used by `rustc` when compiling a plugin crate.
 
 use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
@@ -10,14 +10,14 @@ use rustc_span::Span;
 
 struct RegistrarFinder<'tcx> {
     tcx: TyCtxt<'tcx>,
-    registrars: Vec<(hir::HirId, Span)>,
+    registrars: Vec<(LocalDefId, Span)>,
 }
 
 impl<'v, 'tcx> ItemLikeVisitor<'v> for RegistrarFinder<'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
         if let hir::ItemKind::Fn(..) = item.kind {
             if self.tcx.sess.contains_name(&item.attrs, sym::plugin_registrar) {
-                self.registrars.push((item.hir_id, item.span));
+                self.registrars.push((item.def_id, item.span));
             }
         }
     }
@@ -43,8 +43,8 @@ fn plugin_registrar_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<DefId> {
     match finder.registrars.len() {
         0 => None,
         1 => {
-            let (hir_id, _) = finder.registrars.pop().unwrap();
-            Some(tcx.hir().local_def_id(hir_id).to_def_id())
+            let (def_id, _) = finder.registrars.pop().unwrap();
+            Some(def_id.to_def_id())
         }
         _ => {
             let diagnostic = tcx.sess.diagnostic();
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 631dcb60594..6e0e1c5eeef 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -77,6 +77,12 @@ trait DefIdVisitor<'tcx> {
     fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> {
         self.skeleton().visit_trait(trait_ref)
     }
+    fn visit_projection_ty(
+        &mut self,
+        projection: ty::ProjectionTy<'tcx>,
+    ) -> ControlFlow<Self::BreakTy> {
+        self.skeleton().visit_projection_ty(projection)
+    }
     fn visit_predicates(
         &mut self,
         predicates: ty::GenericPredicates<'tcx>,
@@ -101,6 +107,20 @@ where
         if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
     }
 
+    fn visit_projection_ty(
+        &mut self,
+        projection: ty::ProjectionTy<'tcx>,
+    ) -> ControlFlow<V::BreakTy> {
+        let (trait_ref, assoc_substs) =
+            projection.trait_ref_and_own_substs(self.def_id_visitor.tcx());
+        self.visit_trait(trait_ref)?;
+        if self.def_id_visitor.shallow() {
+            ControlFlow::CONTINUE
+        } else {
+            assoc_substs.iter().try_for_each(|subst| subst.visit_with(self))
+        }
+    }
+
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
         match predicate.kind().skip_binder() {
             ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref }, _) => {
@@ -108,7 +128,7 @@ where
             }
             ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
                 ty.visit_with(self)?;
-                self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
+                self.visit_projection_ty(projection_ty)
             }
             ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
                 ty.visit_with(self)
@@ -197,7 +217,7 @@ where
                     return ControlFlow::CONTINUE;
                 }
                 // This will also visit substs if necessary, so we don't need to recurse.
-                return self.visit_trait(proj.trait_ref(tcx));
+                return self.visit_projection_ty(proj);
             }
             ty::Dynamic(predicates, ..) => {
                 // All traits in the list are considered the "primary" part of the type
@@ -454,11 +474,9 @@ impl EmbargoVisitor<'tcx> {
         let module_def_id = self.tcx.hir().local_def_id(reachable_mod);
         let module = self.tcx.hir().get_module(module_def_id).0;
         for item_id in module.item_ids {
-            let hir_id = item_id.id;
-            let item_def_id = self.tcx.hir().local_def_id(hir_id);
-            let def_kind = self.tcx.def_kind(item_def_id);
-            let vis = self.tcx.visibility(item_def_id);
-            self.update_macro_reachable_def(hir_id, def_kind, vis, defining_mod);
+            let def_kind = self.tcx.def_kind(item_id.def_id);
+            let vis = self.tcx.visibility(item_id.def_id);
+            self.update_macro_reachable_def(item_id.hir_id(), def_kind, vis, defining_mod);
         }
         if let Some(exports) = self.tcx.module_exports(module_def_id) {
             for export in exports {
@@ -588,14 +606,17 @@ impl EmbargoVisitor<'tcx> {
                 .map(|module_hir_id| self.tcx.hir().expect_item(module_hir_id))
             {
                 if let hir::ItemKind::Mod(m) = &item.kind {
-                    for item_id in m.item_ids {
-                        let item = self.tcx.hir().expect_item(item_id.id);
-                        let def_id = self.tcx.hir().local_def_id(item_id.id);
-                        if !self.tcx.hygienic_eq(segment.ident, item.ident, def_id.to_def_id()) {
+                    for &item_id in m.item_ids {
+                        let item = self.tcx.hir().item(item_id);
+                        if !self.tcx.hygienic_eq(
+                            segment.ident,
+                            item.ident,
+                            item_id.def_id.to_def_id(),
+                        ) {
                             continue;
                         }
                         if let hir::ItemKind::Use(..) = item.kind {
-                            self.update(item.hir_id, Some(AccessLevel::Exported));
+                            self.update(item.hir_id(), Some(AccessLevel::Exported));
                         }
                     }
                 }
@@ -616,7 +637,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         let inherited_item_level = match item.kind {
             hir::ItemKind::Impl { .. } => {
-                Option::<AccessLevel>::of_impl(item.hir_id, self.tcx, &self.access_levels)
+                Option::<AccessLevel>::of_impl(item.hir_id(), self.tcx, &self.access_levels)
             }
             // Foreign modules inherit level from parents.
             hir::ItemKind::ForeignMod { .. } => self.prev_level,
@@ -644,7 +665,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
         };
 
         // Update level of the item itself.
-        let item_level = self.update(item.hir_id, inherited_item_level);
+        let item_level = self.update(item.hir_id(), inherited_item_level);
 
         // Update levels of nested things.
         match item.kind {
@@ -662,13 +683,13 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             hir::ItemKind::Impl(ref impl_) => {
                 for impl_item_ref in impl_.items {
                     if impl_.of_trait.is_some() || impl_item_ref.vis.node.is_pub() {
-                        self.update(impl_item_ref.id.hir_id, item_level);
+                        self.update(impl_item_ref.id.hir_id(), item_level);
                     }
                 }
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
                 for trait_item_ref in trait_item_refs {
-                    self.update(trait_item_ref.id.hir_id, item_level);
+                    self.update(trait_item_ref.id.hir_id(), item_level);
                 }
             }
             hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
@@ -684,7 +705,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
                     if foreign_item.vis.node.is_pub() {
-                        self.update(foreign_item.id.hir_id, item_level);
+                        self.update(foreign_item.id.hir_id(), item_level);
                     }
                 }
             }
@@ -727,7 +748,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     // reachable if they are returned via `impl Trait`, even from private functions.
                     let exist_level =
                         cmp::max(item_level, Some(AccessLevel::ReachableFromImplTrait));
-                    self.reach(item.hir_id, exist_level).generics().predicates().ty();
+                    self.reach(item.hir_id(), exist_level).generics().predicates().ty();
                 }
             }
             // Visit everything.
@@ -736,15 +757,15 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             | hir::ItemKind::Fn(..)
             | hir::ItemKind::TyAlias(..) => {
                 if item_level.is_some() {
-                    self.reach(item.hir_id, item_level).generics().predicates().ty();
+                    self.reach(item.hir_id(), item_level).generics().predicates().ty();
                 }
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
                 if item_level.is_some() {
-                    self.reach(item.hir_id, item_level).generics().predicates();
+                    self.reach(item.hir_id(), item_level).generics().predicates();
 
                     for trait_item_ref in trait_item_refs {
-                        let mut reach = self.reach(trait_item_ref.id.hir_id, item_level);
+                        let mut reach = self.reach(trait_item_ref.id.hir_id(), item_level);
                         reach.generics().predicates();
 
                         if trait_item_ref.kind == AssocItemKind::Type
@@ -759,18 +780,18 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
             hir::ItemKind::TraitAlias(..) => {
                 if item_level.is_some() {
-                    self.reach(item.hir_id, item_level).generics().predicates();
+                    self.reach(item.hir_id(), item_level).generics().predicates();
                 }
             }
             // Visit everything except for private impl items.
             hir::ItemKind::Impl(ref impl_) => {
                 if item_level.is_some() {
-                    self.reach(item.hir_id, item_level).generics().predicates().ty().trait_ref();
+                    self.reach(item.hir_id(), item_level).generics().predicates().ty().trait_ref();
 
                     for impl_item_ref in impl_.items {
-                        let impl_item_level = self.get(impl_item_ref.id.hir_id);
+                        let impl_item_level = self.get(impl_item_ref.id.hir_id());
                         if impl_item_level.is_some() {
-                            self.reach(impl_item_ref.id.hir_id, impl_item_level)
+                            self.reach(impl_item_ref.id.hir_id(), impl_item_level)
                                 .generics()
                                 .predicates()
                                 .ty();
@@ -782,7 +803,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             // Visit everything, but enum variants have their own levels.
             hir::ItemKind::Enum(ref def, _) => {
                 if item_level.is_some() {
-                    self.reach(item.hir_id, item_level).generics().predicates();
+                    self.reach(item.hir_id(), item_level).generics().predicates();
                 }
                 for variant in def.variants {
                     let variant_level = self.get(variant.id);
@@ -792,16 +813,16 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
                         }
                         // Corner case: if the variant is reachable, but its
                         // enum is not, make the enum reachable as well.
-                        self.update(item.hir_id, variant_level);
+                        self.update(item.hir_id(), variant_level);
                     }
                 }
             }
             // Visit everything, but foreign items have their own levels.
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    let foreign_item_level = self.get(foreign_item.id.hir_id);
+                    let foreign_item_level = self.get(foreign_item.id.hir_id());
                     if foreign_item_level.is_some() {
-                        self.reach(foreign_item.id.hir_id, foreign_item_level)
+                        self.reach(foreign_item.id.hir_id(), foreign_item_level)
                             .generics()
                             .predicates()
                             .ty();
@@ -811,7 +832,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             // Visit everything except for private fields.
             hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
                 if item_level.is_some() {
-                    self.reach(item.hir_id, item_level).generics().predicates();
+                    self.reach(item.hir_id(), item_level).generics().predicates();
                     for field in struct_def.fields() {
                         let field_level = self.get(field.hir_id);
                         if field_level.is_some() {
@@ -866,14 +887,12 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             // `#[macro_export]`-ed `macro_rules!` are `Public` since they
             // ignore their containing path to always appear at the crate root.
             if md.ast.macro_rules {
-                self.update(md.hir_id, Some(AccessLevel::Public));
+                self.update(md.hir_id(), Some(AccessLevel::Public));
             }
             return;
         }
 
-        let macro_module_def_id =
-            ty::DefIdTree::parent(self.tcx, self.tcx.hir().local_def_id(md.hir_id).to_def_id())
-                .unwrap();
+        let macro_module_def_id = ty::DefIdTree::parent(self.tcx, md.def_id.to_def_id()).unwrap();
         let hir_id = macro_module_def_id
             .as_local()
             .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id));
@@ -883,7 +902,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
             _ => return,
         };
         let level = if md.vis.node.is_pub() { self.get(module_id) } else { None };
-        let new_level = self.update(md.hir_id, level);
+        let new_level = self.update(md.hir_id(), level);
         if new_level.is_none() {
             return;
         }
@@ -1037,7 +1056,7 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let orig_current_item = self.current_item.replace(item.hir_id);
+        let orig_current_item = self.current_item.replace(item.hir_id());
         intravisit::walk_item(self, item);
         self.current_item = orig_current_item;
     }
@@ -1204,10 +1223,9 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
             }
 
             for (poly_predicate, _) in bounds.projection_bounds {
-                let tcx = self.tcx;
                 if self.visit(poly_predicate.skip_binder().ty).is_break()
                     || self
-                        .visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx))
+                        .visit_projection_ty(poly_predicate.skip_binder().projection_ty)
                         .is_break()
                 {
                     return;
@@ -1322,8 +1340,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
 
     // Check types in item interfaces.
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let orig_current_item =
-            mem::replace(&mut self.current_item, self.tcx.hir().local_def_id(item.hir_id));
+        let orig_current_item = mem::replace(&mut self.current_item, item.def_id);
         let old_maybe_typeck_results = self.maybe_typeck_results.take();
         intravisit::walk_item(self, item);
         self.maybe_typeck_results = old_maybe_typeck_results;
@@ -1463,7 +1480,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
             hir::ItemKind::ForeignMod { .. } => {}
 
             hir::ItemKind::Trait(.., ref bounds, _) => {
-                if !self.trait_is_public(item.hir_id) {
+                if !self.trait_is_public(item.hir_id()) {
                     return;
                 }
 
@@ -1526,7 +1543,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
                         let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                         match impl_item.kind {
                             hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => {
-                                self.access_levels.is_reachable(impl_item_ref.id.hir_id)
+                                self.access_levels.is_reachable(impl_item_ref.id.hir_id())
                             }
                             hir::ImplItemKind::TyAlias(_) => false,
                         }
@@ -1546,8 +1563,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
                                 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                                 match impl_item.kind {
                                     hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..)
-                                        if self
-                                            .item_is_public(&impl_item.hir_id, &impl_item.vis) =>
+                                        if self.item_is_public(
+                                            &impl_item.hir_id(),
+                                            &impl_item.vis,
+                                        ) =>
                                     {
                                         intravisit::walk_impl_item(self, impl_item)
                                     }
@@ -1588,7 +1607,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
                     // methods will be visible as `Public::foo`.
                     let mut found_pub_static = false;
                     for impl_item_ref in impl_.items {
-                        if self.item_is_public(&impl_item_ref.id.hir_id, &impl_item_ref.vis) {
+                        if self.item_is_public(&impl_item_ref.id.hir_id(), &impl_item_ref.vis) {
                             let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
                             match impl_item_ref.kind {
                                 AssocItemKind::Const => {
@@ -1615,7 +1634,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
             hir::ItemKind::TyAlias(..) => return,
 
             // Not at all public, so we don't care.
-            _ if !self.item_is_public(&item.hir_id, &item.vis) => {
+            _ if !self.item_is_public(&item.hir_id(), &item.vis) => {
                 return;
             }
 
@@ -1651,7 +1670,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     }
 
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
-        if self.access_levels.is_reachable(item.hir_id) {
+        if self.access_levels.is_reachable(item.hir_id()) {
             intravisit::walk_foreign_item(self, item)
         }
     }
@@ -1849,41 +1868,18 @@ impl DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
     }
 }
 
-struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
+struct PrivateItemsInPublicInterfacesVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     has_pub_restricted: bool,
-    old_error_set: &'a HirIdSet,
+    old_error_set_ancestry: HirIdSet,
 }
 
-impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
+impl<'tcx> PrivateItemsInPublicInterfacesVisitor<'tcx> {
     fn check(
         &self,
         item_id: hir::HirId,
         required_visibility: ty::Visibility,
     ) -> SearchInterfaceForPrivateItemsVisitor<'tcx> {
-        let mut has_old_errors = false;
-
-        // Slow path taken only if there any errors in the crate.
-        for &id in self.old_error_set {
-            // Walk up the nodes until we find `item_id` (or we hit a root).
-            let mut id = id;
-            loop {
-                if id == item_id {
-                    has_old_errors = true;
-                    break;
-                }
-                let parent = self.tcx.hir().get_parent_node(id);
-                if parent == id {
-                    break;
-                }
-                id = parent;
-            }
-
-            if has_old_errors {
-                break;
-            }
-        }
-
         SearchInterfaceForPrivateItemsVisitor {
             tcx: self.tcx,
             item_id,
@@ -1891,7 +1887,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
             span: self.tcx.hir().span(item_id),
             required_visibility,
             has_pub_restricted: self.has_pub_restricted,
-            has_old_errors,
+            has_old_errors: self.old_error_set_ancestry.contains(&item_id),
             in_assoc_ty: false,
         }
     }
@@ -1917,7 +1913,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
+impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
     type Map = Map<'tcx>;
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -1926,7 +1922,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         let tcx = self.tcx;
-        let item_visibility = tcx.visibility(tcx.hir().local_def_id(item.hir_id).to_def_id());
+        let item_visibility = tcx.visibility(item.def_id);
 
         match item.kind {
             // Crates are always public.
@@ -1942,34 +1938,34 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
             | hir::ItemKind::Static(..)
             | hir::ItemKind::Fn(..)
             | hir::ItemKind::TyAlias(..) => {
-                self.check(item.hir_id, item_visibility).generics().predicates().ty();
+                self.check(item.hir_id(), item_visibility).generics().predicates().ty();
             }
             hir::ItemKind::OpaqueTy(..) => {
                 // `ty()` for opaque types is the underlying type,
                 // it's not a part of interface, so we skip it.
-                self.check(item.hir_id, item_visibility).generics().bounds();
+                self.check(item.hir_id(), item_visibility).generics().bounds();
             }
             hir::ItemKind::Trait(.., trait_item_refs) => {
-                self.check(item.hir_id, item_visibility).generics().predicates();
+                self.check(item.hir_id(), item_visibility).generics().predicates();
 
                 for trait_item_ref in trait_item_refs {
                     self.check_assoc_item(
-                        trait_item_ref.id.hir_id,
+                        trait_item_ref.id.hir_id(),
                         trait_item_ref.kind,
                         trait_item_ref.defaultness,
                         item_visibility,
                     );
 
                     if let AssocItemKind::Type = trait_item_ref.kind {
-                        self.check(trait_item_ref.id.hir_id, item_visibility).bounds();
+                        self.check(trait_item_ref.id.hir_id(), item_visibility).bounds();
                     }
                 }
             }
             hir::ItemKind::TraitAlias(..) => {
-                self.check(item.hir_id, item_visibility).generics().predicates();
+                self.check(item.hir_id(), item_visibility).generics().predicates();
             }
             hir::ItemKind::Enum(ref def, _) => {
-                self.check(item.hir_id, item_visibility).generics().predicates();
+                self.check(item.hir_id(), item_visibility).generics().predicates();
 
                 for variant in def.variants {
                     for field in variant.data.fields() {
@@ -1980,13 +1976,13 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
             // Subitems of foreign modules have their own publicity.
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
-                    let vis = tcx.visibility(tcx.hir().local_def_id(foreign_item.id.hir_id));
-                    self.check(foreign_item.id.hir_id, vis).generics().predicates().ty();
+                    let vis = tcx.visibility(foreign_item.id.def_id);
+                    self.check(foreign_item.id.hir_id(), vis).generics().predicates().ty();
                 }
             }
             // Subitems of structs and unions have their own publicity.
             hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
-                self.check(item.hir_id, item_visibility).generics().predicates();
+                self.check(item.hir_id(), item_visibility).generics().predicates();
 
                 for field in struct_def.fields() {
                     let field_visibility = tcx.visibility(tcx.hir().local_def_id(field.hir_id));
@@ -1998,20 +1994,16 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
             // A trait impl is public when both its type and its trait are public
             // Subitems of trait impls have inherited publicity.
             hir::ItemKind::Impl(ref impl_) => {
-                let impl_vis = ty::Visibility::of_impl(item.hir_id, tcx, &Default::default());
-                self.check(item.hir_id, impl_vis).generics().predicates();
+                let impl_vis = ty::Visibility::of_impl(item.hir_id(), tcx, &Default::default());
+                self.check(item.hir_id(), impl_vis).generics().predicates();
                 for impl_item_ref in impl_.items {
                     let impl_item_vis = if impl_.of_trait.is_none() {
-                        min(
-                            tcx.visibility(tcx.hir().local_def_id(impl_item_ref.id.hir_id)),
-                            impl_vis,
-                            tcx,
-                        )
+                        min(tcx.visibility(impl_item_ref.id.def_id), impl_vis, tcx)
                     } else {
                         impl_vis
                     };
                     self.check_assoc_item(
-                        impl_item_ref.id.hir_id,
+                        impl_item_ref.id.hir_id(),
                         impl_item_ref.kind,
                         impl_item_ref.defaultness,
                         impl_item_vis,
@@ -2141,11 +2133,22 @@ fn check_private_in_public(tcx: TyCtxt<'_>, krate: CrateNum) {
         pub_restricted_visitor.has_pub_restricted
     };
 
+    let mut old_error_set_ancestry = HirIdSet::default();
+    for mut id in visitor.old_error_set.iter().copied() {
+        loop {
+            if !old_error_set_ancestry.insert(id) {
+                break;
+            }
+            let parent = tcx.hir().get_parent_node(id);
+            if parent == id {
+                break;
+            }
+            id = parent;
+        }
+    }
+
     // Check for private types and traits in public interfaces.
-    let mut visitor = PrivateItemsInPublicInterfacesVisitor {
-        tcx,
-        has_pub_restricted,
-        old_error_set: &visitor.old_error_set,
-    };
+    let mut visitor =
+        PrivateItemsInPublicInterfacesVisitor { tcx, has_pub_restricted, old_error_set_ancestry };
     krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
 }
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
new file mode 100644
index 00000000000..c88b766a55a
--- /dev/null
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -0,0 +1,27 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_query_impl"
+version = "0.0.0"
+edition = "2018"
+
+[lib]
+doctest = false
+
+[dependencies]
+measureme = "9.0.0"
+rustc-rayon-core = "0.3.0"
+tracing = "0.1"
+rustc_ast = { path = "../rustc_ast" }
+rustc_attr = { path = "../rustc_attr" }
+rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_errors = { path = "../rustc_errors" }
+rustc_feature = { path = "../rustc_feature" }
+rustc_hir = { path = "../rustc_hir" }
+rustc_index = { path = "../rustc_index" }
+rustc_macros = { path = "../rustc_macros" }
+rustc_middle = { path = "../rustc_middle" }
+rustc_query_system = { path = "../rustc_query_system" }
+rustc_span = { path = "../rustc_span" }
+rustc_serialize = { path = "../rustc_serialize" }
+rustc_session = { path = "../rustc_session" }
+rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_middle/src/ty/query/README.md b/compiler/rustc_query_impl/src/README.md
index 8ec07b9fdeb..8ec07b9fdeb 100644
--- a/compiler/rustc_middle/src/ty/query/README.md
+++ b/compiler/rustc_query_impl/src/README.md
diff --git a/compiler/rustc_middle/src/ty/query/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index bfa1581aaae..1ae5bf12cab 100644
--- a/compiler/rustc_middle/src/ty/query/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -1,20 +1,17 @@
 //! Defines the set of legal keys that can be used in queries.
 
-use crate::infer::canonical::Canonical;
-use crate::mir;
-use crate::ty::fast_reject::SimplifiedType;
-use crate::ty::subst::{GenericArg, SubstsRef};
-use crate::ty::{self, Ty, TyCtxt};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
-use rustc_query_system::query::DefaultCacheSelector;
-use rustc_span::symbol::Symbol;
+use rustc_middle::infer::canonical::Canonical;
+use rustc_middle::mir;
+use rustc_middle::ty::fast_reject::SimplifiedType;
+use rustc_middle::ty::subst::{GenericArg, SubstsRef};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 
 /// The `Key` trait controls what types can legally be used as the key
 /// for a query.
 pub trait Key {
-    type CacheSelector;
-
     /// Given an instance of this key, what crate is it referring to?
     /// This is used to find the provider.
     fn query_crate(&self) -> CrateNum;
@@ -25,8 +22,6 @@ pub trait Key {
 }
 
 impl<'tcx> Key for ty::InstanceDef<'tcx> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -37,8 +32,6 @@ impl<'tcx> Key for ty::InstanceDef<'tcx> {
 }
 
 impl<'tcx> Key for ty::Instance<'tcx> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -49,8 +42,6 @@ impl<'tcx> Key for ty::Instance<'tcx> {
 }
 
 impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         self.instance.query_crate()
     }
@@ -61,8 +52,6 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
 }
 
 impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -73,8 +62,6 @@ impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> {
 }
 
 impl Key for CrateNum {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         *self
     }
@@ -84,8 +71,6 @@ impl Key for CrateNum {
 }
 
 impl Key for LocalDefId {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         self.to_def_id().query_crate()
     }
@@ -95,8 +80,6 @@ impl Key for LocalDefId {
 }
 
 impl Key for DefId {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         self.krate
     }
@@ -106,8 +89,6 @@ impl Key for DefId {
 }
 
 impl Key for ty::WithOptConstParam<LocalDefId> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         self.did.query_crate()
     }
@@ -117,8 +98,6 @@ impl Key for ty::WithOptConstParam<LocalDefId> {
 }
 
 impl Key for (DefId, DefId) {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         self.0.krate
     }
@@ -128,8 +107,6 @@ impl Key for (DefId, DefId) {
 }
 
 impl Key for (ty::Instance<'tcx>, LocalDefId) {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         self.0.query_crate()
     }
@@ -139,8 +116,6 @@ impl Key for (ty::Instance<'tcx>, LocalDefId) {
 }
 
 impl Key for (DefId, LocalDefId) {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         self.0.krate
     }
@@ -150,8 +125,6 @@ impl Key for (DefId, LocalDefId) {
 }
 
 impl Key for (LocalDefId, DefId) {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -160,9 +133,25 @@ impl Key for (LocalDefId, DefId) {
     }
 }
 
-impl Key for (CrateNum, DefId) {
-    type CacheSelector = DefaultCacheSelector;
+impl Key for (DefId, Option<Ident>) {
+    fn query_crate(&self) -> CrateNum {
+        self.0.krate
+    }
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        tcx.def_span(self.0)
+    }
+}
 
+impl Key for (DefId, LocalDefId, Ident) {
+    fn query_crate(&self) -> CrateNum {
+        self.0.krate
+    }
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.1.default_span(tcx)
+    }
+}
+
+impl Key for (CrateNum, DefId) {
     fn query_crate(&self) -> CrateNum {
         self.0
     }
@@ -172,8 +161,6 @@ impl Key for (CrateNum, DefId) {
 }
 
 impl Key for (DefId, SimplifiedType) {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         self.0.krate
     }
@@ -183,8 +170,6 @@ impl Key for (DefId, SimplifiedType) {
 }
 
 impl<'tcx> Key for SubstsRef<'tcx> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -194,8 +179,6 @@ impl<'tcx> Key for SubstsRef<'tcx> {
 }
 
 impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         self.0.krate
     }
@@ -210,8 +193,6 @@ impl<'tcx> Key
         (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
     )
 {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         (self.0).0.did.krate
     }
@@ -221,8 +202,6 @@ impl<'tcx> Key
 }
 
 impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -232,8 +211,6 @@ impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) {
 }
 
 impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         self.1.def_id().krate
     }
@@ -243,8 +220,6 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) {
 }
 
 impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -254,8 +229,6 @@ impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) {
 }
 
 impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         self.def_id().krate
     }
@@ -265,8 +238,6 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
 }
 
 impl<'tcx> Key for GenericArg<'tcx> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -276,8 +247,6 @@ impl<'tcx> Key for GenericArg<'tcx> {
 }
 
 impl<'tcx> Key for &'tcx ty::Const<'tcx> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -287,8 +256,6 @@ impl<'tcx> Key for &'tcx ty::Const<'tcx> {
 }
 
 impl<'tcx> Key for Ty<'tcx> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -298,8 +265,6 @@ impl<'tcx> Key for Ty<'tcx> {
 }
 
 impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -309,8 +274,6 @@ impl<'tcx> Key for &'tcx ty::List<ty::Predicate<'tcx>> {
 }
 
 impl<'tcx> Key for ty::ParamEnv<'tcx> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -320,8 +283,6 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> {
 }
 
 impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         self.value.query_crate()
     }
@@ -331,8 +292,6 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
 }
 
 impl Key for Symbol {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -344,8 +303,6 @@ impl Key for Symbol {
 /// Canonical query goals correspond to abstract trait operations that
 /// are not tied to any crate in particular.
 impl<'tcx, T> Key for Canonical<'tcx, T> {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -356,8 +313,6 @@ impl<'tcx, T> Key for Canonical<'tcx, T> {
 }
 
 impl Key for (Symbol, u32, u32) {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
@@ -368,8 +323,6 @@ impl Key for (Symbol, u32, u32) {
 }
 
 impl<'tcx> Key for (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>) {
-    type CacheSelector = DefaultCacheSelector;
-
     fn query_crate(&self) -> CrateNum {
         LOCAL_CRATE
     }
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
new file mode 100644
index 00000000000..43dfe6892b1
--- /dev/null
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -0,0 +1,65 @@
+//! Support for serializing the dep-graph and reloading it.
+
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(in_band_lifetimes)]
+#![feature(exhaustive_patterns)]
+#![feature(nll)]
+#![feature(min_specialization)]
+#![feature(crate_visibility_modifier)]
+#![feature(once_cell)]
+#![feature(rustc_attrs)]
+#![feature(never_type)]
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate rustc_middle;
+#[macro_use]
+extern crate tracing;
+
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_errors::{Diagnostic, Handler, Level};
+use rustc_hir::def_id::CrateNum;
+use rustc_index::vec::IndexVec;
+use rustc_middle::dep_graph;
+use rustc_middle::ich::StableHashingContext;
+use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values};
+use rustc_middle::ty::query::{Providers, QueryEngine};
+use rustc_middle::ty::TyCtxt;
+use rustc_serialize::opaque;
+use rustc_span::{Span, DUMMY_SP};
+use std::mem;
+
+#[macro_use]
+mod plumbing;
+pub use plumbing::QueryCtxt;
+use plumbing::QueryStruct;
+use rustc_query_system::query::*;
+
+mod stats;
+pub use self::stats::print_stats;
+
+mod keys;
+use keys::Key;
+
+mod values;
+use self::values::Value;
+
+use rustc_query_system::query::QueryAccessors;
+pub use rustc_query_system::query::QueryConfig;
+pub(crate) use rustc_query_system::query::QueryDescription;
+
+use rustc_middle::ty::query::on_disk_cache;
+
+mod profiling_support;
+pub use self::profiling_support::alloc_self_profile_query_strings;
+
+rustc_query_append! { [define_queries!][<'tcx>] }
+
+impl<'tcx> Queries<'tcx> {
+    // Force codegen in the dyn-trait transformation in this crate.
+    pub fn as_dyn(&'tcx self) -> &'tcx dyn QueryEngine<'tcx> {
+        self
+    }
+}
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
new file mode 100644
index 00000000000..d4093f281dd
--- /dev/null
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -0,0 +1,728 @@
+//! The implementation of the query system itself. This defines the macros that
+//! generate the actual methods on tcx which find and execute the provider,
+//! manage the caches, and so forth.
+
+use super::{queries, Query};
+use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeExt, DepNodeIndex, SerializedDepNodeIndex};
+use rustc_middle::ty::query::on_disk_cache;
+use rustc_middle::ty::tls::{self, ImplicitCtxt};
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_query_system::dep_graph::HasDepContext;
+use rustc_query_system::query::{CycleError, QueryJobId, QueryJobInfo};
+use rustc_query_system::query::{QueryContext, QueryDescription};
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::Lock;
+use rustc_data_structures::thin_vec::ThinVec;
+use rustc_errors::{struct_span_err, Diagnostic, DiagnosticBuilder};
+use rustc_serialize::opaque;
+use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::Span;
+
+#[derive(Copy, Clone)]
+pub struct QueryCtxt<'tcx> {
+    pub tcx: TyCtxt<'tcx>,
+    pub queries: &'tcx super::Queries<'tcx>,
+}
+
+impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
+    type Target = TyCtxt<'tcx>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.tcx
+    }
+}
+
+impl HasDepContext for QueryCtxt<'tcx> {
+    type DepKind = rustc_middle::dep_graph::DepKind;
+    type StableHashingContext = rustc_middle::ich::StableHashingContext<'tcx>;
+    type DepContext = TyCtxt<'tcx>;
+
+    #[inline]
+    fn dep_context(&self) -> &Self::DepContext {
+        &self.tcx
+    }
+}
+
+impl QueryContext for QueryCtxt<'tcx> {
+    type Query = Query<'tcx>;
+
+    fn incremental_verify_ich(&self) -> bool {
+        self.sess.opts.debugging_opts.incremental_verify_ich
+    }
+    fn verbose(&self) -> bool {
+        self.sess.verbose()
+    }
+
+    fn def_path_str(&self, def_id: DefId) -> String {
+        self.tcx.def_path_str(def_id)
+    }
+
+    fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>> {
+        tls::with_related_context(**self, |icx| icx.query)
+    }
+
+    fn try_collect_active_jobs(
+        &self,
+    ) -> Option<FxHashMap<QueryJobId<Self::DepKind>, QueryJobInfo<Self::DepKind, Self::Query>>>
+    {
+        self.queries.try_collect_active_jobs()
+    }
+
+    fn try_load_from_on_disk_cache(&self, dep_node: &DepNode) {
+        let cb = &super::QUERY_CALLBACKS[dep_node.kind as usize];
+        (cb.try_load_from_on_disk_cache)(*self, dep_node)
+    }
+
+    fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool {
+        // FIXME: This match is just a workaround for incremental bugs and should
+        // be removed. https://github.com/rust-lang/rust/issues/62649 is one such
+        // bug that must be fixed before removing this.
+        match dep_node.kind {
+            DepKind::hir_owner | DepKind::hir_owner_nodes => {
+                if let Some(def_id) = dep_node.extract_def_id(**self) {
+                    let def_id = def_id.expect_local();
+                    let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+                    if def_id != hir_id.owner {
+                        // This `DefPath` does not have a
+                        // corresponding `DepNode` (e.g. a
+                        // struct field), and the ` DefPath`
+                        // collided with the `DefPath` of a
+                        // proper item that existed in the
+                        // previous compilation session.
+                        //
+                        // Since the given `DefPath` does not
+                        // denote the item that previously
+                        // existed, we just fail to mark green.
+                        return false;
+                    }
+                } else {
+                    // If the node does not exist anymore, we
+                    // just fail to mark green.
+                    return false;
+                }
+            }
+            _ => {
+                // For other kinds of nodes it's OK to be
+                // forced.
+            }
+        }
+
+        debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
+
+        // We must avoid ever having to call `force_from_dep_node()` for a
+        // `DepNode::codegen_unit`:
+        // Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
+        // would always end up having to evaluate the first caller of the
+        // `codegen_unit` query that *is* reconstructible. This might very well be
+        // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
+        // to re-trigger calling the `codegen_unit` query with the right key. At
+        // that point we would already have re-done all the work we are trying to
+        // avoid doing in the first place.
+        // The solution is simple: Just explicitly call the `codegen_unit` query for
+        // each CGU, right after partitioning. This way `try_mark_green` will always
+        // hit the cache instead of having to go through `force_from_dep_node`.
+        // This assertion makes sure, we actually keep applying the solution above.
+        debug_assert!(
+            dep_node.kind != DepKind::codegen_unit,
+            "calling force_from_dep_node() on DepKind::codegen_unit"
+        );
+
+        let cb = &super::QUERY_CALLBACKS[dep_node.kind as usize];
+        (cb.force_from_dep_node)(*self, dep_node)
+    }
+
+    fn has_errors_or_delayed_span_bugs(&self) -> bool {
+        self.sess.has_errors_or_delayed_span_bugs()
+    }
+
+    fn diagnostic(&self) -> &rustc_errors::Handler {
+        self.sess.diagnostic()
+    }
+
+    // Interactions with on_disk_cache
+    fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic> {
+        self.on_disk_cache
+            .as_ref()
+            .map(|c| c.load_diagnostics(**self, prev_dep_node_index))
+            .unwrap_or_default()
+    }
+
+    fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>) {
+        if let Some(c) = self.on_disk_cache.as_ref() {
+            c.store_diagnostics(dep_node_index, diagnostics)
+        }
+    }
+
+    fn store_diagnostics_for_anon_node(
+        &self,
+        dep_node_index: DepNodeIndex,
+        diagnostics: ThinVec<Diagnostic>,
+    ) {
+        if let Some(c) = self.on_disk_cache.as_ref() {
+            c.store_diagnostics_for_anon_node(dep_node_index, diagnostics)
+        }
+    }
+
+    /// Executes a job by changing the `ImplicitCtxt` to point to the
+    /// new query job while it executes. It returns the diagnostics
+    /// captured during execution and the actual result.
+    #[inline(always)]
+    fn start_query<R>(
+        &self,
+        token: QueryJobId<Self::DepKind>,
+        diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
+        compute: impl FnOnce() -> R,
+    ) -> R {
+        // The `TyCtxt` stored in TLS has the same global interner lifetime
+        // as `self`, so we use `with_related_context` to relate the 'tcx lifetimes
+        // when accessing the `ImplicitCtxt`.
+        tls::with_related_context(**self, move |current_icx| {
+            // Update the `ImplicitCtxt` to point to our new query job.
+            let new_icx = ImplicitCtxt {
+                tcx: **self,
+                query: Some(token),
+                diagnostics,
+                layout_depth: current_icx.layout_depth,
+                task_deps: current_icx.task_deps,
+            };
+
+            // Use the `ImplicitCtxt` while we execute the query.
+            tls::enter_context(&new_icx, |_| {
+                rustc_data_structures::stack::ensure_sufficient_stack(compute)
+            })
+        })
+    }
+}
+
+impl<'tcx> QueryCtxt<'tcx> {
+    #[inline(never)]
+    #[cold]
+    pub(super) fn report_cycle(
+        self,
+        CycleError { usage, cycle: stack }: CycleError<Query<'tcx>>,
+    ) -> DiagnosticBuilder<'tcx> {
+        assert!(!stack.is_empty());
+
+        let fix_span = |span: Span, query: &Query<'tcx>| {
+            self.sess.source_map().guess_head_span(query.default_span(*self, span))
+        };
+
+        // Disable naming impls with types in this path, since that
+        // sometimes cycles itself, leading to extra cycle errors.
+        // (And cycle errors around impls tend to occur during the
+        // collect/coherence phases anyhow.)
+        ty::print::with_forced_impl_filename_line(|| {
+            let span = fix_span(stack[1 % stack.len()].span, &stack[0].query);
+            let mut err = struct_span_err!(
+                self.sess,
+                span,
+                E0391,
+                "cycle detected when {}",
+                stack[0].query.describe(self)
+            );
+
+            for i in 1..stack.len() {
+                let query = &stack[i].query;
+                let span = fix_span(stack[(i + 1) % stack.len()].span, query);
+                err.span_note(span, &format!("...which requires {}...", query.describe(self)));
+            }
+
+            err.note(&format!(
+                "...which again requires {}, completing the cycle",
+                stack[0].query.describe(self)
+            ));
+
+            if let Some((span, query)) = usage {
+                err.span_note(
+                    fix_span(span, &query),
+                    &format!("cycle used when {}", query.describe(self)),
+                );
+            }
+
+            err
+        })
+    }
+
+    pub(super) fn encode_query_results(
+        self,
+        encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>,
+        query_result_index: &mut on_disk_cache::EncodedQueryResultIndex,
+    ) -> opaque::FileEncodeResult {
+        macro_rules! encode_queries {
+            ($($query:ident,)*) => {
+                $(
+                    on_disk_cache::encode_query_results::<_, super::queries::$query<'_>>(
+                        self,
+                        encoder,
+                        query_result_index
+                    )?;
+                )*
+            }
+        }
+
+        rustc_cached_queries!(encode_queries!);
+
+        Ok(())
+    }
+}
+
+/// This struct stores metadata about each Query.
+///
+/// Information is retrieved by indexing the `QUERIES` array using the integer value
+/// of the `DepKind`. Overall, this allows to implement `QueryContext` using this manual
+/// jump table instead of large matches.
+pub struct QueryStruct {
+    /// The red/green evaluation system will try to mark a specific DepNode in the
+    /// dependency graph as green by recursively trying to mark the dependencies of
+    /// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
+    /// where we don't know if it is red or green and we therefore actually have
+    /// to recompute its value in order to find out. Since the only piece of
+    /// information that we have at that point is the `DepNode` we are trying to
+    /// re-evaluate, we need some way to re-run a query from just that. This is what
+    /// `force_from_dep_node()` implements.
+    ///
+    /// In the general case, a `DepNode` consists of a `DepKind` and an opaque
+    /// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
+    /// is usually constructed by computing a stable hash of the query-key that the
+    /// `DepNode` corresponds to. Consequently, it is not in general possible to go
+    /// back from hash to query-key (since hash functions are not reversible). For
+    /// this reason `force_from_dep_node()` is expected to fail from time to time
+    /// because we just cannot find out, from the `DepNode` alone, what the
+    /// corresponding query-key is and therefore cannot re-run the query.
+    ///
+    /// The system deals with this case letting `try_mark_green` fail which forces
+    /// the root query to be re-evaluated.
+    ///
+    /// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
+    /// Fortunately, we can use some contextual information that will allow us to
+    /// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
+    /// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
+    /// valid `DefPathHash`. Since we also always build a huge table that maps every
+    /// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
+    /// everything we need to re-run the query.
+    ///
+    /// Take the `mir_promoted` query as an example. Like many other queries, it
+    /// just has a single parameter: the `DefId` of the item it will compute the
+    /// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
+    /// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
+    /// is actually a `DefPathHash`, and can therefore just look up the corresponding
+    /// `DefId` in `tcx.def_path_hash_to_def_id`.
+    ///
+    /// When you implement a new query, it will likely have a corresponding new
+    /// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As
+    /// a rule of thumb, if your query takes a `DefId` or `LocalDefId` as sole parameter,
+    /// then `force_from_dep_node()` should not fail for it. Otherwise, you can just
+    /// add it to the "We don't have enough information to reconstruct..." group in
+    /// the match below.
+    pub(crate) force_from_dep_node: fn(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool,
+
+    /// Invoke a query to put the on-disk cached value in memory.
+    pub(crate) try_load_from_on_disk_cache: fn(QueryCtxt<'_>, &DepNode),
+}
+
+macro_rules! handle_cycle_error {
+    ([][$tcx: expr, $error:expr]) => {{
+        $tcx.report_cycle($error).emit();
+        Value::from_cycle_error($tcx)
+    }};
+    ([fatal_cycle $($rest:tt)*][$tcx:expr, $error:expr]) => {{
+        $tcx.report_cycle($error).emit();
+        $tcx.sess.abort_if_errors();
+        unreachable!()
+    }};
+    ([cycle_delay_bug $($rest:tt)*][$tcx:expr, $error:expr]) => {{
+        $tcx.report_cycle($error).delay_as_bug();
+        Value::from_cycle_error($tcx)
+    }};
+    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
+        handle_cycle_error!([$($($modifiers)*)*][$($args)*])
+    };
+}
+
+macro_rules! is_anon {
+    ([]) => {{
+        false
+    }};
+    ([anon $($rest:tt)*]) => {{
+        true
+    }};
+    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => {
+        is_anon!([$($($modifiers)*)*])
+    };
+}
+
+macro_rules! is_eval_always {
+    ([]) => {{
+        false
+    }};
+    ([eval_always $($rest:tt)*]) => {{
+        true
+    }};
+    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*]) => {
+        is_eval_always!([$($($modifiers)*)*])
+    };
+}
+
+macro_rules! hash_result {
+    ([][$hcx:expr, $result:expr]) => {{
+        dep_graph::hash_result($hcx, &$result)
+    }};
+    ([no_hash $($rest:tt)*][$hcx:expr, $result:expr]) => {{
+        None
+    }};
+    ([$other:ident $(($($other_args:tt)*))* $(, $($modifiers:tt)*)*][$($args:tt)*]) => {
+        hash_result!([$($($modifiers)*)*][$($args)*])
+    };
+}
+
+macro_rules! define_queries {
+    (<$tcx:tt>
+     $($(#[$attr:meta])*
+        [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
+
+        define_queries_struct! {
+            tcx: $tcx,
+            input: ($(([$($modifiers)*] [$($attr)*] [$name]))*)
+        }
+
+        #[allow(nonstandard_style)]
+        #[derive(Clone, Debug)]
+        pub enum Query<$tcx> {
+            $($(#[$attr])* $name(query_keys::$name<$tcx>)),*
+        }
+
+        impl<$tcx> Query<$tcx> {
+            pub fn name(&self) -> &'static str {
+                match *self {
+                    $(Query::$name(_) => stringify!($name),)*
+                }
+            }
+
+            pub(crate) fn describe(&self, tcx: QueryCtxt<$tcx>) -> String {
+                let (r, name) = match *self {
+                    $(Query::$name(key) => {
+                        (queries::$name::describe(tcx, key), stringify!($name))
+                    })*
+                };
+                if tcx.sess.verbose() {
+                    format!("{} [{}]", r, name)
+                } else {
+                    r
+                }
+            }
+
+            // FIXME(eddyb) Get more valid `Span`s on queries.
+            pub fn default_span(&self, tcx: TyCtxt<$tcx>, span: Span) -> Span {
+                if !span.is_dummy() {
+                    return span;
+                }
+                // The `def_span` query is used to calculate `default_span`,
+                // so exit to avoid infinite recursion.
+                if let Query::def_span(..) = *self {
+                    return span
+                }
+                match *self {
+                    $(Query::$name(key) => key.default_span(tcx),)*
+                }
+            }
+        }
+
+        impl<'a, $tcx> HashStable<StableHashingContext<'a>> for Query<$tcx> {
+            fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+                mem::discriminant(self).hash_stable(hcx, hasher);
+                match *self {
+                    $(Query::$name(key) => key.hash_stable(hcx, hasher),)*
+                }
+            }
+        }
+
+        #[allow(nonstandard_style)]
+        pub mod queries {
+            use std::marker::PhantomData;
+
+            $(pub struct $name<$tcx> {
+                data: PhantomData<&$tcx ()>
+            })*
+        }
+
+        $(impl<$tcx> QueryConfig for queries::$name<$tcx> {
+            type Key = query_keys::$name<$tcx>;
+            type Value = query_values::$name<$tcx>;
+            type Stored = query_stored::$name<$tcx>;
+            const NAME: &'static str = stringify!($name);
+        }
+
+        impl<$tcx> QueryAccessors<QueryCtxt<$tcx>> for queries::$name<$tcx> {
+            const ANON: bool = is_anon!([$($modifiers)*]);
+            const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
+            const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$name;
+
+            type Cache = query_storage::$name<$tcx>;
+
+            #[inline(always)]
+            fn query_state<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryState<crate::dep_graph::DepKind, Query<$tcx>, Self::Key> {
+                &tcx.queries.$name
+            }
+
+            #[inline(always)]
+            fn query_cache<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryCacheStore<Self::Cache>
+                where 'tcx:'a
+            {
+                &tcx.query_caches.$name
+            }
+
+            #[inline]
+            fn compute(tcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value {
+                let provider = tcx.queries.providers.get(key.query_crate())
+                    // HACK(eddyb) it's possible crates may be loaded after
+                    // the query engine is created, and because crate loading
+                    // is not yet integrated with the query engine, such crates
+                    // would be missing appropriate entries in `providers`.
+                    .unwrap_or(&tcx.queries.fallback_extern_providers)
+                    .$name;
+                provider(*tcx, key)
+            }
+
+            fn hash_result(
+                _hcx: &mut StableHashingContext<'_>,
+                _result: &Self::Value
+            ) -> Option<Fingerprint> {
+                hash_result!([$($modifiers)*][_hcx, _result])
+            }
+
+            fn handle_cycle_error(
+                tcx: QueryCtxt<'tcx>,
+                error: CycleError<Query<'tcx>>
+            ) -> Self::Value {
+                handle_cycle_error!([$($modifiers)*][tcx, error])
+            }
+        })*
+
+        #[allow(non_upper_case_globals)]
+        pub mod query_callbacks {
+            use super::*;
+            use rustc_middle::dep_graph::DepNode;
+            use rustc_middle::ty::query::query_keys;
+            use rustc_query_system::dep_graph::DepNodeParams;
+            use rustc_query_system::query::{force_query, QueryDescription};
+
+            // We use this for most things when incr. comp. is turned off.
+            pub const Null: QueryStruct = QueryStruct {
+                force_from_dep_node: |_, dep_node| bug!("force_from_dep_node: encountered {:?}", dep_node),
+                try_load_from_on_disk_cache: |_, _| {},
+            };
+
+            pub const TraitSelect: QueryStruct = QueryStruct {
+                force_from_dep_node: |_, _| false,
+                try_load_from_on_disk_cache: |_, _| {},
+            };
+
+            pub const CompileCodegenUnit: QueryStruct = QueryStruct {
+                force_from_dep_node: |_, _| false,
+                try_load_from_on_disk_cache: |_, _| {},
+            };
+
+            $(pub const $name: QueryStruct = {
+                const is_anon: bool = is_anon!([$($modifiers)*]);
+
+                #[inline(always)]
+                fn can_reconstruct_query_key() -> bool {
+                    <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>
+                        ::can_reconstruct_query_key()
+                }
+
+                fn recover<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<query_keys::$name<'tcx>> {
+                    <query_keys::$name<'_> as DepNodeParams<TyCtxt<'_>>>::recover(tcx, dep_node)
+                }
+
+                fn force_from_dep_node(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool {
+                    if is_anon {
+                        return false;
+                    }
+
+                    if !can_reconstruct_query_key() {
+                        return false;
+                    }
+
+                    if let Some(key) = recover(*tcx, dep_node) {
+                        force_query::<queries::$name<'_>, _>(tcx, key, DUMMY_SP, *dep_node);
+                        return true;
+                    }
+
+                    false
+                }
+
+                fn try_load_from_on_disk_cache(tcx: QueryCtxt<'_>, dep_node: &DepNode) {
+                    if is_anon {
+                        return
+                    }
+
+                    if !can_reconstruct_query_key() {
+                        return
+                    }
+
+                    debug_assert!(tcx.dep_graph
+                                     .node_color(dep_node)
+                                     .map(|c| c.is_green())
+                                     .unwrap_or(false));
+
+                    let key = recover(*tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
+                    if queries::$name::cache_on_disk(tcx, &key, None) {
+                        let _ = tcx.$name(key);
+                    }
+                }
+
+                QueryStruct {
+                    force_from_dep_node,
+                    try_load_from_on_disk_cache,
+                }
+            };)*
+        }
+
+        static QUERY_CALLBACKS: &[QueryStruct] = &make_dep_kind_array!(query_callbacks);
+    }
+}
+
+// FIXME(eddyb) this macro (and others?) use `$tcx` and `'tcx` interchangeably.
+// We should either not take `$tcx` at all and use `'tcx` everywhere, or use
+// `$tcx` everywhere (even if that isn't necessary due to lack of hygiene).
+macro_rules! define_queries_struct {
+    (tcx: $tcx:tt,
+     input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
+        pub struct Queries<$tcx> {
+            providers: IndexVec<CrateNum, Providers>,
+            fallback_extern_providers: Box<Providers>,
+
+            $($(#[$attr])*  $name: QueryState<
+                crate::dep_graph::DepKind,
+                Query<$tcx>,
+                query_keys::$name<$tcx>,
+            >,)*
+        }
+
+        impl<$tcx> Queries<$tcx> {
+            pub fn new(
+                providers: IndexVec<CrateNum, Providers>,
+                fallback_extern_providers: Providers,
+            ) -> Self {
+                Queries {
+                    providers,
+                    fallback_extern_providers: Box::new(fallback_extern_providers),
+                    $($name: Default::default()),*
+                }
+            }
+
+            pub(crate) fn try_collect_active_jobs(
+                &self
+            ) -> Option<FxHashMap<QueryJobId<crate::dep_graph::DepKind>, QueryJobInfo<crate::dep_graph::DepKind, Query<$tcx>>>> {
+                let mut jobs = FxHashMap::default();
+
+                $(
+                    self.$name.try_collect_active_jobs(
+                        <queries::$name<'tcx> as QueryAccessors<QueryCtxt<'tcx>>>::DEP_KIND,
+                        Query::$name,
+                        &mut jobs,
+                    )?;
+                )*
+
+                Some(jobs)
+            }
+        }
+
+        impl QueryEngine<'tcx> for Queries<'tcx> {
+            unsafe fn deadlock(&'tcx self, _tcx: TyCtxt<'tcx>, _registry: &rustc_rayon_core::Registry) {
+                #[cfg(parallel_compiler)]
+                {
+                    let tcx = QueryCtxt { tcx: _tcx, queries: self };
+                    rustc_query_system::query::deadlock(tcx, _registry)
+                }
+            }
+
+            fn encode_query_results(
+                &'tcx self,
+                tcx: TyCtxt<'tcx>,
+                encoder: &mut on_disk_cache::CacheEncoder<'a, 'tcx, opaque::FileEncoder>,
+                query_result_index: &mut on_disk_cache::EncodedQueryResultIndex,
+            ) -> opaque::FileEncodeResult {
+                let tcx = QueryCtxt { tcx, queries: self };
+                tcx.encode_query_results(encoder, query_result_index)
+            }
+
+            fn exec_cache_promotions(&'tcx self, tcx: TyCtxt<'tcx>) {
+                let tcx = QueryCtxt { tcx, queries: self };
+                tcx.dep_graph.exec_cache_promotions(tcx)
+            }
+
+            fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool {
+                let qcx = QueryCtxt { tcx, queries: self };
+                tcx.dep_graph.try_mark_green(qcx, dep_node).is_some()
+            }
+
+            fn try_print_query_stack(
+                &'tcx self,
+                tcx: TyCtxt<'tcx>,
+                query: Option<QueryJobId<dep_graph::DepKind>>,
+                handler: &Handler,
+                num_frames: Option<usize>,
+            ) -> usize {
+                let query_map = self.try_collect_active_jobs();
+
+                let mut current_query = 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
+                    } else {
+                        break;
+                    };
+                    let mut diag = Diagnostic::new(
+                        Level::FailureNote,
+                        &format!(
+                            "#{} [{}] {}",
+                            i,
+                            query_info.info.query.name(),
+                            query_info.info.query.describe(QueryCtxt { tcx, queries: self })
+                        ),
+                    );
+                    diag.span = tcx.sess.source_map().guess_head_span(query_info.info.span).into();
+                    handler.force_print_diagnostic(diag);
+
+                    current_query = query_info.job.parent;
+                    i += 1;
+                }
+
+                i
+            }
+
+            $($(#[$attr])*
+            #[inline(always)]
+            fn $name(
+                &'tcx self,
+                tcx: TyCtxt<$tcx>,
+                span: Span,
+                key: query_keys::$name<$tcx>,
+                lookup: QueryLookup,
+                mode: QueryMode,
+            ) -> Option<query_stored::$name<$tcx>> {
+                let qcx = QueryCtxt { tcx, queries: self };
+                get_query::<queries::$name<$tcx>, _>(qcx, span, key, lookup, mode)
+            })*
+        }
+    };
+}
+
+fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
+    if def_id.is_top_level_module() {
+        "top-level module".to_string()
+    } else {
+        format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
+    }
+}
+
+rustc_query_description! {}
diff --git a/compiler/rustc_middle/src/ty/query/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index cbcecb88491..24485889731 100644
--- a/compiler/rustc_middle/src/ty/query/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -1,32 +1,31 @@
-use crate::ty::context::TyCtxt;
-use crate::ty::WithOptConstParam;
 use measureme::{StringComponent, StringId};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::profiling::SelfProfiler;
 use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::DefPathData;
-use rustc_query_system::query::{QueryCache, QueryContext, QueryState};
+use rustc_middle::ty::{TyCtxt, WithOptConstParam};
+use rustc_query_system::query::{QueryCache, QueryCacheStore};
 use std::fmt::Debug;
 use std::io::Write;
 
-pub struct QueryKeyStringCache {
+struct QueryKeyStringCache {
     def_id_cache: FxHashMap<DefId, StringId>,
 }
 
 impl QueryKeyStringCache {
-    pub fn new() -> QueryKeyStringCache {
+    fn new() -> QueryKeyStringCache {
         QueryKeyStringCache { def_id_cache: Default::default() }
     }
 }
 
-pub struct QueryKeyStringBuilder<'p, 'c, 'tcx> {
+struct QueryKeyStringBuilder<'p, 'c, 'tcx> {
     profiler: &'p SelfProfiler,
     tcx: TyCtxt<'tcx>,
     string_cache: &'c mut QueryKeyStringCache,
 }
 
 impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> {
-    pub fn new(
+    fn new(
         profiler: &'p SelfProfiler,
         tcx: TyCtxt<'tcx>,
         string_cache: &'c mut QueryKeyStringCache,
@@ -98,7 +97,7 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> {
     }
 }
 
-pub trait IntoSelfProfilingString {
+trait IntoSelfProfilingString {
     fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId;
 }
 
@@ -123,7 +122,7 @@ impl<T: SpecIntoSelfProfilingString> IntoSelfProfilingString for T {
 }
 
 #[rustc_specialization_trait]
-pub trait SpecIntoSelfProfilingString: Debug {
+trait SpecIntoSelfProfilingString: Debug {
     fn spec_to_self_profile_string(
         &self,
         builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
@@ -227,10 +226,10 @@ where
 /// Allocate the self-profiling query strings for a single query cache. This
 /// method is called from `alloc_self_profile_query_strings` which knows all
 /// the queries via macro magic.
-pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
+fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
     tcx: TyCtxt<'tcx>,
     query_name: &'static str,
-    query_state: &QueryState<crate::dep_graph::DepKind, <TyCtxt<'tcx> as QueryContext>::Query, C>,
+    query_cache: &QueryCacheStore<C>,
     string_cache: &mut QueryKeyStringCache,
 ) where
     C: QueryCache,
@@ -251,7 +250,7 @@ pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
             // need to invoke queries itself, we cannot keep the query caches
             // locked while doing so. Instead we copy out the
             // `(query_key, dep_node_index)` pairs and release the lock again.
-            let query_keys_and_indices: Vec<_> = query_state
+            let query_keys_and_indices: Vec<_> = query_cache
                 .iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect());
 
             // Now actually allocate the strings. If allocating the strings
@@ -276,7 +275,7 @@ pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
             let query_name = profiler.get_or_alloc_cached_string(query_name);
             let event_id = event_id_builder.from_label(query_name).to_string_id();
 
-            query_state.iter_results(|results| {
+            query_cache.iter_results(|results| {
                 let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect();
 
                 profiler.bulk_map_query_invocation_id_to_single_string(
@@ -287,3 +286,35 @@ pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
         }
     });
 }
+
+/// All self-profiling events generated by the query engine use
+/// virtual `StringId`s for their `event_id`. This method makes all
+/// those virtual `StringId`s point to actual strings.
+///
+/// If we are recording only summary data, the ids will point to
+/// just the query names. If we are recording query keys too, we
+/// allocate the corresponding strings here.
+pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'tcx>) {
+    if !tcx.prof.enabled() {
+        return;
+    }
+
+    let mut string_cache = QueryKeyStringCache::new();
+
+    macro_rules! alloc_once {
+        (<$tcx:tt>
+            $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($K:ty) -> $V:ty,)*
+        ) => {
+            $({
+                alloc_self_profile_query_strings_for_query_cache(
+                    tcx,
+                    stringify!($name),
+                    &tcx.query_caches.$name,
+                    &mut string_cache,
+                );
+            })*
+        }
+    }
+
+    rustc_query_append! { [alloc_once!][<'tcx>] }
+}
diff --git a/compiler/rustc_middle/src/ty/query/stats.rs b/compiler/rustc_query_impl/src/stats.rs
index e0b44ce23c9..4d52483c3b8 100644
--- a/compiler/rustc_middle/src/ty/query/stats.rs
+++ b/compiler/rustc_query_impl/src/stats.rs
@@ -1,10 +1,9 @@
-use crate::ty::query::queries;
-use crate::ty::TyCtxt;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_query_system::query::{QueryAccessors, QueryCache, QueryContext, QueryState};
+use rustc_middle::ty::query::query_storage;
+use rustc_middle::ty::TyCtxt;
+use rustc_query_system::query::{QueryCache, QueryCacheStore};
 
 use std::any::type_name;
-use std::hash::Hash;
 use std::mem;
 #[cfg(debug_assertions)]
 use std::sync::atomic::Ordering;
@@ -37,10 +36,8 @@ struct QueryStats {
     local_def_id_keys: Option<usize>,
 }
 
-fn stats<D, Q, C>(name: &'static str, map: &QueryState<D, Q, C>) -> QueryStats
+fn stats<C>(name: &'static str, map: &QueryCacheStore<C>) -> QueryStats
 where
-    D: Copy + Clone + Eq + Hash,
-    Q: Clone,
     C: QueryCache,
 {
     let mut stats = QueryStats {
@@ -70,29 +67,29 @@ pub fn print_stats(tcx: TyCtxt<'_>) {
     if cfg!(debug_assertions) {
         let hits: usize = queries.iter().map(|s| s.cache_hits).sum();
         let results: usize = queries.iter().map(|s| s.entry_count).sum();
-        println!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
+        eprintln!("\nQuery cache hit rate: {}", hits as f64 / (hits + results) as f64);
     }
 
     let mut query_key_sizes = queries.clone();
     query_key_sizes.sort_by_key(|q| q.key_size);
-    println!("\nLarge query keys:");
+    eprintln!("\nLarge query keys:");
     for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) {
-        println!("   {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
+        eprintln!("   {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
     }
 
     let mut query_value_sizes = queries.clone();
     query_value_sizes.sort_by_key(|q| q.value_size);
-    println!("\nLarge query values:");
+    eprintln!("\nLarge query values:");
     for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) {
-        println!("   {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
+        eprintln!("   {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
     }
 
     if cfg!(debug_assertions) {
         let mut query_cache_hits = queries.clone();
         query_cache_hits.sort_by_key(|q| q.cache_hits);
-        println!("\nQuery cache hits:");
+        eprintln!("\nQuery cache hits:");
         for q in query_cache_hits.iter().rev() {
-            println!(
+            eprintln!(
                 "   {} - {} ({}%)",
                 q.name,
                 q.cache_hits,
@@ -103,19 +100,19 @@ pub fn print_stats(tcx: TyCtxt<'_>) {
 
     let mut query_value_count = queries.clone();
     query_value_count.sort_by_key(|q| q.entry_count);
-    println!("\nQuery value count:");
+    eprintln!("\nQuery value count:");
     for q in query_value_count.iter().rev() {
-        println!("   {} - {}", q.name, q.entry_count);
+        eprintln!("   {} - {}", q.name, q.entry_count);
     }
 
     let mut def_id_density: Vec<_> =
         queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect();
     def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap());
-    println!("\nLocal DefId density:");
+    eprintln!("\nLocal DefId density:");
     let total = tcx.hir().definitions().def_index_count() as f64;
     for q in def_id_density.iter().rev() {
         let local = q.local_def_id_keys.unwrap();
-        println!("   {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
+        eprintln!("   {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
     }
 }
 
@@ -128,12 +125,10 @@ macro_rules! print_stats {
 
             $(
                 queries.push(stats::<
-                    crate::dep_graph::DepKind,
-                    <TyCtxt<'_> as QueryContext>::Query,
-                    <queries::$name<'_> as QueryAccessors<TyCtxt<'_>>>::Cache,
+                    query_storage::$name<'_>,
                 >(
                     stringify!($name),
-                    &tcx.queries.$name,
+                    &tcx.query_caches.$name,
                 ));
             )*
 
diff --git a/compiler/rustc_middle/src/ty/query/values.rs b/compiler/rustc_query_impl/src/values.rs
index f28b0f499f0..003867beeb7 100644
--- a/compiler/rustc_middle/src/ty/query/values.rs
+++ b/compiler/rustc_query_impl/src/values.rs
@@ -1,18 +1,19 @@
-use crate::ty::{self, AdtSizedConstraint, Ty, TyCtxt, TyS};
+use super::QueryCtxt;
+use rustc_middle::ty::{self, AdtSizedConstraint, Ty, TyS};
 
 pub(super) trait Value<'tcx>: Sized {
-    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self;
+    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self;
 }
 
 impl<'tcx, T> Value<'tcx> for T {
-    default fn from_cycle_error(tcx: TyCtxt<'tcx>) -> T {
+    default fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> T {
         tcx.sess.abort_if_errors();
         bug!("Value::from_cycle_error called without errors");
     }
 }
 
 impl<'tcx> Value<'tcx> for &'_ TyS<'_> {
-    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
+    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
         // SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
         // FIXME: Represent the above fact in the trait system somehow.
         unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(tcx.ty_error()) }
@@ -20,19 +21,19 @@ impl<'tcx> Value<'tcx> for &'_ TyS<'_> {
 }
 
 impl<'tcx> Value<'tcx> for ty::SymbolName<'_> {
-    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
+    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
         // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
         // FIXME: Represent the above fact in the trait system somehow.
         unsafe {
             std::mem::transmute::<ty::SymbolName<'tcx>, ty::SymbolName<'_>>(ty::SymbolName::new(
-                tcx, "<error>",
+                *tcx, "<error>",
             ))
         }
     }
 }
 
 impl<'tcx> Value<'tcx> for AdtSizedConstraint<'_> {
-    fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
+    fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
         // SAFETY: This is never called when `Self` is not `AdtSizedConstraint<'tcx>`.
         // FIXME: Represent the above fact in the trait system somehow.
         unsafe {
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index f38d62dec00..d18a2a6faed 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -18,4 +18,4 @@ rustc_index = { path = "../rustc_index" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_span = { path = "../rustc_span" }
 parking_lot = "0.11"
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_query_system/src/cache.rs b/compiler/rustc_query_system/src/cache.rs
index be3d3607728..c6dc7b4fe28 100644
--- a/compiler/rustc_query_system/src/cache.rs
+++ b/compiler/rustc_query_system/src/cache.rs
@@ -1,7 +1,6 @@
 //! Cache for candidate selection.
 
-use crate::dep_graph::DepNodeIndex;
-use crate::query::QueryContext;
+use crate::dep_graph::{DepContext, DepNodeIndex};
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::HashMapExt;
@@ -28,7 +27,7 @@ impl<Key, Value> Cache<Key, Value> {
 }
 
 impl<Key: Eq + Hash, Value: Clone> Cache<Key, Value> {
-    pub fn get<CTX: QueryContext>(&self, key: &Key, tcx: CTX) -> Option<Value> {
+    pub fn get<CTX: DepContext>(&self, key: &Key, tcx: CTX) -> Option<Value> {
         Some(self.hashmap.borrow().get(key)?.get(tcx))
     }
 
@@ -55,7 +54,7 @@ impl<T: Clone> WithDepNode<T> {
         WithDepNode { dep_node, cached_value }
     }
 
-    pub fn get<CTX: QueryContext>(&self, tcx: CTX) -> T {
+    pub fn get<CTX: DepContext>(&self, tcx: CTX) -> T {
         tcx.dep_graph().read_index(self.dep_node);
         self.cached_value.clone()
     }
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 64aba870502..1319a31b8f5 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -79,7 +79,7 @@ impl<K: DepKind> DepNode<K> {
 
     pub fn construct<Ctxt, Key>(tcx: Ctxt, kind: K, arg: &Key) -> DepNode<K>
     where
-        Ctxt: crate::query::QueryContext<DepKind = K>,
+        Ctxt: super::DepContext<DepKind = K>,
         Key: DepNodeParams<Ctxt>,
     {
         let hash = arg.to_fingerprint(tcx);
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 4fb3a683ea2..f579052c106 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -23,7 +23,8 @@ use super::debug::EdgeFilter;
 use super::prev::PreviousDepGraph;
 use super::query::DepGraphQuery;
 use super::serialized::SerializedDepNodeIndex;
-use super::{DepContext, DepKind, DepNode, WorkProductId};
+use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
+use crate::query::QueryContext;
 
 #[derive(Clone)]
 pub struct DepGraph<K: DepKind> {
@@ -235,7 +236,7 @@ impl<K: DepKind> DepGraph<K> {
     ///   `arg` parameter.
     ///
     /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/incremental-compilation.html
-    pub fn with_task<Ctxt: DepContext<DepKind = K>, A, R>(
+    pub fn with_task<Ctxt: HasDepContext<DepKind = K>, A, R>(
         &self,
         key: DepNode<K>,
         cx: Ctxt,
@@ -261,7 +262,7 @@ impl<K: DepKind> DepGraph<K> {
         )
     }
 
-    fn with_task_impl<Ctxt: DepContext<DepKind = K>, A, R>(
+    fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A, R>(
         &self,
         key: DepNode<K>,
         cx: Ctxt,
@@ -271,14 +272,15 @@ impl<K: DepKind> DepGraph<K> {
         hash_result: impl FnOnce(&mut Ctxt::StableHashingContext, &R) -> Option<Fingerprint>,
     ) -> (R, DepNodeIndex) {
         if let Some(ref data) = self.data {
+            let dcx = cx.dep_context();
             let task_deps = create_task(key).map(Lock::new);
             let result = K::with_deps(task_deps.as_ref(), || task(cx, arg));
             let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);
 
-            let mut hcx = cx.create_stable_hashing_context();
+            let mut hcx = dcx.create_stable_hashing_context();
             let current_fingerprint = hash_result(&mut hcx, &result);
 
-            let print_status = cfg!(debug_assertions) && cx.debug_dep_tasks();
+            let print_status = cfg!(debug_assertions) && dcx.debug_dep_tasks();
 
             // Intern the new `DepNode`.
             let dep_node_index = if let Some(prev_index) = data.previous.node_to_index_opt(&key) {
@@ -408,7 +410,7 @@ impl<K: DepKind> DepGraph<K> {
 
     /// Executes something within an "eval-always" task which is a task
     /// that runs whenever anything changes.
-    pub fn with_eval_always_task<Ctxt: DepContext<DepKind = K>, A, R>(
+    pub fn with_eval_always_task<Ctxt: HasDepContext<DepKind = K>, A, R>(
         &self,
         key: DepNode<K>,
         cx: Ctxt,
@@ -585,7 +587,7 @@ impl<K: DepKind> DepGraph<K> {
     /// A node will have an index, when it's already been marked green, or when we can mark it
     /// green. This function will mark the current task as a reader of the specified node, when
     /// a node index can be found for that node.
-    pub fn try_mark_green_and_read<Ctxt: DepContext<DepKind = K>>(
+    pub fn try_mark_green_and_read<Ctxt: QueryContext<DepKind = K>>(
         &self,
         tcx: Ctxt,
         dep_node: &DepNode<K>,
@@ -597,7 +599,7 @@ impl<K: DepKind> DepGraph<K> {
         })
     }
 
-    pub fn try_mark_green<Ctxt: DepContext<DepKind = K>>(
+    pub fn try_mark_green<Ctxt: QueryContext<DepKind = K>>(
         &self,
         tcx: Ctxt,
         dep_node: &DepNode<K>,
@@ -625,7 +627,7 @@ impl<K: DepKind> DepGraph<K> {
     }
 
     /// Try to mark a dep-node which existed in the previous compilation session as green.
-    fn try_mark_previous_green<Ctxt: DepContext<DepKind = K>>(
+    fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
         &self,
         tcx: Ctxt,
         data: &DepGraphData<K>,
@@ -809,7 +811,7 @@ impl<K: DepKind> DepGraph<K> {
     /// This may be called concurrently on multiple threads for the same dep node.
     #[cold]
     #[inline(never)]
-    fn emit_diagnostics<Ctxt: DepContext<DepKind = K>>(
+    fn emit_diagnostics<Ctxt: QueryContext<DepKind = K>>(
         &self,
         tcx: Ctxt,
         data: &DepGraphData<K>,
@@ -874,7 +876,8 @@ impl<K: DepKind> DepGraph<K> {
     //
     // This method will only load queries that will end up in the disk cache.
     // Other queries will not be executed.
-    pub fn exec_cache_promotions<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
+    pub fn exec_cache_promotions<Ctxt: QueryContext<DepKind = K>>(&self, qcx: Ctxt) {
+        let tcx = qcx.dep_context();
         let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion");
 
         let data = self.data.as_ref().unwrap();
@@ -882,7 +885,7 @@ impl<K: DepKind> DepGraph<K> {
             match data.colors.get(prev_index) {
                 Some(DepNodeColor::Green(_)) => {
                     let dep_node = data.previous.index_to_node(prev_index);
-                    tcx.try_load_from_on_disk_cache(&dep_node);
+                    qcx.try_load_from_on_disk_cache(&dep_node);
                 }
                 None | Some(DepNodeColor::Red) => {
                     // We can skip red nodes because a node can only be marked
@@ -964,29 +967,29 @@ impl<K: DepKind> DepGraph<K> {
                                  ----------------------------------------------\
                                  ------------";
 
-        println!("[incremental]");
-        println!("[incremental] DepGraph Statistics");
-        println!("{}", SEPARATOR);
-        println!("[incremental]");
-        println!("[incremental] Total Node Count: {}", total_node_count);
-        println!("[incremental] Total Edge Count: {}", total_edge_count);
+        eprintln!("[incremental]");
+        eprintln!("[incremental] DepGraph Statistics");
+        eprintln!("{}", SEPARATOR);
+        eprintln!("[incremental]");
+        eprintln!("[incremental] Total Node Count: {}", total_node_count);
+        eprintln!("[incremental] Total Edge Count: {}", total_edge_count);
 
         if cfg!(debug_assertions) {
             let total_edge_reads = current.total_read_count.load(Relaxed);
             let total_duplicate_edge_reads = current.total_duplicate_read_count.load(Relaxed);
 
-            println!("[incremental] Total Edge Reads: {}", total_edge_reads);
-            println!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
+            eprintln!("[incremental] Total Edge Reads: {}", total_edge_reads);
+            eprintln!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
         }
 
-        println!("[incremental]");
+        eprintln!("[incremental]");
 
-        println!(
+        eprintln!(
             "[incremental]  {:<36}| {:<17}| {:<12}| {:<17}|",
             "Node Kind", "Node Frequency", "Node Count", "Avg. Edge Count"
         );
 
-        println!(
+        eprintln!(
             "[incremental] -------------------------------------\
                   |------------------\
                   |-------------\
@@ -997,7 +1000,7 @@ impl<K: DepKind> DepGraph<K> {
             let node_kind_ratio = (100.0 * (stat.node_counter as f64)) / (total_node_count as f64);
             let node_kind_avg_edges = (stat.edge_counter as f64) / (stat.node_counter as f64);
 
-            println!(
+            eprintln!(
                 "[incremental]  {:<36}|{:>16.1}% |{:>12} |{:>17.1} |",
                 format!("{:?}", stat.kind),
                 node_kind_ratio,
@@ -1006,8 +1009,8 @@ impl<K: DepKind> DepGraph<K> {
             );
         }
 
-        println!("{}", SEPARATOR);
-        println!("[incremental]");
+        eprintln!("{}", SEPARATOR);
+        eprintln!("[incremental]");
     }
 
     fn next_virtual_depnode_index(&self) -> DepNodeIndex {
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index b1c901633a7..a647381fb03 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -13,8 +13,6 @@ pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex};
 
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sync::Lock;
-use rustc_data_structures::thin_vec::ThinVec;
-use rustc_errors::Diagnostic;
 
 use std::fmt;
 use std::hash::Hash;
@@ -29,35 +27,34 @@ pub trait DepContext: Copy {
     fn debug_dep_tasks(&self) -> bool;
     fn debug_dep_node(&self) -> bool;
 
-    /// Try to force a dep node to execute and see if it's green.
-    fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;
+    /// Access the DepGraph.
+    fn dep_graph(&self) -> &DepGraph<Self::DepKind>;
 
     fn register_reused_dep_node(&self, dep_node: &DepNode<Self::DepKind>);
 
-    /// Return whether the current session is tainted by errors.
-    fn has_errors_or_delayed_span_bugs(&self) -> bool;
-
-    /// Return the diagnostic handler.
-    fn diagnostic(&self) -> &rustc_errors::Handler;
-
-    /// Load data from the on-disk cache.
-    fn try_load_from_on_disk_cache(&self, dep_node: &DepNode<Self::DepKind>);
+    /// Access the profiler.
+    fn profiler(&self) -> &SelfProfilerRef;
+}
 
-    /// Load diagnostics associated to the node in the previous session.
-    fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic>;
+pub trait HasDepContext: Copy {
+    type DepKind: self::DepKind;
+    type StableHashingContext;
+    type DepContext: self::DepContext<
+        DepKind = Self::DepKind,
+        StableHashingContext = Self::StableHashingContext,
+    >;
 
-    /// Register diagnostics for the given node, for use in next session.
-    fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>);
+    fn dep_context(&self) -> &Self::DepContext;
+}
 
-    /// Register diagnostics for the given node, for use in next session.
-    fn store_diagnostics_for_anon_node(
-        &self,
-        dep_node_index: DepNodeIndex,
-        diagnostics: ThinVec<Diagnostic>,
-    );
+impl<T: DepContext> HasDepContext for T {
+    type DepKind = T::DepKind;
+    type StableHashingContext = T::StableHashingContext;
+    type DepContext = Self;
 
-    /// Access the profiler.
-    fn profiler(&self) -> &SelfProfilerRef;
+    fn dep_context(&self) -> &Self::DepContext {
+        self
+    }
 }
 
 /// Describe the different families of dependency nodes.
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index 1d2bc1a99a5..ec71c868580 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -1,5 +1,5 @@
 use crate::dep_graph::DepNodeIndex;
-use crate::query::plumbing::{QueryLookup, QueryState};
+use crate::query::plumbing::{QueryCacheStore, QueryLookup};
 
 use rustc_arena::TypedArena;
 use rustc_data_structures::fx::FxHashMap;
@@ -31,17 +31,15 @@ pub trait QueryCache: QueryStorage {
     /// It returns the shard index and a lock guard to the shard,
     /// which will be used if the query is not in the cache and we need
     /// to compute it.
-    fn lookup<D, Q, R, OnHit, OnMiss>(
+    fn lookup<'s, R, OnHit>(
         &self,
-        state: &QueryState<D, Q, Self>,
-        key: Self::Key,
+        state: &'s QueryCacheStore<Self>,
+        key: &Self::Key,
         // `on_hit` can be called while holding a lock to the query state shard.
         on_hit: OnHit,
-        on_miss: OnMiss,
-    ) -> R
+    ) -> Result<R, QueryLookup>
     where
-        OnHit: FnOnce(&Self::Stored, DepNodeIndex) -> R,
-        OnMiss: FnOnce(Self::Key, QueryLookup<'_, D, Q, Self::Key, Self::Sharded>) -> R;
+        OnHit: FnOnce(&Self::Stored, DepNodeIndex) -> R;
 
     fn complete(
         &self,
@@ -95,23 +93,24 @@ where
     type Sharded = FxHashMap<K, (V, DepNodeIndex)>;
 
     #[inline(always)]
-    fn lookup<D, Q, R, OnHit, OnMiss>(
+    fn lookup<'s, R, OnHit>(
         &self,
-        state: &QueryState<D, Q, Self>,
-        key: K,
+        state: &'s QueryCacheStore<Self>,
+        key: &K,
         on_hit: OnHit,
-        on_miss: OnMiss,
-    ) -> R
+    ) -> Result<R, QueryLookup>
     where
         OnHit: FnOnce(&V, DepNodeIndex) -> R,
-        OnMiss: FnOnce(K, QueryLookup<'_, D, Q, K, Self::Sharded>) -> R,
     {
-        let mut lookup = state.get_lookup(&key);
-        let lock = &mut *lookup.lock;
+        let (lookup, lock) = state.get_lookup(key);
+        let result = lock.raw_entry().from_key_hashed_nocheck(lookup.key_hash, key);
 
-        let result = lock.cache.raw_entry().from_key_hashed_nocheck(lookup.key_hash, &key);
-
-        if let Some((_, value)) = result { on_hit(&value.0, value.1) } else { on_miss(key, lookup) }
+        if let Some((_, value)) = result {
+            let hit_result = on_hit(&value.0, value.1);
+            Ok(hit_result)
+        } else {
+            Err(lookup)
+        }
     }
 
     #[inline]
@@ -177,26 +176,23 @@ where
     type Sharded = FxHashMap<K, &'tcx (V, DepNodeIndex)>;
 
     #[inline(always)]
-    fn lookup<D, Q, R, OnHit, OnMiss>(
+    fn lookup<'s, R, OnHit>(
         &self,
-        state: &QueryState<D, Q, Self>,
-        key: K,
+        state: &'s QueryCacheStore<Self>,
+        key: &K,
         on_hit: OnHit,
-        on_miss: OnMiss,
-    ) -> R
+    ) -> Result<R, QueryLookup>
     where
         OnHit: FnOnce(&&'tcx V, DepNodeIndex) -> R,
-        OnMiss: FnOnce(K, QueryLookup<'_, D, Q, K, Self::Sharded>) -> R,
     {
-        let mut lookup = state.get_lookup(&key);
-        let lock = &mut *lookup.lock;
-
-        let result = lock.cache.raw_entry().from_key_hashed_nocheck(lookup.key_hash, &key);
+        let (lookup, lock) = state.get_lookup(key);
+        let result = lock.raw_entry().from_key_hashed_nocheck(lookup.key_hash, key);
 
         if let Some((_, value)) = result {
-            on_hit(&&value.0, value.1)
+            let hit_result = on_hit(&&value.0, value.1);
+            Ok(hit_result)
         } else {
-            on_miss(key, lookup)
+            Err(lookup)
         }
     }
 
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index 0f0684b3547..3873b47d4d4 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -4,10 +4,9 @@ use crate::dep_graph::DepNode;
 use crate::dep_graph::SerializedDepNodeIndex;
 use crate::query::caches::QueryCache;
 use crate::query::plumbing::CycleError;
-use crate::query::{QueryContext, QueryState};
+use crate::query::{QueryCacheStore, QueryContext, QueryState};
 
 use rustc_data_structures::fingerprint::Fingerprint;
-use std::borrow::Cow;
 use std::fmt::Debug;
 use std::hash::Hash;
 
@@ -34,9 +33,9 @@ pub(crate) struct QueryVtable<CTX: QueryContext, K, V> {
 }
 
 impl<CTX: QueryContext, K, V> QueryVtable<CTX, K, V> {
-    pub(crate) fn to_dep_node(&self, tcx: CTX, key: &K) -> DepNode<CTX::DepKind>
+    pub(crate) fn to_dep_node(&self, tcx: CTX::DepContext, key: &K) -> DepNode<CTX::DepKind>
     where
-        K: crate::dep_graph::DepNodeParams<CTX>,
+        K: crate::dep_graph::DepNodeParams<CTX::DepContext>,
     {
         DepNode::construct(tcx, self.dep_kind, key)
     }
@@ -74,14 +73,12 @@ pub trait QueryAccessors<CTX: QueryContext>: QueryConfig {
     type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>;
 
     // Don't use this method to access query results, instead use the methods on TyCtxt
-    fn query_state<'a>(tcx: CTX) -> &'a QueryState<CTX::DepKind, CTX::Query, Self::Cache>;
+    fn query_state<'a>(tcx: CTX) -> &'a QueryState<CTX::DepKind, CTX::Query, Self::Key>;
 
-    fn to_dep_node(tcx: CTX, key: &Self::Key) -> DepNode<CTX::DepKind>
+    // Don't use this method to access query results, instead use the methods on TyCtxt
+    fn query_cache<'a>(tcx: CTX) -> &'a QueryCacheStore<Self::Cache>
     where
-        Self::Key: crate::dep_graph::DepNodeParams<CTX>,
-    {
-        DepNode::construct(tcx, Self::DEP_KIND, key)
-    }
+        CTX: 'a;
 
     // Don't use this method to compute query results, instead use the methods on TyCtxt
     fn compute(tcx: CTX, key: Self::Key) -> Self::Value;
@@ -95,7 +92,7 @@ pub trait QueryAccessors<CTX: QueryContext>: QueryConfig {
 }
 
 pub trait QueryDescription<CTX: QueryContext>: QueryAccessors<CTX> {
-    fn describe(tcx: CTX, key: Self::Key) -> Cow<'static, str>;
+    fn describe(tcx: CTX, key: Self::Key) -> String;
 
     #[inline]
     fn cache_on_disk(_: CTX, _: &Self::Key, _: Option<&Self::Value>) -> bool {
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index 5fed500390b..0ecc2694a79 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -10,7 +10,8 @@ use std::num::NonZeroU32;
 
 #[cfg(parallel_compiler)]
 use {
-    super::QueryContext,
+    crate::dep_graph::DepContext,
+    crate::query::QueryContext,
     parking_lot::{Condvar, Mutex},
     rustc_data_structures::fx::FxHashSet,
     rustc_data_structures::stable_hasher::{HashStable, StableHasher},
@@ -432,7 +433,7 @@ where
 {
     // Deterministically pick an entry point
     // FIXME: Sort this instead
-    let mut hcx = tcx.create_stable_hashing_context();
+    let mut hcx = tcx.dep_context().create_stable_hashing_context();
     queries
         .iter()
         .min_by_key(|v| {
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index da45565dbe6..c935e1b9c5c 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -14,7 +14,7 @@ pub use self::caches::{
 mod config;
 pub use self::config::{QueryAccessors, QueryConfig, QueryDescription};
 
-use crate::dep_graph::{DepContext, DepGraph};
+use crate::dep_graph::{DepNode, DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
 use crate::query::job::QueryMap;
 
 use rustc_data_structures::stable_hasher::HashStable;
@@ -23,7 +23,7 @@ use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::Diagnostic;
 use rustc_span::def_id::DefId;
 
-pub trait QueryContext: DepContext {
+pub trait QueryContext: HasDepContext {
     type Query: Clone + HashStable<Self::StableHashingContext>;
 
     fn incremental_verify_ich(&self) -> bool;
@@ -32,14 +32,36 @@ pub trait QueryContext: DepContext {
     /// Get string representation from DefPath.
     fn def_path_str(&self, def_id: DefId) -> String;
 
-    /// Access the DepGraph.
-    fn dep_graph(&self) -> &DepGraph<Self::DepKind>;
-
     /// Get the query information from the TLS context.
     fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>>;
 
     fn try_collect_active_jobs(&self) -> Option<QueryMap<Self::DepKind, Self::Query>>;
 
+    /// Load data from the on-disk cache.
+    fn try_load_from_on_disk_cache(&self, dep_node: &DepNode<Self::DepKind>);
+
+    /// Try to force a dep node to execute and see if it's green.
+    fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;
+
+    /// Return whether the current session is tainted by errors.
+    fn has_errors_or_delayed_span_bugs(&self) -> bool;
+
+    /// Return the diagnostic handler.
+    fn diagnostic(&self) -> &rustc_errors::Handler;
+
+    /// Load diagnostics associated to the node in the previous session.
+    fn load_diagnostics(&self, prev_dep_node_index: SerializedDepNodeIndex) -> Vec<Diagnostic>;
+
+    /// Register diagnostics for the given node, for use in next session.
+    fn store_diagnostics(&self, dep_node_index: DepNodeIndex, diagnostics: ThinVec<Diagnostic>);
+
+    /// Register diagnostics for the given node, for use in next session.
+    fn store_diagnostics_for_anon_node(
+        &self,
+        dep_node_index: DepNodeIndex,
+        diagnostics: ThinVec<Diagnostic>,
+    );
+
     /// Executes a job by changing the `ImplicitCtxt` to point to the
     /// new query job while it executes. It returns the diagnostics
     /// captured during execution and the actual result.
@@ -47,6 +69,6 @@ pub trait QueryContext: DepContext {
         &self,
         token: QueryJobId<Self::DepKind>,
         diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
-        compute: impl FnOnce(Self) -> R,
+        compute: impl FnOnce() -> R,
     ) -> R;
 }
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 36532135f01..bd22ee2c18b 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -2,7 +2,7 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::dep_graph::{DepKind, DepNode};
+use crate::dep_graph::{DepContext, DepKind, DepNode};
 use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
 use crate::query::caches::QueryCache;
 use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt};
@@ -13,11 +13,10 @@ use crate::query::{QueryContext, QueryMap};
 use rustc_data_structures::cold_path;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHasher};
-use rustc_data_structures::sharded::Sharded;
+use rustc_data_structures::sharded::{get_shard_index_by_hash, Sharded};
 use rustc_data_structures::sync::{Lock, LockGuard};
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::{Diagnostic, FatalError};
-use rustc_span::source_map::DUMMY_SP;
 use rustc_span::Span;
 use std::collections::hash_map::Entry;
 use std::fmt::Debug;
@@ -28,46 +27,77 @@ use std::ptr;
 #[cfg(debug_assertions)]
 use std::sync::atomic::{AtomicUsize, Ordering};
 
-pub(super) struct QueryStateShard<D, Q, K, C> {
-    pub(super) cache: C,
-    active: FxHashMap<K, QueryResult<D, Q>>,
-
-    /// Used to generate unique ids for active jobs.
-    jobs: u32,
+pub struct QueryCacheStore<C: QueryCache> {
+    cache: C,
+    shards: Sharded<C::Sharded>,
+    #[cfg(debug_assertions)]
+    pub cache_hits: AtomicUsize,
 }
 
-impl<D, Q, K, C: Default> Default for QueryStateShard<D, Q, K, C> {
-    fn default() -> QueryStateShard<D, Q, K, C> {
-        QueryStateShard { cache: Default::default(), active: Default::default(), jobs: 0 }
+impl<C: QueryCache> Default for QueryCacheStore<C> {
+    fn default() -> Self {
+        Self {
+            cache: C::default(),
+            shards: Default::default(),
+            #[cfg(debug_assertions)]
+            cache_hits: AtomicUsize::new(0),
+        }
     }
 }
 
-pub struct QueryState<D, Q, C: QueryCache> {
-    cache: C,
-    shards: Sharded<QueryStateShard<D, Q, C::Key, C::Sharded>>,
-    #[cfg(debug_assertions)]
-    pub cache_hits: AtomicUsize,
+/// Values used when checking a query cache which can be reused on a cache-miss to execute the query.
+pub struct QueryLookup {
+    pub(super) key_hash: u64,
+    shard: usize,
+}
+
+// We compute the key's hash once and then use it for both the
+// shard lookup and the hashmap lookup. This relies on the fact
+// that both of them use `FxHasher`.
+fn hash_for_shard<K: Hash>(key: &K) -> u64 {
+    let mut hasher = FxHasher::default();
+    key.hash(&mut hasher);
+    hasher.finish()
 }
 
-impl<D, Q, C: QueryCache> QueryState<D, Q, C> {
-    #[inline]
+impl<C: QueryCache> QueryCacheStore<C> {
     pub(super) fn get_lookup<'tcx>(
         &'tcx self,
         key: &C::Key,
-    ) -> QueryLookup<'tcx, D, Q, C::Key, C::Sharded> {
-        // We compute the key's hash once and then use it for both the
-        // shard lookup and the hashmap lookup. This relies on the fact
-        // that both of them use `FxHasher`.
-        let mut hasher = FxHasher::default();
-        key.hash(&mut hasher);
-        let key_hash = hasher.finish();
-
-        let shard = self.shards.get_shard_index_by_hash(key_hash);
+    ) -> (QueryLookup, LockGuard<'tcx, C::Sharded>) {
+        let key_hash = hash_for_shard(key);
+        let shard = get_shard_index_by_hash(key_hash);
         let lock = self.shards.get_shard_by_index(shard).lock();
-        QueryLookup { key_hash, shard, lock }
+        (QueryLookup { key_hash, shard }, lock)
+    }
+
+    pub fn iter_results<R>(
+        &self,
+        f: impl for<'a> FnOnce(
+            Box<dyn Iterator<Item = (&'a C::Key, &'a C::Value, DepNodeIndex)> + 'a>,
+        ) -> R,
+    ) -> R {
+        self.cache.iter(&self.shards, |shard| &mut *shard, f)
     }
 }
 
+struct QueryStateShard<D, Q, K> {
+    active: FxHashMap<K, QueryResult<D, Q>>,
+
+    /// Used to generate unique ids for active jobs.
+    jobs: u32,
+}
+
+impl<D, Q, K> Default for QueryStateShard<D, Q, K> {
+    fn default() -> QueryStateShard<D, Q, K> {
+        QueryStateShard { active: Default::default(), jobs: 0 }
+    }
+}
+
+pub struct QueryState<D, Q, K> {
+    shards: Sharded<QueryStateShard<D, Q, K>>,
+}
+
 /// Indicates the state of a query for a given key in a query map.
 enum QueryResult<D, Q> {
     /// An already executing query. The query job can be used to await for its completion.
@@ -78,23 +108,12 @@ enum QueryResult<D, Q> {
     Poisoned,
 }
 
-impl<D, Q, C> QueryState<D, Q, C>
+impl<D, Q, K> QueryState<D, Q, K>
 where
     D: Copy + Clone + Eq + Hash,
     Q: Clone,
-    C: QueryCache,
+    K: Eq + Hash + Clone + Debug,
 {
-    #[inline(always)]
-    pub fn iter_results<R>(
-        &self,
-        f: impl for<'a> FnOnce(
-            Box<dyn Iterator<Item = (&'a C::Key, &'a C::Value, DepNodeIndex)> + 'a>,
-        ) -> R,
-    ) -> R {
-        self.cache.iter(&self.shards, |shard| &mut shard.cache, f)
-    }
-
-    #[inline(always)]
     pub fn all_inactive(&self) -> bool {
         let shards = self.shards.lock_shards();
         shards.iter().all(|shard| shard.active.is_empty())
@@ -103,7 +122,7 @@ where
     pub fn try_collect_active_jobs(
         &self,
         kind: D,
-        make_query: fn(C::Key) -> Q,
+        make_query: fn(K) -> Q,
         jobs: &mut QueryMap<D, Q>,
     ) -> Option<()> {
         // We use try_lock_shards here since we are called from the
@@ -126,24 +145,12 @@ where
     }
 }
 
-impl<D, Q, C: QueryCache> Default for QueryState<D, Q, C> {
-    fn default() -> QueryState<D, Q, C> {
-        QueryState {
-            cache: C::default(),
-            shards: Default::default(),
-            #[cfg(debug_assertions)]
-            cache_hits: AtomicUsize::new(0),
-        }
+impl<D, Q, K> Default for QueryState<D, Q, K> {
+    fn default() -> QueryState<D, Q, K> {
+        QueryState { shards: Default::default() }
     }
 }
 
-/// Values used when checking a query cache which can be reused on a cache-miss to execute the query.
-pub struct QueryLookup<'tcx, D, Q, K, C> {
-    pub(super) key_hash: u64,
-    shard: usize,
-    pub(super) lock: LockGuard<'tcx, QueryStateShard<D, Q, K, C>>,
-}
-
 /// A type representing the responsibility to execute the job in the `job` field.
 /// This will poison the relevant query if dropped.
 struct JobOwner<'tcx, D, Q, C>
@@ -152,7 +159,8 @@ where
     Q: Clone,
     C: QueryCache,
 {
-    state: &'tcx QueryState<D, Q, C>,
+    state: &'tcx QueryState<D, Q, C::Key>,
+    cache: &'tcx QueryCacheStore<C>,
     key: C::Key,
     id: QueryJobId<D>,
 }
@@ -172,18 +180,21 @@ where
     /// This function is inlined because that results in a noticeable speed-up
     /// for some compile-time benchmarks.
     #[inline(always)]
-    fn try_start<'a, 'b, CTX>(
+    fn try_start<'b, CTX>(
         tcx: CTX,
-        state: &'b QueryState<CTX::DepKind, CTX::Query, C>,
+        state: &'b QueryState<CTX::DepKind, CTX::Query, C::Key>,
+        cache: &'b QueryCacheStore<C>,
         span: Span,
         key: &C::Key,
-        mut lookup: QueryLookup<'a, CTX::DepKind, CTX::Query, C::Key, C::Sharded>,
+        lookup: QueryLookup,
         query: &QueryVtable<CTX, C::Key, C::Value>,
     ) -> TryGetJob<'b, CTX::DepKind, CTX::Query, C>
     where
         CTX: QueryContext,
     {
-        let lock = &mut *lookup.lock;
+        let shard = lookup.shard;
+        let mut state_lock = state.shards.get_shard_by_index(shard).lock();
+        let lock = &mut *state_lock;
 
         let (latch, mut _query_blocked_prof_timer) = match lock.active.entry((*key).clone()) {
             Entry::Occupied(mut entry) => {
@@ -193,13 +204,13 @@ where
                         // in another thread has completed. Record how long we wait in the
                         // self-profiler.
                         let _query_blocked_prof_timer = if cfg!(parallel_compiler) {
-                            Some(tcx.profiler().query_blocked())
+                            Some(tcx.dep_context().profiler().query_blocked())
                         } else {
                             None
                         };
 
                         // Create the id of the job we're waiting for
-                        let id = QueryJobId::new(job.id, lookup.shard, query.dep_kind);
+                        let id = QueryJobId::new(job.id, shard, query.dep_kind);
 
                         (job.latch(id), _query_blocked_prof_timer)
                     }
@@ -214,18 +225,18 @@ where
                 lock.jobs = id;
                 let id = QueryShardJobId(NonZeroU32::new(id).unwrap());
 
-                let global_id = QueryJobId::new(id, lookup.shard, query.dep_kind);
+                let global_id = QueryJobId::new(id, shard, query.dep_kind);
 
                 let job = tcx.current_query_job();
                 let job = QueryJob::new(id, span, job);
 
                 entry.insert(QueryResult::Started(job));
 
-                let owner = JobOwner { state, id: global_id, key: (*key).clone() };
+                let owner = JobOwner { state, cache, id: global_id, key: (*key).clone() };
                 return TryGetJob::NotYetStarted(owner);
             }
         };
-        mem::drop(lookup.lock);
+        mem::drop(state_lock);
 
         // If we are single-threaded we know that we have cycle error,
         // so we just return the error.
@@ -237,7 +248,7 @@ where
                 span,
             );
             let value = query.handle_cycle_error(tcx, error);
-            state.cache.store_nocache(value)
+            cache.cache.store_nocache(value)
         }));
 
         // With parallel queries we might just have to wait on some other
@@ -248,17 +259,23 @@ where
 
             if let Err(cycle) = result {
                 let value = query.handle_cycle_error(tcx, cycle);
-                let value = state.cache.store_nocache(value);
+                let value = cache.cache.store_nocache(value);
                 return TryGetJob::Cycle(value);
             }
 
-            let cached = try_get_cached(
-                tcx,
-                state,
-                (*key).clone(),
-                |value, index| (value.clone(), index),
-                |_, _| panic!("value must be in cache after waiting"),
-            );
+            let cached = cache
+                .cache
+                .lookup(cache, &key, |value, index| {
+                    if unlikely!(tcx.dep_context().profiler().enabled()) {
+                        tcx.dep_context().profiler().query_cache_hit(index.into());
+                    }
+                    #[cfg(debug_assertions)]
+                    {
+                        cache.cache_hits.fetch_add(1, Ordering::Relaxed);
+                    }
+                    (value.clone(), index)
+                })
+                .unwrap_or_else(|_| panic!("value must be in cache after waiting"));
 
             if let Some(prof_timer) = _query_blocked_prof_timer.take() {
                 prof_timer.finish_with_query_invocation_id(cached.1.into());
@@ -270,22 +287,29 @@ where
 
     /// Completes the query by updating the query cache with the `result`,
     /// signals the waiter and forgets the JobOwner, so it won't poison the query
-    #[inline(always)]
     fn complete(self, result: C::Value, dep_node_index: DepNodeIndex) -> C::Stored {
         // We can move out of `self` here because we `mem::forget` it below
         let key = unsafe { ptr::read(&self.key) };
         let state = self.state;
+        let cache = self.cache;
 
         // Forget ourself so our destructor won't poison the query
         mem::forget(self);
 
         let (job, result) = {
-            let mut lock = state.shards.get_shard_by_value(&key).lock();
-            let job = match lock.active.remove(&key).unwrap() {
-                QueryResult::Started(job) => job,
-                QueryResult::Poisoned => panic!(),
+            let key_hash = hash_for_shard(&key);
+            let shard = get_shard_index_by_hash(key_hash);
+            let job = {
+                let mut lock = state.shards.get_shard_by_index(shard).lock();
+                match lock.active.remove(&key).unwrap() {
+                    QueryResult::Started(job) => job,
+                    QueryResult::Poisoned => panic!(),
+                }
+            };
+            let result = {
+                let mut lock = cache.shards.get_shard_by_index(shard).lock();
+                cache.cache.complete(&mut lock, key, result, dep_node_index)
             };
-            let result = state.cache.complete(&mut lock.cache, key, result, dep_node_index);
             (job, result)
         };
 
@@ -294,7 +318,6 @@ where
     }
 }
 
-#[inline(always)]
 fn with_diagnostics<F, R>(f: F) -> (R, ThinVec<Diagnostic>)
 where
     F: FnOnce(Option<&Lock<ThinVec<Diagnostic>>>) -> R,
@@ -362,83 +385,79 @@ where
 /// It returns the shard index and a lock guard to the shard,
 /// which will be used if the query is not in the cache and we need
 /// to compute it.
-#[inline(always)]
-fn try_get_cached<CTX, C, R, OnHit, OnMiss>(
+#[inline]
+pub fn try_get_cached<'a, CTX, C, R, OnHit>(
     tcx: CTX,
-    state: &QueryState<CTX::DepKind, CTX::Query, C>,
-    key: C::Key,
+    cache: &'a QueryCacheStore<C>,
+    key: &C::Key,
     // `on_hit` can be called while holding a lock to the query cache
     on_hit: OnHit,
-    on_miss: OnMiss,
-) -> R
+) -> Result<R, QueryLookup>
 where
     C: QueryCache,
-    CTX: QueryContext,
-    OnHit: FnOnce(&C::Stored, DepNodeIndex) -> R,
-    OnMiss: FnOnce(C::Key, QueryLookup<'_, CTX::DepKind, CTX::Query, C::Key, C::Sharded>) -> R,
+    CTX: DepContext,
+    OnHit: FnOnce(&C::Stored) -> R,
 {
-    state.cache.lookup(
-        state,
-        key,
-        |value, index| {
-            if unlikely!(tcx.profiler().enabled()) {
-                tcx.profiler().query_cache_hit(index.into());
-            }
-            #[cfg(debug_assertions)]
-            {
-                state.cache_hits.fetch_add(1, Ordering::Relaxed);
-            }
-            on_hit(value, index)
-        },
-        on_miss,
-    )
+    cache.cache.lookup(cache, &key, |value, index| {
+        if unlikely!(tcx.profiler().enabled()) {
+            tcx.profiler().query_cache_hit(index.into());
+        }
+        #[cfg(debug_assertions)]
+        {
+            cache.cache_hits.fetch_add(1, Ordering::Relaxed);
+        }
+        tcx.dep_graph().read_index(index);
+        on_hit(value)
+    })
 }
 
-#[inline(always)]
 fn try_execute_query<CTX, C>(
     tcx: CTX,
-    state: &QueryState<CTX::DepKind, CTX::Query, C>,
+    state: &QueryState<CTX::DepKind, CTX::Query, C::Key>,
+    cache: &QueryCacheStore<C>,
     span: Span,
     key: C::Key,
-    lookup: QueryLookup<'_, CTX::DepKind, CTX::Query, C::Key, C::Sharded>,
+    lookup: QueryLookup,
     query: &QueryVtable<CTX, C::Key, C::Value>,
 ) -> C::Stored
 where
     C: QueryCache,
-    C::Key: crate::dep_graph::DepNodeParams<CTX>,
+    C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
     let job = match JobOwner::<'_, CTX::DepKind, CTX::Query, C>::try_start(
-        tcx, state, span, &key, lookup, query,
+        tcx, state, cache, span, &key, lookup, query,
     ) {
         TryGetJob::NotYetStarted(job) => job,
         TryGetJob::Cycle(result) => return result,
         #[cfg(parallel_compiler)]
         TryGetJob::JobCompleted((v, index)) => {
-            tcx.dep_graph().read_index(index);
+            tcx.dep_context().dep_graph().read_index(index);
             return v;
         }
     };
 
     // Fast path for when incr. comp. is off. `to_dep_node` is
     // expensive for some `DepKind`s.
-    if !tcx.dep_graph().is_fully_enabled() {
+    if !tcx.dep_context().dep_graph().is_fully_enabled() {
         let null_dep_node = DepNode::new_no_params(DepKind::NULL);
         return force_query_with_job(tcx, key, job, null_dep_node, query).0;
     }
 
     if query.anon {
-        let prof_timer = tcx.profiler().query_provider();
+        let prof_timer = tcx.dep_context().profiler().query_provider();
 
         let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
-            tcx.start_query(job.id, diagnostics, |tcx| {
-                tcx.dep_graph().with_anon_task(query.dep_kind, || query.compute(tcx, key))
+            tcx.start_query(job.id, diagnostics, || {
+                tcx.dep_context()
+                    .dep_graph()
+                    .with_anon_task(query.dep_kind, || query.compute(tcx, key))
             })
         });
 
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
-        tcx.dep_graph().read_index(dep_node_index);
+        tcx.dep_context().dep_graph().read_index(dep_node_index);
 
         if unlikely!(!diagnostics.is_empty()) {
             tcx.store_diagnostics_for_anon_node(dep_node_index, diagnostics);
@@ -447,14 +466,14 @@ where
         return job.complete(result, dep_node_index);
     }
 
-    let dep_node = query.to_dep_node(tcx, &key);
+    let dep_node = query.to_dep_node(*tcx.dep_context(), &key);
 
     if !query.eval_always {
         // The diagnostics for this query will be
         // promoted to the current session during
         // `try_mark_green()`, so we can ignore them here.
-        let loaded = tcx.start_query(job.id, None, |tcx| {
-            let marked = tcx.dep_graph().try_mark_green_and_read(tcx, &dep_node);
+        let loaded = tcx.start_query(job.id, None, || {
+            let marked = tcx.dep_context().dep_graph().try_mark_green_and_read(tcx, &dep_node);
             marked.map(|(prev_dep_node_index, dep_node_index)| {
                 (
                     load_from_disk_and_cache_in_memory(
@@ -475,7 +494,7 @@ where
     }
 
     let (result, dep_node_index) = force_query_with_job(tcx, key, job, dep_node, query);
-    tcx.dep_graph().read_index(dep_node_index);
+    tcx.dep_context().dep_graph().read_index(dep_node_index);
     result
 }
 
@@ -493,11 +512,11 @@ where
     // Note this function can be called concurrently from the same query
     // We must ensure that this is handled correctly.
 
-    debug_assert!(tcx.dep_graph().is_green(dep_node));
+    debug_assert!(tcx.dep_context().dep_graph().is_green(dep_node));
 
     // First we try to load the result from the on-disk cache.
     let result = if query.cache_on_disk(tcx, &key, None) {
-        let prof_timer = tcx.profiler().incr_cache_loading();
+        let prof_timer = tcx.dep_context().profiler().incr_cache_loading();
         let result = query.try_load_from_disk(tcx, prev_dep_node_index);
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
@@ -519,10 +538,10 @@ where
     } else {
         // We could not load a result from the on-disk cache, so
         // recompute.
-        let prof_timer = tcx.profiler().query_provider();
+        let prof_timer = tcx.dep_context().profiler().query_provider();
 
         // The dep-graph for this computation is already in-place.
-        let result = tcx.dep_graph().with_ignore(|| query.compute(tcx, key));
+        let result = tcx.dep_context().dep_graph().with_ignore(|| query.compute(tcx, key));
 
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
@@ -532,7 +551,7 @@ where
     // If `-Zincremental-verify-ich` is specified, re-hash results from
     // the cache and make sure that they have the expected fingerprint.
     if unlikely!(tcx.incremental_verify_ich()) {
-        incremental_verify_ich(tcx, &result, dep_node, dep_node_index, query);
+        incremental_verify_ich(*tcx.dep_context(), &result, dep_node, dep_node_index, query);
     }
 
     result
@@ -541,7 +560,7 @@ where
 #[inline(never)]
 #[cold]
 fn incremental_verify_ich<CTX, K, V: Debug>(
-    tcx: CTX,
+    tcx: CTX::DepContext,
     result: &V,
     dep_node: &DepNode<CTX::DepKind>,
     dep_node_index: DepNodeIndex,
@@ -584,7 +603,7 @@ where
     // 2. Two distinct query keys get mapped to the same `DepNode`
     //    (see for example #48923).
     assert!(
-        !tcx.dep_graph().dep_node_exists(&dep_node),
+        !tcx.dep_context().dep_graph().dep_node_exists(&dep_node),
         "forcing query with already existing `DepNode`\n\
                  - query-key: {:?}\n\
                  - dep-node: {:?}",
@@ -592,12 +611,12 @@ where
         dep_node
     );
 
-    let prof_timer = tcx.profiler().query_provider();
+    let prof_timer = tcx.dep_context().profiler().query_provider();
 
     let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
-        tcx.start_query(job.id, diagnostics, |tcx| {
+        tcx.start_query(job.id, diagnostics, || {
             if query.eval_always {
-                tcx.dep_graph().with_eval_always_task(
+                tcx.dep_context().dep_graph().with_eval_always_task(
                     dep_node,
                     tcx,
                     key,
@@ -605,7 +624,13 @@ where
                     query.hash_result,
                 )
             } else {
-                tcx.dep_graph().with_task(dep_node, tcx, key, query.compute, query.hash_result)
+                tcx.dep_context().dep_graph().with_task(
+                    dep_node,
+                    tcx,
+                    key,
+                    query.compute,
+                    query.hash_result,
+                )
             }
         })
     });
@@ -624,57 +649,45 @@ where
 #[inline(never)]
 fn get_query_impl<CTX, C>(
     tcx: CTX,
-    state: &QueryState<CTX::DepKind, CTX::Query, C>,
+    state: &QueryState<CTX::DepKind, CTX::Query, C::Key>,
+    cache: &QueryCacheStore<C>,
     span: Span,
     key: C::Key,
+    lookup: QueryLookup,
     query: &QueryVtable<CTX, C::Key, C::Value>,
 ) -> C::Stored
 where
     CTX: QueryContext,
     C: QueryCache,
-    C::Key: crate::dep_graph::DepNodeParams<CTX>,
+    C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
 {
-    try_get_cached(
-        tcx,
-        state,
-        key,
-        |value, index| {
-            tcx.dep_graph().read_index(index);
-            value.clone()
-        },
-        |key, lookup| try_execute_query(tcx, state, span, key, lookup, query),
-    )
+    try_execute_query(tcx, state, cache, span, key, lookup, query)
 }
 
 /// Ensure that either this query has all green inputs or been executed.
 /// Executing `query::ensure(D)` is considered a read of the dep-node `D`.
+/// Returns true if the query should still run.
 ///
 /// This function is particularly useful when executing passes for their
 /// side-effects -- e.g., in order to report errors for erroneous programs.
 ///
 /// Note: The optimization is only available during incr. comp.
 #[inline(never)]
-fn ensure_query_impl<CTX, C>(
-    tcx: CTX,
-    state: &QueryState<CTX::DepKind, CTX::Query, C>,
-    key: C::Key,
-    query: &QueryVtable<CTX, C::Key, C::Value>,
-) where
-    C: QueryCache,
-    C::Key: crate::dep_graph::DepNodeParams<CTX>,
+fn ensure_must_run<CTX, K, V>(tcx: CTX, key: &K, query: &QueryVtable<CTX, K, V>) -> bool
+where
+    K: crate::dep_graph::DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
     if query.eval_always {
-        let _ = get_query_impl(tcx, state, DUMMY_SP, key, query);
-        return;
+        return true;
     }
 
     // Ensuring an anonymous query makes no sense
     assert!(!query.anon);
 
-    let dep_node = query.to_dep_node(tcx, &key);
+    let dep_node = query.to_dep_node(*tcx.dep_context(), key);
 
-    match tcx.dep_graph().try_mark_green_and_read(tcx, &dep_node) {
+    match tcx.dep_context().dep_graph().try_mark_green_and_read(tcx, &dep_node) {
         None => {
             // A None return from `try_mark_green_and_read` means that this is either
             // a new dep node or that the dep node has already been marked red.
@@ -682,10 +695,11 @@ fn ensure_query_impl<CTX, C>(
             // DepNodeIndex. We must invoke the query itself. The performance cost
             // this introduces should be negligible as we'll immediately hit the
             // in-memory cache, or another query down the line will.
-            let _ = get_query_impl(tcx, state, DUMMY_SP, key, query);
+            true
         }
         Some((_, dep_node_index)) => {
-            tcx.profiler().query_cache_hit(dep_node_index.into());
+            tcx.dep_context().profiler().query_cache_hit(dep_node_index.into());
+            false
         }
     }
 }
@@ -693,68 +707,80 @@ fn ensure_query_impl<CTX, C>(
 #[inline(never)]
 fn force_query_impl<CTX, C>(
     tcx: CTX,
-    state: &QueryState<CTX::DepKind, CTX::Query, C>,
+    state: &QueryState<CTX::DepKind, CTX::Query, C::Key>,
+    cache: &QueryCacheStore<C>,
     key: C::Key,
     span: Span,
     dep_node: DepNode<CTX::DepKind>,
     query: &QueryVtable<CTX, C::Key, C::Value>,
 ) where
     C: QueryCache,
-    C::Key: crate::dep_graph::DepNodeParams<CTX>,
+    C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
     // We may be concurrently trying both execute and force a query.
     // Ensure that only one of them runs the query.
+    let cached = cache.cache.lookup(cache, &key, |_, index| {
+        if unlikely!(tcx.dep_context().profiler().enabled()) {
+            tcx.dep_context().profiler().query_cache_hit(index.into());
+        }
+        #[cfg(debug_assertions)]
+        {
+            cache.cache_hits.fetch_add(1, Ordering::Relaxed);
+        }
+    });
 
-    try_get_cached(
-        tcx,
-        state,
-        key,
-        |_, _| {
-            // Cache hit, do nothing
-        },
-        |key, lookup| {
-            let job = match JobOwner::<'_, CTX::DepKind, CTX::Query, C>::try_start(
-                tcx, state, span, &key, lookup, query,
-            ) {
-                TryGetJob::NotYetStarted(job) => job,
-                TryGetJob::Cycle(_) => return,
-                #[cfg(parallel_compiler)]
-                TryGetJob::JobCompleted(_) => return,
-            };
-            force_query_with_job(tcx, key, job, dep_node, query);
-        },
-    );
-}
+    let lookup = match cached {
+        Ok(()) => return,
+        Err(lookup) => lookup,
+    };
 
-#[inline(always)]
-pub fn get_query<Q, CTX>(tcx: CTX, span: Span, key: Q::Key) -> Q::Stored
-where
-    Q: QueryDescription<CTX>,
-    Q::Key: crate::dep_graph::DepNodeParams<CTX>,
-    CTX: QueryContext,
-{
-    debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span);
+    let job = match JobOwner::<'_, CTX::DepKind, CTX::Query, C>::try_start(
+        tcx, state, cache, span, &key, lookup, query,
+    ) {
+        TryGetJob::NotYetStarted(job) => job,
+        TryGetJob::Cycle(_) => return,
+        #[cfg(parallel_compiler)]
+        TryGetJob::JobCompleted(_) => return,
+    };
+    force_query_with_job(tcx, key, job, dep_node, query);
+}
 
-    get_query_impl(tcx, Q::query_state(tcx), span, key, &Q::VTABLE)
+pub enum QueryMode {
+    Get,
+    Ensure,
 }
 
-#[inline(always)]
-pub fn ensure_query<Q, CTX>(tcx: CTX, key: Q::Key)
+pub fn get_query<Q, CTX>(
+    tcx: CTX,
+    span: Span,
+    key: Q::Key,
+    lookup: QueryLookup,
+    mode: QueryMode,
+) -> Option<Q::Stored>
 where
     Q: QueryDescription<CTX>,
-    Q::Key: crate::dep_graph::DepNodeParams<CTX>,
+    Q::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
-    ensure_query_impl(tcx, Q::query_state(tcx), key, &Q::VTABLE)
+    let query = &Q::VTABLE;
+    if let QueryMode::Ensure = mode {
+        if !ensure_must_run(tcx, &key, query) {
+            return None;
+        }
+    }
+
+    debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span);
+    let value =
+        get_query_impl(tcx, Q::query_state(tcx), Q::query_cache(tcx), span, key, lookup, query);
+    Some(value)
 }
 
-#[inline(always)]
 pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, span: Span, dep_node: DepNode<CTX::DepKind>)
 where
     Q: QueryDescription<CTX>,
-    Q::Key: crate::dep_graph::DepNodeParams<CTX>,
+    Q::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
-    force_query_impl(tcx, Q::query_state(tcx), key, span, dep_node, &Q::VTABLE)
+    force_query_impl(tcx, Q::query_state(tcx), Q::query_cache(tcx), key, span, dep_node, &Q::VTABLE)
 }
diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml
index 821f9ea4738..7441f4a9f22 100644
--- a/compiler/rustc_resolve/Cargo.toml
+++ b/compiler/rustc_resolve/Cargo.toml
@@ -26,4 +26,4 @@ rustc_index = { path = "../rustc_index" }
 rustc_metadata = { path = "../rustc_metadata" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index c4ee4df2128..79ed0b5308d 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -258,16 +258,16 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
                 Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)))
             }
             ast::VisibilityKind::Inherited => {
-                if matches!(self.parent_scope.module.kind, ModuleKind::Def(DefKind::Enum, _, _)) {
-                    // Any inherited visibility resolved directly inside an enum
-                    // (e.g. variants or fields) inherits from the visibility of the enum.
-                    let parent_enum = self.parent_scope.module.def_id().unwrap().expect_local();
-                    Ok(self.r.visibilities[&parent_enum])
-                } else {
-                    // If it's not in an enum, its visibility is restricted to the `mod` item
-                    // that it's defined in.
-                    Ok(ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod))
-                }
+                Ok(match self.parent_scope.module.kind {
+                    // Any inherited visibility resolved directly inside an enum or trait
+                    // (i.e. variants, fields, and trait items) inherits from the visibility
+                    // of the enum or trait.
+                    ModuleKind::Def(DefKind::Enum | DefKind::Trait, def_id, _) => {
+                        self.r.visibilities[&def_id.expect_local()]
+                    }
+                    // Otherwise, the visibility is restricted to the nearest parent `mod` item.
+                    _ => ty::Visibility::Restricted(self.parent_scope.module.nearest_parent_mod),
+                })
             }
             ast::VisibilityKind::Restricted { ref path, id, .. } => {
                 // For visibilities we are not ready to provide correct implementation of "uniform
@@ -1365,58 +1365,40 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
             return;
         }
 
+        let vis = self.resolve_visibility(&item.vis);
         let local_def_id = self.r.local_def_id(item.id);
         let def_id = local_def_id.to_def_id();
-        let vis = match ctxt {
-            AssocCtxt::Trait => {
-                let (def_kind, ns) = match item.kind {
-                    AssocItemKind::Const(..) => (DefKind::AssocConst, ValueNS),
-                    AssocItemKind::Fn(box FnKind(_, ref sig, _, _)) => {
-                        if sig.decl.has_self() {
-                            self.r.has_self.insert(def_id);
-                        }
-                        (DefKind::AssocFn, ValueNS)
-                    }
-                    AssocItemKind::TyAlias(..) => (DefKind::AssocTy, TypeNS),
-                    AssocItemKind::MacCall(_) => bug!(), // handled above
-                };
 
-                let parent = self.parent_scope.module;
-                let expansion = self.parent_scope.expansion;
-                let res = Res::Def(def_kind, def_id);
-                // Trait item visibility is inherited from its trait when not specified explicitly.
-                let vis = match &item.vis.kind {
-                    ast::VisibilityKind::Inherited => {
-                        self.r.visibilities[&parent.def_id().unwrap().expect_local()]
+        if !(ctxt == AssocCtxt::Impl
+            && matches!(item.vis.kind, ast::VisibilityKind::Inherited)
+            && self
+                .r
+                .trait_impl_items
+                .contains(&ty::DefIdTree::parent(&*self.r, def_id).unwrap().expect_local()))
+        {
+            // Trait impl item visibility is inherited from its trait when not specified
+            // explicitly. In that case we cannot determine it here in early resolve,
+            // so we leave a hole in the visibility table to be filled later.
+            self.r.visibilities.insert(local_def_id, vis);
+        }
+
+        if ctxt == AssocCtxt::Trait {
+            let (def_kind, ns) = match item.kind {
+                AssocItemKind::Const(..) => (DefKind::AssocConst, ValueNS),
+                AssocItemKind::Fn(box FnKind(_, ref sig, _, _)) => {
+                    if sig.decl.has_self() {
+                        self.r.has_self.insert(def_id);
                     }
-                    _ => self.resolve_visibility(&item.vis),
-                };
-                // FIXME: For historical reasons the binding visibility is set to public,
-                // use actual visibility here instead, using enum variants as an example.
-                let vis_hack = ty::Visibility::Public;
-                self.r.define(parent, item.ident, ns, (res, vis_hack, item.span, expansion));
-                Some(vis)
-            }
-            AssocCtxt::Impl => {
-                // Trait impl item visibility is inherited from its trait when not specified
-                // explicitly. In that case we cannot determine it here in early resolve,
-                // so we leave a hole in the visibility table to be filled later.
-                // Inherent impl item visibility is never inherited from other items.
-                if matches!(item.vis.kind, ast::VisibilityKind::Inherited)
-                    && self
-                        .r
-                        .trait_impl_items
-                        .contains(&ty::DefIdTree::parent(&*self.r, def_id).unwrap().expect_local())
-                {
-                    None
-                } else {
-                    Some(self.resolve_visibility(&item.vis))
+                    (DefKind::AssocFn, ValueNS)
                 }
-            }
-        };
+                AssocItemKind::TyAlias(..) => (DefKind::AssocTy, TypeNS),
+                AssocItemKind::MacCall(_) => bug!(), // handled above
+            };
 
-        if let Some(vis) = vis {
-            self.r.visibilities.insert(local_def_id, vis);
+            let parent = self.parent_scope.module;
+            let expansion = self.parent_scope.expansion;
+            let res = Res::Def(def_kind, def_id);
+            self.r.define(parent, item.ident, ns, (res, vis, item.span, expansion));
         }
 
         visit::walk_assoc_item(self, item, ctxt);
@@ -1490,19 +1472,13 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> {
         }
 
         let parent = self.parent_scope.module;
-        let vis = match variant.vis.kind {
-            // Variant visibility is inherited from its enum when not specified explicitly.
-            ast::VisibilityKind::Inherited => {
-                self.r.visibilities[&parent.def_id().unwrap().expect_local()]
-            }
-            _ => self.resolve_visibility(&variant.vis),
-        };
         let expn_id = self.parent_scope.expansion;
         let ident = variant.ident;
 
         // Define a name in the type namespace.
         let def_id = self.r.local_def_id(variant.id);
         let res = Res::Def(DefKind::Variant, def_id.to_def_id());
+        let vis = self.resolve_visibility(&variant.vis);
         self.r.define(parent, ident, TypeNS, (res, vis, variant.span, expn_id));
         self.r.visibilities.insert(def_id, vis);
 
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 9d55bafd286..7493fd68505 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -9,6 +9,7 @@ use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::PrimTy;
 use rustc_middle::bug;
 use rustc_middle::ty::{self, DefIdTree};
 use rustc_session::Session;
@@ -718,10 +719,9 @@ impl<'a> Resolver<'a> {
                     }
                 }
                 Scope::BuiltinTypes => {
-                    let primitive_types = &this.primitive_type_table.primitive_types;
-                    suggestions.extend(primitive_types.iter().flat_map(|(name, prim_ty)| {
+                    suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| {
                         let res = Res::PrimTy(*prim_ty);
-                        filter_fn(res).then_some(TypoSuggestion::from_res(*name, res))
+                        filter_fn(res).then_some(TypoSuggestion::from_res(prim_ty.name(), res))
                     }))
                 }
             }
@@ -1111,10 +1111,9 @@ impl<'a> Resolver<'a> {
             _,
         ) = binding.kind
         {
-            let def_id = (&*self).parent(ctor_def_id).expect("no parent for a constructor");
+            let def_id = self.parent(ctor_def_id).expect("no parent for a constructor");
             let fields = self.field_names.get(&def_id)?;
-            let first_field = fields.first()?; // Handle `struct Foo()`
-            return Some(fields.iter().fold(first_field.span, |acc, field| acc.to(field.span)));
+            return fields.iter().map(|name| name.span).reduce(Span::to); // None for `struct Foo()`
         }
         None
     }
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index cb1f0834ce7..bd0296751a5 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -18,11 +18,10 @@ use rustc_errors::{pluralize, struct_span_err, Applicability};
 use rustc_hir::def::{self, PartialRes};
 use rustc_hir::def_id::DefId;
 use rustc_middle::hir::exports::Export;
+use rustc_middle::span_bug;
 use rustc_middle::ty;
-use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS};
 use rustc_session::lint::BuiltinLintDiagnostics;
-use rustc_session::DiagnosticMessageId;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
@@ -456,13 +455,13 @@ impl<'a> Resolver<'a> {
         binding: &'a NameBinding<'a>,
         import: &'a Import<'a>,
     ) -> &'a NameBinding<'a> {
-        let vis = if binding.pseudo_vis().is_at_least(import.vis.get(), self) ||
+        let vis = if binding.vis.is_at_least(import.vis.get(), self) ||
                      // cf. `PUB_USE_OF_PRIVATE_EXTERN_CRATE`
                      !import.is_glob() && binding.is_extern_crate()
         {
             import.vis.get()
         } else {
-            binding.pseudo_vis()
+            binding.vis
         };
 
         if let ImportKind::Glob { ref max_vis, .. } = import.kind {
@@ -1178,7 +1177,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         self.r.per_ns(|this, ns| {
             if let Ok(binding) = source_bindings[ns].get() {
                 let vis = import.vis.get();
-                if !binding.pseudo_vis().is_at_least(vis, &*this) {
+                if !binding.vis.is_at_least(vis, &*this) {
                     reexport_error = Some((ns, binding));
                 } else {
                     any_successful_reexport = true;
@@ -1362,7 +1361,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 Some(None) => import.parent_scope.module,
                 None => continue,
             };
-            if self.r.is_accessible_from(binding.pseudo_vis(), scope) {
+            if self.r.is_accessible_from(binding.vis, scope) {
                 let imported_binding = self.r.import(binding, import);
                 let _ = self.r.try_define(import.parent_scope.module, key, imported_binding);
             }
@@ -1380,9 +1379,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
 
         let mut reexports = Vec::new();
 
-        module.for_each_child(self.r, |this, ident, ns, binding| {
-            // Filter away ambiguous imports and anything that has def-site
-            // hygiene.
+        module.for_each_child(self.r, |this, ident, _, binding| {
+            // Filter away ambiguous imports and anything that has def-site hygiene.
             // FIXME: Implement actual cross-crate hygiene.
             let is_good_import =
                 binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion();
@@ -1392,71 +1390,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                     reexports.push(Export { ident, res, span: binding.span, vis: binding.vis });
                 }
             }
-
-            if let NameBindingKind::Import { binding: orig_binding, import, .. } = binding.kind {
-                if ns == TypeNS
-                    && orig_binding.is_variant()
-                    && !orig_binding.vis.is_at_least(binding.vis, &*this)
-                {
-                    let msg = match import.kind {
-                        ImportKind::Single { .. } => {
-                            format!("variant `{}` is private and cannot be re-exported", ident)
-                        }
-                        ImportKind::Glob { .. } => {
-                            let msg = "enum is private and its variants \
-                                           cannot be re-exported"
-                                .to_owned();
-                            let error_id = (
-                                DiagnosticMessageId::ErrorId(0), // no code?!
-                                Some(binding.span),
-                                msg.clone(),
-                            );
-                            let fresh =
-                                this.session.one_time_diagnostics.borrow_mut().insert(error_id);
-                            if !fresh {
-                                return;
-                            }
-                            msg
-                        }
-                        ref s => bug!("unexpected import kind {:?}", s),
-                    };
-                    let mut err = this.session.struct_span_err(binding.span, &msg);
-
-                    let imported_module = match import.imported_module.get() {
-                        Some(ModuleOrUniformRoot::Module(module)) => module,
-                        _ => bug!("module should exist"),
-                    };
-                    let parent_module = imported_module.parent.expect("parent should exist");
-                    let resolutions = this.resolutions(parent_module).borrow();
-                    let enum_path_segment_index = import.module_path.len() - 1;
-                    let enum_ident = import.module_path[enum_path_segment_index].ident;
-
-                    let key = this.new_key(enum_ident, TypeNS);
-                    let enum_resolution = resolutions.get(&key).expect("resolution should exist");
-                    let enum_span =
-                        enum_resolution.borrow().binding.expect("binding should exist").span;
-                    let enum_def_span = this.session.source_map().guess_head_span(enum_span);
-                    let enum_def_snippet = this
-                        .session
-                        .source_map()
-                        .span_to_snippet(enum_def_span)
-                        .expect("snippet should exist");
-                    // potentially need to strip extant `crate`/`pub(path)` for suggestion
-                    let after_vis_index = enum_def_snippet
-                        .find("enum")
-                        .expect("`enum` keyword should exist in snippet");
-                    let suggestion = format!("pub {}", &enum_def_snippet[after_vis_index..]);
-
-                    this.session.diag_span_suggestion_once(
-                        &mut err,
-                        DiagnosticMessageId::ErrorId(0),
-                        enum_def_span,
-                        "consider making the enum public",
-                        suggestion,
-                    );
-                    err.emit();
-                }
-            }
         });
 
         if !reexports.is_empty() {
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 9b5b793363b..701d48a982d 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -20,7 +20,7 @@ use rustc_errors::DiagnosticId;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, DefKind, PartialRes, PerNS};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
-use rustc_hir::TraitCandidate;
+use rustc_hir::{PrimTy, TraitCandidate};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -1023,7 +1023,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 });
             }
 
-            ItemKind::Mod(_) | ItemKind::ForeignMod(_) => {
+            ItemKind::Mod(..) | ItemKind::ForeignMod(_) => {
                 self.with_scope(item.id, |this| {
                     visit::walk_item(this, item);
                 });
@@ -1801,7 +1801,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
         crate_lint: CrateLint,
     ) -> PartialRes {
         tracing::debug!(
-            "smart_resolve_path_fragment(id={:?},qself={:?},path={:?}",
+            "smart_resolve_path_fragment(id={:?}, qself={:?}, path={:?})",
             id,
             qself,
             path
@@ -1841,11 +1841,10 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
 
             // Before we start looking for candidates, we have to get our hands
             // on the type user is trying to perform invocation on; basically:
-            // we're transforming `HashMap::new` into just `HashMap`
-            let path = if let Some((_, path)) = path.split_last() {
-                path
-            } else {
-                return Some(parent_err);
+            // we're transforming `HashMap::new` into just `HashMap`.
+            let path = match path.split_last() {
+                Some((_, path)) if !path.is_empty() => path,
+                _ => return Some(parent_err),
             };
 
             let (mut err, candidates) =
@@ -1927,7 +1926,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                     self.r.trait_map.insert(id, traits);
                 }
 
-                if self.r.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) {
+                if PrimTy::from_name(path[0].ident.name).is_some() {
                     let mut std_path = Vec::with_capacity(1 + path.len());
 
                     std_path.push(Segment::from_ident(Ident::with_dummy_span(sym::std)));
@@ -2121,13 +2120,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             // The same fallback is used when `a` resolves to nothing.
             PathResult::Module(ModuleOrUniformRoot::Module(_)) | PathResult::Failed { .. }
                 if (ns == TypeNS || path.len() > 1)
-                    && self
-                        .r
-                        .primitive_type_table
-                        .primitive_types
-                        .contains_key(&path[0].ident.name) =>
+                    && PrimTy::from_name(path[0].ident.name).is_some() =>
             {
-                let prim = self.r.primitive_type_table.primitive_types[&path[0].ident.name];
+                let prim = PrimTy::from_name(path[0].ident.name).unwrap();
                 PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1)
             }
             PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 927535b72bd..6457c6cee57 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1105,7 +1105,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         }
 
         if let Some(items) = self.diagnostic_metadata.current_trait_assoc_items {
-            for assoc_item in &items[..] {
+            for assoc_item in items {
                 if assoc_item.ident == ident {
                     return Some(match &assoc_item.kind {
                         ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
@@ -1212,8 +1212,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
             // Add primitive types to the mix
             if filter_fn(Res::PrimTy(PrimTy::Bool)) {
                 names.extend(
-                    self.r.primitive_type_table.primitive_types.iter().map(|(name, prim_ty)| {
-                        TypoSuggestion::from_res(*name, Res::PrimTy(*prim_ty))
+                    PrimTy::ALL.iter().map(|prim_ty| {
+                        TypoSuggestion::from_res(prim_ty.name(), Res::PrimTy(*prim_ty))
                     }),
                 )
             }
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 0bab33976b2..c0e4a1bdf07 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -587,7 +587,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 // `type MyAnonTy<'b> = impl MyTrait<'b>;`
                 //                 ^                  ^ this gets resolved in the scope of
                 //                                      the opaque_ty generics
-                let opaque_ty = self.tcx.hir().expect_item(item_id.id);
+                let opaque_ty = self.tcx.hir().item(item_id);
                 let (generics, bounds) = match opaque_ty.kind {
                     // Named opaque `impl Trait` types are reached via `TyKind::Path`.
                     // This arm is for `impl Trait` in the types of statics, constants and locals.
@@ -632,20 +632,32 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                                 let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
                                 // Ensure that the parent of the def is an item, not HRTB
                                 let parent_id = self.tcx.hir().get_parent_node(hir_id);
-                                let parent_impl_id = hir::ImplItemId { hir_id: parent_id };
-                                let parent_trait_id = hir::TraitItemId { hir_id: parent_id };
-                                let krate = self.tcx.hir().krate();
-
-                                if !(krate.items.contains_key(&parent_id)
-                                    || krate.impl_items.contains_key(&parent_impl_id)
-                                    || krate.trait_items.contains_key(&parent_trait_id))
+                                let parent_is_item = if let Some(parent_def_id) =
+                                    parent_id.as_owner()
                                 {
+                                    let parent_item_id = hir::ItemId { def_id: parent_def_id };
+                                    let parent_impl_id = hir::ImplItemId { def_id: parent_def_id };
+                                    let parent_trait_id =
+                                        hir::TraitItemId { def_id: parent_def_id };
+                                    let parent_foreign_id =
+                                        hir::ForeignItemId { def_id: parent_def_id };
+                                    let krate = self.tcx.hir().krate();
+
+                                    krate.items.contains_key(&parent_item_id)
+                                        || krate.impl_items.contains_key(&parent_impl_id)
+                                        || krate.trait_items.contains_key(&parent_trait_id)
+                                        || krate.foreign_items.contains_key(&parent_foreign_id)
+                                } else {
+                                    false
+                                };
+
+                                if !parent_is_item {
                                     struct_span_err!(
                                         self.tcx.sess,
                                         lifetime.span,
                                         E0657,
                                         "`impl Trait` can only capture lifetimes \
-                                         bound at the fn or impl level"
+                                             bound at the fn or impl level"
                                     )
                                     .emit();
                                     self.uninsert_lifetime_on_error(lifetime, def.unwrap());
@@ -738,7 +750,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 self.missing_named_lifetime_spots.push((&trait_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
-                    Some(tcx.hir().get_parent_item(trait_item.hir_id)),
+                    Some(tcx.hir().get_parent_item(trait_item.hir_id())),
                     &sig.decl,
                     &trait_item.generics,
                     |this| intravisit::walk_trait_item(this, trait_item),
@@ -800,7 +812,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 self.missing_named_lifetime_spots.push((&impl_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
-                    Some(tcx.hir().get_parent_item(impl_item.hir_id)),
+                    Some(tcx.hir().get_parent_item(impl_item.hir_id())),
                     &sig.decl,
                     &impl_item.generics,
                     |this| intravisit::walk_impl_item(this, impl_item),
@@ -1255,7 +1267,7 @@ fn compute_object_lifetime_defaults(tcx: TyCtxt<'_>) -> HirIdMap<Vec<ObjectLifet
                     tcx.sess.span_err(item.span, &object_lifetime_default_reprs);
                 }
 
-                map.insert(item.hir_id, result);
+                map.insert(item.hir_id(), result);
             }
             _ => {}
         }
@@ -2111,7 +2123,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
                 {
                     assoc_item_kind =
-                        trait_items.iter().find(|ti| ti.id.hir_id == parent).map(|ti| ti.kind);
+                        trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind);
                 }
                 match *m {
                     hir::TraitFn::Required(_) => None,
@@ -2125,7 +2137,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 {
                     impl_self = Some(self_ty);
                     assoc_item_kind =
-                        items.iter().find(|ii| ii.id.hir_id == parent).map(|ii| ii.kind);
+                        items.iter().find(|ii| ii.id.hir_id() == parent).map(|ii| ii.kind);
                 }
                 Some(body)
             }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index b19990e49b8..77fbbaa1532 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -11,6 +11,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
 #![feature(bool_to_option)]
+#![feature(control_flow_enum)]
 #![feature(crate_visibility_modifier)]
 #![feature(format_args_capture)]
 #![feature(nll)]
@@ -23,11 +24,12 @@ use Determinacy::*;
 
 use rustc_arena::{DroplessArena, TypedArena};
 use rustc_ast::node_id::NodeMap;
+use rustc_ast::ptr::P;
 use rustc_ast::unwrap_or;
 use rustc_ast::visit::{self, Visitor};
-use rustc_ast::{self as ast, FloatTy, IntTy, NodeId, UintTy};
+use rustc_ast::{self as ast, NodeId};
 use rustc_ast::{Crate, CRATE_NODE_ID};
-use rustc_ast::{ItemKind, Path};
+use rustc_ast::{ItemKind, ModKind, Path};
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
@@ -39,8 +41,7 @@ use rustc_hir::def::Namespace::*;
 use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
-use rustc_hir::PrimTy::{self, Bool, Char, Float, Int, Str, Uint};
-use rustc_hir::TraitCandidate;
+use rustc_hir::{PrimTy, TraitCandidate};
 use rustc_index::vec::IndexVec;
 use rustc_metadata::creader::{CStore, CrateLoader};
 use rustc_middle::hir::exports::ExportMap;
@@ -60,6 +61,7 @@ use rustc_span::{Span, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
+use std::ops::ControlFlow;
 use std::{cmp, fmt, iter, ptr};
 use tracing::debug;
 
@@ -284,28 +286,21 @@ struct UsePlacementFinder {
 impl UsePlacementFinder {
     fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, bool) {
         let mut finder = UsePlacementFinder { target_module, span: None, found_use: false };
-        visit::walk_crate(&mut finder, krate);
+        if let ControlFlow::Continue(..) = finder.check_mod(&krate.items, CRATE_NODE_ID) {
+            visit::walk_crate(&mut finder, krate);
+        }
         (finder.span, finder.found_use)
     }
-}
 
-impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
-    fn visit_mod(
-        &mut self,
-        module: &'tcx ast::Mod,
-        _: Span,
-        _: &[ast::Attribute],
-        node_id: NodeId,
-    ) {
+    fn check_mod(&mut self, items: &[P<ast::Item>], node_id: NodeId) -> ControlFlow<()> {
         if self.span.is_some() {
-            return;
+            return ControlFlow::Break(());
         }
         if node_id != self.target_module {
-            visit::walk_mod(self, module);
-            return;
+            return ControlFlow::Continue(());
         }
         // find a use statement
-        for item in &module.items {
+        for item in items {
             match item.kind {
                 ItemKind::Use(..) => {
                     // don't suggest placing a use before the prelude
@@ -313,7 +308,7 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
                     if !item.span.from_expansion() {
                         self.span = Some(item.span.shrink_to_lo());
                         self.found_use = true;
-                        return;
+                        return ControlFlow::Break(());
                     }
                 }
                 // don't place use before extern crate
@@ -338,6 +333,18 @@ impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
                 }
             }
         }
+        ControlFlow::Continue(())
+    }
+}
+
+impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
+    fn visit_item(&mut self, item: &'tcx ast::Item) {
+        if let ItemKind::Mod(_, ModKind::Loaded(items, ..)) = &item.kind {
+            if let ControlFlow::Break(..) = self.check_mod(items, item.id) {
+                return;
+            }
+        }
+        visit::walk_item(self, item);
     }
 }
 
@@ -751,27 +758,12 @@ impl<'a> NameBinding<'a> {
     fn is_possibly_imported_variant(&self) -> bool {
         match self.kind {
             NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(),
-            _ => self.is_variant(),
-        }
-    }
-
-    // We sometimes need to treat variants as `pub` for backwards compatibility.
-    fn pseudo_vis(&self) -> ty::Visibility {
-        if self.is_variant() && self.res().def_id().is_local() {
-            ty::Visibility::Public
-        } else {
-            self.vis
-        }
-    }
-
-    fn is_variant(&self) -> bool {
-        matches!(
-            self.kind,
             NameBindingKind::Res(
                 Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _),
                 _,
-            )
-        )
+            ) => true,
+            NameBindingKind::Res(..) | NameBindingKind::Module(..) => false,
+        }
     }
 
     fn is_extern_crate(&self) -> bool {
@@ -834,39 +826,6 @@ impl<'a> NameBinding<'a> {
     }
 }
 
-/// Interns the names of the primitive types.
-///
-/// All other types are defined somewhere and possibly imported, but the primitive ones need
-/// special handling, since they have no place of origin.
-struct PrimitiveTypeTable {
-    primitive_types: FxHashMap<Symbol, PrimTy>,
-}
-
-impl PrimitiveTypeTable {
-    fn new() -> PrimitiveTypeTable {
-        let mut table = FxHashMap::default();
-
-        table.insert(sym::bool, Bool);
-        table.insert(sym::char, Char);
-        table.insert(sym::f32, Float(FloatTy::F32));
-        table.insert(sym::f64, Float(FloatTy::F64));
-        table.insert(sym::isize, Int(IntTy::Isize));
-        table.insert(sym::i8, Int(IntTy::I8));
-        table.insert(sym::i16, Int(IntTy::I16));
-        table.insert(sym::i32, Int(IntTy::I32));
-        table.insert(sym::i64, Int(IntTy::I64));
-        table.insert(sym::i128, Int(IntTy::I128));
-        table.insert(sym::str, Str);
-        table.insert(sym::usize, Uint(UintTy::Usize));
-        table.insert(sym::u8, Uint(UintTy::U8));
-        table.insert(sym::u16, Uint(UintTy::U16));
-        table.insert(sym::u32, Uint(UintTy::U32));
-        table.insert(sym::u64, Uint(UintTy::U64));
-        table.insert(sym::u128, Uint(UintTy::U128));
-        Self { primitive_types: table }
-    }
-}
-
 #[derive(Debug, Default, Clone)]
 pub struct ExternPreludeEntry<'a> {
     extern_crate_item: Option<&'a NameBinding<'a>>,
@@ -912,9 +871,6 @@ pub struct Resolver<'a> {
     /// "self-confirming" import resolutions during import validation.
     unusable_binding: Option<&'a NameBinding<'a>>,
 
-    /// The idents for the primitive types.
-    primitive_type_table: PrimitiveTypeTable,
-
     /// Resolutions for nodes that have a single resolution.
     partial_res_map: NodeMap<PartialRes>,
     /// Resolutions for import nodes, which have multiple resolutions in different namespaces.
@@ -1004,6 +960,8 @@ pub struct Resolver<'a> {
     output_macro_rules_scopes: FxHashMap<ExpnId, MacroRulesScopeRef<'a>>,
     /// Helper attributes that are in scope for the given expansion.
     helper_attrs: FxHashMap<ExpnId, Vec<Ident>>,
+    /// Resolutions for paths inside the `#[derive(...)]` attribute with the given `ExpnId`.
+    derive_resolutions: FxHashMap<ExpnId, Vec<(Lrc<SyntaxExtension>, ast::Path)>>,
 
     /// Avoid duplicated errors for "name already defined".
     name_already_seen: FxHashMap<Symbol, Span>,
@@ -1284,8 +1242,6 @@ impl<'a> Resolver<'a> {
             last_import_segment: false,
             unusable_binding: None,
 
-            primitive_type_table: PrimitiveTypeTable::new(),
-
             partial_res_map: Default::default(),
             import_res_map: Default::default(),
             label_res_map: Default::default(),
@@ -1334,6 +1290,7 @@ impl<'a> Resolver<'a> {
             invocation_parent_scopes: Default::default(),
             output_macro_rules_scopes: Default::default(),
             helper_attrs: Default::default(),
+            derive_resolutions: Default::default(),
             local_macro_def_scopes: FxHashMap::default(),
             name_already_seen: FxHashMap::default(),
             potentially_unused_imports: Vec::new(),
@@ -1994,9 +1951,9 @@ impl<'a> Resolver<'a> {
         }
 
         if ns == TypeNS {
-            if let Some(prim_ty) = self.primitive_type_table.primitive_types.get(&ident.name) {
+            if let Some(prim_ty) = PrimTy::from_name(ident.name) {
                 let binding =
-                    (Res::PrimTy(*prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
+                    (Res::PrimTy(prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
                         .to_name_binding(self.arenas);
                 return Some(LexicalScopeBinding::Item(binding));
             }
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index d0adee2429d..f7010ca94bd 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -14,16 +14,17 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
-use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand};
-use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
+use rustc_expand::base::{Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::compile_declarative_macro;
 use rustc_expand::expand::{AstFragment, Invocation, InvocationKind};
 use rustc_feature::is_builtin_attr_name;
 use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
 use rustc_hir::def_id;
+use rustc_hir::PrimTy;
 use rustc_middle::middle::stability;
 use rustc_middle::ty;
-use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS};
+use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNUSED_MACROS};
+use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
@@ -226,7 +227,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
         invoc: &Invocation,
         eager_expansion_root: ExpnId,
         force: bool,
-    ) -> Result<InvocationRes, Indeterminate> {
+    ) -> Result<Lrc<SyntaxExtension>, Indeterminate> {
         let invoc_id = invoc.expansion_data.id;
         let parent_scope = match self.invocation_parent_scopes.get(&invoc_id) {
             Some(parent_scope) => *parent_scope,
@@ -243,65 +244,15 @@ impl<'a> ResolverExpand for Resolver<'a> {
             }
         };
 
-        let (path, kind, inner_attr, derives, after_derive) = match invoc.kind {
-            InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => (
+        let (path, kind, inner_attr, derives) = match invoc.kind {
+            InvocationKind::Attr { ref attr, ref derives, .. } => (
                 &attr.get_normal_item().path,
                 MacroKind::Attr,
                 attr.style == ast::AttrStyle::Inner,
                 self.arenas.alloc_ast_paths(derives),
-                after_derive,
             ),
-            InvocationKind::Bang { ref mac, .. } => {
-                (&mac.path, MacroKind::Bang, false, &[][..], false)
-            }
-            InvocationKind::Derive { ref path, .. } => {
-                (path, MacroKind::Derive, false, &[][..], false)
-            }
-            InvocationKind::DeriveContainer { ref derives, .. } => {
-                // Block expansion of the container until we resolve all derives in it.
-                // This is required for two reasons:
-                // - Derive helper attributes are in scope for the item to which the `#[derive]`
-                //   is applied, so they have to be produced by the container's expansion rather
-                //   than by individual derives.
-                // - Derives in the container need to know whether one of them is a built-in `Copy`.
-                // FIXME: Try to avoid repeated resolutions for derives here and in expansion.
-                let mut exts = Vec::new();
-                let mut helper_attrs = Vec::new();
-                for path in derives {
-                    exts.push(
-                        match self.resolve_macro_path(
-                            path,
-                            Some(MacroKind::Derive),
-                            &parent_scope,
-                            true,
-                            force,
-                        ) {
-                            Ok((Some(ext), _)) => {
-                                let span = path
-                                    .segments
-                                    .last()
-                                    .unwrap()
-                                    .ident
-                                    .span
-                                    .normalize_to_macros_2_0();
-                                helper_attrs.extend(
-                                    ext.helper_attrs.iter().map(|name| Ident::new(*name, span)),
-                                );
-                                if ext.builtin_name == Some(sym::Copy) {
-                                    self.containers_deriving_copy.insert(invoc_id);
-                                }
-                                ext
-                            }
-                            Ok(_) | Err(Determinacy::Determined) => {
-                                self.dummy_ext(MacroKind::Derive)
-                            }
-                            Err(Determinacy::Undetermined) => return Err(Indeterminate),
-                        },
-                    )
-                }
-                self.helper_attrs.insert(invoc_id, helper_attrs);
-                return Ok(InvocationRes::DeriveContainer(exts));
-            }
+            InvocationKind::Bang { ref mac, .. } => (&mac.path, MacroKind::Bang, false, &[][..]),
+            InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, false, &[][..]),
         };
 
         // Derives are not included when `invocations` are collected, so we have to add them here.
@@ -327,14 +278,41 @@ impl<'a> ResolverExpand for Resolver<'a> {
         ));
 
         if let Res::Def(_, _) = res {
-            if after_derive {
-                self.session.span_err(span, "macro attributes must be placed before `#[derive]`");
-            }
             let normal_module_def_id = self.macro_def_scope(invoc_id).nearest_parent_mod;
             self.definitions.add_parent_module_of_macro_def(invoc_id, normal_module_def_id);
+
+            // Gate macro attributes in `#[derive]` output.
+            if !self.session.features_untracked().macro_attributes_in_derive_output
+                && kind == MacroKind::Attr
+                && ext.builtin_name != Some(sym::derive)
+            {
+                let mut expn_id = parent_scope.expansion;
+                loop {
+                    // Helper attr table is a quick way to determine whether the attr is `derive`.
+                    if self.helper_attrs.contains_key(&expn_id) {
+                        feature_err(
+                            &self.session.parse_sess,
+                            sym::macro_attributes_in_derive_output,
+                            path.span,
+                            "macro attributes in `#[derive]` output are unstable",
+                        )
+                        .emit();
+                        break;
+                    } else {
+                        let expn_data = expn_id.expn_data();
+                        match expn_data.kind {
+                            ExpnKind::Root
+                            | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => {
+                                break;
+                            }
+                            _ => expn_id = expn_data.parent,
+                        }
+                    }
+                }
+            }
         }
 
-        Ok(InvocationRes::Single(ext))
+        Ok(ext)
     }
 
     fn check_unused_macros(&mut self) {
@@ -343,7 +321,7 @@ impl<'a> ResolverExpand for Resolver<'a> {
         }
     }
 
-    fn lint_node_id(&mut self, expn_id: ExpnId) -> NodeId {
+    fn lint_node_id(&self, expn_id: ExpnId) -> NodeId {
         // FIXME - make this more precise. This currently returns the NodeId of the
         // nearest closing item - we should try to return the closest parent of the ExpnId
         self.invocation_parents
@@ -355,6 +333,63 @@ impl<'a> ResolverExpand for Resolver<'a> {
         self.containers_deriving_copy.contains(&expn_id)
     }
 
+    fn resolve_derives(
+        &mut self,
+        expn_id: ExpnId,
+        derives: Vec<ast::Path>,
+        force: bool,
+    ) -> Result<(), Indeterminate> {
+        // Block expansion of the container until we resolve all derives in it.
+        // This is required for two reasons:
+        // - Derive helper attributes are in scope for the item to which the `#[derive]`
+        //   is applied, so they have to be produced by the container's expansion rather
+        //   than by individual derives.
+        // - Derives in the container need to know whether one of them is a built-in `Copy`.
+        // FIXME: Try to cache intermediate results to avoid resolving same derives multiple times.
+        let parent_scope = self.invocation_parent_scopes[&expn_id];
+        let mut exts = Vec::new();
+        let mut helper_attrs = Vec::new();
+        let mut has_derive_copy = false;
+        for path in derives {
+            exts.push((
+                match self.resolve_macro_path(
+                    &path,
+                    Some(MacroKind::Derive),
+                    &parent_scope,
+                    true,
+                    force,
+                ) {
+                    Ok((Some(ext), _)) => {
+                        let span =
+                            path.segments.last().unwrap().ident.span.normalize_to_macros_2_0();
+                        helper_attrs
+                            .extend(ext.helper_attrs.iter().map(|name| Ident::new(*name, span)));
+                        has_derive_copy |= ext.builtin_name == Some(sym::Copy);
+                        ext
+                    }
+                    Ok(_) | Err(Determinacy::Determined) => self.dummy_ext(MacroKind::Derive),
+                    Err(Determinacy::Undetermined) => return Err(Indeterminate),
+                },
+                path,
+            ))
+        }
+        self.derive_resolutions.insert(expn_id, exts);
+        self.helper_attrs.insert(expn_id, helper_attrs);
+        // Mark this derive as having `Copy` either if it has `Copy` itself or if its parent derive
+        // has `Copy`, to support cases like `#[derive(Clone, Copy)] #[derive(Debug)]`.
+        if has_derive_copy || self.has_derive_copy(parent_scope.expansion) {
+            self.containers_deriving_copy.insert(expn_id);
+        }
+        Ok(())
+    }
+
+    fn take_derive_resolutions(
+        &mut self,
+        expn_id: ExpnId,
+    ) -> Option<Vec<(Lrc<SyntaxExtension>, ast::Path)>> {
+        self.derive_resolutions.remove(&expn_id)
+    }
+
     // The function that implements the resolution logic of `#[cfg_accessible(path)]`.
     // Returns true if the path can certainly be resolved in one of three namespaces,
     // returns false if the path certainly cannot be resolved in any of the three namespaces.
@@ -796,12 +831,10 @@ impl<'a> Resolver<'a> {
                         }
                         result
                     }
-                    Scope::BuiltinTypes => {
-                        match this.primitive_type_table.primitive_types.get(&ident.name).cloned() {
-                            Some(prim_ty) => ok(Res::PrimTy(prim_ty), DUMMY_SP, this.arenas),
-                            None => Err(Determinacy::Determined),
-                        }
-                    }
+                    Scope::BuiltinTypes => match PrimTy::from_name(ident.name) {
+                        Some(prim_ty) => ok(Res::PrimTy(prim_ty), DUMMY_SP, this.arenas),
+                        None => Err(Determinacy::Determined),
+                    },
                 };
 
                 match result {
@@ -819,6 +852,8 @@ impl<'a> Resolver<'a> {
                                 let is_builtin = |res| {
                                     matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..)))
                                 };
+                                let derive_helper =
+                                    Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
                                 let derive_helper_compat =
                                     Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
 
@@ -827,7 +862,7 @@ impl<'a> Resolver<'a> {
                                 } else if is_builtin(innermost_res) || is_builtin(res) {
                                     Some(AmbiguityKind::BuiltinAttr)
                                 } else if innermost_res == derive_helper_compat
-                                    || res == derive_helper_compat
+                                    || res == derive_helper_compat && innermost_res != derive_helper
                                 {
                                     Some(AmbiguityKind::DeriveHelper)
                                 } else if innermost_flags.contains(Flags::MACRO_RULES)
@@ -993,6 +1028,15 @@ impl<'a> Resolver<'a> {
                     let res = binding.res();
                     let seg = Segment::from_ident(ident);
                     check_consistency(self, &[seg], ident.span, kind, initial_res, res);
+                    if res == Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat) {
+                        self.lint_buffer.buffer_lint_with_diagnostic(
+                            LEGACY_DERIVE_HELPERS,
+                            self.lint_node_id(parent_scope.expansion),
+                            ident.span,
+                            "derive helper attribute is used before it is introduced",
+                            BuiltinLintDiagnostics::LegacyDeriveHelpers(binding.span),
+                        );
+                    }
                 }
                 Err(..) => {
                     let expected = kind.descr_expected();
@@ -1079,7 +1123,7 @@ impl<'a> Resolver<'a> {
     crate fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) {
         // Reserve some names that are not quite covered by the general check
         // performed on `Resolver::builtin_attrs`.
-        if ident.name == sym::cfg || ident.name == sym::cfg_attr || ident.name == sym::derive {
+        if ident.name == sym::cfg || ident.name == sym::cfg_attr {
             let macro_kind = self.get_macro(res).map(|ext| ext.macro_kind());
             if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
                 self.session.span_err(
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 2834e7b6322..625d7c83120 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -373,14 +373,14 @@ impl<'tcx> DumpVisitor<'tcx> {
         body: hir::BodyId,
     ) {
         let map = &self.tcx.hir();
-        self.nest_typeck_results(map.local_def_id(item.hir_id), |v| {
+        self.nest_typeck_results(item.def_id, |v| {
             let body = map.body(body);
             if let Some(fn_data) = v.save_ctxt.get_item_data(item) {
                 down_cast_data!(fn_data, DefData, item.span);
                 v.process_formals(body.params, &fn_data.qualname);
-                v.process_generic_params(ty_params, &fn_data.qualname, item.hir_id);
+                v.process_generic_params(ty_params, &fn_data.qualname, item.hir_id());
 
-                v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.hir_id), fn_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.hir_id()), fn_data);
             }
 
             for arg in decl.inputs {
@@ -401,10 +401,10 @@ impl<'tcx> DumpVisitor<'tcx> {
         typ: &'tcx hir::Ty<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
     ) {
-        self.nest_typeck_results(self.tcx.hir().local_def_id(item.hir_id), |v| {
+        self.nest_typeck_results(item.def_id, |v| {
             if let Some(var_data) = v.save_ctxt.get_item_data(item) {
                 down_cast_data!(var_data, DefData, item.span);
-                v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.hir_id), var_data);
+                v.dumper.dump_def(&access_from!(v.save_ctxt, item, item.hir_id()), var_data);
             }
             v.visit_ty(&typ);
             v.visit_expr(expr);
@@ -465,10 +465,7 @@ impl<'tcx> DumpVisitor<'tcx> {
     ) {
         debug!("process_struct {:?} {:?}", item, item.span);
         let name = item.ident.to_string();
-        let qualname = format!(
-            "::{}",
-            self.tcx.def_path_str(self.tcx.hir().local_def_id(item.hir_id).to_def_id())
-        );
+        let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
 
         let kind = match item.kind {
             hir::ItemKind::Struct(_, _) => DefKind::Struct,
@@ -500,10 +497,10 @@ impl<'tcx> DumpVisitor<'tcx> {
         if !self.span.filter_generated(item.ident.span) {
             let span = self.span_from_span(item.ident.span);
             self.dumper.dump_def(
-                &access_from!(self.save_ctxt, item, item.hir_id),
+                &access_from!(self.save_ctxt, item, item.hir_id()),
                 Def {
                     kind,
-                    id: id_from_hir_id(item.hir_id, &self.save_ctxt),
+                    id: id_from_def_id(item.def_id.to_def_id()),
                     span,
                     name,
                     qualname: qualname.clone(),
@@ -518,13 +515,13 @@ impl<'tcx> DumpVisitor<'tcx> {
             );
         }
 
-        self.nest_typeck_results(self.tcx.hir().local_def_id(item.hir_id), |v| {
+        self.nest_typeck_results(item.def_id, |v| {
             for field in def.fields() {
-                v.process_struct_field_def(field, item.hir_id);
+                v.process_struct_field_def(field, item.hir_id());
                 v.visit_ty(&field.ty);
             }
 
-            v.process_generic_params(ty_params, &qualname, item.hir_id);
+            v.process_generic_params(ty_params, &qualname, item.hir_id());
         });
     }
 
@@ -541,7 +538,7 @@ impl<'tcx> DumpVisitor<'tcx> {
         };
         down_cast_data!(enum_data, DefData, item.span);
 
-        let access = access_from!(self.save_ctxt, item, item.hir_id);
+        let access = access_from!(self.save_ctxt, item, item.hir_id());
 
         for variant in enum_definition.variants {
             let name = variant.ident.name.to_string();
@@ -556,7 +553,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                     if !self.span.filter_generated(name_span) {
                         let span = self.span_from_span(name_span);
                         let id = id_from_hir_id(variant.id, &self.save_ctxt);
-                        let parent = Some(id_from_hir_id(item.hir_id, &self.save_ctxt));
+                        let parent = Some(id_from_def_id(item.def_id.to_def_id()));
 
                         self.dumper.dump_def(
                             &access,
@@ -596,7 +593,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                     if !self.span.filter_generated(name_span) {
                         let span = self.span_from_span(name_span);
                         let id = id_from_hir_id(variant.id, &self.save_ctxt);
-                        let parent = Some(id_from_hir_id(item.hir_id, &self.save_ctxt));
+                        let parent = Some(id_from_def_id(item.def_id.to_def_id()));
 
                         self.dumper.dump_def(
                             &access,
@@ -627,7 +624,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                 self.visit_ty(field.ty);
             }
         }
-        self.process_generic_params(ty_params, &enum_data.qualname, item.hir_id);
+        self.process_generic_params(ty_params, &enum_data.qualname, item.hir_id());
         self.dumper.dump_def(&access, enum_data);
     }
 
@@ -644,17 +641,14 @@ impl<'tcx> DumpVisitor<'tcx> {
         }
 
         let map = &self.tcx.hir();
-        self.nest_typeck_results(map.local_def_id(item.hir_id), |v| {
+        self.nest_typeck_results(item.def_id, |v| {
             v.visit_ty(&impl_.self_ty);
             if let Some(trait_ref) = &impl_.of_trait {
                 v.process_path(trait_ref.hir_ref_id, &hir::QPath::Resolved(None, &trait_ref.path));
             }
-            v.process_generic_params(&impl_.generics, "", item.hir_id);
+            v.process_generic_params(&impl_.generics, "", item.hir_id());
             for impl_item in impl_.items {
-                v.process_impl_item(
-                    map.impl_item(impl_item.id),
-                    map.local_def_id(item.hir_id).to_def_id(),
-                );
+                v.process_impl_item(map.impl_item(impl_item.id), item.def_id.to_def_id());
             }
         });
     }
@@ -667,10 +661,7 @@ impl<'tcx> DumpVisitor<'tcx> {
         methods: &'tcx [hir::TraitItemRef],
     ) {
         let name = item.ident.to_string();
-        let qualname = format!(
-            "::{}",
-            self.tcx.def_path_str(self.tcx.hir().local_def_id(item.hir_id).to_def_id())
-        );
+        let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
         let mut val = name.clone();
         if !generics.params.is_empty() {
             val.push_str(&generic_params_to_string(generics.params));
@@ -680,12 +671,12 @@ impl<'tcx> DumpVisitor<'tcx> {
             val.push_str(&bounds_to_string(trait_refs));
         }
         if !self.span.filter_generated(item.ident.span) {
-            let id = id_from_hir_id(item.hir_id, &self.save_ctxt);
+            let id = id_from_def_id(item.def_id.to_def_id());
             let span = self.span_from_span(item.ident.span);
             let children =
-                methods.iter().map(|i| id_from_hir_id(i.id.hir_id, &self.save_ctxt)).collect();
+                methods.iter().map(|i| id_from_def_id(i.id.def_id.to_def_id())).collect();
             self.dumper.dump_def(
-                &access_from!(self.save_ctxt, item, item.hir_id),
+                &access_from!(self.save_ctxt, item, item.hir_id()),
                 Def {
                     kind: DefKind::Trait,
                     id,
@@ -729,20 +720,17 @@ impl<'tcx> DumpVisitor<'tcx> {
                         kind: RelationKind::SuperTrait,
                         span,
                         from: id_from_def_id(id),
-                        to: id_from_hir_id(item.hir_id, &self.save_ctxt),
+                        to: id_from_def_id(item.def_id.to_def_id()),
                     });
                 }
             }
         }
 
         // walk generics and methods
-        self.process_generic_params(generics, &qualname, item.hir_id);
+        self.process_generic_params(generics, &qualname, item.hir_id());
         for method in methods {
             let map = &self.tcx.hir();
-            self.process_trait_item(
-                map.trait_item(method.id),
-                map.local_def_id(item.hir_id).to_def_id(),
-            )
+            self.process_trait_item(map.trait_item(method.id), item.def_id.to_def_id())
         }
     }
 
@@ -750,7 +738,7 @@ impl<'tcx> DumpVisitor<'tcx> {
     fn process_mod(&mut self, item: &'tcx hir::Item<'tcx>) {
         if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
             down_cast_data!(mod_data, DefData, item.span);
-            self.dumper.dump_def(&access_from!(self.save_ctxt, item, item.hir_id), mod_data);
+            self.dumper.dump_def(&access_from!(self.save_ctxt, item, item.hir_id()), mod_data);
         }
     }
 
@@ -1011,7 +999,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                 let body = body.map(|b| &self.tcx.hir().body(b).value);
                 let respan = respan(vis_span, hir::VisibilityKind::Public);
                 self.process_assoc_const(
-                    trait_item.hir_id,
+                    trait_item.hir_id(),
                     trait_item.ident,
                     &ty,
                     body,
@@ -1027,7 +1015,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                 self.process_method(
                     sig,
                     body,
-                    trait_item.hir_id,
+                    trait_item.hir_id(),
                     trait_item.ident,
                     &trait_item.generics,
                     &respan,
@@ -1037,15 +1025,12 @@ impl<'tcx> DumpVisitor<'tcx> {
             hir::TraitItemKind::Type(ref bounds, ref default_ty) => {
                 // FIXME do something with _bounds (for type refs)
                 let name = trait_item.ident.name.to_string();
-                let qualname = format!(
-                    "::{}",
-                    self.tcx
-                        .def_path_str(self.tcx.hir().local_def_id(trait_item.hir_id).to_def_id())
-                );
+                let qualname =
+                    format!("::{}", self.tcx.def_path_str(trait_item.def_id.to_def_id()));
 
                 if !self.span.filter_generated(trait_item.ident.span) {
                     let span = self.span_from_span(trait_item.ident.span);
-                    let id = id_from_hir_id(trait_item.hir_id, &self.save_ctxt);
+                    let id = id_from_def_id(trait_item.def_id.to_def_id());
 
                     self.dumper.dump_def(
                         &Access { public: true, reachable: true },
@@ -1061,7 +1046,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                             decl_id: None,
                             docs: self.save_ctxt.docs_for_attrs(&trait_item.attrs),
                             sig: sig::assoc_type_signature(
-                                trait_item.hir_id,
+                                trait_item.hir_id(),
                                 trait_item.ident,
                                 Some(bounds),
                                 default_ty.as_ref().map(|ty| &**ty),
@@ -1088,7 +1073,7 @@ impl<'tcx> DumpVisitor<'tcx> {
             hir::ImplItemKind::Const(ref ty, body) => {
                 let body = self.tcx.hir().body(body);
                 self.process_assoc_const(
-                    impl_item.hir_id,
+                    impl_item.hir_id(),
                     impl_item.ident,
                     &ty,
                     Some(&body.value),
@@ -1101,7 +1086,7 @@ impl<'tcx> DumpVisitor<'tcx> {
                 self.process_method(
                     sig,
                     Some(body),
-                    impl_item.hir_id,
+                    impl_item.hir_id(),
                     impl_item.ident,
                     &impl_item.generics,
                     &impl_item.vis,
@@ -1130,7 +1115,7 @@ impl<'tcx> DumpVisitor<'tcx> {
             .module
             .item_ids
             .iter()
-            .map(|i| id_from_hir_id(i.id, &self.save_ctxt))
+            .map(|i| id_from_def_id(i.def_id.to_def_id()))
             .collect();
         let span = self.span_from_span(krate.item.span);
 
@@ -1179,16 +1164,11 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
             hir::ItemKind::Use(path, hir::UseKind::Single) => {
                 let sub_span = path.segments.last().unwrap().ident.span;
                 if !self.span.filter_generated(sub_span) {
-                    let access = access_from!(self.save_ctxt, item, item.hir_id);
-                    let ref_id = self.lookup_def_id(item.hir_id).map(id_from_def_id);
+                    let access = access_from!(self.save_ctxt, item, item.hir_id());
+                    let ref_id = self.lookup_def_id(item.hir_id()).map(id_from_def_id);
                     let span = self.span_from_span(sub_span);
-                    let parent = self
-                        .save_ctxt
-                        .tcx
-                        .hir()
-                        .opt_local_def_id(item.hir_id)
-                        .and_then(|id| self.save_ctxt.tcx.parent(id.to_def_id()))
-                        .map(id_from_def_id);
+                    let parent =
+                        self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
                     self.dumper.import(
                         &access,
                         Import {
@@ -1206,23 +1186,17 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
             }
             hir::ItemKind::Use(path, hir::UseKind::Glob) => {
                 // Make a comma-separated list of names of imported modules.
-                let def_id = self.tcx.hir().local_def_id(item.hir_id);
-                let names = self.tcx.names_imported_by_glob_use(def_id);
+                let names = self.tcx.names_imported_by_glob_use(item.def_id);
                 let names: Vec<_> = names.iter().map(|n| n.to_string()).collect();
 
                 // Otherwise it's a span with wrong macro expansion info, which
                 // we don't want to track anyway, since it's probably macro-internal `use`
                 if let Some(sub_span) = self.span.sub_span_of_star(item.span) {
                     if !self.span.filter_generated(item.span) {
-                        let access = access_from!(self.save_ctxt, item, item.hir_id);
+                        let access = access_from!(self.save_ctxt, item, item.hir_id());
                         let span = self.span_from_span(sub_span);
-                        let parent = self
-                            .save_ctxt
-                            .tcx
-                            .hir()
-                            .opt_local_def_id(item.hir_id)
-                            .and_then(|id| self.save_ctxt.tcx.parent(id.to_def_id()))
-                            .map(id_from_def_id);
+                        let parent =
+                            self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
                         self.dumper.import(
                             &access,
                             Import {
@@ -1243,13 +1217,8 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                 let name_span = item.ident.span;
                 if !self.span.filter_generated(name_span) {
                     let span = self.span_from_span(name_span);
-                    let parent = self
-                        .save_ctxt
-                        .tcx
-                        .hir()
-                        .opt_local_def_id(item.hir_id)
-                        .and_then(|id| self.save_ctxt.tcx.parent(id.to_def_id()))
-                        .map(id_from_def_id);
+                    let parent =
+                        self.save_ctxt.tcx.parent(item.def_id.to_def_id()).map(id_from_def_id);
                     self.dumper.import(
                         &Access { public: false, reachable: false },
                         Import {
@@ -1286,20 +1255,17 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
             }
             hir::ItemKind::Mod(ref m) => {
                 self.process_mod(item);
-                intravisit::walk_mod(self, m, item.hir_id);
+                intravisit::walk_mod(self, m, item.hir_id());
             }
             hir::ItemKind::TyAlias(ty, ref generics) => {
-                let qualname = format!(
-                    "::{}",
-                    self.tcx.def_path_str(self.tcx.hir().local_def_id(item.hir_id).to_def_id())
-                );
+                let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
                 let value = ty_to_string(&ty);
                 if !self.span.filter_generated(item.ident.span) {
                     let span = self.span_from_span(item.ident.span);
-                    let id = id_from_hir_id(item.hir_id, &self.save_ctxt);
+                    let id = id_from_def_id(item.def_id.to_def_id());
 
                     self.dumper.dump_def(
-                        &access_from!(self.save_ctxt, item, item.hir_id),
+                        &access_from!(self.save_ctxt, item, item.hir_id()),
                         Def {
                             kind: DefKind::Type,
                             id,
@@ -1318,7 +1284,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                 }
 
                 self.visit_ty(ty);
-                self.process_generic_params(generics, &qualname, item.hir_id);
+                self.process_generic_params(generics, &qualname, item.hir_id());
             }
             _ => intravisit::walk_item(self, item),
         }
@@ -1382,10 +1348,8 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
                 });
             }
             hir::TyKind::OpaqueDef(item_id, _) => {
-                let item = self.tcx.hir().item(item_id.id);
-                self.nest_typeck_results(self.tcx.hir().local_def_id(item_id.id), |v| {
-                    v.visit_item(item)
-                });
+                let item = self.tcx.hir().item(item_id);
+                self.nest_typeck_results(item_id.def_id, |v| v.visit_item(item));
             }
             _ => intravisit::walk_ty(self, t),
         }
@@ -1485,14 +1449,14 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
     }
 
     fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
-        let access = access_from!(self.save_ctxt, item, item.hir_id);
+        let access = access_from!(self.save_ctxt, item, item.hir_id());
 
         match item.kind {
             hir::ForeignItemKind::Fn(decl, _, ref generics) => {
                 if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
                     down_cast_data!(fn_data, DefData, item.span);
 
-                    self.process_generic_params(generics, &fn_data.qualname, item.hir_id);
+                    self.process_generic_params(generics, &fn_data.qualname, item.hir_id());
                     self.dumper.dump_def(&access, fn_data);
                 }
 
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 129123349a0..b3f281bcabc 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -137,7 +137,7 @@ impl<'tcx> SaveContext<'tcx> {
     }
 
     pub fn get_extern_item_data(&self, item: &hir::ForeignItem<'_>) -> Option<Data> {
-        let def_id = self.tcx.hir().local_def_id(item.hir_id).to_def_id();
+        let def_id = item.def_id.to_def_id();
         let qualname = format!("::{}", self.tcx.def_path_str(def_id));
         match item.kind {
             hir::ForeignItemKind::Fn(ref decl, arg_names, ref generics) => {
@@ -156,7 +156,7 @@ impl<'tcx> SaveContext<'tcx> {
                             unsafety: hir::Unsafety::Unsafe,
                             // functions in extern block cannot be const
                             constness: hir::Constness::NotConst,
-                            abi: self.tcx.hir().get_foreign_abi(item.hir_id),
+                            abi: self.tcx.hir().get_foreign_abi(item.hir_id()),
                             // functions in extern block cannot be async
                             asyncness: hir::IsAsync::NotAsync,
                         },
@@ -201,7 +201,7 @@ impl<'tcx> SaveContext<'tcx> {
     }
 
     pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> {
-        let def_id = self.tcx.hir().local_def_id(item.hir_id).to_def_id();
+        let def_id = item.def_id.to_def_id();
         match item.kind {
             hir::ItemKind::Fn(ref sig, ref generics, _) => {
                 let qualname = format!("::{}", self.tcx.def_path_str(def_id));
@@ -290,7 +290,11 @@ impl<'tcx> SaveContext<'tcx> {
                     span: self.span_from_span(item.ident.span),
                     value: filename.to_string(),
                     parent: None,
-                    children: m.item_ids.iter().map(|i| id_from_hir_id(i.id, self)).collect(),
+                    children: m
+                        .item_ids
+                        .iter()
+                        .map(|i| id_from_def_id(i.def_id.to_def_id()))
+                        .collect(),
                     decl_id: None,
                     docs: self.docs_for_attrs(&item.attrs),
                     sig: sig::item_signature(item, self),
@@ -354,7 +358,7 @@ impl<'tcx> SaveContext<'tcx> {
                                 parent: None,
                                 children: items
                                     .iter()
-                                    .map(|i| id_from_hir_id(i.id.hir_id, self))
+                                    .map(|i| id_from_def_id(i.id.def_id.to_def_id()))
                                     .collect(),
                                 docs: String::new(),
                                 sig: None,
diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs
index 8ada7e34fe8..33db189af37 100644
--- a/compiler/rustc_save_analysis/src/sig.rs
+++ b/compiler/rustc_save_analysis/src/sig.rs
@@ -317,8 +317,8 @@ impl<'hir> Sig for hir::Ty<'hir> {
                 Ok(replace_text(nested_ty, text))
             }
             hir::TyKind::OpaqueDef(item_id, _) => {
-                let item = scx.tcx.hir().item(item_id.id);
-                item.make(offset, Some(item_id.id), scx)
+                let item = scx.tcx.hir().item(item_id);
+                item.make(offset, Some(item_id.hir_id()), scx)
             }
             hir::TyKind::Typeof(_) | hir::TyKind::Infer | hir::TyKind::Err => Err("Ty"),
         }
@@ -327,7 +327,7 @@ impl<'hir> Sig for hir::Ty<'hir> {
 
 impl<'hir> Sig for hir::Item<'hir> {
     fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
-        let id = Some(self.hir_id);
+        let id = Some(self.hir_id());
 
         match self.kind {
             hir::ItemKind::Static(ref ty, m, ref body) => {
@@ -337,7 +337,7 @@ impl<'hir> Sig for hir::Item<'hir> {
                 }
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_hir_id(self.hir_id, scx),
+                    id: id_from_def_id(self.def_id.to_def_id()),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -359,7 +359,7 @@ impl<'hir> Sig for hir::Item<'hir> {
                 let mut text = "const ".to_owned();
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_hir_id(self.hir_id, scx),
+                    id: id_from_def_id(self.def_id.to_def_id()),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -391,7 +391,7 @@ impl<'hir> Sig for hir::Item<'hir> {
                 text.push_str("fn ");
 
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
 
                 sig.text.push('(');
                 for i in decl.inputs {
@@ -420,7 +420,7 @@ impl<'hir> Sig for hir::Item<'hir> {
                 let mut text = "mod ".to_owned();
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_hir_id(self.hir_id, scx),
+                    id: id_from_def_id(self.def_id.to_def_id()),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -433,7 +433,7 @@ impl<'hir> Sig for hir::Item<'hir> {
             hir::ItemKind::TyAlias(ref ty, ref generics) => {
                 let text = "type ".to_owned();
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
 
                 sig.text.push_str(" = ");
                 let ty = ty.make(offset + sig.text.len(), id, scx)?;
@@ -445,21 +445,21 @@ impl<'hir> Sig for hir::Item<'hir> {
             hir::ItemKind::Enum(_, ref generics) => {
                 let text = "enum ".to_owned();
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
                 sig.text.push_str(" {}");
                 Ok(sig)
             }
             hir::ItemKind::Struct(_, ref generics) => {
                 let text = "struct ".to_owned();
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
                 sig.text.push_str(" {}");
                 Ok(sig)
             }
             hir::ItemKind::Union(_, ref generics) => {
                 let text = "union ".to_owned();
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
                 sig.text.push_str(" {}");
                 Ok(sig)
             }
@@ -475,7 +475,7 @@ impl<'hir> Sig for hir::Item<'hir> {
                 }
                 text.push_str("trait ");
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
 
                 if !bounds.is_empty() {
                     sig.text.push_str(": ");
@@ -490,7 +490,7 @@ impl<'hir> Sig for hir::Item<'hir> {
                 let mut text = String::new();
                 text.push_str("trait ");
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
 
                 if !bounds.is_empty() {
                     sig.text.push_str(" = ");
@@ -736,14 +736,14 @@ impl<'hir> Sig for hir::Variant<'hir> {
 
 impl<'hir> Sig for hir::ForeignItem<'hir> {
     fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
-        let id = Some(self.hir_id);
+        let id = Some(self.hir_id());
         match self.kind {
             hir::ForeignItemKind::Fn(decl, _, ref generics) => {
                 let mut text = String::new();
                 text.push_str("fn ");
 
                 let mut sig =
-                    name_and_generics(text, offset, generics, self.hir_id, self.ident, scx)?;
+                    name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
 
                 sig.text.push('(');
                 for i in decl.inputs {
@@ -774,7 +774,7 @@ impl<'hir> Sig for hir::ForeignItem<'hir> {
                 }
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_hir_id(self.hir_id, scx),
+                    id: id_from_def_id(self.def_id.to_def_id()),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
@@ -790,7 +790,7 @@ impl<'hir> Sig for hir::ForeignItem<'hir> {
                 let mut text = "type ".to_owned();
                 let name = self.ident.to_string();
                 let defs = vec![SigElement {
-                    id: id_from_hir_id(self.hir_id, scx),
+                    id: id_from_def_id(self.def_id.to_def_id()),
                     start: offset + text.len(),
                     end: offset + text.len() + name.len(),
                 }];
diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml
index 16c5dff7341..05fc6a4e11d 100644
--- a/compiler/rustc_serialize/Cargo.toml
+++ b/compiler/rustc_serialize/Cargo.toml
@@ -6,7 +6,7 @@ edition = "2018"
 
 [dependencies]
 indexmap = "1"
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 
 [dev-dependencies]
 rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index ea04e7bb44b..53c3adcc20c 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -17,6 +17,7 @@ Core encoding and decoding interfaces.
 #![feature(min_specialization)]
 #![feature(vec_spare_capacity)]
 #![feature(core_intrinsics)]
+#![feature(int_bits_const)]
 #![feature(maybe_uninit_slice)]
 #![feature(new_uninit)]
 #![cfg_attr(test, feature(test))]
diff --git a/compiler/rustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs
index 3e2aab5125a..a2bcf2c251d 100644
--- a/compiler/rustc_serialize/tests/leb128.rs
+++ b/compiler/rustc_serialize/tests/leb128.rs
@@ -1,3 +1,4 @@
+#![feature(int_bits_const)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array)]
 
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 9d73c3b4424..4533b37f10b 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -15,6 +15,8 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_target::abi::{Align, TargetDataLayout};
 use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
 
+use rustc_serialize::json;
+
 use crate::parse::CrateConfig;
 use rustc_feature::UnstableFeatures;
 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
@@ -41,6 +43,7 @@ bitflags! {
         const LEAK    = 1 << 1;
         const MEMORY  = 1 << 2;
         const THREAD  = 1 << 3;
+        const HWADDRESS  = 1 << 4;
     }
 }
 
@@ -54,6 +57,7 @@ impl fmt::Display for SanitizerSet {
                 SanitizerSet::LEAK => "leak",
                 SanitizerSet::MEMORY => "memory",
                 SanitizerSet::THREAD => "thread",
+                SanitizerSet::HWADDRESS => "hwaddress",
                 _ => panic!("unrecognized sanitizer {:?}", s),
             };
             if !first {
@@ -71,12 +75,18 @@ impl IntoIterator for SanitizerSet {
     type IntoIter = std::vec::IntoIter<SanitizerSet>;
 
     fn into_iter(self) -> Self::IntoIter {
-        [SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD]
-            .iter()
-            .copied()
-            .filter(|&s| self.contains(s))
-            .collect::<Vec<_>>()
-            .into_iter()
+        [
+            SanitizerSet::ADDRESS,
+            SanitizerSet::LEAK,
+            SanitizerSet::MEMORY,
+            SanitizerSet::THREAD,
+            SanitizerSet::HWADDRESS,
+        ]
+        .iter()
+        .copied()
+        .filter(|&s| self.contains(s))
+        .collect::<Vec<_>>()
+        .into_iter()
     }
 }
 
@@ -408,6 +418,9 @@ impl OutputTypes {
 #[derive(Clone)]
 pub struct Externs(BTreeMap<String, ExternEntry>);
 
+#[derive(Clone)]
+pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
+
 #[derive(Clone, Debug)]
 pub struct ExternEntry {
     pub location: ExternLocation,
@@ -439,6 +452,27 @@ pub enum ExternLocation {
     ExactPaths(BTreeSet<CanonicalizedPath>),
 }
 
+/// Supplied source location of a dependency - for example in a build specification
+/// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
+/// a file and line, then the build system can specify that. On the other hand, it may
+/// make more sense to have an arbitrary raw string.
+#[derive(Clone, PartialEq)]
+pub enum ExternDepSpec {
+    /// Raw string
+    Raw(String),
+    /// Raw data in json format
+    Json(json::Json),
+}
+
+impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
+    fn from(from: &'a ExternDepSpec) -> Self {
+        match from {
+            ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
+            ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
+        }
+    }
+}
+
 impl Externs {
     pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
         Externs(data)
@@ -466,6 +500,25 @@ impl ExternEntry {
     }
 }
 
+impl ExternDepSpecs {
+    pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
+        ExternDepSpecs(data)
+    }
+
+    pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
+        self.0.get(key)
+    }
+}
+
+impl fmt::Display for ExternDepSpec {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            ExternDepSpec::Raw(raw) => fmt.write_str(raw),
+            ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
+        }
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum PrintRequest {
     FileNames,
@@ -679,6 +732,7 @@ impl Default for Options {
             cg: basic_codegen_options(),
             error_format: ErrorOutputType::default(),
             externs: Externs(BTreeMap::new()),
+            extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
             crate_name: None,
             alt_std_name: None,
             libs: Vec::new(),
@@ -1105,6 +1159,12 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
             "Specify where an external rust library is located",
             "NAME[=PATH]",
         ),
+        opt::multi_s(
+            "",
+            "extern-location",
+            "Location where an external crate dependency is specified",
+            "NAME=LOCATION",
+        ),
         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
         opt::multi("Z", "", "Set internal debugging options", "FLAG"),
         opt::opt_s(
@@ -1290,7 +1350,7 @@ pub fn parse_error_format(
     error_format
 }
 
-fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
+pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
     let edition = match matches.opt_str("edition") {
         Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
             early_error(
@@ -1727,6 +1787,68 @@ pub fn parse_externs(
     Externs(externs)
 }
 
+fn parse_extern_dep_specs(
+    matches: &getopts::Matches,
+    debugging_opts: &DebuggingOptions,
+    error_format: ErrorOutputType,
+) -> ExternDepSpecs {
+    let is_unstable_enabled = debugging_opts.unstable_options;
+    let mut map = BTreeMap::new();
+
+    for arg in matches.opt_strs("extern-location") {
+        if !is_unstable_enabled {
+            early_error(
+                error_format,
+                "`--extern-location` option is unstable: set `-Z unstable-options`",
+            );
+        }
+
+        let mut parts = arg.splitn(2, '=');
+        let name = parts.next().unwrap_or_else(|| {
+            early_error(error_format, "`--extern-location` value must not be empty")
+        });
+        let loc = parts.next().unwrap_or_else(|| {
+            early_error(
+                error_format,
+                &format!("`--extern-location`: specify location for extern crate `{}`", name),
+            )
+        });
+
+        let locparts: Vec<_> = loc.split(":").collect();
+        let spec = match &locparts[..] {
+            ["raw", ..] => {
+                // Don't want `:` split string
+                let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
+                    early_error(error_format, "`--extern-location`: missing `raw` location")
+                });
+                ExternDepSpec::Raw(raw.to_string())
+            }
+            ["json", ..] => {
+                // Don't want `:` split string
+                let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
+                    early_error(error_format, "`--extern-location`: missing `json` location")
+                });
+                let json = json::from_str(raw).unwrap_or_else(|_| {
+                    early_error(
+                        error_format,
+                        &format!("`--extern-location`: malformed json location `{}`", raw),
+                    )
+                });
+                ExternDepSpec::Json(json)
+            }
+            [bad, ..] => early_error(
+                error_format,
+                &format!("unknown location type `{}`: use `raw` or `json`", bad),
+            ),
+            [] => early_error(error_format, "missing location specification"),
+        };
+
+        map.insert(name.to_string(), spec);
+    }
+
+    ExternDepSpecs::new(map)
+}
+
 fn parse_remap_path_prefix(
     matches: &getopts::Matches,
     error_format: ErrorOutputType,
@@ -1888,6 +2010,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     }
 
     let externs = parse_externs(matches, &debugging_opts, error_format);
+    let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
 
     let crate_name = matches.opt_str("crate-name");
 
@@ -1924,6 +2047,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         error_format,
         externs,
         unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
+        extern_dep_specs,
         crate_name,
         alt_std_name: None,
         libs,
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 3a757e5f007..47f14fa6b7a 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -113,6 +113,8 @@ pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
     sysroot.join(&relative_target_lib_path(sysroot, target_triple))
 }
 
+// This function checks if sysroot is found using env::args().next(), and if it
+// is not found, uses env::current_exe() to imply sysroot.
 pub fn get_or_default_sysroot() -> PathBuf {
     // Follow symlinks.  If the resolved path is relative, make it absolute.
     fn canonicalize(path: PathBuf) -> PathBuf {
@@ -123,15 +125,51 @@ pub fn get_or_default_sysroot() -> PathBuf {
         fix_windows_verbatim_for_gcc(&path)
     }
 
-    match env::current_exe() {
-        Ok(exe) => {
-            let mut p = canonicalize(exe);
-            p.pop();
-            p.pop();
-            p
+    // Use env::current_exe() to get the path of the executable following
+    // symlinks/canonicalizing components.
+    fn from_current_exe() -> PathBuf {
+        match env::current_exe() {
+            Ok(exe) => {
+                let mut p = canonicalize(exe);
+                p.pop();
+                p.pop();
+                p
+            }
+            Err(e) => panic!("failed to get current_exe: {}", e),
+        }
+    }
+
+    // Use env::args().next() to get the path of the executable without
+    // following symlinks/canonicalizing any component. This makes the rustc
+    // binary able to locate Rust libraries in systems using content-addressable
+    // storage (CAS).
+    fn from_env_args_next() -> Option<PathBuf> {
+        match env::args_os().next() {
+            Some(first_arg) => {
+                let mut p = PathBuf::from(first_arg);
+
+                // Check if sysroot is found using env::args().next() only if the rustc in argv[0]
+                // is a symlink (see #79253). We might want to change/remove it to conform with
+                // https://www.gnu.org/prep/standards/standards.html#Finding-Program-Files in the
+                // future.
+                if fs::read_link(&p).is_err() {
+                    // Path is not a symbolic link or does not exist.
+                    return None;
+                }
+
+                p.pop();
+                p.pop();
+                let mut libdir = PathBuf::from(&p);
+                libdir.push(find_libdir(&p).as_ref());
+                if libdir.exists() { Some(p) } else { None }
+            }
+            None => None,
         }
-        Err(e) => panic!("failed to get current_exe: {}", e),
     }
+
+    // Check if sysroot is found using env::args().next(), and if is not found,
+    // use env::current_exe() to imply sysroot.
+    from_env_args_next().unwrap_or(from_current_exe())
 }
 
 // The name of the directory rustc expects libraries to be located.
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 779e0421636..baa0502521d 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -112,6 +112,7 @@ top_level_options!(
         borrowck_mode: BorrowckMode [UNTRACKED],
         cg: CodegenOptions [TRACKED],
         externs: Externs [UNTRACKED],
+        extern_dep_specs: ExternDepSpecs [UNTRACKED],
         crate_name: Option<String> [TRACKED],
         // An optional name to use as the crate for std during std injection,
         // written `extern crate name as std`. Defaults to `std`. Used by
@@ -252,7 +253,7 @@ macro_rules! options {
         pub const parse_passes: &str = "a space-separated list of passes, or `all`";
         pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
         pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
-        pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `leak`, `memory` or `thread`";
+        pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
         pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
         pub const parse_cfguard: &str =
             "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -475,6 +476,7 @@ macro_rules! options {
                         "leak" => SanitizerSet::LEAK,
                         "memory" => SanitizerSet::MEMORY,
                         "thread" => SanitizerSet::THREAD,
+                        "hwaddress" => SanitizerSet::HWADDRESS,
                         _ => return false,
                     }
                 }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 69aa72d899f..823aa61c470 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -959,19 +959,19 @@ impl Session {
     }
 
     pub fn print_perf_stats(&self) {
-        println!(
+        eprintln!(
             "Total time spent computing symbol hashes:      {}",
             duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock())
         );
-        println!(
+        eprintln!(
             "Total queries canonicalized:                   {}",
             self.perf_stats.queries_canonicalized.load(Ordering::Relaxed)
         );
-        println!(
+        eprintln!(
             "normalize_generic_arg_after_erasing_regions:   {}",
             self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed)
         );
-        println!(
+        eprintln!(
             "normalize_projection_ty:                       {}",
             self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed)
         );
@@ -1126,7 +1126,8 @@ impl Session {
         self.opts.optimize != config::OptLevel::No
         // AddressSanitizer uses lifetimes to detect use after scope bugs.
         // MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
-        || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY)
+        // HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
+        || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
     }
 
     pub fn link_dead_code(&self) -> bool {
@@ -1562,6 +1563,8 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         "x86_64-unknown-freebsd",
         "x86_64-unknown-linux-gnu",
     ];
+    const HWASAN_SUPPORTED_TARGETS: &[&str] =
+        &["aarch64-linux-android", "aarch64-unknown-linux-gnu"];
 
     // Sanitizers can only be used on some tested platforms.
     for s in sess.opts.debugging_opts.sanitizer {
@@ -1570,6 +1573,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             SanitizerSet::LEAK => LSAN_SUPPORTED_TARGETS,
             SanitizerSet::MEMORY => MSAN_SUPPORTED_TARGETS,
             SanitizerSet::THREAD => TSAN_SUPPORTED_TARGETS,
+            SanitizerSet::HWADDRESS => HWASAN_SUPPORTED_TARGETS,
             _ => panic!("unrecognized sanitizer {}", s),
         };
         if !supported_targets.contains(&&*sess.opts.target_triple.triple()) {
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index b24ede9c53a..70e9526f626 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -227,6 +227,8 @@ pub struct LocalDefId {
     pub local_def_index: DefIndex,
 }
 
+pub const CRATE_DEF_ID: LocalDefId = LocalDefId { local_def_index: CRATE_DEF_INDEX };
+
 impl Idx for LocalDefId {
     #[inline]
     fn new(idx: usize) -> Self {
@@ -268,6 +270,8 @@ impl<D: Decoder> Decodable<D> for LocalDefId {
     }
 }
 
+rustc_data_structures::define_id_collections!(LocalDefIdMap, LocalDefIdSet, LocalDefId);
+
 impl<CTX: HashStableContext> HashStable<CTX> for DefId {
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         hcx.hash_def_id(*self, hasher)
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 9f265f37f35..4ccf657335f 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1405,8 +1405,8 @@ fn update_disambiguator(expn_id: ExpnId) {
     });
 
     if modified {
-        info!("Set disambiguator for {:?} (hash {:?})", expn_id, first_hash);
-        info!("expn_data = {:?}", expn_id.expn_data());
+        debug!("Set disambiguator for {:?} (hash {:?})", expn_id, first_hash);
+        debug!("expn_data = {:?}", expn_id.expn_data());
 
         // Verify that the new disambiguator makes the hash unique
         #[cfg(debug_assertions)]
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index f3d876a5770..4b03d38ccba 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -22,6 +22,7 @@
 #![feature(nll)]
 #![feature(min_specialization)]
 #![feature(option_expect_none)]
+#![feature(str_split_once)]
 
 #[macro_use]
 extern crate rustc_macros;
@@ -509,11 +510,10 @@ impl Span {
     /// items can be used (that is, a macro marked with
     /// `#[allow_internal_unstable]`).
     pub fn allows_unstable(&self, feature: Symbol) -> bool {
-        self.ctxt().outer_expn_data().allow_internal_unstable.map_or(false, |features| {
-            features
-                .iter()
-                .any(|&f| f == feature || f == sym::allow_internal_unstable_backcompat_hack)
-        })
+        self.ctxt()
+            .outer_expn_data()
+            .allow_internal_unstable
+            .map_or(false, |features| features.iter().any(|&f| f == feature))
     }
 
     /// Checks if this span arises from a compiler desugaring of kind `kind`.
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 2b429372dcf..b7eb6d5b379 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -539,7 +539,7 @@ impl SourceMap {
 
     pub fn is_line_before_span_empty(&self, sp: Span) -> bool {
         match self.span_to_prev_source(sp) {
-            Ok(s) => s.split('\n').last().map_or(false, |l| l.trim_start().is_empty()),
+            Ok(s) => s.rsplit_once('\n').unwrap_or(("", &s)).1.trim_start().is_empty(),
             Err(_) => false,
         }
     }
@@ -632,10 +632,11 @@ impl SourceMap {
     pub fn span_to_margin(&self, sp: Span) -> Option<usize> {
         match self.span_to_prev_source(sp) {
             Err(_) => None,
-            Ok(source) => source
-                .split('\n')
-                .last()
-                .map(|last_line| last_line.len() - last_line.trim_start().len()),
+            Ok(source) => {
+                let last_line = source.rsplit_once('\n').unwrap_or(("", &source)).1;
+
+                Some(last_line.len() - last_line.trim_start().len())
+            }
         }
     }
 
@@ -651,7 +652,7 @@ impl SourceMap {
     pub fn span_extend_to_prev_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
         if let Ok(prev_source) = self.span_to_prev_source(sp) {
             let prev_source = prev_source.rsplit(c).next().unwrap_or("");
-            if !prev_source.is_empty() && (!prev_source.contains('\n') || accept_newlines) {
+            if !prev_source.is_empty() && (accept_newlines || !prev_source.contains('\n')) {
                 return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
             }
         }
@@ -673,7 +674,7 @@ impl SourceMap {
                 let prev_source = prev_source.rsplit(&pat).next().unwrap_or("").trim_start();
                 if prev_source.is_empty() && sp.lo().0 != 0 {
                     return sp.with_lo(BytePos(sp.lo().0 - 1));
-                } else if !prev_source.contains('\n') || accept_newlines {
+                } else if accept_newlines || !prev_source.contains('\n') {
                     return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
                 }
             }
@@ -693,7 +694,7 @@ impl SourceMap {
     pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span {
         if let Ok(next_source) = self.span_to_next_source(sp) {
             let next_source = next_source.split(c).next().unwrap_or("");
-            if !next_source.is_empty() && (!next_source.contains('\n') || accept_newlines) {
+            if !next_source.is_empty() && (accept_newlines || !next_source.contains('\n')) {
                 return sp.with_hi(BytePos(sp.hi().0 + next_source.len() as u32));
             }
         }
@@ -777,16 +778,35 @@ impl SourceMap {
         self.span_until_char(sp, '{')
     }
 
-    /// Returns a new span representing just the start point of this span.
+    /// Returns a new span representing just the first character of the given span.
     pub fn start_point(&self, sp: Span) -> Span {
-        let pos = sp.lo().0;
-        let width = self.find_width_of_character_at_span(sp, false);
-        let corrected_start_position = pos.checked_add(width).unwrap_or(pos);
-        let end_point = BytePos(cmp::max(corrected_start_position, sp.lo().0));
-        sp.with_hi(end_point)
+        let width = {
+            let sp = sp.data();
+            let local_begin = self.lookup_byte_offset(sp.lo);
+            let start_index = local_begin.pos.to_usize();
+            let src = local_begin.sf.external_src.borrow();
+
+            let snippet = if let Some(ref src) = local_begin.sf.src {
+                Some(&src[start_index..])
+            } else if let Some(src) = src.get_source() {
+                Some(&src[start_index..])
+            } else {
+                None
+            };
+
+            match snippet {
+                None => 1,
+                Some(snippet) => match snippet.chars().next() {
+                    None => 1,
+                    Some(c) => c.len_utf8(),
+                },
+            }
+        };
+
+        sp.with_hi(BytePos(sp.lo().0 + width as u32))
     }
 
-    /// Returns a new span representing just the end point of this span.
+    /// Returns a new span representing just the last character of this span.
     pub fn end_point(&self, sp: Span) -> Span {
         let pos = sp.hi().0;
 
@@ -815,7 +835,8 @@ impl SourceMap {
         Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt())
     }
 
-    /// Finds the width of a character, either before or after the provided span.
+    /// Finds the width of the character, either before or after the end of provided span,
+    /// depending on the `forwards` parameter.
     fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 {
         let sp = sp.data();
         if sp.lo == sp.hi {
@@ -862,11 +883,9 @@ impl SourceMap {
         // We need to extend the snippet to the end of the src rather than to end_index so when
         // searching forwards for boundaries we've got somewhere to search.
         let snippet = if let Some(ref src) = local_begin.sf.src {
-            let len = src.len();
-            &src[start_index..len]
+            &src[start_index..]
         } else if let Some(src) = src.get_source() {
-            let len = src.len();
-            &src[start_index..len]
+            &src[start_index..]
         } else {
             return 1;
         };
diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs
index 3f22829b049..0aca677248b 100644
--- a/compiler/rustc_span/src/source_map/tests.rs
+++ b/compiler/rustc_span/src/source_map/tests.rs
@@ -243,7 +243,7 @@ impl SourceMapExtension for SourceMap {
         substring: &str,
         n: usize,
     ) -> Span {
-        println!(
+        eprintln!(
             "span_substr(file={:?}/{:?}, substring={:?}, n={})",
             file.name, file.start_pos, substring, n
         );
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index df23b4006b3..653d70b6cf2 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -252,7 +252,6 @@ symbols! {
         allow_fail,
         allow_internal_unsafe,
         allow_internal_unstable,
-        allow_internal_unstable_backcompat_hack,
         allowed,
         always,
         and,
@@ -476,6 +475,7 @@ symbols! {
         dropck_eyepatch,
         dropck_parametricity,
         dylib,
+        dyn_metadata,
         dyn_trait,
         edition_macro_pats,
         eh_catch_typeinfo,
@@ -593,6 +593,7 @@ symbols! {
         html_no_source,
         html_playground_url,
         html_root_url,
+        hwaddress,
         i,
         i128,
         i128_type,
@@ -679,6 +680,7 @@ symbols! {
         loop_break_value,
         lt,
         macro_at_most_once_rep,
+        macro_attributes_in_derive_output,
         macro_escape,
         macro_export,
         macro_lifetime_matcher,
@@ -708,6 +710,7 @@ symbols! {
         memory,
         message,
         meta,
+        metadata_type,
         min_align_of,
         min_align_of_val,
         min_const_fn,
@@ -830,6 +833,7 @@ symbols! {
         plugin,
         plugin_registrar,
         plugins,
+        pointee_trait,
         pointer,
         pointer_trait,
         pointer_trait_fmt,
@@ -907,6 +911,7 @@ symbols! {
         register_attr,
         register_tool,
         relaxed_adts,
+        relaxed_struct_unsize,
         rem,
         rem_assign,
         repr,
@@ -1601,6 +1606,7 @@ pub mod sym {
     use super::Symbol;
     use std::convert::TryInto;
 
+    #[doc(inline)]
     pub use super::sym_generated::*;
 
     // Used from a macro in `librustc_feature/accepted.rs`
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index 8c5e438a728..bfe9c4d6de3 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -5,6 +5,7 @@
 //! paths etc in all kinds of annoying scenarios.
 
 use rustc_hir as hir;
+use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{subst::InternalSubsts, Instance, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
@@ -31,9 +32,8 @@ struct SymbolNamesTest<'tcx> {
 }
 
 impl SymbolNamesTest<'tcx> {
-    fn process_attrs(&mut self, hir_id: hir::HirId) {
+    fn process_attrs(&mut self, def_id: LocalDefId) {
         let tcx = self.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) {
                 let def_id = def_id.to_def_id();
@@ -61,18 +61,18 @@ impl SymbolNamesTest<'tcx> {
 
 impl hir::itemlikevisit::ItemLikeVisitor<'tcx> for SymbolNamesTest<'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        self.process_attrs(item.hir_id);
+        self.process_attrs(item.def_id);
     }
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
-        self.process_attrs(trait_item.hir_id);
+        self.process_attrs(trait_item.def_id);
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
-        self.process_attrs(impl_item.hir_id);
+        self.process_attrs(impl_item.def_id);
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &'tcx hir::ForeignItem<'tcx>) {
-        self.process_attrs(foreign_item.hir_id);
+        self.process_attrs(foreign_item.def_id);
     }
 }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 962374a21b2..ae803dbdb31 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -589,7 +589,7 @@ impl StackProbeType {
                 Ok(StackProbeType::InlineOrCall { min_llvm_version_for_inline })
             }
             _ => Err(String::from(
-                "`kind` expected to be one of `inline-or-none`, `call` or `inline-or-call`",
+                "`kind` expected to be one of `none`, `inline`, `call` or `inline-or-call`",
             )),
         }
     }
@@ -784,9 +784,11 @@ supported_targets! {
     ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
     ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
     ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu),
+    ("riscv32gc-unknown-linux-musl", riscv32gc_unknown_linux_musl),
     ("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf),
     ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf),
     ("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu),
+    ("riscv64gc-unknown-linux-musl", riscv64gc_unknown_linux_musl),
 
     ("aarch64-unknown-none", aarch64_unknown_none),
     ("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat),
@@ -1493,7 +1495,7 @@ impl Target {
             } );
             ($key_name:ident = $json_name:expr, optional) => ( {
                 let name = $json_name;
-                if let Some(o) = obj.find(&name[..]) {
+                if let Some(o) = obj.find(name) {
                     base.$key_name = o
                         .as_string()
                         .map(|s| s.to_string() );
diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_musl.rs
new file mode 100644
index 00000000000..e5fbd09297f
--- /dev/null
+++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_musl.rs
@@ -0,0 +1,19 @@
+use crate::spec::{CodeModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "riscv32-unknown-linux-musl".to_string(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
+        arch: "riscv32".to_string(),
+        options: TargetOptions {
+            unsupported_abis: super::riscv_base::unsupported_abis(),
+            code_model: Some(CodeModel::Medium),
+            cpu: "generic-rv32".to_string(),
+            features: "+m,+a,+f,+d,+c".to_string(),
+            llvm_abiname: "ilp32d".to_string(),
+            max_atomic_width: Some(32),
+            ..super::linux_musl_base::opts()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_musl.rs
new file mode 100644
index 00000000000..0232b15e8c2
--- /dev/null
+++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_musl.rs
@@ -0,0 +1,19 @@
+use crate::spec::{CodeModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    Target {
+        llvm_target: "riscv64-unknown-linux-musl".to_string(),
+        pointer_width: 64,
+        data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(),
+        arch: "riscv64".to_string(),
+        options: TargetOptions {
+            unsupported_abis: super::riscv_base::unsupported_abis(),
+            code_model: Some(CodeModel::Medium),
+            cpu: "generic-rv64".to_string(),
+            features: "+m,+a,+f,+d,+c".to_string(),
+            llvm_abiname: "lp64d".to_string(),
+            max_atomic_width: Some(64),
+            ..super::linux_musl_base::opts()
+        },
+    }
+}
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
index a72c172918b..c5d4c2400f8 100644
--- a/compiler/rustc_trait_selection/Cargo.toml
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -22,4 +22,4 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
index 05b6c4a48de..3f24a33f7d5 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -6,7 +6,6 @@ use rustc_infer::infer::InferCtxt;
 use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness};
 use rustc_middle::ty::{ToPredicate, TypeFoldable};
 use rustc_session::DiagnosticMessageId;
-use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 
 #[derive(Copy, Clone, Debug)]
@@ -146,11 +145,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
         let normalized_ty = fulfillcx.normalize_projection_type(
             &self.infcx,
             self.param_env,
-            ty::ProjectionTy::from_ref_and_name(
-                tcx,
-                trait_ref,
-                Ident::with_dummy_span(sym::Target),
-            ),
+            ty::ProjectionTy {
+                item_def_id: tcx.lang_items().deref_target()?,
+                substs: trait_ref.substs,
+            },
             cause,
         );
         if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 6593c1000f2..97cc258d425 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -77,7 +77,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
         ty: Ty<'tcx>,
         orig_env: ty::ParamEnv<'tcx>,
         trait_did: DefId,
-        auto_trait_callback: impl Fn(&InferCtxt<'_, 'tcx>, AutoTraitInfo<'tcx>) -> A,
+        mut auto_trait_callback: impl FnMut(&InferCtxt<'_, 'tcx>, AutoTraitInfo<'tcx>) -> A,
     ) -> AutoTraitResult<A> {
         let tcx = self.tcx;
 
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 657d5c123e8..45853a66efc 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -91,7 +91,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
         });
         let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
 
-        info!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
+        debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
         Ok(impl_source)
     })
 }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 99b96f60964..e8ae1f44a36 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -11,7 +11,7 @@ use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionCont
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, fast_reject, Ty, TyCtxt};
 use rustc_span::symbol::sym;
 use rustc_span::DUMMY_SP;
 use std::iter;
@@ -67,6 +67,34 @@ where
            impl2_def_id={:?})",
         impl1_def_id, impl2_def_id,
     );
+    // Before doing expensive operations like entering an inference context, do
+    // a quick check via fast_reject to tell if the impl headers could possibly
+    // unify.
+    let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
+    let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
+
+    // Check if any of the input types definitely do not unify.
+    if impl1_ref
+        .iter()
+        .flat_map(|tref| tref.substs.types())
+        .zip(impl2_ref.iter().flat_map(|tref| tref.substs.types()))
+        .any(|(ty1, ty2)| {
+            let t1 = fast_reject::simplify_type(tcx, ty1, false);
+            let t2 = fast_reject::simplify_type(tcx, ty2, false);
+            if let (Some(t1), Some(t2)) = (t1, t2) {
+                // Simplified successfully
+                // Types cannot unify if they differ in their reference mutability or simplify to different types
+                t1 != t2 || ty1.ref_mutability() != ty2.ref_mutability()
+            } else {
+                // Types might unify
+                false
+            }
+        })
+    {
+        // Some types involved are definitely different, so the impls couldn't possibly overlap.
+        debug!("overlapping_impls: fast_reject early-exit");
+        return no_overlap();
+    }
 
     let overlaps = tcx.infer_ctxt().enter(|infcx| {
         let selcx = &mut SelectionContext::intercrate(&infcx);
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 89820bb1417..8a1be7ea172 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -72,17 +72,16 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
                 // We were unable to unify the abstract constant with
                 // a constant found in the caller bounds, there are
                 // now three possible cases here.
-                //
-                // - The substs are concrete enough that we can simply
-                //   try and evaluate the given constant.
-                // - The abstract const still references an inference
-                //   variable, in this case we return `TooGeneric`.
-                // - The abstract const references a generic parameter,
-                //   this means that we emit an error here.
                 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
                 enum FailureKind {
+                    /// The abstract const still references an inference
+                    /// variable, in this case we return `TooGeneric`.
                     MentionsInfer,
+                    /// The abstract const references a generic parameter,
+                    /// this means that we emit an error here.
                     MentionsParam,
+                    /// The substs are concrete enough that we can simply
+                    /// try and evaluate the given constant.
                     Concrete,
                 }
                 let mut failure_kind = FailureKind::Concrete;
@@ -117,7 +116,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
                         {
                             err.span_help(
                                 tcx.def_span(def.did),
-                                &format!("try adding a `where` bound using this expression: where [u8; {}]: Sized", snippet),
+                                &format!("try adding a `where` bound using this expression: `where [u8; {}]: Sized`", snippet),
                             );
                         } else {
                             err.span_help(
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 d3b3403ac3e..bfb5ebcea58 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -468,22 +468,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                                 trait_ref,
                                 obligation.cause.body_id,
                             );
-                        } else {
-                            if !have_alt_message {
-                                // Can't show anything else useful, try to find similar impls.
-                                let impl_candidates = self.find_similar_impl_candidates(trait_ref);
-                                self.report_similar_impl_candidates(impl_candidates, &mut err);
-                            }
-                            // Changing mutability doesn't make a difference to whether we have
-                            // an `Unsize` impl (Fixes ICE in #71036)
-                            if !is_unsize {
-                                self.suggest_change_mut(
-                                    &obligation,
-                                    &mut err,
-                                    trait_ref,
-                                    points_at_arg,
-                                );
-                            }
+                        } else if !have_alt_message {
+                            // Can't show anything else useful, try to find similar impls.
+                            let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+                            self.report_similar_impl_candidates(impl_candidates, &mut err);
+                        }
+
+                        // Changing mutability doesn't make a difference to whether we have
+                        // an `Unsize` impl (Fixes ICE in #71036)
+                        if !is_unsize {
+                            self.suggest_change_mut(
+                                &obligation,
+                                &mut err,
+                                trait_ref,
+                                points_at_arg,
+                            );
                         }
 
                         // If this error is due to `!: Trait` not implemented but `(): Trait` is
@@ -1369,8 +1368,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                     Some(t) => Some(t),
                     None => {
                         let ty = parent_trait_ref.skip_binder().self_ty();
-                        let span =
-                            TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id));
+                        let span = TyCategory::from_ty(self.tcx, ty)
+                            .map(|(_, def_id)| self.tcx.def_span(def_id));
                         Some((ty.to_string(), span))
                     }
                 }
@@ -1590,8 +1589,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                 self.emit_inference_failure_err(body_id, span, a.into(), vec![], ErrorCode::E0282)
             }
             ty::PredicateKind::Projection(data) => {
-                let trait_ref = bound_predicate.rebind(data).to_poly_trait_ref(self.tcx);
-                let self_ty = trait_ref.skip_binder().self_ty();
+                let self_ty = data.projection_ty.self_ty();
                 let ty = data.ty;
                 if predicate.references_error() {
                     return;
@@ -1780,7 +1778,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
                             multispan.push_span_label(
                                 sp,
                                 format!(
-                                    "...if indirection was used here: `Box<{}>`",
+                                    "...if indirection were used here: `Box<{}>`",
                                     param.name.ident(),
                                 ),
                             );
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 69f66f6e6b1..e6a1cf58fe3 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -200,22 +200,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             if let Some(def) = aty.ty_adt_def() {
                 // We also want to be able to select the array's type's original
                 // signature with no type arguments resolved
-                flags.push((
-                    sym::_Self,
-                    Some(format!("[{}]", self.tcx.type_of(def.did).to_string())),
-                ));
-                let tcx = self.tcx;
-                if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
-                    flags.push((
-                        sym::_Self,
-                        Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)),
-                    ));
-                } else {
-                    flags.push((
-                        sym::_Self,
-                        Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())),
-                    ));
-                }
+                let type_string = self.tcx.type_of(def.did).to_string();
+                flags.push((sym::_Self, Some(format!("[{}]", type_string))));
+
+                let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
+                let string = match len {
+                    Some(n) => format!("[{}; {}]", type_string, n),
+                    None => format!("[{}; _]", type_string),
+                };
+                flags.push((sym::_Self, Some(string)));
             }
         }
         if let ty::Dynamic(traits, _) = self_ty.kind() {
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 21828006164..5c97791530d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -17,8 +17,8 @@ use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_middle::ty::{
-    self, suggest_constraining_type_param, AdtKind, DefIdTree, Infer, InferTy, ToPredicate, Ty,
-    TyCtxt, TypeFoldable, WithConstness,
+    self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree,
+    Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -334,7 +334,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let (param_ty, projection) = match self_ty.kind() {
             ty::Param(_) => (true, None),
             ty::Projection(projection) => (false, Some(projection)),
-            _ => return,
+            _ => (false, None),
         };
 
         // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
@@ -453,6 +453,26 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     }
                 }
 
+                hir::Node::Item(hir::Item {
+                    kind:
+                        hir::ItemKind::Struct(_, generics)
+                        | hir::ItemKind::Enum(_, generics)
+                        | hir::ItemKind::Union(_, generics)
+                        | hir::ItemKind::Trait(_, _, generics, ..)
+                        | hir::ItemKind::Impl(hir::Impl { generics, .. })
+                        | hir::ItemKind::Fn(_, generics, _)
+                        | hir::ItemKind::TyAlias(_, generics)
+                        | hir::ItemKind::TraitAlias(generics, _)
+                        | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
+                    ..
+                }) if !param_ty => {
+                    // Missing generic type parameter bound.
+                    let param_name = self_ty.to_string();
+                    let constraint = trait_ref.print_only_trait_path().to_string();
+                    if suggest_arbitrary_trait_bound(generics, &mut err, &param_name, &constraint) {
+                        return;
+                    }
+                }
                 hir::Node::Crate(..) => return,
 
                 _ => {}
@@ -1103,7 +1123,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 // This is currently not possible to trigger because E0038 takes precedence, but
                 // leave it in for completeness in case anything changes in an earlier stage.
                 err.note(&format!(
-                    "if trait `{}` was object safe, you could return a trait object",
+                    "if trait `{}` were object-safe, you could return a trait object",
                     trait_obj,
                 ));
             }
@@ -1881,10 +1901,26 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             ObligationCauseCode::Coercion { source: _, target } => {
                 err.note(&format!("required by cast to type `{}`", self.ty_to_string(target)));
             }
-            ObligationCauseCode::RepeatVec => {
+            ObligationCauseCode::RepeatVec(is_const_fn) => {
                 err.note(
                     "the `Copy` trait is required because the repeated element will be copied",
                 );
+
+                if is_const_fn {
+                    err.help(
+                        "consider creating a new `const` item and initializing with the result \
+                        of the function call to be used in the repeat position, like \
+                        `const VAL: Type = const_fn();` and `let x = [VAL; 42];`",
+                    );
+                }
+
+                if self.tcx.sess.is_nightly_build() && is_const_fn {
+                    err.help(
+                        "create an inline `const` block, see PR \
+                        #2920 <https://github.com/rust-lang/rfcs/pull/2920> \
+                        for more information",
+                    );
+                }
             }
             ObligationCauseCode::VariableType(hir_id) => {
                 let parent_node = self.tcx.hir().get_parent_node(hir_id);
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index d4ced20f863..3d9f98273db 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -6,6 +6,7 @@ use rustc_errors::ErrorReported;
 use rustc_infer::traits::{TraitEngine, TraitEngineExt as _, TraitObligation};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
 use std::marker::PhantomData;
@@ -633,9 +634,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 // only reason we can fail to make progress on
                 // trait selection is because we don't have enough
                 // information about the types in the trait.
-                *stalled_on = trait_ref_infer_vars(
+                *stalled_on = substs_infer_vars(
                     self.selcx,
-                    trait_obligation.predicate.map_bound(|pred| pred.trait_ref),
+                    trait_obligation.predicate.map_bound(|pred| pred.trait_ref.substs),
                 );
 
                 debug!(
@@ -647,7 +648,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                 ProcessResult::Unchanged
             }
             Err(selection_err) => {
-                info!("selecting trait at depth {} yielded Err", obligation.recursion_depth);
+                debug!("selecting trait at depth {} yielded Err", obligation.recursion_depth);
 
                 ProcessResult::Error(CodeSelectionError(selection_err))
             }
@@ -663,9 +664,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
         match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
             Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)),
             Ok(Ok(None)) => {
-                *stalled_on = trait_ref_infer_vars(
+                *stalled_on = substs_infer_vars(
                     self.selcx,
-                    project_obligation.predicate.to_poly_trait_ref(tcx),
+                    project_obligation.predicate.map_bound(|pred| pred.projection_ty.substs),
                 );
                 ProcessResult::Unchanged
             }
@@ -678,16 +679,15 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
     }
 }
 
-/// Returns the set of inference variables contained in a trait ref.
-fn trait_ref_infer_vars<'a, 'tcx>(
+/// Returns the set of inference variables contained in `substs`.
+fn substs_infer_vars<'a, 'tcx>(
     selcx: &mut SelectionContext<'a, 'tcx>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
+    substs: ty::Binder<SubstsRef<'tcx>>,
 ) -> Vec<TyOrConstInferVar<'tcx>> {
     selcx
         .infcx()
-        .resolve_vars_if_possible(trait_ref)
-        .skip_binder()
-        .substs
+        .resolve_vars_if_possible(substs)
+        .skip_binder() // ok because this check doesn't care about regions
         .iter()
         // FIXME(eddyb) try using `skip_current_subtree` to skip everything that
         // doesn't contain inference variables, not just the outermost level.
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index f7c0bafff05..0a81b6e105d 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -65,7 +65,8 @@ pub use self::util::{
     get_vtable_index_of_object_method, impl_item_is_final, predicate_for_trait_def, upcast_choices,
 };
 pub use self::util::{
-    supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
+    supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type,
+    SupertraitDefIds, Supertraits,
 };
 
 pub use self::chalk_fulfill::FulfillmentContext as ChalkFulfillmentContext;
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 3852005ee3f..7de20e477fe 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -257,13 +257,11 @@ fn predicates_reference_self(
 }
 
 fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
-    let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
     tcx.associated_items(trait_def_id)
         .in_definition_order()
         .filter(|item| item.kind == ty::AssocKind::Type)
         .flat_map(|item| tcx.explicit_item_bounds(item.def_id))
-        .map(|&(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp))
-        .filter_map(|predicate| predicate_references_self(tcx, predicate))
+        .filter_map(|pred_span| predicate_references_self(tcx, *pred_span))
         .collect()
 }
 
@@ -294,11 +292,7 @@ fn predicate_references_self(
             //
             // This is ALT2 in issue #56288, see that for discussion of the
             // possible alternatives.
-            if data.projection_ty.trait_ref(tcx).substs[1..].iter().any(has_self_ty) {
-                Some(sp)
-            } else {
-                None
-            }
+            if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
         }
         ty::PredicateKind::WellFormed(..)
         | ty::PredicateKind::ObjectSafe(..)
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 6908480f431..0af6d645915 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -12,7 +12,7 @@ use super::SelectionContext;
 use super::SelectionError;
 use super::{
     ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
-    ImplSourceGeneratorData, ImplSourceUserDefinedData,
+    ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
 };
 use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
 
@@ -741,11 +741,7 @@ fn project_type<'cx, 'tcx>(
         return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow));
     }
 
-    let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx());
-
-    debug!(?obligation_trait_ref);
-
-    if obligation_trait_ref.references_error() {
+    if obligation.predicate.references_error() {
         return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx())));
     }
 
@@ -754,19 +750,19 @@ fn project_type<'cx, 'tcx>(
     // Make sure that the following procedures are kept in order. ParamEnv
     // needs to be first because it has highest priority, and Select checks
     // the return value of push_candidate which assumes it's ran at last.
-    assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, &mut candidates);
+    assemble_candidates_from_param_env(selcx, obligation, &mut candidates);
 
-    assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates);
+    assemble_candidates_from_trait_def(selcx, obligation, &mut candidates);
 
-    assemble_candidates_from_object_ty(selcx, obligation, &obligation_trait_ref, &mut candidates);
+    assemble_candidates_from_object_ty(selcx, obligation, &mut candidates);
 
     if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates {
         // Avoid normalization cycle from selection (see
         // `assemble_candidates_from_object_ty`).
         // FIXME(lazy_normalization): Lazy normalization should save us from
-        // having to do special case this.
+        // having to special case this.
     } else {
-        assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates);
+        assemble_candidates_from_impls(selcx, obligation, &mut candidates);
     };
 
     match candidates {
@@ -792,14 +788,12 @@ fn project_type<'cx, 'tcx>(
 fn assemble_candidates_from_param_env<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_param_env(..)");
     assemble_candidates_from_predicates(
         selcx,
         obligation,
-        obligation_trait_ref,
         candidate_set,
         ProjectionTyCandidate::ParamEnv,
         obligation.param_env.caller_bounds().iter(),
@@ -820,7 +814,6 @@ fn assemble_candidates_from_param_env<'cx, 'tcx>(
 fn assemble_candidates_from_trait_def<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_trait_def(..)");
@@ -828,7 +821,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
     let tcx = selcx.tcx();
     // Check whether the self-type is itself a projection.
     // If so, extract what we know from the trait and try to come up with a good answer.
-    let bounds = match *obligation_trait_ref.self_ty().kind() {
+    let bounds = match *obligation.predicate.self_ty().kind() {
         ty::Projection(ref data) => tcx.item_bounds(data.item_def_id).subst(tcx, data.substs),
         ty::Opaque(def_id, substs) => tcx.item_bounds(def_id).subst(tcx, substs),
         ty::Infer(ty::TyVar(_)) => {
@@ -843,7 +836,6 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
     assemble_candidates_from_predicates(
         selcx,
         obligation,
-        obligation_trait_ref,
         candidate_set,
         ProjectionTyCandidate::TraitDef,
         bounds.iter(),
@@ -863,14 +855,13 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
 fn assemble_candidates_from_object_ty<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_object_ty(..)");
 
     let tcx = selcx.tcx();
 
-    let self_ty = obligation_trait_ref.self_ty();
+    let self_ty = obligation.predicate.self_ty();
     let object_ty = selcx.infcx().shallow_resolve(self_ty);
     let data = match object_ty.kind() {
         ty::Dynamic(data, ..) => data,
@@ -890,7 +881,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
     assemble_candidates_from_predicates(
         selcx,
         obligation,
-        obligation_trait_ref,
         candidate_set,
         ProjectionTyCandidate::Object,
         env_predicates,
@@ -901,7 +891,6 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
 fn assemble_candidates_from_predicates<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
     ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
     env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
@@ -921,8 +910,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
                 && infcx.probe(|_| {
                     selcx.match_projection_projections(
                         obligation,
-                        obligation_trait_ref,
-                        &data,
+                        data,
                         potentially_unnormalized_candidates,
                     )
                 });
@@ -948,14 +936,13 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
 fn assemble_candidates_from_impls<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'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 = ty::Binder::dummy(*obligation_trait_ref);
+    let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref();
     let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
     let _ = selcx.infcx().commit_if_ok(|_| {
         let impl_source = match selcx.select(&trait_obligation) {
@@ -1069,6 +1056,51 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     | ty::Error(_) => false,
                 }
             }
+            super::ImplSource::Pointee(..) => {
+                // While `Pointee` is automatically implemented for every type,
+                // the concrete metadata type may not be known yet.
+                //
+                // Any type with multiple potential metadata types is therefore not eligible.
+                let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+
+                // FIXME: should this normalize?
+                let tail = selcx.tcx().struct_tail_without_normalization(self_ty);
+                match tail.kind() {
+                    ty::Bool
+                    | ty::Char
+                    | ty::Int(_)
+                    | ty::Uint(_)
+                    | ty::Float(_)
+                    | ty::Foreign(_)
+                    | ty::Str
+                    | ty::Array(..)
+                    | ty::Slice(_)
+                    | ty::RawPtr(..)
+                    | ty::Ref(..)
+                    | ty::FnDef(..)
+                    | ty::FnPtr(..)
+                    | ty::Dynamic(..)
+                    | ty::Closure(..)
+                    | ty::Generator(..)
+                    | ty::GeneratorWitness(..)
+                    | ty::Never
+                    // If returned by `struct_tail_without_normalization` this is a unit struct
+                    // without any fields, or not a struct, and therefore is Sized.
+                    | ty::Adt(..)
+                    // If returned by `struct_tail_without_normalization` this is the empty tuple.
+                    | ty::Tuple(..)
+                    // Integers and floats are always Sized, and so have unit type metadata.
+                    | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..)) => true,
+
+                    ty::Projection(..)
+                    | ty::Opaque(..)
+                    | ty::Param(..)
+                    | ty::Bound(..)
+                    | ty::Placeholder(..)
+                    | ty::Infer(..)
+                    | ty::Error(_) => false,
+                }
+            }
             super::ImplSource::Param(..) => {
                 // This case tell us nothing about the value of an
                 // associated type. Consider:
@@ -1169,6 +1201,7 @@ fn confirm_select_candidate<'cx, 'tcx>(
         super::ImplSource::DiscriminantKind(data) => {
             confirm_discriminant_kind_candidate(selcx, obligation, data)
         }
+        super::ImplSource::Pointee(data) => confirm_pointee_candidate(selcx, obligation, data),
         super::ImplSource::Object(_)
         | super::ImplSource::AutoImpl(..)
         | super::ImplSource::Param(..)
@@ -1256,6 +1289,26 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
     confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
 }
 
+fn confirm_pointee_candidate<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    _: ImplSourcePointeeData,
+) -> Progress<'tcx> {
+    let tcx = selcx.tcx();
+
+    let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
+    let substs = tcx.mk_substs([self_ty.into()].iter());
+
+    let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
+
+    let predicate = ty::ProjectionPredicate {
+        projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
+        ty: self_ty.ptr_metadata_ty(tcx),
+    };
+
+    confirm_param_env_candidate(selcx, obligation, ty::Binder::bind(predicate), false)
+}
+
 fn confirm_fn_pointer_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
@@ -1344,25 +1397,25 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
         poly_cache_entry,
     );
 
-    let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx);
-    let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx);
+    let cache_projection = cache_entry.projection_ty;
+    let obligation_projection = obligation.predicate;
     let mut nested_obligations = Vec::new();
-    let cache_trait_ref = if potentially_unnormalized_candidate {
+    let cache_projection = if potentially_unnormalized_candidate {
         ensure_sufficient_stack(|| {
             normalize_with_depth_to(
                 selcx,
                 obligation.param_env,
                 obligation.cause.clone(),
                 obligation.recursion_depth + 1,
-                cache_trait_ref,
+                cache_projection,
                 &mut nested_obligations,
             )
         })
     } else {
-        cache_trait_ref
+        cache_projection
     };
 
-    match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) {
+    match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
         Ok(InferOk { value: _, obligations }) => {
             nested_obligations.extend(obligations);
             assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 33cd509cbb8..c908e1418c1 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -97,7 +97,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
         self.infcx.tcx
     }
 
-    #[instrument(skip(self))]
+    #[instrument(level = "debug", skip(self))]
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         if !ty.has_projections() {
             return ty;
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 1688539165a..68356ce73aa 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -43,7 +43,7 @@ where
             info!("fully_perform({:?})", self);
         }
 
-        scrape_region_constraints(infcx, || Ok((self.closure)(infcx)?))
+        scrape_region_constraints(infcx, || (self.closure)(infcx))
     }
 }
 
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 f09ce8d64ed..752f6a8debc 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -267,6 +267,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         } else if lang_items.discriminant_kind_trait() == Some(def_id) {
             // `DiscriminantKind` is automatically implemented for every type.
             candidates.vec.push(DiscriminantKindCandidate);
+        } else if lang_items.pointee_trait() == Some(def_id) {
+            // `Pointee` is automatically implemented for every type.
+            candidates.vec.push(PointeeCandidate);
         } else if lang_items.sized_trait() == Some(def_id) {
             // Sized is never implementable by end-users, it is
             // always automatically computed.
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 3015188fd44..272930f6bb9 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -30,7 +30,8 @@ use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation};
 use crate::traits::{
     ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
     ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData,
-    ImplSourceObjectData, ImplSourceTraitAliasData, ImplSourceUserDefinedData,
+    ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData,
+    ImplSourceUserDefinedData,
 };
 use crate::traits::{ObjectCastObligation, PredicateObligation, TraitObligation};
 use crate::traits::{Obligation, ObligationCause};
@@ -99,6 +100,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData))
             }
 
+            PointeeCandidate => Ok(ImplSource::Pointee(ImplSourcePointeeData)),
+
             TraitAliasCandidate(alias_def_id) => {
                 let data = self.confirm_trait_alias_candidate(obligation, alias_def_id);
                 Ok(ImplSource::TraitAlias(data))
@@ -823,33 +826,59 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     },
                 };
 
+                // FIXME(eddyb) cache this (including computing `unsizing_params`)
+                // by putting it in a query; it would only need the `DefId` as it
+                // looks at declared field types, not anything substituted.
+
                 // The last field of the structure has to exist and contain type/const parameters.
                 let (tail_field, prefix_fields) =
                     def.non_enum_variant().fields.split_last().ok_or(Unimplemented)?;
                 let tail_field_ty = tcx.type_of(tail_field.did);
 
                 let mut unsizing_params = GrowableBitSet::new_empty();
-                let mut found = false;
-                for arg in tail_field_ty.walk() {
-                    if let Some(i) = maybe_unsizing_param_idx(arg) {
-                        unsizing_params.insert(i);
-                        found = true;
+                if tcx.features().relaxed_struct_unsize {
+                    for arg in tail_field_ty.walk() {
+                        if let Some(i) = maybe_unsizing_param_idx(arg) {
+                            unsizing_params.insert(i);
+                        }
                     }
-                }
-                if !found {
-                    return Err(Unimplemented);
-                }
 
-                // Ensure none of the other fields mention the parameters used
-                // in unsizing.
-                // FIXME(eddyb) cache this (including computing `unsizing_params`)
-                // by putting it in a query; it would only need the `DefId` as it
-                // looks at declared field types, not anything substituted.
-                for field in prefix_fields {
-                    for arg in tcx.type_of(field.did).walk() {
+                    // Ensure none of the other fields mention the parameters used
+                    // in unsizing.
+                    for field in prefix_fields {
+                        for arg in tcx.type_of(field.did).walk() {
+                            if let Some(i) = maybe_unsizing_param_idx(arg) {
+                                unsizing_params.remove(i);
+                            }
+                        }
+                    }
+
+                    if unsizing_params.is_empty() {
+                        return Err(Unimplemented);
+                    }
+                } else {
+                    let mut found = false;
+                    for arg in tail_field_ty.walk() {
                         if let Some(i) = maybe_unsizing_param_idx(arg) {
-                            if unsizing_params.contains(i) {
-                                return Err(Unimplemented);
+                            unsizing_params.insert(i);
+                            found = true;
+                        }
+                    }
+                    if !found {
+                        return Err(Unimplemented);
+                    }
+
+                    // Ensure none of the other fields mention the parameters used
+                    // in unsizing.
+                    // FIXME(eddyb) cache this (including computing `unsizing_params`)
+                    // by putting it in a query; it would only need the `DefId` as it
+                    // looks at declared field types, not anything substituted.
+                    for field in prefix_fields {
+                        for arg in tcx.type_of(field.did).walk() {
+                            if let Some(i) = maybe_unsizing_param_idx(arg) {
+                                if unsizing_params.contains(i) {
+                                    return Err(Unimplemented);
+                                }
                             }
                         }
                     }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 87c8099dc3a..45b5aff40a6 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -32,6 +32,7 @@ use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::Constness;
+use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::fast_reject;
@@ -1254,32 +1255,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     pub(super) fn match_projection_projections(
         &mut self,
         obligation: &ProjectionTyObligation<'tcx>,
-        obligation_trait_ref: &ty::TraitRef<'tcx>,
-        data: &PolyProjectionPredicate<'tcx>,
+        env_predicate: PolyProjectionPredicate<'tcx>,
         potentially_unnormalized_candidates: bool,
     ) -> bool {
         let mut nested_obligations = Vec::new();
-        let projection_ty = if potentially_unnormalized_candidates {
+        let (infer_predicate, _) = self.infcx.replace_bound_vars_with_fresh_vars(
+            obligation.cause.span,
+            LateBoundRegionConversionTime::HigherRankedType,
+            env_predicate,
+        );
+        let infer_projection = if potentially_unnormalized_candidates {
             ensure_sufficient_stack(|| {
                 project::normalize_with_depth_to(
                     self,
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.recursion_depth + 1,
-                    data.map_bound(|data| data.projection_ty),
+                    infer_predicate.projection_ty,
                     &mut nested_obligations,
                 )
             })
         } else {
-            data.map_bound(|data| data.projection_ty)
+            infer_predicate.projection_ty
         };
 
-        // FIXME(generic_associated_types): Compare the whole projections
-        let data_poly_trait_ref = projection_ty.map_bound(|proj| proj.trait_ref(self.tcx()));
-        let obligation_poly_trait_ref = ty::Binder::dummy(*obligation_trait_ref);
         self.infcx
             .at(&obligation.cause, obligation.param_env)
-            .sup(obligation_poly_trait_ref, data_poly_trait_ref)
+            .sup(obligation.predicate, infer_projection)
             .map_or(false, |InferOk { obligations, value: () }| {
                 self.evaluate_predicates_recursively(
                     TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
@@ -1318,8 +1320,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let is_global =
             |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions();
 
-        // (*) Prefer `BuiltinCandidate { has_nested: false }` and `DiscriminantKindCandidate`
-        // to anything else.
+        // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
+        // and `DiscriminantKindCandidate` to anything else.
         //
         // This is a fix for #53123 and prevents winnowing from accidentally extending the
         // lifetime of a variable.
@@ -1332,8 +1334,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             // (*)
-            (BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate, _) => true,
-            (_, BuiltinCandidate { has_nested: false } | DiscriminantKindCandidate) => false,
+            (
+                BuiltinCandidate { has_nested: false }
+                | DiscriminantKindCandidate
+                | PointeeCandidate,
+                _,
+            ) => true,
+            (
+                _,
+                BuiltinCandidate { has_nested: false }
+                | DiscriminantKindCandidate
+                | PointeeCandidate,
+            ) => false,
 
             (ParamCandidate(other), ParamCandidate(victim)) => {
                 if other.value == victim.value && victim.constness == Constness::NotConst {
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml
index 8fdbc3b76b4..a7ce14afaa3 100644
--- a/compiler/rustc_traits/Cargo.toml
+++ b/compiler/rustc_traits/Cargo.toml
@@ -16,6 +16,6 @@ rustc_span = { path = "../rustc_span" }
 chalk-ir = "0.55.0"
 chalk-solve = "0.55.0"
 chalk-engine = "0.55.0"
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_infer = { path = "../rustc_infer" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 7d3589c4b6b..fdf5f697e61 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -779,14 +779,11 @@ impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>
         self,
         interner: &RustInterner<'tcx>,
     ) -> chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>> {
-        let trait_ref = self.projection_ty.trait_ref(interner.tcx);
+        let (trait_ref, own_substs) = self.projection_ty.trait_ref_and_own_substs(interner.tcx);
         chalk_solve::rust_ir::AliasEqBound {
             trait_bound: trait_ref.lower_into(interner),
             associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
-            parameters: self.projection_ty.substs[trait_ref.substs.len()..]
-                .iter()
-                .map(|arg| arg.lower_into(interner))
-                .collect(),
+            parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
             value: self.ty.lower_into(interner),
         }
     }
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 2827163d854..cfcbc77c172 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -80,7 +80,7 @@ fn dropck_outlives<'tcx>(
             let cause = ObligationCause::dummy();
             let mut constraints = DtorckConstraint::empty();
             while let Some((ty, depth)) = ty_stack.pop() {
-                info!(
+                debug!(
                     "{} kinds, {} overflows, {} ty_stack",
                     result.kinds.len(),
                     result.overflows.len(),
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index cf2c6efb471..6b9d46ee0af 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -10,6 +10,7 @@ use traits::{translate_substs, Reveal};
 
 use tracing::debug;
 
+#[instrument(level = "debug", skip(tcx))]
 fn resolve_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>,
@@ -38,13 +39,13 @@ fn resolve_instance_of_const_arg<'tcx>(
     )
 }
 
+#[instrument(level = "debug", skip(tcx))]
 fn inner_resolve_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)>,
 ) -> Result<Option<Instance<'tcx>>, ErrorReported> {
     let (param_env, (def, substs)) = key.into_parts();
 
-    debug!("resolve(def={:?}, substs={:?})", def.did, substs);
     let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) {
         debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
         let item = tcx.associated_item(def.did);
@@ -93,7 +94,7 @@ fn inner_resolve_instance<'tcx>(
         };
         Ok(Some(Instance { def, substs }))
     };
-    debug!("resolve(def.did={:?}, substs={:?}) = {:?}", def.did, substs, result);
+    debug!("inner_resolve_instance: result={:?}", result);
     result
 }
 
@@ -274,7 +275,8 @@ fn resolve_associated_item<'tcx>(
         traits::ImplSource::AutoImpl(..)
         | traits::ImplSource::Param(..)
         | traits::ImplSource::TraitAlias(..)
-        | traits::ImplSource::DiscriminantKind(..) => None,
+        | traits::ImplSource::DiscriminantKind(..)
+        | traits::ImplSource::Pointee(..) => None,
     })
 }
 
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 77aa4413409..76d27c29226 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -82,7 +82,7 @@ fn associated_item_from_trait_item_ref(
     parent_def_id: LocalDefId,
     trait_item_ref: &hir::TraitItemRef,
 ) -> ty::AssocItem {
-    let def_id = tcx.hir().local_def_id(trait_item_ref.id.hir_id);
+    let def_id = trait_item_ref.id.def_id;
     let (kind, has_self) = match trait_item_ref.kind {
         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
@@ -105,7 +105,7 @@ fn associated_item_from_impl_item_ref(
     parent_def_id: LocalDefId,
     impl_item_ref: &hir::ImplItemRef<'_>,
 ) -> ty::AssocItem {
-    let def_id = tcx.hir().local_def_id(impl_item_ref.id.hir_id);
+    let def_id = impl_item_ref.id.def_id;
     let (kind, has_self) = match impl_item_ref.kind {
         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
@@ -130,7 +130,9 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
     let parent_item = tcx.hir().expect_item(parent_id);
     match parent_item.kind {
         hir::ItemKind::Impl(ref impl_) => {
-            if let Some(impl_item_ref) = impl_.items.iter().find(|i| i.id.hir_id == id) {
+            if let Some(impl_item_ref) =
+                impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+            {
                 let assoc_item =
                     associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
                 debug_assert_eq!(assoc_item.def_id, def_id);
@@ -139,7 +141,9 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
         }
 
         hir::ItemKind::Trait(.., ref trait_item_refs) => {
-            if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.hir_id == id) {
+            if let Some(trait_item_ref) =
+                trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+            {
                 let assoc_item =
                     associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
                 debug_assert_eq!(assoc_item.def_id, def_id);
@@ -196,17 +200,10 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
     let item = tcx.hir().expect_item(id);
     match item.kind {
         hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
-            trait_item_refs
-                .iter()
-                .map(|trait_item_ref| trait_item_ref.id)
-                .map(|id| tcx.hir().local_def_id(id.hir_id).to_def_id()),
+            trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
         ),
         hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
-            impl_
-                .items
-                .iter()
-                .map(|impl_item_ref| impl_item_ref.id)
-                .map(|id| tcx.hir().local_def_id(id.hir_id).to_def_id()),
+            impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
         ),
         hir::ItemKind::TraitAlias(..) => &[],
         _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml
index e3ba0bea7e8..d92d317e34a 100644
--- a/compiler/rustc_typeck/Cargo.toml
+++ b/compiler/rustc_typeck/Cargo.toml
@@ -20,7 +20,7 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
-smallvec = { version = "1.0", features = ["union", "may_dangle"] }
+smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
 rustc_index = { path = "../rustc_index" }
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index 545c30169b9..b5404c3a15c 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -237,7 +237,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
         }
         if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
-            match &bound.trait_ref.path.segments[..] {
+            match bound.trait_ref.path.segments {
                 // FIXME: `trait_ref.path.span` can point to a full path with multiple
                 // segments, even though `trait_ref.path.segments` is of length `1`. Work
                 // around that bug here, even though it should be fixed elsewhere.
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 67e37ca8d8e..0ea0ccaceab 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -6,8 +6,9 @@ use crate::astconv::{
 use crate::errors::AssocTypeBindingNotAllowed;
 use crate::structured_errors::{StructuredDiagnostic, WrongNumberOfGenericArgs};
 use rustc_ast::ast::ParamKindOrd;
-use rustc_errors::{struct_span_err, Applicability, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
 use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
 use rustc_middle::ty::{
@@ -43,23 +44,57 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
         }
 
+        let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut DiagnosticBuilder<'_>| {
+            let suggestions = vec![
+                (arg.span().shrink_to_lo(), String::from("{ ")),
+                (arg.span().shrink_to_hi(), String::from(" }")),
+            ];
+            err.multipart_suggestion(
+                "if this generic argument was intended as a const parameter, \
+                 surround it with braces",
+                suggestions,
+                Applicability::MaybeIncorrect,
+            );
+        };
+
         // Specific suggestion set for diagnostics
         match (arg, &param.kind) {
             (
-                GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }),
-                GenericParamDefKind::Const { .. },
-            ) => {
-                let suggestions = vec![
-                    (arg.span().shrink_to_lo(), String::from("{ ")),
-                    (arg.span().shrink_to_hi(), String::from(" }")),
-                ];
-                err.multipart_suggestion(
-                    "if this generic argument was intended as a const parameter, \
-                try surrounding it with braces:",
-                    suggestions,
-                    Applicability::MaybeIncorrect,
-                );
-            }
+                GenericArg::Type(hir::Ty {
+                    kind: hir::TyKind::Path(rustc_hir::QPath::Resolved(_, path)),
+                    ..
+                }),
+                GenericParamDefKind::Const,
+            ) => match path.res {
+                Res::Err => {
+                    add_braces_suggestion(arg, &mut err);
+                    err.set_primary_message(
+                        "unresolved item provided when a constant was expected",
+                    )
+                    .emit();
+                    return;
+                }
+                Res::Def(DefKind::TyParam, src_def_id) => {
+                    if let Some(param_local_id) = param.def_id.as_local() {
+                        let param_hir_id = tcx.hir().local_def_id_to_hir_id(param_local_id);
+                        let param_name = tcx.hir().ty_param_name(param_hir_id);
+                        let param_type = tcx.type_of(param.def_id);
+                        if param_type.is_suggestable() {
+                            err.span_suggestion(
+                                tcx.def_span(src_def_id),
+                                "consider changing this type paramater to a `const`-generic",
+                                format!("const {}: {}", param_name, param_type),
+                                Applicability::MaybeIncorrect,
+                            );
+                        };
+                    }
+                }
+                _ => add_braces_suggestion(arg, &mut err),
+            },
+            (
+                GenericArg::Type(hir::Ty { kind: hir::TyKind::Path(_), .. }),
+                GenericParamDefKind::Const,
+            ) => add_braces_suggestion(arg, &mut err),
             (
                 GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
                 GenericParamDefKind::Const { .. },
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 437813ea41b..947363fc3ed 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -49,9 +49,10 @@ pub trait AstConv<'tcx> {
 
     fn default_constness_for_trait_bounds(&self) -> Constness;
 
-    /// Returns predicates in scope of the form `X: Foo`, where `X` is
-    /// a type parameter `X` with the given id `def_id`. This is a
-    /// subset of the full set of predicates.
+    /// Returns predicates in scope of the form `X: Foo<T>`, where `X`
+    /// is a type parameter `X` with the given id `def_id` and T
+    /// matches `assoc_name`. This is a subset of the full set of
+    /// predicates.
     ///
     /// This is used for one specific purpose: resolving "short-hand"
     /// associated type references like `T::Item`. In principle, we
@@ -60,7 +61,12 @@ pub trait AstConv<'tcx> {
     /// but this can lead to cycle errors. The problem is that we have
     /// to do this resolution *in order to create the predicates in
     /// the first place*. Hence, we have this "special pass".
-    fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx>;
+    fn get_type_parameter_bounds(
+        &self,
+        span: Span,
+        def_id: DefId,
+        assoc_name: Ident,
+    ) -> ty::GenericPredicates<'tcx>;
 
     /// Returns the lifetime to use when a lifetime is omitted (and not elided).
     fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span)
@@ -112,12 +118,15 @@ pub enum SizedByDefault {
     No,
 }
 
+#[derive(Debug)]
 struct ConvertedBinding<'a, 'tcx> {
     item_name: Ident,
     kind: ConvertedBindingKind<'a, 'tcx>,
+    gen_args: &'a GenericArgs<'a>,
     span: Span,
 }
 
+#[derive(Debug)]
 enum ConvertedBindingKind<'a, 'tcx> {
     Equality(Ty<'tcx>),
     Constraint(&'a [hir::GenericBound<'a>]),
@@ -323,6 +332,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         let tcx = self.tcx();
         let generics = tcx.generics_of(def_id);
+        debug!("generics: {:?}", generics);
 
         if generics.has_self {
             if generics.parent.is_some() {
@@ -557,7 +567,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         ConvertedBindingKind::Constraint(bounds)
                     }
                 };
-                ConvertedBinding { item_name: binding.ident, kind, span: binding.span }
+                ConvertedBinding {
+                    item_name: binding.ident,
+                    kind,
+                    gen_args: binding.gen_args,
+                    span: binding.span,
+                }
             })
             .collect();
 
@@ -783,7 +798,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     }
 
     // Returns `true` if a bounds list includes `?Sized`.
-    pub fn is_unsized(&self, ast_bounds: &[hir::GenericBound<'_>], span: Span) -> bool {
+    pub fn is_unsized(&self, ast_bounds: &[&hir::GenericBound<'_>], span: Span) -> bool {
         let tcx = self.tcx();
 
         // Try to find an unbound in bounds.
@@ -841,7 +856,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     fn add_bounds(
         &self,
         param_ty: Ty<'tcx>,
-        ast_bounds: &[hir::GenericBound<'_>],
+        ast_bounds: &[&hir::GenericBound<'_>],
         bounds: &mut Bounds<'tcx>,
     ) {
         let constness = self.default_constness_for_trait_bounds();
@@ -856,7 +871,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 hir::GenericBound::Trait(_, hir::TraitBoundModifier::Maybe) => {}
                 hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => self
                     .instantiate_lang_item_trait_ref(
-                        lang_item, span, hir_id, args, param_ty, bounds,
+                        *lang_item, *span, *hir_id, args, param_ty, bounds,
                     ),
                 hir::GenericBound::Outlives(ref l) => bounds
                     .region_bounds
@@ -888,6 +903,42 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         sized_by_default: SizedByDefault,
         span: Span,
     ) -> Bounds<'tcx> {
+        let ast_bounds: Vec<_> = ast_bounds.iter().collect();
+        self.compute_bounds_inner(param_ty, &ast_bounds, sized_by_default, span)
+    }
+
+    /// Convert the bounds in `ast_bounds` that refer to traits which define an associated type
+    /// named `assoc_name` into ty::Bounds. Ignore the rest.
+    pub fn compute_bounds_that_match_assoc_type(
+        &self,
+        param_ty: Ty<'tcx>,
+        ast_bounds: &[hir::GenericBound<'_>],
+        sized_by_default: SizedByDefault,
+        span: Span,
+        assoc_name: Ident,
+    ) -> Bounds<'tcx> {
+        let mut result = Vec::new();
+
+        for ast_bound in ast_bounds {
+            if let Some(trait_ref) = ast_bound.trait_ref() {
+                if let Some(trait_did) = trait_ref.trait_def_id() {
+                    if self.tcx().trait_may_define_assoc_type(trait_did, assoc_name) {
+                        result.push(ast_bound);
+                    }
+                }
+            }
+        }
+
+        self.compute_bounds_inner(param_ty, &result, sized_by_default, span)
+    }
+
+    fn compute_bounds_inner(
+        &self,
+        param_ty: Ty<'tcx>,
+        ast_bounds: &[&hir::GenericBound<'_>],
+        sized_by_default: SizedByDefault,
+        span: Span,
+    ) -> Bounds<'tcx> {
         let mut bounds = Bounds::default();
 
         self.add_bounds(param_ty, ast_bounds, &mut bounds);
@@ -918,60 +969,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         dup_bindings: &mut FxHashMap<DefId, Span>,
         path_span: Span,
     ) -> Result<(), ErrorReported> {
-        let tcx = self.tcx();
-
-        if !speculative {
-            // Given something like `U: SomeTrait<T = X>`, we want to produce a
-            // predicate like `<U as SomeTrait>::T = X`. This is somewhat
-            // subtle in the event that `T` is defined in a supertrait of
-            // `SomeTrait`, because in that case we need to upcast.
-            //
-            // That is, consider this case:
-            //
-            // ```
-            // trait SubTrait: SuperTrait<i32> { }
-            // trait SuperTrait<A> { type T; }
-            //
-            // ... B: SubTrait<T = foo> ...
-            // ```
-            //
-            // We want to produce `<B as SuperTrait<i32>>::T == foo`.
-
-            // Find any late-bound regions declared in `ty` that are not
-            // declared in the trait-ref. These are not well-formed.
-            //
-            // Example:
-            //
-            //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
-            //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
-            if let ConvertedBindingKind::Equality(ty) = binding.kind {
-                let late_bound_in_trait_ref =
-                    tcx.collect_constrained_late_bound_regions(&trait_ref);
-                let late_bound_in_ty =
-                    tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
-                debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
-                debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
+        // Given something like `U: SomeTrait<T = X>`, we want to produce a
+        // predicate like `<U as SomeTrait>::T = X`. This is somewhat
+        // subtle in the event that `T` is defined in a supertrait of
+        // `SomeTrait`, because in that case we need to upcast.
+        //
+        // That is, consider this case:
+        //
+        // ```
+        // trait SubTrait: SuperTrait<i32> { }
+        // trait SuperTrait<A> { type T; }
+        //
+        // ... B: SubTrait<T = foo> ...
+        // ```
+        //
+        // We want to produce `<B as SuperTrait<i32>>::T == foo`.
 
-                // FIXME: point at the type params that don't have appropriate lifetimes:
-                // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
-                //                         ----  ----     ^^^^^^^
-                self.validate_late_bound_regions(
-                    late_bound_in_trait_ref,
-                    late_bound_in_ty,
-                    |br_name| {
-                        struct_span_err!(
-                            tcx.sess,
-                            binding.span,
-                            E0582,
-                            "binding for associated type `{}` references {}, \
-                             which does not appear in the trait input types",
-                            binding.item_name,
-                            br_name
-                        )
-                    },
-                );
-            }
-        }
+        debug!(?hir_ref_id, ?trait_ref, ?binding, ?bounds, "add_predicates_for_ast_type_binding",);
+        let tcx = self.tcx();
 
         let candidate =
             if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
@@ -1030,6 +1045,72 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 .or_insert(binding.span);
         }
 
+        // Include substitutions for generic parameters of associated types
+        let projection_ty = candidate.map_bound(|trait_ref| {
+            let item_segment = hir::PathSegment {
+                ident: assoc_ty.ident,
+                hir_id: None,
+                res: None,
+                args: Some(binding.gen_args),
+                infer_args: false,
+            };
+
+            let substs_trait_ref_and_assoc_item = self.create_substs_for_associated_item(
+                tcx,
+                path_span,
+                assoc_ty.def_id,
+                &item_segment,
+                trait_ref.substs,
+            );
+
+            debug!(
+                "add_predicates_for_ast_type_binding: substs for trait-ref and assoc_item: {:?}",
+                substs_trait_ref_and_assoc_item
+            );
+
+            ty::ProjectionTy {
+                item_def_id: assoc_ty.def_id,
+                substs: substs_trait_ref_and_assoc_item,
+            }
+        });
+
+        if !speculative {
+            // Find any late-bound regions declared in `ty` that are not
+            // declared in the trait-ref or assoc_ty. These are not well-formed.
+            //
+            // Example:
+            //
+            //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
+            //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
+            if let ConvertedBindingKind::Equality(ty) = binding.kind {
+                let late_bound_in_trait_ref =
+                    tcx.collect_constrained_late_bound_regions(&projection_ty);
+                let late_bound_in_ty =
+                    tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(ty));
+                debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
+                debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
+
+                // FIXME: point at the type params that don't have appropriate lifetimes:
+                // struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
+                //                         ----  ----     ^^^^^^^
+                self.validate_late_bound_regions(
+                    late_bound_in_trait_ref,
+                    late_bound_in_ty,
+                    |br_name| {
+                        struct_span_err!(
+                            tcx.sess,
+                            binding.span,
+                            E0582,
+                            "binding for associated type `{}` references {}, \
+                             which does not appear in the trait input types",
+                            binding.item_name,
+                            br_name
+                        )
+                    },
+                );
+            }
+        }
+
         match binding.kind {
             ConvertedBindingKind::Equality(ref ty) => {
                 // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
@@ -1037,13 +1118,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 //
                 // `<T as Iterator>::Item = u32`
                 bounds.projection_bounds.push((
-                    candidate.map_bound(|trait_ref| ty::ProjectionPredicate {
-                        projection_ty: ty::ProjectionTy::from_ref_and_name(
-                            tcx,
-                            trait_ref,
-                            binding.item_name,
-                        ),
-                        ty,
+                    projection_ty.map_bound(|projection_ty| {
+                        debug!(
+                            "add_predicates_for_ast_type_binding: projection_ty {:?}, substs: {:?}",
+                            projection_ty, projection_ty.substs
+                        );
+                        ty::ProjectionPredicate { projection_ty, ty }
                     }),
                     binding.span,
                 ));
@@ -1055,8 +1135,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 //
                 // Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
                 // parameter to have a skipped binder.
-                let param_ty = tcx.mk_projection(assoc_ty.def_id, candidate.skip_binder().substs);
-                self.add_bounds(param_ty, ast_bounds, bounds);
+                let param_ty =
+                    tcx.mk_projection(assoc_ty.def_id, projection_ty.skip_binder().substs);
+                let ast_bounds: Vec<_> = ast_bounds.iter().collect();
+                self.add_bounds(param_ty, &ast_bounds, bounds);
             }
         }
         Ok(())
@@ -1241,37 +1323,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         debug!("regular_traits: {:?}", regular_traits);
         debug!("auto_traits: {:?}", auto_traits);
 
-        // Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
-        // removing the dummy `Self` type (`trait_object_dummy_self`).
-        let trait_ref_to_existential = |trait_ref: ty::TraitRef<'tcx>| {
-            if trait_ref.self_ty() != dummy_self {
-                // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
-                // which picks up non-supertraits where clauses - but also, the object safety
-                // completely ignores trait aliases, which could be object safety hazards. We
-                // `delay_span_bug` here to avoid an ICE in stable even when the feature is
-                // disabled. (#66420)
-                tcx.sess.delay_span_bug(
-                    DUMMY_SP,
-                    &format!(
-                        "trait_ref_to_existential called on {:?} with non-dummy Self",
-                        trait_ref,
-                    ),
-                );
-            }
-            ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
-        };
-
         // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
-        let existential_trait_refs =
-            regular_traits.iter().map(|i| i.trait_ref().map_bound(trait_ref_to_existential));
+        let existential_trait_refs = regular_traits.iter().map(|i| {
+            i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
+                if trait_ref.self_ty() != dummy_self {
+                    // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
+                    // which picks up non-supertraits where clauses - but also, the object safety
+                    // completely ignores trait aliases, which could be object safety hazards. We
+                    // `delay_span_bug` here to avoid an ICE in stable even when the feature is
+                    // disabled. (#66420)
+                    tcx.sess.delay_span_bug(
+                        DUMMY_SP,
+                        &format!(
+                            "trait_ref_to_existential called on {:?} with non-dummy Self",
+                            trait_ref,
+                        ),
+                    );
+                }
+                ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
+            })
+        });
         let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
             bound.map_bound(|b| {
-                let trait_ref = trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
-                ty::ExistentialProjection {
-                    ty: b.ty,
-                    item_def_id: b.projection_ty.item_def_id,
-                    substs: trait_ref.substs,
+                if b.projection_ty.self_ty() != dummy_self {
+                    tcx.sess.delay_span_bug(
+                        DUMMY_SP,
+                        &format!("trait_ref_to_existential called on {:?} with non-dummy Self", b),
+                    );
                 }
+                ty::ExistentialProjection::erase_self_ty(tcx, b)
             })
         });
 
@@ -1371,8 +1451,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             ty_param_def_id, assoc_name, span,
         );
 
-        let predicates =
-            &self.get_type_parameter_bounds(span, ty_param_def_id.to_def_id()).predicates;
+        let predicates = &self
+            .get_type_parameter_bounds(span, ty_param_def_id.to_def_id(), assoc_name)
+            .predicates;
 
         debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
 
@@ -1380,11 +1461,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let param_name = tcx.hir().ty_param_name(param_hir_id);
         self.one_bound_for_assoc_type(
             || {
-                traits::transitive_bounds(
+                traits::transitive_bounds_that_define_assoc_type(
                     tcx,
                     predicates.iter().filter_map(|(p, _)| {
                         p.to_opt_poly_trait_ref().map(|trait_ref| trait_ref.value)
                     }),
+                    assoc_name,
                 )
             },
             || param_name.to_string(),
@@ -2103,12 +2185,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             }
             hir::TyKind::BareFn(ref bf) => {
                 require_c_abi_if_c_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
+
                 tcx.mk_fn_ptr(self.ty_of_fn(
                     bf.unsafety,
                     bf.abi,
                     &bf.decl,
                     &hir::Generics::empty(),
                     None,
+                    Some(ast_ty),
                 ))
             }
             hir::TyKind::TraitObject(ref bounds, ref lifetime) => {
@@ -2120,8 +2204,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 self.res_to_ty(opt_self_ty, path, false)
             }
             hir::TyKind::OpaqueDef(item_id, ref lifetimes) => {
-                let opaque_ty = tcx.hir().expect_item(item_id.id);
-                let def_id = tcx.hir().local_def_id(item_id.id).to_def_id();
+                let opaque_ty = tcx.hir().item(item_id);
+                let def_id = item_id.def_id.to_def_id();
 
                 match opaque_ty.kind {
                     hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
@@ -2248,6 +2332,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         decl: &hir::FnDecl<'_>,
         generics: &hir::Generics<'_>,
         ident_span: Option<Span>,
+        hir_ty: Option<&hir::Ty<'_>>,
     ) -> ty::PolyFnSig<'tcx> {
         debug!("ty_of_fn");
 
@@ -2279,12 +2364,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             // only want to emit an error complaining about them if infer types (`_`) are not
             // allowed. `allow_ty_infer` gates this behavior. We check for the presence of
             // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`.
+
             crate::collect::placeholder_type_error(
                 tcx,
                 ident_span.map(|sp| sp.shrink_to_hi()),
-                &generics.params[..],
+                generics.params,
                 visitor.0,
                 true,
+                hir_ty,
             );
         }
 
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 7924ffe8a6f..16c344e8e2b 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -765,9 +765,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         m_expr: ty::TypeAndMut<'tcx>,
         m_cast: ty::TypeAndMut<'tcx>,
     ) -> Result<CastKind, CastError> {
-        // array-ptr-cast.
-
-        if m_expr.mutbl == hir::Mutability::Not && m_cast.mutbl == hir::Mutability::Not {
+        // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
+        if m_expr.mutbl == hir::Mutability::Mut || m_cast.mutbl == hir::Mutability::Not {
             if let ty::Array(ety, _) = m_expr.ty.kind() {
                 // Due to the limitations of LLVM global constants,
                 // region pointers end up pointing at copies of
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 8e2b0bfd662..5d7f5bf1c7b 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -7,11 +7,13 @@ use rustc_attr as attr;
 use rustc_errors::{Applicability, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ItemKind, Node};
+use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_middle::ty::fold::TypeFoldable;
+use rustc_middle::ty::layout::MAX_SIMD_LANES;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::util::{Discr, IntTypeExt, Representability};
 use rustc_middle::ty::{self, ParamEnv, RegionKind, ToPredicate, Ty, TyCtxt};
@@ -372,8 +374,7 @@ pub(super) fn check_fn<'a, 'tcx>(
     (fcx, gen_ty)
 }
 
-pub(super) fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
-    let def_id = tcx.hir().local_def_id(id);
+fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
     let def = tcx.adt_def(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
     check_representable(tcx, span, def_id);
@@ -386,8 +387,7 @@ pub(super) fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
     check_packed(tcx, span, def);
 }
 
-fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) {
-    let def_id = tcx.hir().local_def_id(id);
+fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
     let def = tcx.adt_def(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
     check_representable(tcx, span, def_id);
@@ -476,7 +476,7 @@ pub(super) fn check_opaque<'tcx>(
 
 /// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
 /// in "inheriting lifetimes".
-#[instrument(skip(tcx, span))]
+#[instrument(level = "debug", skip(tcx, span))]
 pub(super) fn check_opaque_for_inheriting_lifetimes(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
@@ -514,10 +514,11 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
         }
     }
 
-    #[derive(Debug)]
     struct ProhibitOpaqueVisitor<'tcx> {
         opaque_identity_ty: Ty<'tcx>,
         generics: &'tcx ty::Generics,
+        tcx: TyCtxt<'tcx>,
+        selftys: Vec<(Span, Option<String>)>,
     }
 
     impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
@@ -534,6 +535,29 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
         }
     }
 
+    impl Visitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
+        type Map = rustc_middle::hir::map::Map<'tcx>;
+
+        fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
+            hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+        }
+
+        fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
+            match arg.kind {
+                hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
+                    [PathSegment { res: Some(Res::SelfTy(_, impl_ref)), .. }] => {
+                        let impl_ty_name =
+                            impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id));
+                        self.selftys.push((path.span, impl_ty_name));
+                    }
+                    _ => {}
+                },
+                _ => {}
+            }
+            hir::intravisit::walk_ty(self, arg);
+        }
+    }
+
     if let ItemKind::OpaqueTy(hir::OpaqueTy {
         origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
         ..
@@ -545,17 +569,20 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
                 InternalSubsts::identity_for_item(tcx, def_id.to_def_id()),
             ),
             generics: tcx.generics_of(def_id),
+            tcx,
+            selftys: vec![],
         };
         let prohibit_opaque = tcx
             .explicit_item_bounds(def_id)
             .iter()
             .try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
         debug!(
-            "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
-            prohibit_opaque, visitor
+            "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor.opaque_identity_ty={:?}, visitor.generics={:?}",
+            prohibit_opaque, visitor.opaque_identity_ty, visitor.generics
         );
 
         if let Some(ty) = prohibit_opaque.break_value() {
+            visitor.visit_item(&item);
             let is_async = match item.kind {
                 ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
                     matches!(origin, hir::OpaqueTyOrigin::AsyncFn)
@@ -572,15 +599,13 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
                 if is_async { "async fn" } else { "impl Trait" },
             );
 
-            if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
-                if snippet == "Self" {
-                    err.span_suggestion(
-                        span,
-                        "consider spelling out the type instead",
-                        format!("{:?}", ty),
-                        Applicability::MaybeIncorrect,
-                    );
-                }
+            for (span, name) in visitor.selftys {
+                err.span_suggestion(
+                    span,
+                    "consider spelling out the type instead",
+                    name.unwrap_or_else(|| format!("{:?}", ty)),
+                    Applicability::MaybeIncorrect,
+                );
             }
             err.emit();
         }
@@ -682,34 +707,32 @@ fn check_opaque_meets_bounds<'tcx>(
 
 pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
     debug!(
-        "check_item_type(it.hir_id={}, it.name={})",
-        it.hir_id,
-        tcx.def_path_str(tcx.hir().local_def_id(it.hir_id).to_def_id())
+        "check_item_type(it.def_id={:?}, it.name={})",
+        it.def_id,
+        tcx.def_path_str(it.def_id.to_def_id())
     );
     let _indenter = indenter();
     match it.kind {
         // Consts can play a role in type-checking, so they are included here.
         hir::ItemKind::Static(..) => {
-            let def_id = tcx.hir().local_def_id(it.hir_id);
-            tcx.ensure().typeck(def_id);
-            maybe_check_static_with_link_section(tcx, def_id, it.span);
-            check_static_inhabited(tcx, def_id, it.span);
+            tcx.ensure().typeck(it.def_id);
+            maybe_check_static_with_link_section(tcx, it.def_id, it.span);
+            check_static_inhabited(tcx, it.def_id, it.span);
         }
         hir::ItemKind::Const(..) => {
-            tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id));
+            tcx.ensure().typeck(it.def_id);
         }
         hir::ItemKind::Enum(ref enum_definition, _) => {
-            check_enum(tcx, it.span, &enum_definition.variants, it.hir_id);
+            check_enum(tcx, it.span, &enum_definition.variants, it.def_id);
         }
         hir::ItemKind::Fn(..) => {} // entirely within check_item_body
         hir::ItemKind::Impl(ref impl_) => {
-            debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id);
-            let impl_def_id = tcx.hir().local_def_id(it.hir_id);
-            if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
+            debug!("ItemKind::Impl {} with id {:?}", it.ident, it.def_id);
+            if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.def_id) {
                 check_impl_items_against_trait(
                     tcx,
                     it.span,
-                    impl_def_id,
+                    it.def_id,
                     impl_trait_ref,
                     &impl_.items,
                 );
@@ -718,8 +741,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
             }
         }
         hir::ItemKind::Trait(_, _, _, _, ref items) => {
-            let def_id = tcx.hir().local_def_id(it.hir_id);
-            check_on_unimplemented(tcx, def_id.to_def_id(), it);
+            check_on_unimplemented(tcx, it.def_id.to_def_id(), it);
 
             for item in items.iter() {
                 let item = tcx.hir().trait_item(item.id);
@@ -729,16 +751,15 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
                         fn_maybe_err(tcx, item.ident.span, abi);
                     }
                     hir::TraitItemKind::Type(.., Some(_default)) => {
-                        let item_def_id = tcx.hir().local_def_id(item.hir_id).to_def_id();
-                        let assoc_item = tcx.associated_item(item_def_id);
+                        let assoc_item = tcx.associated_item(item.def_id);
                         let trait_substs =
-                            InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+                            InternalSubsts::identity_for_item(tcx, it.def_id.to_def_id());
                         let _: Result<_, rustc_errors::ErrorReported> = check_type_bounds(
                             tcx,
                             assoc_item,
                             assoc_item,
                             item.span,
-                            ty::TraitRef { def_id: def_id.to_def_id(), substs: trait_substs },
+                            ty::TraitRef { def_id: it.def_id.to_def_id(), substs: trait_substs },
                         );
                     }
                     _ => {}
@@ -746,10 +767,10 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
             }
         }
         hir::ItemKind::Struct(..) => {
-            check_struct(tcx, it.hir_id, it.span);
+            check_struct(tcx, it.def_id, it.span);
         }
         hir::ItemKind::Union(..) => {
-            check_union(tcx, it.hir_id, it.span);
+            check_union(tcx, it.def_id, it.span);
         }
         hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
             // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting
@@ -757,16 +778,13 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
             // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it!
             // See https://github.com/rust-lang/rust/issues/75100
             if !tcx.sess.opts.actually_rustdoc {
-                let def_id = tcx.hir().local_def_id(it.hir_id);
-
-                let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
-                check_opaque(tcx, def_id, substs, it.span, &origin);
+                let substs = InternalSubsts::identity_for_item(tcx, it.def_id.to_def_id());
+                check_opaque(tcx, it.def_id, substs, it.span, &origin);
             }
         }
         hir::ItemKind::TyAlias(..) => {
-            let def_id = tcx.hir().local_def_id(it.hir_id);
-            let pty_ty = tcx.type_of(def_id);
-            let generics = tcx.generics_of(def_id);
+            let pty_ty = tcx.type_of(it.def_id);
+            let generics = tcx.generics_of(it.def_id);
             check_type_params_are_used(tcx, &generics, pty_ty);
         }
         hir::ItemKind::ForeignMod { abi, items } => {
@@ -784,7 +802,7 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
                 }
             } else {
                 for item in items {
-                    let def_id = tcx.hir().local_def_id(item.id.hir_id);
+                    let def_id = item.id.def_id;
                     let generics = tcx.generics_of(def_id);
                     let own_counts = generics.own_counts();
                     if generics.params.len() - own_counts.lifetimes != 0 {
@@ -834,9 +852,8 @@ pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) {
 }
 
 pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) {
-    let item_def_id = tcx.hir().local_def_id(item.hir_id);
     // an error would be reported if this fails.
-    let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id.to_def_id());
+    let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item.def_id.to_def_id());
 }
 
 pub(super) fn check_specialization_validity<'tcx>(
@@ -937,7 +954,7 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
     // Check existing impl methods to see if they are both present in trait
     // and compatible with trait signature
     for impl_item in impl_items {
-        let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id));
+        let ty_impl_item = tcx.associated_item(impl_item.def_id);
 
         let mut items =
             associated_items.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id);
@@ -1134,6 +1151,38 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
                     .emit();
                 return;
             }
+
+            let len = if let ty::Array(_ty, c) = e.kind() {
+                c.try_eval_usize(tcx, tcx.param_env(def.did))
+            } else {
+                Some(fields.len() as u64)
+            };
+            if let Some(len) = len {
+                if len == 0 {
+                    struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit();
+                    return;
+                } else if !len.is_power_of_two() {
+                    struct_span_err!(
+                        tcx.sess,
+                        sp,
+                        E0075,
+                        "SIMD vector length must be a power of two"
+                    )
+                    .emit();
+                    return;
+                } else if len > MAX_SIMD_LANES {
+                    struct_span_err!(
+                        tcx.sess,
+                        sp,
+                        E0075,
+                        "SIMD vector cannot have more than {} elements",
+                        MAX_SIMD_LANES,
+                    )
+                    .emit();
+                    return;
+                }
+            }
+
             match e.kind() {
                 ty::Param(_) => { /* struct<T>(T, T, T, T) is ok */ }
                 _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ }
@@ -1312,13 +1361,12 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty
 }
 
 #[allow(trivial_numeric_casts)]
-pub fn check_enum<'tcx>(
+fn check_enum<'tcx>(
     tcx: TyCtxt<'tcx>,
     sp: Span,
     vs: &'tcx [hir::Variant<'tcx>],
-    id: hir::HirId,
+    def_id: LocalDefId,
 ) {
-    let def_id = tcx.hir().local_def_id(id);
     let def = tcx.adt_def(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
 
@@ -1472,6 +1520,9 @@ fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) {
     struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
         .span_label(span, "recursive `async fn`")
         .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
+        .note(
+            "consider using the `async_recursion` crate: https://crates.io/crates/async_recursion",
+        )
         .emit();
 }
 
diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs
index f34aaec10a9..431e6d70ff3 100644
--- a/compiler/rustc_typeck/src/check/closure.rs
+++ b/compiler/rustc_typeck/src/check/closure.rs
@@ -208,7 +208,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             });
 
         // Even if we can't infer the full signature, we may be able to
-        // infer the kind. This can occur if there is a trait-reference
+        // infer the kind. This can occur when we elaborate a predicate
         // like `F : Fn<A>`. Note that due to subtyping we could encounter
         // many viable options, so pick the most restrictive.
         let expected_kind = self
@@ -234,11 +234,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         debug!("deduce_sig_from_projection({:?})", projection);
 
-        let trait_ref = projection.to_poly_trait_ref(tcx);
+        let trait_def_id = projection.trait_def_id(tcx);
 
-        let is_fn = tcx.fn_trait_kind_from_lang_item(trait_ref.def_id()).is_some();
+        let is_fn = tcx.fn_trait_kind_from_lang_item(trait_def_id).is_some();
         let gen_trait = tcx.require_lang_item(LangItem::Generator, cause_span);
-        let is_gen = gen_trait == trait_ref.def_id();
+        let is_gen = gen_trait == trait_def_id;
         if !is_fn && !is_gen {
             debug!("deduce_sig_from_projection: not fn or generator");
             return None;
@@ -256,7 +256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let input_tys = if is_fn {
-            let arg_param_ty = trait_ref.skip_binder().substs.type_at(1);
+            let arg_param_ty = projection.skip_binder().projection_ty.substs.type_at(1);
             let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
             debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty);
 
@@ -662,9 +662,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         // Check that this is a projection from the `Future` trait.
-        let trait_ref = predicate.projection_ty.trait_ref(self.tcx);
+        let trait_def_id = predicate.projection_ty.trait_def_id(self.tcx);
         let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span));
-        if trait_ref.def_id != future_trait {
+        if trait_def_id != future_trait {
             debug!("deduce_future_output_from_projection: not a future");
             return None;
         }
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index d37d6bc4f2d..a30a8107933 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -823,11 +823,11 @@ fn compare_synthetic_generics<'tcx>(
                         // FIXME: this is obviously suboptimal since the name can already be used
                         // as another generic argument
                         let new_name = tcx.sess.source_map().span_to_snippet(trait_span).ok()?;
-                        let trait_m = tcx.hir().local_def_id_to_hir_id(trait_m.def_id.as_local()?);
-                        let trait_m = tcx.hir().trait_item(hir::TraitItemId { hir_id: trait_m });
+                        let trait_m = trait_m.def_id.as_local()?;
+                        let trait_m = tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m });
 
-                        let impl_m = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.as_local()?);
-                        let impl_m = tcx.hir().impl_item(hir::ImplItemId { hir_id: impl_m });
+                        let impl_m = impl_m.def_id.as_local()?;
+                        let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m });
 
                         // in case there are no generics, take the spot between the function name
                         // and the opening paren of the argument list
@@ -860,8 +860,8 @@ fn compare_synthetic_generics<'tcx>(
                 (None, Some(hir::SyntheticTyParamKind::ImplTrait)) => {
                     err.span_label(impl_span, "expected `impl Trait`, found generic parameter");
                     (|| {
-                        let impl_m = tcx.hir().local_def_id_to_hir_id(impl_m.def_id.as_local()?);
-                        let impl_m = tcx.hir().impl_item(hir::ImplItemId { hir_id: impl_m });
+                        let impl_m = impl_m.def_id.as_local()?;
+                        let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m });
                         let input_tys = match impl_m.kind {
                             hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
                             _ => unreachable!(),
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 3c9c683f4b0..8d2004a543b 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -773,7 +773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let hir::ExprKind::Lit(lit) = &expr.kind { lit.node.is_suffixed() } else { false }
         };
         let is_negative_int =
-            |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnNeg, ..));
+            |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::Neg, ..));
         let is_uint = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(..));
 
         let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id);
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 33b1c0bb2c9..32bf0ab7e85 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -168,7 +168,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // without the final expr (e.g. `try { return; }`). We don't want to generate an
         // unreachable_code lint for it since warnings for autogenerated code are confusing.
         let is_try_block_generated_unit_expr = match expr.kind {
-            ExprKind::Call(_, ref args) if expr.span.is_desugaring(DesugaringKind::TryBlock) => {
+            ExprKind::Call(_, args) if expr.span.is_desugaring(DesugaringKind::TryBlock) => {
                 args.len() == 1 && args[0].span.is_desugaring(DesugaringKind::TryBlock)
             }
 
@@ -193,9 +193,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // diverging expression (e.g. it arose from desugaring of `try { return }`),
             // we skip issuing a warning because it is autogenerated code.
             ExprKind::Call(..) if expr.span.is_desugaring(DesugaringKind::TryBlock) => {}
-            ExprKind::Call(ref callee, _) => {
-                self.warn_if_unreachable(expr.hir_id, callee.span, "call")
-            }
+            ExprKind::Call(callee, _) => self.warn_if_unreachable(expr.hir_id, callee.span, "call"),
             ExprKind::MethodCall(_, ref span, _, _) => {
                 self.warn_if_unreachable(expr.hir_id, *span, "call")
             }
@@ -231,15 +229,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let tcx = self.tcx;
         match expr.kind {
-            ExprKind::Box(ref subexpr) => self.check_expr_box(subexpr, expected),
+            ExprKind::Box(subexpr) => self.check_expr_box(subexpr, expected),
             ExprKind::Lit(ref lit) => self.check_lit(&lit, expected),
-            ExprKind::Binary(op, ref lhs, ref rhs) => self.check_binop(expr, op, lhs, rhs),
-            ExprKind::Assign(ref lhs, ref rhs, ref span) => {
+            ExprKind::Binary(op, lhs, rhs) => self.check_binop(expr, op, lhs, rhs),
+            ExprKind::Assign(lhs, rhs, ref span) => {
                 self.check_expr_assign(expr, expected, lhs, rhs, span)
             }
-            ExprKind::AssignOp(op, ref lhs, ref rhs) => self.check_binop_assign(expr, op, lhs, rhs),
-            ExprKind::Unary(unop, ref oprnd) => self.check_expr_unary(unop, oprnd, expected, expr),
-            ExprKind::AddrOf(kind, mutbl, ref oprnd) => {
+            ExprKind::AssignOp(op, lhs, rhs) => self.check_binop_assign(expr, op, lhs, rhs),
+            ExprKind::Unary(unop, oprnd) => self.check_expr_unary(unop, oprnd, expected, expr),
+            ExprKind::AddrOf(kind, mutbl, oprnd) => {
                 self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
             }
             ExprKind::Path(QPath::LangItem(lang_item, _)) => {
@@ -247,7 +245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr),
             ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
-            ExprKind::LlvmInlineAsm(ref asm) => {
+            ExprKind::LlvmInlineAsm(asm) => {
                 for expr in asm.outputs_exprs.iter().chain(asm.inputs_exprs.iter()) {
                     self.check_expr(expr);
                 }
@@ -265,46 +263,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             ExprKind::Ret(ref expr_opt) => self.check_expr_return(expr_opt.as_deref(), expr),
-            ExprKind::Loop(ref body, _, source, _) => {
+            ExprKind::Loop(body, _, source, _) => {
                 self.check_expr_loop(body, source, expected, expr)
             }
-            ExprKind::Match(ref discrim, ref arms, match_src) => {
+            ExprKind::Match(discrim, arms, match_src) => {
                 self.check_match(expr, &discrim, arms, expected, match_src)
             }
-            ExprKind::Closure(capture, ref decl, body_id, _, gen) => {
+            ExprKind::Closure(capture, decl, body_id, _, gen) => {
                 self.check_expr_closure(expr, capture, &decl, body_id, gen, expected)
             }
-            ExprKind::Block(ref body, _) => self.check_block_with_expected(&body, expected),
-            ExprKind::Call(ref callee, ref args) => self.check_call(expr, &callee, args, expected),
-            ExprKind::MethodCall(ref segment, span, ref args, _) => {
+            ExprKind::Block(body, _) => self.check_block_with_expected(&body, expected),
+            ExprKind::Call(callee, args) => self.check_call(expr, &callee, args, expected),
+            ExprKind::MethodCall(segment, span, args, _) => {
                 self.check_method_call(expr, segment, span, args, expected)
             }
-            ExprKind::Cast(ref e, ref t) => self.check_expr_cast(e, t, expr),
-            ExprKind::Type(ref e, ref t) => {
+            ExprKind::Cast(e, t) => self.check_expr_cast(e, t, expr),
+            ExprKind::Type(e, t) => {
                 let ty = self.to_ty_saving_user_provided_ty(&t);
                 self.check_expr_eq_type(&e, ty);
                 ty
             }
-            ExprKind::If(ref cond, ref then_expr, ref opt_else_expr) => self.check_then_else(
-                &cond,
-                then_expr,
-                opt_else_expr.as_ref().map(|e| &**e),
-                expr.span,
-                expected,
-            ),
-            ExprKind::DropTemps(ref e) => self.check_expr_with_expectation(e, expected),
-            ExprKind::Array(ref args) => self.check_expr_array(args, expected, expr),
+            ExprKind::If(cond, then_expr, opt_else_expr) => {
+                self.check_then_else(cond, then_expr, opt_else_expr, expr.span, expected)
+            }
+            ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
+            ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
             ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty,
-            ExprKind::Repeat(ref element, ref count) => {
+            ExprKind::Repeat(element, ref count) => {
                 self.check_expr_repeat(element, count, expected, expr)
             }
-            ExprKind::Tup(ref elts) => self.check_expr_tuple(elts, expected, expr),
-            ExprKind::Struct(ref qpath, fields, ref base_expr) => {
+            ExprKind::Tup(elts) => self.check_expr_tuple(elts, expected, expr),
+            ExprKind::Struct(qpath, fields, ref base_expr) => {
                 self.check_expr_struct(expr, expected, qpath, fields, base_expr)
             }
-            ExprKind::Field(ref base, field) => self.check_field(expr, &base, field),
-            ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, expr),
-            ExprKind::Yield(ref value, ref src) => self.check_expr_yield(value, expr, src),
+            ExprKind::Field(base, field) => self.check_field(expr, &base, field),
+            ExprKind::Index(base, idx) => self.check_expr_index(base, idx, expr),
+            ExprKind::Yield(value, ref src) => self.check_expr_yield(value, expr, src),
             hir::ExprKind::Err => tcx.ty_error(),
         }
     }
@@ -327,15 +321,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let expected_inner = match unop {
-            hir::UnOp::UnNot | hir::UnOp::UnNeg => expected,
-            hir::UnOp::UnDeref => NoExpectation,
+            hir::UnOp::Not | hir::UnOp::Neg => expected,
+            hir::UnOp::Deref => NoExpectation,
         };
         let mut oprnd_t = self.check_expr_with_expectation(&oprnd, expected_inner);
 
         if !oprnd_t.references_error() {
             oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
             match unop {
-                hir::UnOp::UnDeref => {
+                hir::UnOp::Deref => {
                     if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) {
                         oprnd_t = ty;
                     } else {
@@ -357,14 +351,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         oprnd_t = tcx.ty_error();
                     }
                 }
-                hir::UnOp::UnNot => {
+                hir::UnOp::Not => {
                     let result = self.check_user_unop(expr, oprnd_t, unop);
                     // If it's builtin, we can reuse the type, this helps inference.
                     if !(oprnd_t.is_integral() || *oprnd_t.kind() == ty::Bool) {
                         oprnd_t = result;
                     }
                 }
-                hir::UnOp::UnNeg => {
+                hir::UnOp::Neg => {
                     let result = self.check_user_unop(expr, oprnd_t, unop);
                     // If it's builtin, we can reuse the type, this helps inference.
                     if !oprnd_t.is_numeric() {
@@ -545,7 +539,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let tcx = self.tcx;
         if let Ok(target_id) = destination.target_id {
             let (e_ty, cause);
-            if let Some(ref e) = expr_opt {
+            if let Some(e) = expr_opt {
                 // If this is a break with a value, we need to type-check
                 // the expression. Get an expected type from the loop context.
                 let opt_coerce_to = {
@@ -654,12 +648,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             // We still need to assign a type to the inner expression to
             // prevent the ICE in #43162.
-            if let Some(ref e) = expr_opt {
+            if let Some(e) = expr_opt {
                 self.check_expr_with_hint(e, err);
 
                 // ... except when we try to 'break rust;'.
                 // ICE this expression in particular (see #43162).
-                if let ExprKind::Path(QPath::Resolved(_, ref path)) = e.kind {
+                if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind {
                     if path.segments.len() == 1 && path.segments[0].ident.name == sym::rust {
                         fatally_break_rust(self.tcx.sess);
                     }
@@ -678,7 +672,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> Ty<'tcx> {
         if self.ret_coercion.is_none() {
             self.tcx.sess.emit_err(ReturnStmtOutsideOfFnBody { span: expr.span });
-        } else if let Some(ref e) = expr_opt {
+        } else if let Some(e) = expr_opt {
             if self.ret_coercion_span.get().is_none() {
                 self.ret_coercion_span.set(Some(e.span));
             }
@@ -1137,13 +1131,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let flds = expected.only_has_type(self).and_then(|ty| {
             let ty = self.resolve_vars_with_obligations(ty);
             match ty.kind() {
-                ty::Tuple(ref flds) => Some(&flds[..]),
+                ty::Tuple(flds) => Some(&flds[..]),
                 _ => None,
             }
         });
 
         let elt_ts_iter = elts.iter().enumerate().map(|(i, e)| match flds {
-            Some(ref fs) if i < fs.len() => {
+            Some(fs) if i < fs.len() => {
                 let ety = fs[i].expect_ty();
                 self.check_expr_coercable_to_type(&e, ety, None);
                 ety
@@ -1332,7 +1326,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         for field in fields {
             self.check_expr(&field.expr);
         }
-        if let Some(ref base) = *base_expr {
+        if let Some(base) = *base_expr {
             self.check_expr(&base);
         }
     }
@@ -1460,34 +1454,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ),
                     );
                     err.span_label(field.ident.span, "field does not exist");
-                    err.span_label(
+                    err.span_suggestion(
                         ty_span,
+                        &format!(
+                            "`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax",
+                            adt = ty,
+                            variant = variant.ident,
+                        ),
                         format!(
-                            "`{adt}::{variant}` is a tuple {kind_name}, \
-                             use the appropriate syntax: `{adt}::{variant}(/* fields */)`",
+                            "{adt}::{variant}(/* fields */)",
                             adt = ty,
                             variant = variant.ident,
-                            kind_name = kind_name
                         ),
+                        Applicability::HasPlaceholders,
                     );
                 }
                 _ => {
                     err.span_label(variant.ident.span, format!("`{adt}` defined here", adt = ty));
                     err.span_label(field.ident.span, "field does not exist");
-                    err.span_label(
+                    err.span_suggestion(
                         ty_span,
-                        format!(
-                            "`{adt}` is a tuple {kind_name}, \
-                                 use the appropriate syntax: `{adt}(/* fields */)`",
+                        &format!(
+                            "`{adt}` is a tuple {kind_name}, use the appropriate syntax",
                             adt = ty,
-                            kind_name = kind_name
+                            kind_name = kind_name,
                         ),
+                        format!("{adt}(/* fields */)", adt = ty),
+                        Applicability::HasPlaceholders,
                     );
                 }
             },
             _ => {
                 // prevent all specified fields from being suggested
-                let skip_fields = skip_fields.iter().map(|ref x| x.ident.name);
+                let skip_fields = skip_fields.iter().map(|x| x.ident.name);
                 if let Some(field_name) =
                     Self::suggest_field_name(variant, field.ident.name, skip_fields.collect())
                 {
@@ -1616,7 +1615,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         private_candidate = Some((base_def.did, field_ty));
                     }
                 }
-                ty::Tuple(ref tys) => {
+                ty::Tuple(tys) => {
                     let fstr = field.as_str();
                     if let Ok(index) = fstr.parse::<usize>() {
                         if fstr == index.to_string() {
@@ -2082,6 +2081,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             _ => {
                 self.tcx.sess.emit_err(YieldExprOutsideOfGenerator { span: expr.span });
+                // Avoid expressions without types during writeback (#78653).
+                self.check_expr(value);
                 self.tcx.mk_unit()
             }
         }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index bc1a07801ae..f5e9cc1efcc 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -769,9 +769,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .filter_map(move |obligation| {
                 let bound_predicate = obligation.predicate.kind();
                 match bound_predicate.skip_binder() {
-                    ty::PredicateKind::Projection(data) => {
-                        Some((bound_predicate.rebind(data).to_poly_trait_ref(self.tcx), obligation))
-                    }
+                    ty::PredicateKind::Projection(data) => Some((
+                        bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
+                        obligation,
+                    )),
                     ty::PredicateKind::Trait(data, _) => {
                         Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
                     }
@@ -897,7 +898,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 return (
                     path.res,
                     opt_qself.as_ref().map(|qself| self.to_ty(qself)),
-                    &path.segments[..],
+                    path.segments,
                 );
             }
             QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment),
@@ -1073,13 +1074,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
         let last_expr_ty = self.node_ty(last_expr.hir_id);
         let needs_box = match (last_expr_ty.kind(), expected_ty.kind()) {
+            (ty::Opaque(last_def_id, _), ty::Opaque(exp_def_id, _))
+                if last_def_id == exp_def_id =>
+            {
+                StatementAsExpression::CorrectType
+            }
             (ty::Opaque(last_def_id, last_bounds), ty::Opaque(exp_def_id, exp_bounds)) => {
                 debug!(
                     "both opaque, likely future {:?} {:?} {:?} {:?}",
                     last_def_id, last_bounds, exp_def_id, exp_bounds
                 );
-                let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_def_id.expect_local());
-                let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_def_id.expect_local());
+
+                let (last_local_id, exp_local_id) =
+                    match (last_def_id.as_local(), exp_def_id.as_local()) {
+                        (Some(last_hir_id), Some(exp_hir_id)) => (last_hir_id, exp_hir_id),
+                        (_, _) => return None,
+                    };
+
+                let last_hir_id = self.tcx.hir().local_def_id_to_hir_id(last_local_id);
+                let exp_hir_id = self.tcx.hir().local_def_id_to_hir_id(exp_local_id);
+
                 match (
                     &self.tcx.hir().expect_item(last_hir_id).kind,
                     &self.tcx.hir().expect_item(exp_hir_id).kind,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index e9223f700dc..4da4835f7cf 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -20,6 +20,7 @@ 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::symbol::Ident;
 use rustc_span::{self, Span};
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
 
@@ -183,7 +184,12 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         }
     }
 
-    fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
+    fn get_type_parameter_bounds(
+        &self,
+        _: Span,
+        def_id: DefId,
+        _: Ident,
+    ) -> 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);
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index e99db7a247c..dedf96863ea 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -9,7 +9,6 @@ use crate::require_same_types;
 
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, TyCtxt};
@@ -21,7 +20,6 @@ use std::iter;
 fn equate_intrinsic_type<'tcx>(
     tcx: TyCtxt<'tcx>,
     it: &hir::ForeignItem<'_>,
-    def_id: DefId,
     n_tps: usize,
     sig: ty::PolyFnSig<'tcx>,
 ) {
@@ -35,7 +33,7 @@ fn equate_intrinsic_type<'tcx>(
         }
     }
 
-    let i_n_tps = tcx.generics_of(def_id).own_counts().types;
+    let i_n_tps = tcx.generics_of(it.def_id).own_counts().types;
     if i_n_tps != n_tps {
         let span = match it.kind {
             hir::ForeignItemKind::Fn(_, _, ref generics) => generics.span,
@@ -51,8 +49,8 @@ fn equate_intrinsic_type<'tcx>(
     }
 
     let fty = tcx.mk_fn_ptr(sig);
-    let cause = ObligationCause::new(it.span, it.hir_id, ObligationCauseCode::IntrinsicType);
-    require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(def_id)), fty);
+    let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType);
+    require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty);
 }
 
 /// Returns `true` if the given intrinsic is unsafe to call or not.
@@ -100,8 +98,7 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety {
 /// and in `library/core/src/intrinsics.rs`.
 pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
     let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)));
-    let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id();
-    let intrinsic_name = tcx.item_name(def_id);
+    let intrinsic_name = tcx.item_name(it.def_id.to_def_id());
     let name_str = intrinsic_name.as_str();
 
     let mk_va_list_ty = |mutbl| {
@@ -370,7 +367,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
     };
     let sig = tcx.mk_fn_sig(inputs.into_iter(), output, false, unsafety, Abi::RustIntrinsic);
     let sig = ty::Binder::bind(sig);
-    equate_intrinsic_type(tcx, it, def_id, n_tps, sig)
+    equate_intrinsic_type(tcx, it, n_tps, sig)
 }
 
 /// Type-check `extern "platform-intrinsic" { ... }` functions.
@@ -380,7 +377,6 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         tcx.mk_ty_param(n, name)
     };
 
-    let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id();
     let name = it.ident.name;
 
     let (n_tps, inputs, output) = match name {
@@ -464,5 +460,5 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         Abi::PlatformIntrinsic,
     );
     let sig = ty::Binder::dummy(sig);
-    equate_intrinsic_type(tcx, it, def_id, n_tps, sig)
+    equate_intrinsic_type(tcx, it, n_tps, sig)
 }
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index d49c7cae822..721e8ec54f0 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -11,7 +11,6 @@ use rustc_hir::intravisit;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::hir::map as hir_map;
 use rustc_middle::ty::fast_reject::simplify_type;
 use rustc_middle::ty::print::with_crate_prefix;
 use rustc_middle::ty::{
@@ -24,6 +23,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::Obligation;
 
 use std::cmp::Ordering;
+use std::iter;
 
 use super::probe::Mode;
 use super::{CandidateSource, MethodError, NoMatchData};
@@ -390,7 +390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             "no {} named `{}` found for {} `{}` in the current scope",
                             item_kind,
                             item_name,
-                            actual.prefix_string(),
+                            actual.prefix_string(self.tcx),
                             ty_str,
                         );
                         if let Mode::MethodCall = mode {
@@ -600,7 +600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                     });
                                     if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
                                         if let Some(g) = kind.generics() {
-                                            let key = match &g.where_clause.predicates[..] {
+                                            let key = match g.where_clause.predicates {
                                                 [.., pred] => (pred.span().shrink_to_hi(), false),
                                                 [] => (
                                                     g.where_clause
@@ -649,21 +649,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             ty::PredicateKind::Projection(pred) => {
                                 let pred = bound_predicate.rebind(pred);
                                 // `<Foo as Iterator>::Item = String`.
-                                let trait_ref =
-                                    pred.skip_binder().projection_ty.trait_ref(self.tcx);
-                                let assoc = self
-                                    .tcx
-                                    .associated_item(pred.skip_binder().projection_ty.item_def_id);
-                                let ty = pred.skip_binder().ty;
-                                let obligation = format!("{}::{} = {}", trait_ref, assoc.ident, ty);
-                                let quiet = format!(
-                                    "<_ as {}>::{} = {}",
-                                    trait_ref.print_only_trait_path(),
-                                    assoc.ident,
-                                    ty
+                                let projection_ty = pred.skip_binder().projection_ty;
+
+                                let substs_with_infer_self = tcx.mk_substs(
+                                    iter::once(tcx.mk_ty_var(ty::TyVid { index: 0 }).into())
+                                        .chain(projection_ty.substs.iter().skip(1)),
                                 );
-                                bound_span_label(trait_ref.self_ty(), &obligation, &quiet);
-                                Some((obligation, trait_ref.self_ty()))
+
+                                let quiet_projection_ty = ty::ProjectionTy {
+                                    substs: substs_with_infer_self,
+                                    item_def_id: projection_ty.item_def_id,
+                                };
+
+                                let ty = pred.skip_binder().ty;
+
+                                let obligation = format!("{} = {}", projection_ty, ty);
+                                let quiet = format!("{} = {}", quiet_projection_ty, ty);
+
+                                bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
+                                Some((obligation, projection_ty.self_ty()))
                             }
                             ty::PredicateKind::Trait(poly_trait_ref, _) => {
                                 let p = poly_trait_ref.trait_ref;
@@ -728,7 +732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             .map(|(_, path)| path)
                             .collect::<Vec<_>>()
                             .join("\n");
-                        let actual_prefix = actual.prefix_string();
+                        let actual_prefix = actual.prefix_string(self.tcx);
                         err.set_primary_message(&format!(
                             "the {item_kind} `{item_name}` exists for {actual_prefix} `{ty_str}`, but its trait bounds were not satisfied"
                         ));
@@ -1142,7 +1146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             let trait_def_ids: FxHashSet<DefId> = param
                                 .bounds
                                 .iter()
-                                .filter_map(|bound| Some(bound.trait_ref()?.trait_def_id()?))
+                                .filter_map(|bound| bound.trait_ref()?.trait_def_id())
                                 .collect();
                             if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
                                 err.span_suggestions(
@@ -1352,17 +1356,15 @@ fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
 
     // Crate-local:
 
-    struct Visitor<'a, 'tcx> {
-        map: &'a hir_map::Map<'tcx>,
+    struct Visitor<'a> {
         traits: &'a mut Vec<DefId>,
     }
 
-    impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> {
+    impl<'v, 'a> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a> {
         fn visit_item(&mut self, i: &'v hir::Item<'v>) {
             match i.kind {
                 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) => {
-                    let def_id = self.map.local_def_id(i.hir_id);
-                    self.traits.push(def_id.to_def_id());
+                    self.traits.push(i.def_id.to_def_id());
                 }
                 _ => (),
             }
@@ -1375,7 +1377,7 @@ fn compute_all_traits(tcx: TyCtxt<'_>) -> Vec<DefId> {
         fn visit_foreign_item(&mut self, _foreign_item: &hir::ForeignItem<'_>) {}
     }
 
-    tcx.hir().krate().visit_all_item_likes(&mut Visitor { map: &tcx.hir(), traits: &mut traits });
+    tcx.hir().krate().visit_all_item_likes(&mut Visitor { traits: &mut traits });
 
     // Cross-crate:
 
@@ -1445,8 +1447,8 @@ impl intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> {
             return;
         }
         // Find a `use` statement.
-        for item_id in module.item_ids {
-            let item = self.tcx.hir().expect_item(item_id.id);
+        for &item_id in module.item_ids {
+            let item = self.tcx.hir().item(item_id);
             match item.kind {
                 hir::ItemKind::Use(..) => {
                     // Don't suggest placing a `use` before the prelude
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index dc3e3b4e738..fce7ae8119e 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -502,6 +502,7 @@ fn typeck_with_fallback<'tcx>(
                     decl,
                     &hir::Generics::empty(),
                     None,
+                    None,
                 )
             } else {
                 tcx.fn_sig(def_id)
@@ -838,7 +839,7 @@ fn missing_items_err(
     // Obtain the level of indentation ending in `sugg_sp`.
     let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0);
     // Make the whitespace that will make the suggestion have the right indentation.
-    let padding: String = (0..indentation).map(|_| " ").collect();
+    let padding: String = std::iter::repeat(" ").take(indentation).collect();
 
     for trait_item in missing_items {
         let snippet = suggestion_signature(&trait_item, tcx);
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 9ab056c0d74..567cb1a90d0 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -681,7 +681,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         format!("cannot apply unary operator `{}`", op.as_str()),
                     );
                     match actual.kind() {
-                        Uint(_) if op == hir::UnOp::UnNeg => {
+                        Uint(_) if op == hir::UnOp::Neg => {
                             err.note("unsigned values cannot be negated");
 
                             if let hir::ExprKind::Unary(
@@ -711,9 +711,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         Ref(_, ref lty, _) if *lty.kind() == Str => {}
                         _ => {
                             let missing_trait = match op {
-                                hir::UnOp::UnNeg => "std::ops::Neg",
-                                hir::UnOp::UnNot => "std::ops::Not",
-                                hir::UnOp::UnDeref => "std::ops::UnDerf",
+                                hir::UnOp::Neg => "std::ops::Neg",
+                                hir::UnOp::Not => "std::ops::Not",
+                                hir::UnOp::Deref => "std::ops::UnDerf",
                             };
                             suggest_impl_missing(&mut err, operand_ty, &missing_trait);
                         }
@@ -782,9 +782,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     span_bug!(span, "&& and || are not overloadable")
                 }
             }
-        } else if let Op::Unary(hir::UnOp::UnNot, _) = op {
+        } else if let Op::Unary(hir::UnOp::Not, _) = op {
             (sym::not, lang.not_trait())
-        } else if let Op::Unary(hir::UnOp::UnNeg, _) = op {
+        } else if let Op::Unary(hir::UnOp::Neg, _) = op {
             (sym::neg, lang.neg_trait())
         } else {
             bug!("lookup_op_method: op not supported: {:?}", op)
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index d7e69668e5e..5df00ea1d75 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -150,7 +150,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ///
     /// Outside of this module, `check_pat_top` should always be used.
     /// Conversely, inside this module, `check_pat_top` should never be used.
-    #[instrument(skip(self, ti))]
+    #[instrument(level = "debug", skip(self, ti))]
     fn check_pat(
         &self,
         pat: &'tcx Pat<'tcx>,
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs
index 502cb562385..254e41706f9 100644
--- a/compiler/rustc_typeck/src/check/place_op.rs
+++ b/compiler/rustc_typeck/src/check/place_op.rs
@@ -203,7 +203,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         while let hir::ExprKind::Field(ref expr, _)
         | hir::ExprKind::Index(ref expr, _)
-        | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) = exprs.last().unwrap().kind
+        | hir::ExprKind::Unary(hir::UnOp::Deref, ref expr) = exprs.last().unwrap().kind
         {
             exprs.push(&expr);
         }
@@ -216,7 +216,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr);
 
             let mut source = self.node_ty(expr.hir_id);
-            if matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnDeref, _)) {
+            if matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::Deref, _)) {
                 // Clear previous flag; after a pointer indirection it does not apply any more.
                 inside_union = false;
             }
@@ -270,7 +270,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 hir::ExprKind::Index(ref base_expr, ..) => {
                     self.convert_place_op_to_mutable(PlaceOp::Index, expr, base_expr);
                 }
-                hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => {
+                hir::ExprKind::Unary(hir::UnOp::Deref, ref base_expr) => {
                     self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr);
                 }
                 _ => {}
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 04a9e65e664..69c09528662 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -40,13 +40,16 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_infer::infer::UpvarRegion;
-use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, ProjectionKind};
+use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeckResults, UpvarSubsts};
 use rustc_session::lint;
 use rustc_span::sym;
 use rustc_span::{MultiSpan, Span, Symbol};
 
+use rustc_index::vec::Idx;
+use rustc_target::abi::VariantIdx;
+
 /// Describe the relationship between the paths of two places
 /// eg:
 /// - `foo` is ancestor of `foo.bar.baz`
@@ -177,7 +180,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     debug!("seed place {:?}", place);
 
                     let upvar_id = ty::UpvarId::new(*var_hir_id, local_def_id);
-                    let capture_kind = self.init_capture_kind(capture_clause, upvar_id, span);
+                    let capture_kind =
+                        self.init_capture_kind_for_place(&place, capture_clause, upvar_id, span);
                     let fake_info = ty::CaptureInfo {
                         capture_kind_expr_id: None,
                         path_expr_id: None,
@@ -202,11 +206,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // If we have an origin, store it.
             if let Some(origin) = delegate.current_origin.clone() {
                 let origin = if self.tcx.features().capture_disjoint_fields {
-                    origin
+                    (origin.0, restrict_capture_precision(origin.1))
                 } else {
-                    // FIXME(project-rfc-2229#31): Once the changes to support reborrowing are
-                    //                             made, make sure we are selecting and restricting
-                    //                             the origin correctly.
                     (origin.0, Place { projections: vec![], ..origin.1 })
                 };
 
@@ -260,8 +261,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // local crate or were inlined into it along with some function.
         // This may change if abstract return types of some sort are
         // implemented.
-        let tcx = self.tcx;
-
         self.typeck_results
             .borrow()
             .closure_min_captures_flattened(closure_id)
@@ -276,7 +275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 match capture {
                     ty::UpvarCapture::ByValue(_) => upvar_ty,
-                    ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref(
+                    ty::UpvarCapture::ByRef(borrow) => self.tcx.mk_ref(
                         borrow.region,
                         ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() },
                     ),
@@ -448,7 +447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 base => bug!("Expected upvar, found={:?}", base),
             };
 
-            let place = restrict_capture_precision(place, capture_info.capture_kind);
+            let place = restrict_capture_precision(place);
 
             let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
                 None => {
@@ -537,7 +536,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         body: &'tcx hir::Body<'tcx>,
     ) {
-        let need_migrations = self.compute_2229_migrations_first_pass(
+        let need_migrations = self.compute_2229_migrations(
             closure_def_id,
             span,
             capture_clause,
@@ -546,9 +545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         );
 
         if !need_migrations.is_empty() {
-            let need_migrations_hir_id = need_migrations.iter().map(|m| m.0).collect::<Vec<_>>();
-
-            let migrations_text = migration_suggestion_for_2229(self.tcx, &need_migrations_hir_id);
+            let migrations_text = migration_suggestion_for_2229(self.tcx, &need_migrations);
 
             let local_def_id = closure_def_id.expect_local();
             let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
@@ -575,15 +572,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// - It would have been moved into the closure when `capture_disjoint_fields` wasn't
     ///   enabled, **and**
     /// - It wasn't completely captured by the closure, **and**
-    /// - The type of the root variable needs Drop.
-    fn compute_2229_migrations_first_pass(
+    /// - One of the paths starting at this root variable, that is not captured needs Drop.
+    fn compute_2229_migrations(
         &self,
         closure_def_id: DefId,
         closure_span: Span,
         closure_clause: hir::CaptureBy,
         body: &'tcx hir::Body<'tcx>,
         min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
-    ) -> Vec<(hir::HirId, Ty<'tcx>)> {
+    ) -> Vec<hir::HirId> {
         fn resolve_ty<T: TypeFoldable<'tcx>>(
             fcx: &FnCtxt<'_, 'tcx>,
             span: Span,
@@ -619,7 +616,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 match closure_clause {
                     // Only migrate if closure is a move closure
-                    hir::CaptureBy::Value => need_migrations.push((var_hir_id, ty)),
+                    hir::CaptureBy::Value => need_migrations.push(var_hir_id),
 
                     hir::CaptureBy::Ref => {}
                 }
@@ -627,30 +624,295 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 continue;
             };
 
-            let is_moved = root_var_min_capture_list
+            let projections_list = root_var_min_capture_list
                 .iter()
-                .any(|capture| matches!(capture.info.capture_kind, ty::UpvarCapture::ByValue(_)));
+                .filter_map(|captured_place| match captured_place.info.capture_kind {
+                    // Only care about captures that are moved into the closure
+                    ty::UpvarCapture::ByValue(..) => {
+                        Some(captured_place.place.projections.as_slice())
+                    }
+                    ty::UpvarCapture::ByRef(..) => None,
+                })
+                .collect::<Vec<_>>();
+
+            let is_moved = !projections_list.is_empty();
 
             let is_not_completely_captured =
                 root_var_min_capture_list.iter().any(|capture| capture.place.projections.len() > 0);
 
-            if is_moved && is_not_completely_captured {
-                need_migrations.push((var_hir_id, ty));
+            if is_moved
+                && is_not_completely_captured
+                && self.has_significant_drop_outside_of_captures(
+                    closure_def_id,
+                    closure_span,
+                    ty,
+                    projections_list,
+                )
+            {
+                need_migrations.push(var_hir_id);
             }
         }
 
         need_migrations
     }
 
-    fn init_capture_kind(
+    /// This is a helper function to `compute_2229_migrations_precise_pass`. Provided the type
+    /// of a root variable and a list of captured paths starting at this root variable (expressed
+    /// using list of `Projection` slices), it returns true if there is a path that is not
+    /// captured starting at this root variable that implements Drop.
+    ///
+    /// FIXME(project-rfc-2229#35): This should return true only for significant drops.
+    ///                             A drop is significant if it's implemented by the user or does
+    ///                             anything that will have any observable behavior (other than
+    ///                             freeing up memory).
+    ///
+    /// The way this function works is at a given call it looks at type `base_path_ty` of some base
+    /// path say P and then list of projection slices which represent the different captures moved
+    /// into the closure starting off of P.
+    ///
+    /// This will make more sense with an example:
+    ///
+    /// ```rust
+    /// #![feature(capture_disjoint_fields)]
+    ///
+    /// struct FancyInteger(i32); // This implements Drop
+    ///
+    /// struct Point { x: FancyInteger, y: FancyInteger }
+    /// struct Color;
+    ///
+    /// struct Wrapper { p: Point, c: Color }
+    ///
+    /// fn f(w: Wrapper) {
+    ///   let c = || {
+    ///       // Closure captures w.p.x and w.c by move.
+    ///   };
+    ///
+    ///   c();
+    /// }
+    /// ```
+    ///
+    /// If `capture_disjoint_fields` wasn't enabled the closure would've moved `w` instead of the
+    /// precise paths. If we look closely `w.p.y` isn't captured which implements Drop and
+    /// therefore Drop ordering would change and we want this function to return true.
+    ///
+    /// Call stack to figure out if we need to migrate for `w` would look as follows:
+    ///
+    /// Our initial base path is just `w`, and the paths captured from it are `w[p, x]` and
+    /// `w[c]`.
+    /// Notation:
+    /// - Ty(place): Type of place
+    /// - `(a, b)`: Represents the function parameters `base_path_ty` and `captured_projs`
+    /// respectively.
+    /// ```
+    ///                  (Ty(w), [ &[p, x], &[c] ])
+    ///                                 |
+    ///                    ----------------------------
+    ///                    |                          |
+    ///                    v                          v
+    ///        (Ty(w.p), [ &[x] ])          (Ty(w.c), [ &[] ]) // I(1)
+    ///                    |                          |
+    ///                    v                          v
+    ///        (Ty(w.p), [ &[x] ])                 false
+    ///                    |
+    ///                    |
+    ///          -------------------------------
+    ///          |                             |
+    ///          v                             v
+    ///     (Ty((w.p).x), [ &[] ])     (Ty((w.p).y), []) // IMP 2
+    ///          |                             |
+    ///          v                             v
+    ///        false                     NeedsDrop(Ty(w.p.y))
+    ///                                        |
+    ///                                        v
+    ///                                      true
+    /// ```
+    ///
+    /// IMP 1 `(Ty(w.c), [ &[] ])`: Notice the single empty slice inside `captured_projs`.
+    ///                             This implies that the `w.c` is completely captured by the closure.
+    ///                             Since drop for this path will be called when the closure is
+    ///                             dropped we don't need to migrate for it.
+    ///
+    /// IMP 2 `(Ty((w.p).y), [])`: Notice that `captured_projs` is empty. This implies that this
+    ///                             path wasn't captured by the closure. Also note that even
+    ///                             though we didn't capture this path, the function visits it,
+    ///                             which is kind of the point of this function. We then return
+    ///                             if the type of `w.p.y` implements Drop, which in this case is
+    ///                             true.
+    ///
+    /// Consider another example:
+    ///
+    /// ```rust
+    /// struct X;
+    /// impl Drop for X {}
+    ///
+    /// struct Y(X);
+    /// impl Drop for Y {}
+    ///
+    /// fn foo() {
+    ///     let y = Y(X);
+    ///     let c = || move(y.0);
+    /// }
+    /// ```
+    ///
+    /// Note that `y.0` is captured by the closure. When this function is called for `y`, it will
+    /// return true, because even though all paths starting at `y` are captured, `y` itself
+    /// implements Drop which will be affected since `y` isn't completely captured.
+    fn has_significant_drop_outside_of_captures(
+        &self,
+        closure_def_id: DefId,
+        closure_span: Span,
+        base_path_ty: Ty<'tcx>,
+        captured_projs: Vec<&[Projection<'tcx>]>,
+    ) -> bool {
+        let needs_drop = |ty: Ty<'tcx>| {
+            ty.needs_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local()))
+        };
+
+        let is_drop_defined_for_ty = |ty: Ty<'tcx>| {
+            let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span));
+            let ty_params = self.tcx.mk_substs_trait(base_path_ty, &[]);
+            self.tcx.type_implements_trait((
+                drop_trait,
+                ty,
+                ty_params,
+                self.tcx.param_env(closure_def_id.expect_local()),
+            ))
+        };
+
+        let is_drop_defined_for_ty = is_drop_defined_for_ty(base_path_ty);
+
+        // If there is a case where no projection is applied on top of current place
+        // then there must be exactly one capture corresponding to such a case. Note that this
+        // represents the case of the path being completely captured by the variable.
+        //
+        // eg. If `a.b` is captured and we are processing `a.b`, then we can't have the closure also
+        //     capture `a.b.c`, because that voilates min capture.
+        let is_completely_captured = captured_projs.iter().any(|projs| projs.is_empty());
+
+        assert!(!is_completely_captured || (captured_projs.len() == 1));
+
+        if is_completely_captured {
+            // The place is captured entirely, so doesn't matter if needs dtor, it will be drop
+            // when the closure is dropped.
+            return false;
+        }
+
+        if is_drop_defined_for_ty {
+            // If drop is implemented for this type then we need it to be fully captured,
+            // which we know it is not because of the previous check. Therefore we need to
+            // do migrate.
+            return true;
+        }
+
+        if captured_projs.is_empty() {
+            return needs_drop(base_path_ty);
+        }
+
+        match base_path_ty.kind() {
+            // Observations:
+            // - `captured_projs` is not empty. Therefore we can call
+            //   `captured_projs.first().unwrap()` safely.
+            // - All entries in `captured_projs` have atleast one projection.
+            //   Therefore we can call `captured_projs.first().unwrap().first().unwrap()` safely.
+
+            // We don't capture derefs in case of move captures, which would have be applied to
+            // access any further paths.
+            ty::Adt(def, _) if def.is_box() => unreachable!(),
+            ty::Ref(..) => unreachable!(),
+            ty::RawPtr(..) => unreachable!(),
+
+            ty::Adt(def, substs) => {
+                // Multi-varaint enums are captured in entirety,
+                // which would've been handled in the case of single empty slice in `captured_projs`.
+                assert_eq!(def.variants.len(), 1);
+
+                // Only Field projections can be applied to a non-box Adt.
+                assert!(
+                    captured_projs.iter().all(|projs| matches!(
+                        projs.first().unwrap().kind,
+                        ProjectionKind::Field(..)
+                    ))
+                );
+                def.variants.get(VariantIdx::new(0)).unwrap().fields.iter().enumerate().any(
+                    |(i, field)| {
+                        let paths_using_field = captured_projs
+                            .iter()
+                            .filter_map(|projs| {
+                                if let ProjectionKind::Field(field_idx, _) =
+                                    projs.first().unwrap().kind
+                                {
+                                    if (field_idx as usize) == i { Some(&projs[1..]) } else { None }
+                                } else {
+                                    unreachable!();
+                                }
+                            })
+                            .collect();
+
+                        let after_field_ty = field.ty(self.tcx, substs);
+                        self.has_significant_drop_outside_of_captures(
+                            closure_def_id,
+                            closure_span,
+                            after_field_ty,
+                            paths_using_field,
+                        )
+                    },
+                )
+            }
+
+            ty::Tuple(..) => {
+                // Only Field projections can be applied to a tuple.
+                assert!(
+                    captured_projs.iter().all(|projs| matches!(
+                        projs.first().unwrap().kind,
+                        ProjectionKind::Field(..)
+                    ))
+                );
+
+                base_path_ty.tuple_fields().enumerate().any(|(i, element_ty)| {
+                    let paths_using_field = captured_projs
+                        .iter()
+                        .filter_map(|projs| {
+                            if let ProjectionKind::Field(field_idx, _) = projs.first().unwrap().kind
+                            {
+                                if (field_idx as usize) == i { Some(&projs[1..]) } else { None }
+                            } else {
+                                unreachable!();
+                            }
+                        })
+                        .collect();
+
+                    self.has_significant_drop_outside_of_captures(
+                        closure_def_id,
+                        closure_span,
+                        element_ty,
+                        paths_using_field,
+                    )
+                })
+            }
+
+            // Anything else would be completely captured and therefore handled already.
+            _ => unreachable!(),
+        }
+    }
+
+    fn init_capture_kind_for_place(
         &self,
+        place: &Place<'tcx>,
         capture_clause: hir::CaptureBy,
         upvar_id: ty::UpvarId,
         closure_span: Span,
     ) -> ty::UpvarCapture<'tcx> {
         match capture_clause {
-            hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None),
-            hir::CaptureBy::Ref => {
+            // In case of a move closure if the data is accessed through a reference we
+            // want to capture by ref to allow precise capture using reborrows.
+            //
+            // If the data will be moved out of this place, then the place will be truncated
+            // at the first Deref in `adjust_upvar_borrow_kind_for_consume` and then moved into
+            // the closure.
+            hir::CaptureBy::Value if !place.deref_tys().any(ty::TyS::is_ref) => {
+                ty::UpvarCapture::ByValue(None)
+            }
+            hir::CaptureBy::Value | hir::CaptureBy::Ref => {
                 let origin = UpvarRegion(upvar_id, closure_span);
                 let upvar_region = self.next_region_var(origin);
                 let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
@@ -854,12 +1116,25 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
             place_with_id, diag_expr_id, mode
         );
 
-        // we only care about moves
-        match mode {
-            euv::Copy => {
+        match (self.capture_clause, mode) {
+            // In non-move closures, we only care about moves
+            (hir::CaptureBy::Ref, euv::Copy) => return,
+
+            // We want to capture Copy types that read through a ref via a reborrow
+            (hir::CaptureBy::Value, euv::Copy)
+                if place_with_id.place.deref_tys().any(ty::TyS::is_ref) =>
+            {
                 return;
             }
-            euv::Move => {}
+
+            (hir::CaptureBy::Ref, euv::Move) | (hir::CaptureBy::Value, euv::Move | euv::Copy) => {}
+        };
+
+        let place = truncate_capture_for_move(place_with_id.place.clone());
+        let place_with_id = PlaceWithHirId { place: place.clone(), hir_id: place_with_id.hir_id };
+
+        if !self.capture_information.contains_key(&place) {
+            self.init_capture_info_for_place(&place_with_id, diag_expr_id);
         }
 
         let tcx = self.fcx.tcx;
@@ -873,13 +1148,15 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
 
         let usage_span = tcx.hir().span(diag_expr_id);
 
-        // To move out of an upvar, this must be a FnOnce closure
-        self.adjust_closure_kind(
-            upvar_id.closure_expr_id,
-            ty::ClosureKind::FnOnce,
-            usage_span,
-            place_with_id.place.clone(),
-        );
+        if matches!(mode, euv::Move) {
+            // To move out of an upvar, this must be a FnOnce closure
+            self.adjust_closure_kind(
+                upvar_id.closure_expr_id,
+                ty::ClosureKind::FnOnce,
+                usage_span,
+                place.clone(),
+            );
+        }
 
         let capture_info = ty::CaptureInfo {
             capture_kind_expr_id: Some(diag_expr_id),
@@ -1062,8 +1339,12 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
         if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
             assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id);
 
-            let capture_kind =
-                self.fcx.init_capture_kind(self.capture_clause, upvar_id, self.closure_span);
+            let capture_kind = self.fcx.init_capture_kind_for_place(
+                &place_with_id.place,
+                self.capture_clause,
+                upvar_id,
+                self.closure_span,
+            );
 
             let expr_id = Some(diag_expr_id);
             let capture_info = ty::CaptureInfo {
@@ -1137,15 +1418,10 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
 }
 
 /// Truncate projections so that following rules are obeyed by the captured `place`:
-///
-/// - No Derefs in move closure, this will result in value behind a reference getting moved.
 /// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
 ///   them completely.
 /// - No Index projections are captured, since arrays are captured completely.
-fn restrict_capture_precision<'tcx>(
-    mut place: Place<'tcx>,
-    capture_kind: ty::UpvarCapture<'tcx>,
-) -> Place<'tcx> {
+fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
     if place.projections.is_empty() {
         // Nothing to do here
         return place;
@@ -1157,7 +1433,6 @@ fn restrict_capture_precision<'tcx>(
     }
 
     let mut truncated_length = usize::MAX;
-    let mut first_deref_projection = usize::MAX;
 
     for (i, proj) in place.projections.iter().enumerate() {
         if proj.ty.is_unsafe_ptr() {
@@ -1171,31 +1446,30 @@ fn restrict_capture_precision<'tcx>(
                 truncated_length = truncated_length.min(i);
                 break;
             }
-            ProjectionKind::Deref => {
-                // We only drop Derefs in case of move closures
-                // There might be an index projection or raw ptr ahead, so we don't stop here.
-                first_deref_projection = first_deref_projection.min(i);
-            }
+            ProjectionKind::Deref => {}
             ProjectionKind::Field(..) => {} // ignore
             ProjectionKind::Subslice => {}  // We never capture this
         }
     }
 
-    let length = place
-        .projections
-        .len()
-        .min(truncated_length)
-        // In case of capture `ByValue` we want to not capture derefs
-        .min(match capture_kind {
-            ty::UpvarCapture::ByValue(..) => first_deref_projection,
-            ty::UpvarCapture::ByRef(..) => usize::MAX,
-        });
+    let length = place.projections.len().min(truncated_length);
 
     place.projections.truncate(length);
 
     place
 }
 
+/// Truncates a place so that the resultant capture doesn't move data out of a reference
+fn truncate_capture_for_move(mut place: Place<'tcx>) -> Place<'tcx> {
+    if let Some(i) = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref) {
+        // We only drop Derefs in case of move closures
+        // There might be an index projection or raw ptr ahead, so we don't stop here.
+        place.projections.truncate(i);
+    }
+
+    place
+}
+
 fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
     let variable_name = match place.base {
         PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(),
@@ -1211,7 +1485,7 @@ fn construct_place_string(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
             ProjectionKind::Subslice => String::from("Subslice"),
         };
         if i != 0 {
-            projections_str.push_str(",");
+            projections_str.push(',');
         }
         projections_str.push_str(proj.as_str());
     }
@@ -1382,14 +1656,8 @@ fn determine_place_ancestry_relation(
     // Assume of length of projections_b = m
     let projections_b = &place_b.projections;
 
-    let mut same_initial_projections = true;
-
-    for (proj_a, proj_b) in projections_a.iter().zip(projections_b.iter()) {
-        if proj_a != proj_b {
-            same_initial_projections = false;
-            break;
-        }
-    }
+    let same_initial_projections =
+        projections_a.iter().zip(projections_b.iter()).all(|(proj_a, proj_b)| proj_a == proj_b);
 
     if same_initial_projections {
         // First min(n, m) projections are the same
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index c90db4786e3..00c6550835b 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -80,8 +80,8 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let item = tcx.hir().expect_item(hir_id);
 
     debug!(
-        "check_item_well_formed(it.hir_id={:?}, it.name={})",
-        item.hir_id,
+        "check_item_well_formed(it.def_id={:?}, it.name={})",
+        item.def_id,
         tcx.def_path_str(def_id.to_def_id())
     );
 
@@ -105,7 +105,7 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         // for `T`
         hir::ItemKind::Impl(ref impl_) => {
             let is_auto = tcx
-                .impl_trait_ref(tcx.hir().local_def_id(item.hir_id))
+                .impl_trait_ref(item.def_id)
                 .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.def_id));
             if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
                 let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
@@ -141,23 +141,23 @@ pub fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             }
         }
         hir::ItemKind::Fn(ref sig, ..) => {
-            check_item_fn(tcx, item.hir_id, item.ident, item.span, sig.decl);
+            check_item_fn(tcx, item.hir_id(), item.ident, item.span, sig.decl);
         }
         hir::ItemKind::Static(ref ty, ..) => {
-            check_item_type(tcx, item.hir_id, ty.span, false);
+            check_item_type(tcx, item.hir_id(), ty.span, false);
         }
         hir::ItemKind::Const(ref ty, ..) => {
-            check_item_type(tcx, item.hir_id, ty.span, false);
+            check_item_type(tcx, item.hir_id(), ty.span, false);
         }
         hir::ItemKind::ForeignMod { items, .. } => {
             for it in items.iter() {
                 let it = tcx.hir().foreign_item(it.id);
                 match it.kind {
                     hir::ForeignItemKind::Fn(ref decl, ..) => {
-                        check_item_fn(tcx, it.hir_id, it.ident, it.span, decl)
+                        check_item_fn(tcx, it.hir_id(), it.ident, it.span, decl)
                     }
                     hir::ForeignItemKind::Static(ref ty, ..) => {
-                        check_item_type(tcx, it.hir_id, ty.span, true)
+                        check_item_type(tcx, it.hir_id(), ty.span, true)
                     }
                     hir::ForeignItemKind::Type => (),
                 }
@@ -197,7 +197,7 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         _ => None,
     };
     check_object_unsafe_self_trait_by_name(tcx, &trait_item);
-    check_associated_item(tcx, trait_item.hir_id, trait_item.span, method_sig);
+    check_associated_item(tcx, trait_item.hir_id(), trait_item.span, method_sig);
 }
 
 fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
@@ -213,9 +213,9 @@ fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
 /// Detect when an object unsafe trait is referring to itself in one of its associated items.
 /// When this is done, suggest using `Self` instead.
 fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) {
-    let (trait_name, trait_def_id) = match tcx.hir().get(tcx.hir().get_parent_item(item.hir_id)) {
+    let (trait_name, trait_def_id) = match tcx.hir().get(tcx.hir().get_parent_item(item.hir_id())) {
         hir::Node::Item(item) => match item.kind {
-            hir::ItemKind::Trait(..) => (item.ident, tcx.hir().local_def_id(item.hir_id)),
+            hir::ItemKind::Trait(..) => (item.ident, item.def_id),
             _ => return,
         },
         _ => return,
@@ -271,7 +271,7 @@ pub fn check_impl_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         _ => None,
     };
 
-    check_associated_item(tcx, impl_item.hir_id, impl_item.span, method_sig);
+    check_associated_item(tcx, impl_item.hir_id(), impl_item.span, method_sig);
 }
 
 fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
@@ -432,7 +432,7 @@ fn check_associated_item(
 }
 
 fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<'tcx> {
-    for_id(tcx, item.hir_id, item.span)
+    for_id(tcx, item.hir_id(), item.span)
 }
 
 fn for_id(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) -> CheckWfFcxBuilder<'_> {
@@ -465,8 +465,7 @@ fn check_type_defn<'tcx, F>(
 {
     for_item(tcx, item).with_fcx(|fcx, fcx_tcx| {
         let variants = lookup_fields(fcx);
-        let def_id = fcx.tcx.hir().local_def_id(item.hir_id);
-        let packed = fcx.tcx.adt_def(def_id).repr.packed();
+        let packed = fcx.tcx.adt_def(item.def_id).repr.packed();
 
         for variant in &variants {
             // For DST, or when drop needs to copy things around, all
@@ -482,7 +481,7 @@ fn check_type_defn<'tcx, F>(
                         // Just treat unresolved type expression as if it needs drop.
                         true
                     } else {
-                        ty.needs_drop(fcx_tcx, fcx_tcx.param_env(def_id))
+                        ty.needs_drop(fcx_tcx, fcx_tcx.param_env(item.def_id))
                     }
                 }
             };
@@ -541,7 +540,7 @@ fn check_type_defn<'tcx, F>(
             }
         }
 
-        check_where_clauses(tcx, fcx, item.span, def_id.to_def_id(), None);
+        check_where_clauses(tcx, fcx, item.span, item.def_id.to_def_id(), None);
 
         // No implied bounds in a struct definition.
         vec![]
@@ -549,15 +548,13 @@ fn check_type_defn<'tcx, F>(
 }
 
 fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
-    debug!("check_trait: {:?}", item.hir_id);
+    debug!("check_trait: {:?}", item.def_id);
 
-    let trait_def_id = tcx.hir().local_def_id(item.hir_id);
-
-    let trait_def = tcx.trait_def(trait_def_id);
+    let trait_def = tcx.trait_def(item.def_id);
     if trait_def.is_marker
         || matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker)
     {
-        for associated_def_id in &*tcx.associated_item_def_ids(trait_def_id) {
+        for associated_def_id in &*tcx.associated_item_def_ids(item.def_id) {
             struct_span_err!(
                 tcx.sess,
                 tcx.def_span(*associated_def_id),
@@ -569,7 +566,7 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
     }
 
     for_item(tcx, item).with_fcx(|fcx, _| {
-        check_where_clauses(tcx, fcx, item.span, trait_def_id.to_def_id(), None);
+        check_where_clauses(tcx, fcx, item.span, item.def_id.to_def_id(), None);
 
         vec![]
     });
@@ -665,14 +662,12 @@ fn check_impl<'tcx>(
     debug!("check_impl: {:?}", item);
 
     for_item(tcx, item).with_fcx(|fcx, tcx| {
-        let item_def_id = fcx.tcx.hir().local_def_id(item.hir_id);
-
         match *ast_trait_ref {
             Some(ref ast_trait_ref) => {
                 // `#[rustc_reservation_impl]` impls are not real impls and
                 // therefore don't need to be WF (the trait's `Self: Trait` predicate
                 // won't hold).
-                let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
+                let trait_ref = fcx.tcx.impl_trait_ref(item.def_id).unwrap();
                 let trait_ref =
                     fcx.normalize_associated_types_in(ast_trait_ref.path.span, trait_ref);
                 let obligations = traits::wf::trait_obligations(
@@ -688,7 +683,7 @@ fn check_impl<'tcx>(
                 }
             }
             None => {
-                let self_ty = fcx.tcx.type_of(item_def_id);
+                let self_ty = fcx.tcx.type_of(item.def_id);
                 let self_ty = fcx.normalize_associated_types_in(item.span, self_ty);
                 fcx.register_wf_obligation(
                     self_ty.into(),
@@ -698,9 +693,9 @@ fn check_impl<'tcx>(
             }
         }
 
-        check_where_clauses(tcx, fcx, item.span, item_def_id.to_def_id(), None);
+        check_where_clauses(tcx, fcx, item.span, item.def_id.to_def_id(), None);
 
-        fcx.impl_implied_bounds(item_def_id.to_def_id(), item.span)
+        fcx.impl_implied_bounds(item.def_id.to_def_id(), item.span)
     });
 }
 
@@ -1238,15 +1233,14 @@ fn check_variances_for_type_defn<'tcx>(
     item: &hir::Item<'tcx>,
     hir_generics: &hir::Generics<'_>,
 ) {
-    let item_def_id = tcx.hir().local_def_id(item.hir_id);
-    let ty = tcx.type_of(item_def_id);
+    let ty = tcx.type_of(item.def_id);
     if tcx.has_error_field(ty) {
         return;
     }
 
-    let ty_predicates = tcx.predicates_of(item_def_id);
+    let ty_predicates = tcx.predicates_of(item.def_id);
     assert_eq!(ty_predicates.parent, None);
-    let variances = tcx.variances_of(item_def_id);
+    let variances = tcx.variances_of(item.def_id);
 
     let mut constrained_parameters: FxHashSet<_> = variances
         .iter()
@@ -1354,22 +1348,19 @@ impl Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
 
     fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) {
         debug!("visit_item: {:?}", i);
-        let def_id = self.tcx.hir().local_def_id(i.hir_id);
-        self.tcx.ensure().check_item_well_formed(def_id);
+        self.tcx.ensure().check_item_well_formed(i.def_id);
         hir_visit::walk_item(self, i);
     }
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
         debug!("visit_trait_item: {:?}", trait_item);
-        let def_id = self.tcx.hir().local_def_id(trait_item.hir_id);
-        self.tcx.ensure().check_trait_item_well_formed(def_id);
+        self.tcx.ensure().check_trait_item_well_formed(trait_item.def_id);
         hir_visit::walk_trait_item(self, trait_item);
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
         debug!("visit_impl_item: {:?}", impl_item);
-        let def_id = self.tcx.hir().local_def_id(impl_item.hir_id);
-        self.tcx.ensure().check_impl_item_well_formed(def_id);
+        self.tcx.ensure().check_impl_item_well_formed(impl_item.def_id);
         hir_visit::walk_impl_item(self, impl_item);
     }
 
diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs
index 4d18b2cb3fc..4f785982150 100644
--- a/compiler/rustc_typeck/src/check/writeback.rs
+++ b/compiler/rustc_typeck/src/check/writeback.rs
@@ -138,7 +138,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
     // operating on scalars, we clear the overload.
     fn fix_scalar_builtin_expr(&mut self, e: &hir::Expr<'_>) {
         match e.kind {
-            hir::ExprKind::Unary(hir::UnOp::UnNeg | hir::UnOp::UnNot, ref inner) => {
+            hir::ExprKind::Unary(hir::UnOp::Neg | hir::UnOp::Not, ref inner) => {
                 let inner_ty = self.fcx.node_ty(inner.hir_id);
                 let inner_ty = self.fcx.resolve_vars_if_possible(inner_ty);
 
diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs
index 31121ece898..e1743a5dfc1 100644
--- a/compiler/rustc_typeck/src/check_unused.rs
+++ b/compiler/rustc_typeck/src/check_unused.rs
@@ -28,7 +28,7 @@ impl ItemLikeVisitor<'v> for CheckVisitor<'tcx> {
             return;
         }
         if let hir::ItemKind::Use(ref path, _) = item.kind {
-            self.check_import(item.hir_id, path.span);
+            self.check_import(item.item_id(), path.span);
         }
     }
 
@@ -45,24 +45,28 @@ struct CheckVisitor<'tcx> {
 }
 
 impl CheckVisitor<'tcx> {
-    fn check_import(&self, id: hir::HirId, span: Span) {
-        let def_id = self.tcx.hir().local_def_id(id);
-        if !self.tcx.maybe_unused_trait_import(def_id) {
+    fn check_import(&self, item_id: hir::ItemId, span: Span) {
+        if !self.tcx.maybe_unused_trait_import(item_id.def_id) {
             return;
         }
 
-        if self.used_trait_imports.contains(&def_id) {
+        if self.used_trait_imports.contains(&item_id.def_id) {
             return;
         }
 
-        self.tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, id, span, |lint| {
-            let msg = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                format!("unused import: `{}`", snippet)
-            } else {
-                "unused import".to_owned()
-            };
-            lint.build(&msg).emit();
-        });
+        self.tcx.struct_span_lint_hir(
+            lint::builtin::UNUSED_IMPORTS,
+            item_id.hir_id(),
+            span,
+            |lint| {
+                let msg = if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+                    format!("unused import: `{}`", snippet)
+                } else {
+                    "unused import".to_owned()
+                };
+                lint.build(&msg).emit();
+            },
+        );
     }
 }
 
@@ -109,7 +113,6 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
     // Collect all the extern crates (in a reliable order).
     let mut crates_to_lint = vec![];
     tcx.hir().krate().visit_all_item_likes(&mut CollectExternCrateVisitor {
-        tcx,
         crates_to_lint: &mut crates_to_lint,
     });
 
@@ -189,8 +192,7 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) {
     }
 }
 
-struct CollectExternCrateVisitor<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct CollectExternCrateVisitor<'a> {
     crates_to_lint: &'a mut Vec<ExternCrateToLint>,
 }
 
@@ -211,12 +213,11 @@ struct ExternCrateToLint {
     warn_if_unused: bool,
 }
 
-impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CollectExternCrateVisitor<'a, 'tcx> {
+impl<'a, 'v> ItemLikeVisitor<'v> for CollectExternCrateVisitor<'a> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
         if let hir::ItemKind::ExternCrate(orig_name) = item.kind {
-            let extern_crate_def_id = self.tcx.hir().local_def_id(item.hir_id);
             self.crates_to_lint.push(ExternCrateToLint {
-                def_id: extern_crate_def_id.to_def_id(),
+                def_id: item.def_id.to_def_id(),
                 span: item.span,
                 orig_name,
                 warn_if_unused: !item.ident.as_str().starts_with('_'),
diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs
index 6726b9b4a4b..5b44cb7eae5 100644
--- a/compiler/rustc_typeck/src/coherence/builtin.rs
+++ b/compiler/rustc_typeck/src/coherence/builtin.rs
@@ -38,8 +38,7 @@ impl<'tcx> Checker<'tcx> {
         F: FnMut(TyCtxt<'tcx>, LocalDefId),
     {
         if Some(self.trait_def_id) == trait_def_id {
-            for &impl_id in self.tcx.hir().trait_impls(self.trait_def_id) {
-                let impl_def_id = self.tcx.hir().local_def_id(impl_id);
+            for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) {
                 f(self.tcx, impl_def_id);
             }
         }
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
index 8a500852a03..cc592c7a260 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs
@@ -50,8 +50,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             _ => return,
         };
 
-        let def_id = self.tcx.hir().local_def_id(item.hir_id);
-        let self_ty = self.tcx.type_of(def_id);
+        let self_ty = self.tcx.type_of(item.def_id);
         let lang_items = self.tcx.lang_items();
         match *self_ty.kind() {
             ty::Adt(def, _) => {
@@ -65,7 +64,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Bool => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.bool_impl(),
                     None,
                     "bool",
@@ -76,7 +75,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Char => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.char_impl(),
                     None,
                     "char",
@@ -87,7 +86,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Str => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.str_impl(),
                     lang_items.str_alloc_impl(),
                     "str",
@@ -98,7 +97,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Slice(slice_item) if slice_item == self.tcx.types.u8 => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.slice_u8_impl(),
                     lang_items.slice_u8_alloc_impl(),
                     "slice_u8",
@@ -109,7 +108,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Slice(_) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.slice_impl(),
                     lang_items.slice_alloc_impl(),
                     "slice",
@@ -120,7 +119,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Array(_, _) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.array_impl(),
                     None,
                     "array",
@@ -133,7 +132,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                 if matches!(inner.kind(), ty::Slice(_)) =>
             {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.const_slice_ptr_impl(),
                     None,
                     "const_slice_ptr",
@@ -146,7 +145,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
                 if matches!(inner.kind(), ty::Slice(_)) =>
             {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.mut_slice_ptr_impl(),
                     None,
                     "mut_slice_ptr",
@@ -157,7 +156,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Not }) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.const_ptr_impl(),
                     None,
                     "const_ptr",
@@ -168,7 +167,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::RawPtr(ty::TypeAndMut { ty: _, mutbl: hir::Mutability::Mut }) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.mut_ptr_impl(),
                     None,
                     "mut_ptr",
@@ -179,7 +178,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Int(ty::IntTy::I8) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.i8_impl(),
                     None,
                     "i8",
@@ -190,7 +189,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Int(ty::IntTy::I16) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.i16_impl(),
                     None,
                     "i16",
@@ -201,7 +200,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Int(ty::IntTy::I32) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.i32_impl(),
                     None,
                     "i32",
@@ -212,7 +211,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Int(ty::IntTy::I64) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.i64_impl(),
                     None,
                     "i64",
@@ -223,7 +222,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Int(ty::IntTy::I128) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.i128_impl(),
                     None,
                     "i128",
@@ -234,7 +233,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Int(ty::IntTy::Isize) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.isize_impl(),
                     None,
                     "isize",
@@ -245,7 +244,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Uint(ty::UintTy::U8) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.u8_impl(),
                     None,
                     "u8",
@@ -256,7 +255,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Uint(ty::UintTy::U16) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.u16_impl(),
                     None,
                     "u16",
@@ -267,7 +266,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Uint(ty::UintTy::U32) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.u32_impl(),
                     None,
                     "u32",
@@ -278,7 +277,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Uint(ty::UintTy::U64) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.u64_impl(),
                     None,
                     "u64",
@@ -289,7 +288,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Uint(ty::UintTy::U128) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.u128_impl(),
                     None,
                     "u128",
@@ -300,7 +299,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Uint(ty::UintTy::Usize) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.usize_impl(),
                     None,
                     "usize",
@@ -311,7 +310,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Float(ty::FloatTy::F32) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.f32_impl(),
                     lang_items.f32_runtime_impl(),
                     "f32",
@@ -322,7 +321,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> {
             }
             ty::Float(ty::FloatTy::F64) => {
                 self.check_primitive_impl(
-                    def_id,
+                    item.def_id,
                     lang_items.f64_impl(),
                     lang_items.f64_runtime_impl(),
                     "f64",
@@ -369,9 +368,8 @@ impl InherentCollect<'tcx> {
             // Add the implementation to the mapping from implementation to base
             // type def ID, if there is a base type for this implementation and
             // the implementation does not have any associated traits.
-            let impl_def_id = self.tcx.hir().local_def_id(item.hir_id);
             let vec = self.impls_map.inherent_impls.entry(def_id).or_default();
-            vec.push(impl_def_id.to_def_id());
+            vec.push(item.def_id.to_def_id());
         } else {
             struct_span_err!(
                 self.tcx.sess,
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
index 50d88674328..29654099992 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
@@ -123,8 +123,7 @@ impl ItemLikeVisitor<'v> for InherentOverlapChecker<'tcx> {
             | hir::ItemKind::Struct(..)
             | hir::ItemKind::Trait(..)
             | hir::ItemKind::Union(..) => {
-                let ty_def_id = self.tcx.hir().local_def_id(item.hir_id);
-                let impls = self.tcx.inherent_impls(ty_def_id);
+                let impls = self.tcx.inherent_impls(item.def_id);
 
                 // If there is only one inherent impl block,
                 // there is nothing to overlap check it with
diff --git a/compiler/rustc_typeck/src/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs
index 4294450333c..f04782a1f44 100644
--- a/compiler/rustc_typeck/src/coherence/mod.rs
+++ b/compiler/rustc_typeck/src/coherence/mod.rs
@@ -48,7 +48,20 @@ fn enforce_trait_manually_implementable(
     let did = Some(trait_def_id);
     let li = tcx.lang_items();
 
-    // Disallow *all* explicit impls of `DiscriminantKind`, `Sized` and `Unsize` for now.
+    // Disallow *all* explicit impls of `Pointee`, `DiscriminantKind`, `Sized` and `Unsize` for now.
+    if did == li.pointee_trait() {
+        let span = impl_header_span(tcx, impl_def_id);
+        struct_span_err!(
+            tcx.sess,
+            span,
+            E0322,
+            "explicit impls for the `Pointee` trait are not permitted"
+        )
+        .span_label(span, "impl of 'Pointee' not allowed")
+        .emit();
+        return;
+    }
+
     if did == li.discriminant_kind_trait() {
         let span = impl_header_span(tcx, impl_def_id);
         struct_span_err!(
@@ -172,8 +185,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) {
     tcx.ensure().specialization_graph_of(def_id);
 
     let impls = tcx.hir().trait_impls(def_id);
-    for &hir_id in impls {
-        let impl_def_id = tcx.hir().local_def_id(hir_id);
+    for &impl_def_id in impls {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
 
         check_impl(tcx, impl_def_id, trait_ref);
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs
index 9333aac6018..05932427bcf 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_typeck/src/coherence/orphan.rs
@@ -24,7 +24,6 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> {
     /// to prevent inundating the user with a bunch of similar error
     /// reports.
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        let def_id = self.tcx.hir().local_def_id(item.hir_id);
         // "Trait" impl
         if let hir::ItemKind::Impl(hir::Impl {
             generics, of_trait: Some(ref tr), self_ty, ..
@@ -32,13 +31,13 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> {
         {
             debug!(
                 "coherence2::orphan check: trait impl {}",
-                self.tcx.hir().node_to_string(item.hir_id)
+                self.tcx.hir().node_to_string(item.hir_id())
             );
-            let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
+            let trait_ref = self.tcx.impl_trait_ref(item.def_id).unwrap();
             let trait_def_id = trait_ref.def_id;
             let sm = self.tcx.sess.source_map();
             let sp = sm.guess_head_span(item.span);
-            match traits::orphan_check(self.tcx, def_id.to_def_id()) {
+            match traits::orphan_check(self.tcx, item.def_id.to_def_id()) {
                 Ok(()) => {}
                 Err(traits::OrphanCheckErr::NonLocalInputType(tys)) => {
                     let mut err = struct_span_err!(
diff --git a/compiler/rustc_typeck/src/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs
index 3a290b7756e..6b995b97386 100644
--- a/compiler/rustc_typeck/src/coherence/unsafety.rs
+++ b/compiler/rustc_typeck/src/coherence/unsafety.rs
@@ -24,8 +24,7 @@ impl UnsafetyChecker<'tcx> {
         unsafety: hir::Unsafety,
         polarity: hir::ImplPolarity,
     ) {
-        let local_did = self.tcx.hir().local_def_id(item.hir_id);
-        if let Some(trait_ref) = self.tcx.impl_trait_ref(local_did) {
+        if let Some(trait_ref) = self.tcx.impl_trait_ref(item.def_id) {
             let trait_def = self.tcx.trait_def(trait_ref.def_id);
             let unsafe_attr = impl_generics.and_then(|generics| {
                 generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle")
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index b1d98d75196..fc8e50b4b65 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 //! "Collection" is the process of determining the type and other external
 //! details of each item in Rust. Collection is specifically concerned
 //! with *inter-procedural* things -- for example, for a function
@@ -77,6 +78,7 @@ pub fn provide(providers: &mut Providers) {
         projection_ty_from_predicates,
         explicit_predicates_of,
         super_predicates_of,
+        super_predicates_that_define_assoc_type,
         trait_explicit_predicates_and_bounds,
         type_param_predicates,
         trait_def,
@@ -141,6 +143,7 @@ crate fn placeholder_type_error(
     generics: &[hir::GenericParam<'_>],
     placeholder_types: Vec<Span>,
     suggest: bool,
+    hir_ty: Option<&hir::Ty<'_>>,
 ) {
     if placeholder_types.is_empty() {
         return;
@@ -171,12 +174,40 @@ crate fn placeholder_type_error(
     }
 
     let mut err = bad_placeholder_type(tcx, placeholder_types);
+
+    // Suggest, but only if it is not a function in const or static
     if suggest {
-        err.multipart_suggestion(
-            "use type parameters instead",
-            sugg,
-            Applicability::HasPlaceholders,
-        );
+        let mut is_fn = false;
+        let mut is_const = false;
+        let mut is_static = false;
+
+        if let Some(hir_ty) = hir_ty {
+            if let hir::TyKind::BareFn(_) = hir_ty.kind {
+                is_fn = true;
+
+                // Check if parent is const or static
+                let parent_id = tcx.hir().get_parent_node(hir_ty.hir_id);
+                let parent_node = tcx.hir().get(parent_id);
+
+                if let hir::Node::Item(item) = parent_node {
+                    if let hir::ItemKind::Const(_, _) = item.kind {
+                        is_const = true;
+                    } else if let hir::ItemKind::Static(_, _, _) = item.kind {
+                        is_static = true;
+                    }
+                }
+            }
+        }
+
+        // if function is wrapped around a const or static,
+        // then don't show the suggestion
+        if !(is_fn && (is_const || is_static)) {
+            err.multipart_suggestion(
+                "use type parameters instead",
+                sugg,
+                Applicability::HasPlaceholders,
+            );
+        }
     }
     err.emit();
 }
@@ -198,7 +229,7 @@ fn reject_placeholder_type_signatures_in_item(tcx: TyCtxt<'tcx>, item: &'tcx hir
     let mut visitor = PlaceholderHirTyCollector::default();
     visitor.visit_item(item);
 
-    placeholder_type_error(tcx, Some(generics.span), &generics.params[..], visitor.0, suggest);
+    placeholder_type_error(tcx, Some(generics.span), generics.params, visitor.0, suggest, None);
 }
 
 impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
@@ -209,7 +240,7 @@ impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        convert_item(self.tcx, item.hir_id);
+        convert_item(self.tcx, item.item_id());
         reject_placeholder_type_signatures_in_item(self.tcx, item);
         intravisit::walk_item(self, item);
     }
@@ -243,12 +274,12 @@ impl Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
     }
 
     fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
-        convert_trait_item(self.tcx, trait_item.hir_id);
+        convert_trait_item(self.tcx, trait_item.trait_item_id());
         intravisit::walk_trait_item(self, trait_item);
     }
 
     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
-        convert_impl_item(self.tcx, impl_item.hir_id);
+        convert_impl_item(self.tcx, impl_item.impl_item_id());
         intravisit::walk_impl_item(self, impl_item);
     }
 }
@@ -278,7 +309,7 @@ impl ItemCtxt<'tcx> {
         ItemCtxt { tcx, item_def_id }
     }
 
-    pub fn to_ty(&self, ast_ty: &'tcx hir::Ty<'tcx>) -> Ty<'tcx> {
+    pub fn to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
         AstConv::ast_ty_to_ty(self, ast_ty)
     }
 
@@ -308,8 +339,17 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
         }
     }
 
-    fn get_type_parameter_bounds(&self, span: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> {
-        self.tcx.at(span).type_param_predicates((self.item_def_id, def_id.expect_local()))
+    fn get_type_parameter_bounds(
+        &self,
+        span: Span,
+        def_id: DefId,
+        assoc_name: Ident,
+    ) -> ty::GenericPredicates<'tcx> {
+        self.tcx.at(span).type_param_predicates((
+            self.item_def_id,
+            def_id.expect_local(),
+            assoc_name,
+        ))
     }
 
     fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option<ty::Region<'tcx>> {
@@ -370,7 +410,7 @@ impl AstConv<'tcx> for ItemCtxt<'tcx> {
                         | hir::ItemKind::Struct(_, generics)
                         | hir::ItemKind::Union(_, generics) => {
                             let lt_name = get_new_lifetime_name(self.tcx, poly_trait_ref, generics);
-                            let (lt_sp, sugg) = match &generics.params[..] {
+                            let (lt_sp, sugg) = match generics.params {
                                 [] => (generics.span, format!("<{}>", lt_name)),
                                 [bound, ..] => {
                                     (bound.span.shrink_to_lo(), format!("{}, ", lt_name))
@@ -490,7 +530,7 @@ fn get_new_lifetime_name<'tcx>(
 /// `X: Foo` where `X` is the type parameter `def_id`.
 fn type_param_predicates(
     tcx: TyCtxt<'_>,
-    (item_def_id, def_id): (DefId, LocalDefId),
+    (item_def_id, def_id, assoc_name): (DefId, LocalDefId, Ident),
 ) -> ty::GenericPredicates<'_> {
     use rustc_hir::*;
 
@@ -515,7 +555,7 @@ fn type_param_predicates(
     let mut result = parent
         .map(|parent| {
             let icx = ItemCtxt::new(tcx, parent);
-            icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id())
+            icx.get_type_parameter_bounds(DUMMY_SP, def_id.to_def_id(), assoc_name)
         })
         .unwrap_or_default();
     let mut extend = None;
@@ -558,12 +598,18 @@ fn type_param_predicates(
 
     let icx = ItemCtxt::new(tcx, item_def_id);
     let extra_predicates = extend.into_iter().chain(
-        icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty, OnlySelfBounds(true))
-            .into_iter()
-            .filter(|(predicate, _)| match predicate.kind().skip_binder() {
-                ty::PredicateKind::Trait(data, _) => data.self_ty().is_param(index),
-                _ => false,
-            }),
+        icx.type_parameter_bounds_in_generics(
+            ast_generics,
+            param_id,
+            ty,
+            OnlySelfBounds(true),
+            Some(assoc_name),
+        )
+        .into_iter()
+        .filter(|(predicate, _)| match predicate.kind().skip_binder() {
+            ty::PredicateKind::Trait(data, _) => data.self_ty().is_param(index),
+            _ => false,
+        }),
     );
     result.predicates =
         tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(extra_predicates));
@@ -581,6 +627,7 @@ impl ItemCtxt<'tcx> {
         param_id: hir::HirId,
         ty: Ty<'tcx>,
         only_self_bounds: OnlySelfBounds,
+        assoc_name: Option<Ident>,
     ) -> Vec<(ty::Predicate<'tcx>, Span)> {
         let constness = self.default_constness_for_trait_bounds();
         let from_ty_params = ast_generics
@@ -591,6 +638,10 @@ impl ItemCtxt<'tcx> {
                 _ => None,
             })
             .flat_map(|bounds| bounds.iter())
+            .filter(|b| match assoc_name {
+                Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
+                None => true,
+            })
             .flat_map(|b| predicates_from_bound(self, ty, b, constness));
 
         let from_where_clauses = ast_generics
@@ -609,12 +660,34 @@ impl ItemCtxt<'tcx> {
                 } else {
                     None
                 };
-                bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b)))
+                bp.bounds
+                    .iter()
+                    .filter(|b| match assoc_name {
+                        Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
+                        None => true,
+                    })
+                    .filter_map(move |b| bt.map(|bt| (bt, b)))
             })
             .flat_map(|(bt, b)| predicates_from_bound(self, bt, b, constness));
 
         from_ty_params.chain(from_where_clauses).collect()
     }
+
+    fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
+        debug!("bound_defines_assoc_item(b={:?}, assoc_name={:?})", b, assoc_name);
+
+        match b {
+            hir::GenericBound::Trait(poly_trait_ref, _) => {
+                let trait_ref = &poly_trait_ref.trait_ref;
+                if let Some(trait_did) = trait_ref.trait_def_id() {
+                    self.tcx.trait_may_define_assoc_type(trait_did, assoc_name)
+                } else {
+                    false
+                }
+            }
+            _ => false,
+        }
+    }
 }
 
 /// Tests whether this is the AST for a reference to the type
@@ -634,10 +707,11 @@ fn is_param(tcx: TyCtxt<'_>, ast_ty: &hir::Ty<'_>, param_id: hir::HirId) -> bool
     }
 }
 
-fn convert_item(tcx: TyCtxt<'_>, item_id: hir::HirId) {
-    let it = tcx.hir().expect_item(item_id);
-    debug!("convert: item {} with id {}", it.ident, it.hir_id);
-    let def_id = tcx.hir().local_def_id(item_id);
+fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
+    let it = tcx.hir().item(item_id);
+    debug!("convert: item {} with id {}", it.ident, it.hir_id());
+    let def_id = item_id.def_id;
+
     match it.kind {
         // These don't define types.
         hir::ItemKind::ExternCrate(_)
@@ -647,12 +721,11 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::HirId) {
         hir::ItemKind::ForeignMod { items, .. } => {
             for item in items {
                 let item = tcx.hir().foreign_item(item.id);
-                let def_id = tcx.hir().local_def_id(item.hir_id);
-                tcx.ensure().generics_of(def_id);
-                tcx.ensure().type_of(def_id);
-                tcx.ensure().predicates_of(def_id);
+                tcx.ensure().generics_of(item.def_id);
+                tcx.ensure().type_of(item.def_id);
+                tcx.ensure().predicates_of(item.def_id);
                 if let hir::ForeignItemKind::Fn(..) = item.kind {
-                    tcx.ensure().fn_sig(def_id);
+                    tcx.ensure().fn_sig(item.def_id);
                 }
             }
         }
@@ -723,57 +796,57 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::HirId) {
     }
 }
 
-fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::HirId) {
-    let trait_item = tcx.hir().expect_trait_item(trait_item_id);
-    let def_id = tcx.hir().local_def_id(trait_item.hir_id);
-    tcx.ensure().generics_of(def_id);
+fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
+    let trait_item = tcx.hir().trait_item(trait_item_id);
+    tcx.ensure().generics_of(trait_item_id.def_id);
 
     match trait_item.kind {
         hir::TraitItemKind::Fn(..) => {
-            tcx.ensure().type_of(def_id);
-            tcx.ensure().fn_sig(def_id);
+            tcx.ensure().type_of(trait_item_id.def_id);
+            tcx.ensure().fn_sig(trait_item_id.def_id);
         }
 
         hir::TraitItemKind::Const(.., Some(_)) => {
-            tcx.ensure().type_of(def_id);
+            tcx.ensure().type_of(trait_item_id.def_id);
         }
 
         hir::TraitItemKind::Const(..) => {
-            tcx.ensure().type_of(def_id);
+            tcx.ensure().type_of(trait_item_id.def_id);
             // Account for `const C: _;`.
             let mut visitor = PlaceholderHirTyCollector::default();
             visitor.visit_trait_item(trait_item);
-            placeholder_type_error(tcx, None, &[], visitor.0, false);
+            placeholder_type_error(tcx, None, &[], visitor.0, false, None);
         }
 
         hir::TraitItemKind::Type(_, Some(_)) => {
-            tcx.ensure().item_bounds(def_id);
-            tcx.ensure().type_of(def_id);
+            tcx.ensure().item_bounds(trait_item_id.def_id);
+            tcx.ensure().type_of(trait_item_id.def_id);
             // Account for `type T = _;`.
             let mut visitor = PlaceholderHirTyCollector::default();
             visitor.visit_trait_item(trait_item);
-            placeholder_type_error(tcx, None, &[], visitor.0, false);
+            placeholder_type_error(tcx, None, &[], visitor.0, false, None);
         }
 
         hir::TraitItemKind::Type(_, None) => {
-            tcx.ensure().item_bounds(def_id);
+            tcx.ensure().item_bounds(trait_item_id.def_id);
             // #74612: Visit and try to find bad placeholders
             // even if there is no concrete type.
             let mut visitor = PlaceholderHirTyCollector::default();
             visitor.visit_trait_item(trait_item);
-            placeholder_type_error(tcx, None, &[], visitor.0, false);
+
+            placeholder_type_error(tcx, None, &[], visitor.0, false, None);
         }
     };
 
-    tcx.ensure().predicates_of(def_id);
+    tcx.ensure().predicates_of(trait_item_id.def_id);
 }
 
-fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::HirId) {
-    let def_id = tcx.hir().local_def_id(impl_item_id);
+fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
+    let def_id = impl_item_id.def_id;
     tcx.ensure().generics_of(def_id);
     tcx.ensure().type_of(def_id);
     tcx.ensure().predicates_of(def_id);
-    let impl_item = tcx.hir().expect_impl_item(impl_item_id);
+    let impl_item = tcx.hir().impl_item(impl_item_id);
     match impl_item.kind {
         hir::ImplItemKind::Fn(..) => {
             tcx.ensure().fn_sig(def_id);
@@ -782,7 +855,8 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::HirId) {
             // Account for `type T = _;`
             let mut visitor = PlaceholderHirTyCollector::default();
             visitor.visit_impl_item(impl_item);
-            placeholder_type_error(tcx, None, &[], visitor.0, false);
+
+            placeholder_type_error(tcx, None, &[], visitor.0, false, None);
         }
         hir::ImplItemKind::Const(..) => {}
     }
@@ -983,54 +1057,91 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::AdtDef {
 /// the transitive super-predicates are converted.
 fn super_predicates_of(tcx: TyCtxt<'_>, trait_def_id: DefId) -> ty::GenericPredicates<'_> {
     debug!("super_predicates(trait_def_id={:?})", trait_def_id);
-    let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
+    tcx.super_predicates_that_define_assoc_type((trait_def_id, None))
+}
 
-    let item = match tcx.hir().get(trait_hir_id) {
-        Node::Item(item) => item,
-        _ => bug!("trait_node_id {} is not an item", trait_hir_id),
-    };
+/// Ensures that the super-predicates of the trait with a `DefId`
+/// of `trait_def_id` are converted and stored. This also ensures that
+/// the transitive super-predicates are converted.
+fn super_predicates_that_define_assoc_type(
+    tcx: TyCtxt<'_>,
+    (trait_def_id, assoc_name): (DefId, Option<Ident>),
+) -> ty::GenericPredicates<'_> {
+    debug!(
+        "super_predicates_that_define_assoc_type(trait_def_id={:?}, assoc_name={:?})",
+        trait_def_id, assoc_name
+    );
+    if trait_def_id.is_local() {
+        debug!("super_predicates_that_define_assoc_type: local trait_def_id={:?}", trait_def_id);
+        let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id.expect_local());
 
-    let (generics, bounds) = match item.kind {
-        hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
-        hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
-        _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
-    };
+        let item = match tcx.hir().get(trait_hir_id) {
+            Node::Item(item) => item,
+            _ => bug!("trait_node_id {} is not an item", trait_hir_id),
+        };
 
-    let icx = ItemCtxt::new(tcx, trait_def_id);
-
-    // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
-    let self_param_ty = tcx.types.self_param;
-    let superbounds1 =
-        AstConv::compute_bounds(&icx, self_param_ty, bounds, SizedByDefault::No, item.span);
-
-    let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
-
-    // Convert any explicit superbounds in the where-clause,
-    // e.g., `trait Foo where Self: Bar`.
-    // In the case of trait aliases, however, we include all bounds in the where-clause,
-    // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
-    // as one of its "superpredicates".
-    let is_trait_alias = tcx.is_trait_alias(trait_def_id);
-    let superbounds2 = icx.type_parameter_bounds_in_generics(
-        generics,
-        item.hir_id,
-        self_param_ty,
-        OnlySelfBounds(!is_trait_alias),
-    );
+        let (generics, bounds) = match item.kind {
+            hir::ItemKind::Trait(.., ref generics, ref supertraits, _) => (generics, supertraits),
+            hir::ItemKind::TraitAlias(ref generics, ref supertraits) => (generics, supertraits),
+            _ => span_bug!(item.span, "super_predicates invoked on non-trait"),
+        };
 
-    // Combine the two lists to form the complete set of superbounds:
-    let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
+        let icx = ItemCtxt::new(tcx, trait_def_id);
 
-    // Now require that immediate supertraits are converted,
-    // which will, in turn, reach indirect supertraits.
-    for &(pred, span) in superbounds {
-        debug!("superbound: {:?}", pred);
-        if let ty::PredicateKind::Trait(bound, _) = pred.kind().skip_binder() {
-            tcx.at(span).super_predicates_of(bound.def_id());
+        // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
+        let self_param_ty = tcx.types.self_param;
+        let superbounds1 = if let Some(assoc_name) = assoc_name {
+            AstConv::compute_bounds_that_match_assoc_type(
+                &icx,
+                self_param_ty,
+                &bounds,
+                SizedByDefault::No,
+                item.span,
+                assoc_name,
+            )
+        } else {
+            AstConv::compute_bounds(&icx, self_param_ty, &bounds, SizedByDefault::No, item.span)
+        };
+
+        let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
+
+        // Convert any explicit superbounds in the where-clause,
+        // e.g., `trait Foo where Self: Bar`.
+        // In the case of trait aliases, however, we include all bounds in the where-clause,
+        // so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
+        // as one of its "superpredicates".
+        let is_trait_alias = tcx.is_trait_alias(trait_def_id);
+        let superbounds2 = icx.type_parameter_bounds_in_generics(
+            generics,
+            item.hir_id(),
+            self_param_ty,
+            OnlySelfBounds(!is_trait_alias),
+            assoc_name,
+        );
+
+        // Combine the two lists to form the complete set of superbounds:
+        let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
+
+        // Now require that immediate supertraits are converted,
+        // which will, in turn, reach indirect supertraits.
+        if assoc_name.is_none() {
+            // Now require that immediate supertraits are converted,
+            // which will, in turn, reach indirect supertraits.
+            for &(pred, span) in superbounds {
+                debug!("superbound: {:?}", pred);
+                if let ty::PredicateKind::Trait(bound, _) = pred.kind().skip_binder() {
+                    tcx.at(span).super_predicates_of(bound.def_id());
+                }
+            }
         }
-    }
 
-    ty::GenericPredicates { parent: None, predicates: superbounds }
+        ty::GenericPredicates { parent: None, predicates: superbounds }
+    } else {
+        // if `assoc_name` is None, then the query should've been redirected to an
+        // external provider
+        assert!(assoc_name.is_some());
+        tcx.super_predicates_of(trait_def_id)
+    }
 }
 
 fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
@@ -1326,12 +1437,12 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                     //
                     // Something of a hack: use the node id for the trait, also as
                     // the node id for the Self type parameter.
-                    let param_id = item.hir_id;
+                    let param_id = item.def_id;
 
                     opt_self = Some(ty::GenericParamDef {
                         index: 0,
                         name: kw::SelfUpper,
-                        def_id: tcx.hir().local_def_id(param_id).to_def_id(),
+                        def_id: param_id.to_def_id(),
                         pure_wrt_drop: false,
                         kind: ty::GenericParamDefKind::Type {
                             has_default: false,
@@ -1573,6 +1684,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
                     &sig.decl,
                     &generics,
                     Some(ident.span),
+                    None,
                 ),
             }
         }
@@ -1582,9 +1694,15 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
             ident,
             generics,
             ..
-        }) => {
-            AstConv::ty_of_fn(&icx, header.unsafety, header.abi, decl, &generics, Some(ident.span))
-        }
+        }) => AstConv::ty_of_fn(
+            &icx,
+            header.unsafety,
+            header.abi,
+            decl,
+            &generics,
+            Some(ident.span),
+            None,
+        ),
 
         ForeignItem(&hir::ForeignItem {
             kind: ForeignItemKind::Fn(ref fn_decl, _, _),
@@ -2254,6 +2372,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
         decl,
         &hir::Generics::empty(),
         Some(ident.span),
+        None,
     );
 
     // Feature gate SIMD types in FFI, since I am not sure that the
@@ -2628,10 +2747,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
                     } else if item.has_name(sym::thread) {
                         codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD;
+                    } else if item.has_name(sym::hwaddress) {
+                        codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS;
                     } else {
                         tcx.sess
                             .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
-                            .note("expected one of: `address`, `memory` or `thread`")
+                            .note("expected one of: `address`, `hwaddress`, `memory` or `thread`")
                             .emit();
                     }
                 }
diff --git a/compiler/rustc_typeck/src/collect/item_bounds.rs b/compiler/rustc_typeck/src/collect/item_bounds.rs
index 537a5832894..fe18dc5ed0c 100644
--- a/compiler/rustc_typeck/src/collect/item_bounds.rs
+++ b/compiler/rustc_typeck/src/collect/item_bounds.rs
@@ -28,7 +28,7 @@ fn associated_type_bounds<'tcx>(
     let bounds = AstConv::compute_bounds(
         &ItemCtxt::new(tcx, assoc_item_def_id),
         item_ty,
-        bounds,
+        &bounds,
         SizedByDefault::Yes,
         span,
     );
@@ -69,7 +69,7 @@ fn opaque_type_bounds<'tcx>(
         let bounds = AstConv::compute_bounds(
             &ItemCtxt::new(tcx, opaque_def_id),
             item_ty,
-            bounds,
+            &bounds,
             SizedByDefault::Yes,
             span,
         )
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index e4eabca9c3b..a2aa3b308ec 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -29,6 +29,73 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
         let parent_node = tcx.hir().get(parent_node_id);
 
         match parent_node {
+            // This match arm is for when the def_id appears in a GAT whose
+            // path can't be resolved without typechecking e.g.
+            //
+            // trait Foo {
+            //   type Assoc<const N: usize>;
+            //   fn foo() -> Self::Assoc<3>;
+            // }
+            //
+            // In the above code we would call this query with the def_id of 3 and
+            // the parent_node we match on would be the hir node for Self::Assoc<3>
+            //
+            // `Self::Assoc<3>` cant be resolved without typchecking here as we
+            // didnt write <Self as Foo>::Assoc<3>. If we did then another match
+            // arm would handle this.
+            //
+            // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
+            Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
+                // Find the Item containing the associated type so we can create an ItemCtxt.
+                // Using the ItemCtxt convert the HIR for the unresolved assoc type into a
+                // ty which is a fully resolved projection.
+                // For the code example above, this would mean converting Self::Assoc<3>
+                // into a ty::Projection(<Self as Foo>::Assoc<3>)
+                let item_hir_id = tcx
+                    .hir()
+                    .parent_iter(hir_id)
+                    .filter(|(_, node)| matches!(node, Node::Item(_)))
+                    .map(|(id, _)| id)
+                    .next()
+                    .unwrap();
+                let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id();
+                let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>;
+                let ty = item_ctxt.ast_ty_to_ty(hir_ty);
+
+                // Iterate through the generics of the projection to find the one that corresponds to
+                // the def_id that this query was called with. We filter to only const args here as a
+                // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
+                // but it can't hurt to be safe ^^
+                if let ty::Projection(projection) = ty.kind() {
+                    let generics = tcx.generics_of(projection.item_def_id);
+
+                    let arg_index = segment
+                        .args
+                        .and_then(|args| {
+                            args.args
+                                .iter()
+                                .filter(|arg| arg.is_const())
+                                .position(|arg| arg.id() == hir_id)
+                        })
+                        .unwrap_or_else(|| {
+                            bug!("no arg matching AnonConst in segment");
+                        });
+
+                    return generics
+                        .params
+                        .iter()
+                        .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const))
+                        .nth(arg_index)
+                        .map(|param| param.def_id);
+                }
+
+                // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
+                tcx.sess.delay_span_bug(
+                    tcx.def_span(def_id),
+                    "unexpected non-GAT usage of an anon const",
+                );
+                return None;
+            }
             Node::Expr(&Expr {
                 kind:
                     ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
@@ -515,26 +582,23 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
         }
         fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
             debug!("find_existential_constraints: visiting {:?}", it);
-            let def_id = self.tcx.hir().local_def_id(it.hir_id);
             // The opaque type itself or its children are not within its reveal scope.
-            if def_id.to_def_id() != self.def_id {
-                self.check(def_id);
+            if it.def_id.to_def_id() != self.def_id {
+                self.check(it.def_id);
                 intravisit::walk_item(self, it);
             }
         }
         fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
             debug!("find_existential_constraints: visiting {:?}", it);
-            let def_id = self.tcx.hir().local_def_id(it.hir_id);
             // The opaque type itself or its children are not within its reveal scope.
-            if def_id.to_def_id() != self.def_id {
-                self.check(def_id);
+            if it.def_id.to_def_id() != self.def_id {
+                self.check(it.def_id);
                 intravisit::walk_impl_item(self, it);
             }
         }
         fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
             debug!("find_existential_constraints: visiting {:?}", it);
-            let def_id = self.tcx.hir().local_def_id(it.hir_id);
-            self.check(def_id);
+            self.check(it.def_id);
             intravisit::walk_trait_item(self, it);
         }
     }
diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs
index 95670b9bdb9..529de1a2874 100644
--- a/compiler/rustc_typeck/src/constrained_generic_params.rs
+++ b/compiler/rustc_typeck/src/constrained_generic_params.rs
@@ -198,7 +198,7 @@ pub fn setup_constraining_predicates<'tcx>(
                 //     `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
                 // Then the projection only applies if `T` is known, but it still
                 // does not determine `U`.
-                let inputs = parameters_for(&projection.projection_ty.trait_ref(tcx), true);
+                let inputs = parameters_for(&projection.projection_ty, true);
                 let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
                 if !relies_only_on_inputs {
                     continue;
diff --git a/compiler/rustc_typeck/src/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs
index bd2c266d93d..52110af4792 100644
--- a/compiler/rustc_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_typeck/src/expr_use_visitor.rs
@@ -184,7 +184,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
 
             hir::ExprKind::Type(ref subexpr, _) => self.walk_expr(subexpr),
 
-            hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base) => {
+            hir::ExprKind::Unary(hir::UnOp::Deref, ref base) => {
                 // *base
                 self.select_from_expr(base);
             }
diff --git a/compiler/rustc_typeck/src/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs
index 0bdcbaac0e9..7713381e62e 100644
--- a/compiler/rustc_typeck/src/impl_wf_check.rs
+++ b/compiler/rustc_typeck/src/impl_wf_check.rs
@@ -59,7 +59,7 @@ pub fn impl_wf_check(tcx: TyCtxt<'_>) {
     // but it's one that we must perform earlier than the rest of
     // WfCheck.
     for &module in tcx.hir().krate().modules.keys() {
-        tcx.ensure().check_mod_impl_wf(tcx.hir().local_def_id(module));
+        tcx.ensure().check_mod_impl_wf(module);
     }
 }
 
@@ -81,11 +81,10 @@ struct ImplWfCheck<'tcx> {
 impl ItemLikeVisitor<'tcx> for ImplWfCheck<'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         if let hir::ItemKind::Impl(ref impl_) = item.kind {
-            let impl_def_id = self.tcx.hir().local_def_id(item.hir_id);
-            enforce_impl_params_are_constrained(self.tcx, impl_def_id, impl_.items);
+            enforce_impl_params_are_constrained(self.tcx, item.def_id, impl_.items);
             enforce_impl_items_are_distinct(self.tcx, impl_.items);
             if self.min_specialization {
-                check_min_specialization(self.tcx, impl_def_id.to_def_id(), item.span);
+                check_min_specialization(self.tcx, item.def_id.to_def_id(), item.span);
             }
         }
     }
@@ -131,7 +130,7 @@ fn enforce_impl_params_are_constrained(
     // Disallow unconstrained lifetimes, but only if they appear in assoc types.
     let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs
         .iter()
-        .map(|item_ref| tcx.hir().local_def_id(item_ref.id.hir_id))
+        .map(|item_ref| item_ref.id.def_id)
         .flat_map(|def_id| {
             let item = tcx.associated_item(def_id);
             match item.kind {
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index fd44bafab6f..6ddc26efeae 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -56,6 +56,7 @@ This API is completely unstable and subject to change.
 */
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(bindings_after_at)]
 #![feature(bool_to_option)]
 #![feature(box_syntax)]
 #![feature(crate_visibility_modifier)]
@@ -368,7 +369,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
     tcx.sess.track_errors(|| {
         tcx.sess.time("type_collecting", || {
             for &module in tcx.hir().krate().modules.keys() {
-                tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id(module));
+                tcx.ensure().collect_mod_item_types(module);
             }
         });
     })?;
@@ -400,7 +401,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> {
     // NOTE: This is copy/pasted in librustdoc/core.rs and should be kept in sync.
     tcx.sess.time("item_types_checking", || {
         for &module in tcx.hir().krate().modules.keys() {
-            tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module));
+            tcx.ensure().check_mod_item_types(module);
         }
     });
 
@@ -421,8 +422,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
     let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id);
     let env_def_id = tcx.hir().local_def_id(env_node_id);
     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
-
-    astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty)
+    item_cx.to_ty(hir_ty)
 }
 
 pub fn hir_trait_to_predicates<'tcx>(
diff --git a/compiler/rustc_typeck/src/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs
index fef52a3f87c..14af11097cf 100644
--- a/compiler/rustc_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_typeck/src/mem_categorization.rs
@@ -303,7 +303,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
 
         let expr_ty = self.expr_ty(expr)?;
         match expr.kind {
-            hir::ExprKind::Unary(hir::UnOp::UnDeref, ref e_base) => {
+            hir::ExprKind::Unary(hir::UnOp::Deref, ref e_base) => {
                 if self.typeck_results.is_method_call(expr) {
                     self.cat_overloaded_place(expr, e_base)
                 } else {
diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
index 02008e180b3..6e6ecf6a22b 100644
--- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs
@@ -2,7 +2,6 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::Node;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
@@ -53,16 +52,10 @@ pub struct InferVisitor<'cx, 'tcx> {
 
 impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        let item_did = self.tcx.hir().local_def_id(item.hir_id);
+        let item_did = item.def_id;
 
         debug!("InferVisitor::visit_item(item={:?})", item_did);
 
-        let hir_id = self.tcx.hir().local_def_id_to_hir_id(item_did);
-        let item = match self.tcx.hir().get(hir_id) {
-            Node::Item(item) => item,
-            _ => bug!(),
-        };
-
         let mut item_required_predicates = RequiredPredicates::default();
         match item.kind {
             hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) => {
diff --git a/compiler/rustc_typeck/src/outlives/test.rs b/compiler/rustc_typeck/src/outlives/test.rs
index 56d42f756c4..d4bef0c409a 100644
--- a/compiler/rustc_typeck/src/outlives/test.rs
+++ b/compiler/rustc_typeck/src/outlives/test.rs
@@ -14,12 +14,10 @@ struct OutlivesTest<'tcx> {
 
 impl ItemLikeVisitor<'tcx> for OutlivesTest<'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let item_def_id = self.tcx.hir().local_def_id(item.hir_id);
-
         // For unit testing: check for a special "rustc_outlives"
         // attribute and report an error with various results if found.
-        if self.tcx.has_attr(item_def_id.to_def_id(), sym::rustc_outlives) {
-            let inferred_outlives_of = self.tcx.inferred_outlives_of(item_def_id);
+        if self.tcx.has_attr(item.def_id.to_def_id(), sym::rustc_outlives) {
+            let inferred_outlives_of = self.tcx.inferred_outlives_of(item.def_id);
             struct_span_err!(self.tcx.sess, item.span, E0640, "{:?}", inferred_outlives_of).emit();
         }
     }
diff --git a/compiler/rustc_typeck/src/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs
index 339eb5f9afc..f5355ea042b 100644
--- a/compiler/rustc_typeck/src/variance/constraints.rs
+++ b/compiler/rustc_typeck/src/variance/constraints.rs
@@ -71,7 +71,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
         match item.kind {
             hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
-                self.visit_node_helper(item.hir_id);
+                self.visit_node_helper(item.hir_id());
 
                 if let hir::VariantData::Tuple(..) = *struct_def {
                     self.visit_node_helper(struct_def.ctor_hir_id().unwrap());
@@ -79,7 +79,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
             }
 
             hir::ItemKind::Enum(ref enum_def, _) => {
-                self.visit_node_helper(item.hir_id);
+                self.visit_node_helper(item.hir_id());
 
                 for variant in enum_def.variants {
                     if let hir::VariantData::Tuple(..) = variant.data {
@@ -89,7 +89,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
             }
 
             hir::ItemKind::Fn(..) => {
-                self.visit_node_helper(item.hir_id);
+                self.visit_node_helper(item.hir_id());
             }
 
             _ => {}
@@ -98,19 +98,19 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> {
 
     fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
         if let hir::TraitItemKind::Fn(..) = trait_item.kind {
-            self.visit_node_helper(trait_item.hir_id);
+            self.visit_node_helper(trait_item.hir_id());
         }
     }
 
     fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
         if let hir::ImplItemKind::Fn(..) = impl_item.kind {
-            self.visit_node_helper(impl_item.hir_id);
+            self.visit_node_helper(impl_item.hir_id());
         }
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
         if let hir::ForeignItemKind::Fn(..) = foreign_item.kind {
-            self.visit_node_helper(foreign_item.hir_id);
+            self.visit_node_helper(foreign_item.hir_id());
         }
     }
 }
@@ -207,7 +207,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
         }
     }
 
-    #[instrument(skip(self, current))]
+    #[instrument(level = "debug", skip(self, current))]
     fn add_constraints_from_invariant_substs(
         &mut self,
         current: &CurrentItem,
diff --git a/compiler/rustc_typeck/src/variance/terms.rs b/compiler/rustc_typeck/src/variance/terms.rs
index 3b2a1c24ddd..5d5baf78d33 100644
--- a/compiler/rustc_typeck/src/variance/terms.rs
+++ b/compiler/rustc_typeck/src/variance/terms.rs
@@ -128,11 +128,11 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> {
 
 impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item<'_>) {
-        debug!("add_inferreds for item {}", self.tcx.hir().node_to_string(item.hir_id));
+        debug!("add_inferreds for item {}", self.tcx.hir().node_to_string(item.hir_id()));
 
         match item.kind {
             hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
-                self.add_inferreds_for_item(item.hir_id);
+                self.add_inferreds_for_item(item.hir_id());
 
                 if let hir::VariantData::Tuple(..) = *struct_def {
                     self.add_inferreds_for_item(struct_def.ctor_hir_id().unwrap());
@@ -140,7 +140,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
             }
 
             hir::ItemKind::Enum(ref enum_def, _) => {
-                self.add_inferreds_for_item(item.hir_id);
+                self.add_inferreds_for_item(item.hir_id());
 
                 for variant in enum_def.variants {
                     if let hir::VariantData::Tuple(..) = variant.data {
@@ -150,7 +150,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
             }
 
             hir::ItemKind::Fn(..) => {
-                self.add_inferreds_for_item(item.hir_id);
+                self.add_inferreds_for_item(item.hir_id());
             }
 
             _ => {}
@@ -159,19 +159,19 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for TermsContext<'a, 'tcx> {
 
     fn visit_trait_item(&mut self, trait_item: &hir::TraitItem<'_>) {
         if let hir::TraitItemKind::Fn(..) = trait_item.kind {
-            self.add_inferreds_for_item(trait_item.hir_id);
+            self.add_inferreds_for_item(trait_item.hir_id());
         }
     }
 
     fn visit_impl_item(&mut self, impl_item: &hir::ImplItem<'_>) {
         if let hir::ImplItemKind::Fn(..) = impl_item.kind {
-            self.add_inferreds_for_item(impl_item.hir_id);
+            self.add_inferreds_for_item(impl_item.hir_id());
         }
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem<'_>) {
         if let hir::ForeignItemKind::Fn(..) = foreign_item.kind {
-            self.add_inferreds_for_item(foreign_item.hir_id);
+            self.add_inferreds_for_item(foreign_item.hir_id());
         }
     }
 }
diff --git a/compiler/rustc_typeck/src/variance/test.rs b/compiler/rustc_typeck/src/variance/test.rs
index d6e43b6d669..2a0d950c87d 100644
--- a/compiler/rustc_typeck/src/variance/test.rs
+++ b/compiler/rustc_typeck/src/variance/test.rs
@@ -14,12 +14,10 @@ struct VarianceTest<'tcx> {
 
 impl ItemLikeVisitor<'tcx> for VarianceTest<'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let item_def_id = self.tcx.hir().local_def_id(item.hir_id);
-
         // For unit testing: check for a special "rustc_variance"
         // attribute and report an error with various results if found.
-        if self.tcx.has_attr(item_def_id.to_def_id(), sym::rustc_variance) {
-            let variances_of = self.tcx.variances_of(item_def_id);
+        if self.tcx.has_attr(item.def_id.to_def_id(), sym::rustc_variance) {
+            let variances_of = self.tcx.variances_of(item.def_id);
             struct_span_err!(self.tcx.sess, item.span, E0208, "{:?}", variances_of).emit();
         }
     }