about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--Cargo.lock66
-rw-r--r--README.md24
-rw-r--r--RELEASES.md21
-rw-r--r--compiler/rustc_apfloat/src/lib.rs1
-rw-r--r--compiler/rustc_ast/src/lib.rs6
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs58
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs30
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs4
-rw-r--r--compiler/rustc_ast_passes/src/lib.rs1
-rw-r--r--compiler/rustc_ast_pretty/src/lib.rs1
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs16
-rw-r--r--compiler/rustc_attr/src/lib.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock140
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml28
-rw-r--r--compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock14
-rwxr-xr-xcompiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh2
-rw-r--r--compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Disable-128bit-atomic-operations.patch (renamed from compiler/rustc_codegen_cranelift/crate_patches/0002-compiler-builtins-Disable-128bit-atomic-operations.patch)0
-rw-r--r--compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch35
-rw-r--r--compiler/rustc_codegen_cranelift/example/std_example.rs16
-rw-r--r--compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch40
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh17
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/tests.sh1
-rw-r--r--compiler/rustc_codegen_cranelift/src/archive.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/src/config.rs9
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs102
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs21
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/inline_asm.rs30
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs9
-rw-r--r--compiler/rustc_codegen_cranelift/src/trap.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/consts.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs251
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs42
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs14
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs19
-rw-r--r--compiler/rustc_codegen_ssa/src/coverageinfo/map.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs59
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs79
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_data_structures/src/flock.rs13
-rw-r--r--compiler/rustc_data_structures/src/lib.rs3
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs19
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs32
-rw-r--r--compiler/rustc_data_structures/src/sync.rs62
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr.rs10
-rw-r--r--compiler/rustc_driver/src/pretty.rs16
-rw-r--r--compiler/rustc_errors/src/lib.rs4
-rw-r--r--compiler/rustc_expand/src/lib.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs27
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs31
-rw-r--r--compiler/rustc_feature/src/accepted.rs6
-rw-r--r--compiler/rustc_feature/src/active.rs15
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs4
-rw-r--r--compiler/rustc_hir/src/definitions.rs5
-rw-r--r--compiler/rustc_hir/src/hir.rs8
-rw-r--r--compiler/rustc_hir/src/lang_items.rs11
-rw-r--r--compiler/rustc_hir/src/lib.rs5
-rw-r--r--compiler/rustc_hir/src/tests.rs13
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs1
-rw-r--r--compiler/rustc_incremental/Cargo.toml1
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs128
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs85
-rw-r--r--compiler/rustc_incremental/src/persist/load.rs10
-rw-r--r--compiler/rustc_incremental/src/persist/save.rs5
-rw-r--r--compiler/rustc_index/src/lib.rs1
-rw-r--r--compiler/rustc_index/src/vec.rs7
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs58
-rw-r--r--compiler/rustc_infer/src/infer/undo_log.rs5
-rw-r--r--compiler/rustc_infer/src/lib.rs3
-rw-r--r--compiler/rustc_interface/src/lib.rs1
-rw-r--r--compiler/rustc_interface/src/passes.rs19
-rw-r--r--compiler/rustc_interface/src/queries.rs4
-rw-r--r--compiler/rustc_interface/src/tests.rs10
-rw-r--r--compiler/rustc_interface/src/util.rs36
-rw-r--r--compiler/rustc_lint/src/context.rs39
-rw-r--r--compiler/rustc_lint/src/levels.rs16
-rw-r--r--compiler/rustc_lint/src/lib.rs3
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs1
-rw-r--r--compiler/rustc_lint/src/types.rs26
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs6
-rw-r--r--compiler/rustc_llvm/Cargo.toml2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp13
-rw-r--r--compiler/rustc_metadata/src/creader.rs19
-rw-r--r--compiler/rustc_metadata/src/lib.rs3
-rw-r--r--compiler/rustc_metadata/src/locator.rs8
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs14
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs26
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs3
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs2
-rw-r--r--compiler/rustc_middle/src/arena.rs1
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs1
-rw-r--r--compiler/rustc_middle/src/hir/map/collector.rs42
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs16
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs37
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs1
-rw-r--r--compiler/rustc_middle/src/infer/unify_key.rs55
-rw-r--r--compiler/rustc_middle/src/lib.rs3
-rw-r--r--compiler/rustc_middle/src/lint.rs30
-rw-r--r--compiler/rustc_middle/src/middle/cstore.rs5
-rw-r--r--compiler/rustc_middle/src/middle/exported_symbols.rs6
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs359
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs22
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs3
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs6
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs6
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs24
-rw-r--r--compiler/rustc_middle/src/mir/query.rs6
-rw-r--r--compiler/rustc_middle/src/query/mod.rs26
-rw-r--r--compiler/rustc_middle/src/thir.rs747
-rw-r--r--compiler/rustc_middle/src/ty/adjustment.rs10
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs6
-rw-r--r--compiler/rustc_middle/src/ty/context.rs52
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs1
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs75
-rw-r--r--compiler/rustc_middle/src/ty/list.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs7
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs15
-rw-r--r--compiler/rustc_middle/src/ty/query/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/query/on_disk_cache.rs26
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs12
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs2
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs7
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs15
-rw-r--r--compiler/rustc_mir/src/borrow_check/mod.rs12
-rw-r--r--compiler/rustc_mir/src/borrow_check/places_conflict.rs19
-rw-r--r--compiler/rustc_mir/src/borrow_check/region_infer/mod.rs2
-rw-r--r--compiler/rustc_mir/src/const_eval/error.rs108
-rw-r--r--compiler/rustc_mir/src/const_eval/eval_queries.rs23
-rw-r--r--compiler/rustc_mir/src/const_eval/machine.rs6
-rw-r--r--compiler/rustc_mir/src/const_eval/mod.rs2
-rw-r--r--compiler/rustc_mir/src/dataflow/move_paths/builder.rs6
-rw-r--r--compiler/rustc_mir/src/interpret/eval_context.rs59
-rw-r--r--compiler/rustc_mir/src/interpret/intrinsics.rs18
-rw-r--r--compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs4
-rw-r--r--compiler/rustc_mir/src/interpret/intrinsics/type_name.rs11
-rw-r--r--compiler/rustc_mir/src/interpret/machine.rs56
-rw-r--r--compiler/rustc_mir/src/interpret/memory.rs370
-rw-r--r--compiler/rustc_mir/src/interpret/mod.rs6
-rw-r--r--compiler/rustc_mir/src/interpret/operand.rs26
-rw-r--r--compiler/rustc_mir/src/interpret/place.rs102
-rw-r--r--compiler/rustc_mir/src/interpret/step.rs42
-rw-r--r--compiler/rustc_mir/src/interpret/terminator.rs75
-rw-r--r--compiler/rustc_mir/src/interpret/traits.rs71
-rw-r--r--compiler/rustc_mir/src/interpret/validity.rs60
-rw-r--r--compiler/rustc_mir/src/lib.rs4
-rw-r--r--compiler/rustc_mir/src/monomorphize/collector.rs45
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/ops.rs24
-rw-r--r--compiler/rustc_mir/src/transform/check_consts/validation.rs33
-rw-r--r--compiler/rustc_mir/src/transform/check_unsafety.rs8
-rw-r--r--compiler/rustc_mir/src/transform/const_goto.rs2
-rw-r--r--compiler/rustc_mir/src/transform/const_prop.rs5
-rw-r--r--compiler/rustc_mir/src/transform/coverage/debug.rs1
-rw-r--r--compiler/rustc_mir/src/transform/deduplicate_blocks.rs2
-rw-r--r--compiler/rustc_mir/src/transform/dest_prop.rs15
-rw-r--r--compiler/rustc_mir/src/transform/early_otherwise_branch.rs2
-rw-r--r--compiler/rustc_mir/src/transform/generator.rs4
-rw-r--r--compiler/rustc_mir/src/transform/inline.rs2
-rw-r--r--compiler/rustc_mir/src/transform/match_branches.rs2
-rw-r--r--compiler/rustc_mir/src/transform/multiple_return_terminators.rs2
-rw-r--r--compiler/rustc_mir/src/transform/promote_consts.rs6
-rw-r--r--compiler/rustc_mir/src/transform/remove_unneeded_drops.rs2
-rw-r--r--compiler/rustc_mir/src/transform/remove_zsts.rs11
-rw-r--r--compiler/rustc_mir/src/transform/simplify.rs85
-rw-r--r--compiler/rustc_mir/src/transform/simplify_try.rs2
-rw-r--r--compiler/rustc_mir/src/transform/unreachable_prop.rs2
-rw-r--r--compiler/rustc_mir/src/transform/validate.rs22
-rw-r--r--compiler/rustc_mir/src/util/generic_graph.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs35
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs21
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs46
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs52
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_temp.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/expr/category.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs89
-rw-r--r--compiler/rustc_mir_build/src/build/expr/stmt.rs36
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs41
-rw-r--r--compiler/rustc_mir_build/src/build/matches/simplify.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs104
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs7
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs249
-rw-r--r--compiler/rustc_mir_build/src/lib.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/arena.rs98
-rw-r--r--compiler/rustc_mir_build/src/thir/constant.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/block.rs127
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs452
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs39
-rw-r--r--compiler/rustc_mir_build/src/thir/mod.rs373
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs9
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs3
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs351
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs54
-rw-r--r--compiler/rustc_mir_build/src/thir/visit.rs157
-rw-r--r--compiler/rustc_parse/src/lib.rs2
-rw-r--r--compiler/rustc_parse/src/parser/item.rs5
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs13
-rw-r--r--compiler/rustc_parse_format/src/lib.rs1
-rw-r--r--compiler/rustc_passes/src/lang_items.rs127
-rw-r--r--compiler/rustc_passes/src/lib.rs3
-rw-r--r--compiler/rustc_passes/src/stability.rs6
-rw-r--r--compiler/rustc_privacy/src/lib.rs1
-rw-r--r--compiler/rustc_query_impl/src/lib.rs6
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs57
-rw-r--r--compiler/rustc_query_impl/src/profiling_support.rs2
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs326
-rw-r--r--compiler/rustc_query_system/src/dep_graph/mod.rs2
-rw-r--r--compiler/rustc_query_system/src/dep_graph/prev.rs56
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs40
-rw-r--r--compiler/rustc_query_system/src/lib.rs3
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs4
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs79
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs25
-rw-r--r--compiler/rustc_resolve/src/late.rs36
-rw-r--r--compiler/rustc_resolve/src/lib.rs24
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs7
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs6
-rw-r--r--compiler/rustc_serialize/src/lib.rs3
-rw-r--r--compiler/rustc_session/src/config.rs71
-rw-r--r--compiler/rustc_session/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/options.rs3
-rw-r--r--compiler/rustc_session/src/output.rs5
-rw-r--r--compiler/rustc_session/src/session.rs36
-rw-r--r--compiler/rustc_span/src/crate_disambiguator.rs35
-rw-r--r--compiler/rustc_span/src/def_id.rs106
-rw-r--r--compiler/rustc_span/src/lib.rs3
-rw-r--r--compiler/rustc_span/src/symbol.rs14
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs7
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs9
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs49
-rw-r--r--compiler/rustc_target/src/abi/mod.rs8
-rw-r--r--compiler/rustc_target/src/lib.rs2
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios.rs1
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs1
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs1
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_tvos.rs1
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_none.rs1
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs1
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/apple_sdk_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/avr_gnu_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/dragonfly_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/freebsd_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/fuchsia_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/haiku_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/hermit_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/hermit_kernel_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/illumos_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/l4re_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/linux_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/linux_kernel_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/mipsel_sony_psp.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs5
-rw-r--r--compiler/rustc_target/src/spec/msvc_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/netbsd_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs1
-rw-r--r--compiler/rustc_target/src/spec/openbsd_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/redox_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/solaris_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs1
-rw-r--r--compiler/rustc_target/src/spec/vxworks_base.rs1
-rw-r--r--compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs1
-rw-r--r--compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs1
-rw-r--r--compiler/rustc_trait_selection/src/autoderef.rs4
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs67
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs85
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs24
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs16
-rw-r--r--compiler/rustc_type_ir/src/lib.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs4
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs62
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs38
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior.rs30
-rw-r--r--compiler/rustc_typeck/src/check/method/mod.rs4
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs95
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs11
-rw-r--r--compiler/rustc_typeck/src/check/op.rs19
-rw-r--r--compiler/rustc_typeck/src/check/place_op.rs34
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs9
-rw-r--r--compiler/rustc_typeck/src/collect.rs16
-rw-r--r--compiler/rustc_typeck/src/lib.rs1
-rw-r--r--compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs128
-rw-r--r--config.toml.example8
-rw-r--r--library/alloc/benches/vec.rs1
-rw-r--r--library/alloc/src/collections/linked_list.rs48
-rw-r--r--library/alloc/src/collections/vec_deque/iter.rs4
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs13
-rw-r--r--library/alloc/src/lib.rs8
-rw-r--r--library/alloc/src/rc.rs14
-rw-r--r--library/alloc/src/string.rs41
-rw-r--r--library/alloc/src/sync.rs14
-rw-r--r--library/alloc/src/vec/cow.rs18
-rw-r--r--library/alloc/src/vec/is_zero.rs33
-rw-r--r--library/alloc/src/vec/mod.rs5
-rw-r--r--library/alloc/src/vec/spec_from_iter.rs35
-rw-r--r--library/alloc/tests/arc.rs15
-rw-r--r--library/alloc/tests/lib.rs1
-rw-r--r--library/alloc/tests/rc.rs15
-rw-r--r--library/alloc/tests/vec.rs61
-rw-r--r--library/core/src/array/iter.rs2
-rw-r--r--library/core/src/array/mod.rs5
-rw-r--r--library/core/src/cell.rs9
-rw-r--r--library/core/src/cmp.rs17
-rw-r--r--library/core/src/fmt/mod.rs43
-rw-r--r--library/core/src/future/future.rs3
-rw-r--r--library/core/src/iter/adapters/chain.rs4
-rw-r--r--library/core/src/iter/adapters/cloned.rs4
-rw-r--r--library/core/src/iter/adapters/copied.rs4
-rw-r--r--library/core/src/iter/adapters/cycle.rs2
-rw-r--r--library/core/src/iter/adapters/enumerate.rs4
-rw-r--r--library/core/src/iter/adapters/filter.rs6
-rw-r--r--library/core/src/iter/adapters/filter_map.rs6
-rw-r--r--library/core/src/iter/adapters/flatten.rs16
-rw-r--r--library/core/src/iter/adapters/fuse.rs16
-rw-r--r--library/core/src/iter/adapters/inspect.rs4
-rw-r--r--library/core/src/iter/adapters/map.rs4
-rw-r--r--library/core/src/iter/adapters/map_while.rs2
-rw-r--r--library/core/src/iter/adapters/mod.rs2
-rw-r--r--library/core/src/iter/adapters/peekable.rs36
-rw-r--r--library/core/src/iter/adapters/rev.rs4
-rw-r--r--library/core/src/iter/adapters/scan.rs4
-rw-r--r--library/core/src/iter/adapters/skip.rs6
-rw-r--r--library/core/src/iter/adapters/skip_while.rs2
-rw-r--r--library/core/src/iter/adapters/step_by.rs4
-rw-r--r--library/core/src/iter/adapters/take.rs6
-rw-r--r--library/core/src/iter/adapters/take_while.rs4
-rw-r--r--library/core/src/iter/adapters/zip.rs2
-rw-r--r--library/core/src/iter/mod.rs2
-rw-r--r--library/core/src/iter/range.rs472
-rw-r--r--library/core/src/iter/sources/repeat.rs35
-rw-r--r--library/core/src/iter/traits/collect.rs2
-rw-r--r--library/core/src/iter/traits/double_ended.rs2
-rw-r--r--library/core/src/iter/traits/iterator.rs115
-rw-r--r--library/core/src/iter/traits/marker.rs17
-rw-r--r--library/core/src/iter/traits/mod.rs2
-rw-r--r--library/core/src/lib.rs16
-rw-r--r--library/core/src/macros/mod.rs8
-rw-r--r--library/core/src/mem/manually_drop.rs15
-rw-r--r--library/core/src/num/f32.rs33
-rw-r--r--library/core/src/num/f64.rs33
-rw-r--r--library/core/src/num/int_macros.rs113
-rw-r--r--library/core/src/num/uint_macros.rs113
-rw-r--r--library/core/src/ops/control_flow.rs53
-rw-r--r--library/core/src/ops/mod.rs12
-rw-r--r--library/core/src/ops/try.rs14
-rw-r--r--library/core/src/ops/try_trait.rs130
-rw-r--r--library/core/src/option.rs10
-rw-r--r--library/core/src/prelude/mod.rs20
-rw-r--r--library/core/src/ptr/mod.rs8
-rw-r--r--library/core/src/result.rs5
-rw-r--r--library/core/src/slice/ascii.rs2
-rw-r--r--library/core/src/slice/mod.rs6
-rw-r--r--library/core/src/str/iter.rs2
-rw-r--r--library/core/src/task/poll.rs20
-rw-r--r--library/core/tests/any.rs13
-rw-r--r--library/core/tests/lib.rs3
-rw-r--r--library/core/tests/option.rs12
-rw-r--r--library/core/tests/result.rs30
-rw-r--r--library/proc_macro/src/bridge/buffer.rs54
-rw-r--r--library/proc_macro/src/bridge/mod.rs14
-rw-r--r--library/proc_macro/src/bridge/rpc.rs4
-rw-r--r--library/proc_macro/src/lib.rs31
-rw-r--r--library/profiler_builtins/Cargo.toml2
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/alloc.rs4
-rw-r--r--library/std/src/ffi/c_str.rs4
-rw-r--r--library/std/src/fs.rs26
-rw-r--r--library/std/src/io/buffered/linewritershim.rs2
-rw-r--r--library/std/src/io/cursor.rs19
-rw-r--r--library/std/src/io/mod.rs20
-rw-r--r--library/std/src/keyword_docs.rs4
-rw-r--r--library/std/src/lib.rs7
-rw-r--r--library/std/src/net/ip.rs133
-rw-r--r--library/std/src/net/ip/tests.rs18
-rw-r--r--library/std/src/os/unix/fs.rs2
-rw-r--r--library/std/src/os/unix/process.rs53
-rw-r--r--library/std/src/panic.rs1
-rw-r--r--library/std/src/panicking.rs11
-rw-r--r--library/std/src/path.rs6
-rw-r--r--library/std/src/prelude/mod.rs14
-rw-r--r--library/std/src/primitive_docs.rs12
-rw-r--r--library/std/src/process.rs144
-rw-r--r--library/std/src/sync/mutex.rs10
-rw-r--r--library/std/src/sync/rwlock.rs27
-rw-r--r--library/std/src/sys/hermit/fs.rs2
-rw-r--r--library/std/src/sys/hermit/os.rs2
-rw-r--r--library/std/src/sys/unix/fs.rs4
-rw-r--r--library/std/src/sys/unix/mod.rs1
-rw-r--r--library/std/src/sys/unix/net.rs6
-rw-r--r--library/std/src/sys/unix/os.rs2
-rw-r--r--library/std/src/sys/unix/process/mod.rs2
-rw-r--r--library/std/src/sys/unix/process/process_fuchsia.rs26
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs31
-rw-r--r--library/std/src/sys/unix/process/process_vxworks.rs30
-rw-r--r--library/std/src/sys/unix/stack_overflow.rs8
-rw-r--r--library/std/src/sys/unsupported/fs.rs4
-rw-r--r--library/std/src/sys/unsupported/process.rs18
-rw-r--r--library/std/src/sys/wasi/fs.rs2
-rw-r--r--library/std/src/sys/windows/c.rs323
-rw-r--r--library/std/src/sys/windows/fs.rs29
-rw-r--r--library/std/src/sys/windows/mod.rs14
-rw-r--r--library/std/src/sys/windows/process.rs25
-rw-r--r--library/std/src/sys/windows/stack_overflow.rs7
-rw-r--r--library/std/src/sys_common/fs.rs8
-rw-r--r--library/std/src/sys_common/memchr.rs (renamed from library/std/src/memchr.rs)6
-rw-r--r--library/std/src/sys_common/memchr/tests.rs (renamed from library/std/src/memchr/tests.rs)0
-rw-r--r--library/std/src/sys_common/mod.rs2
-rw-r--r--library/std/src/sys_common/rt.rs21
-rw-r--r--library/std/src/sys_common/util.rs28
-rw-r--r--library/std/src/thread/local.rs24
-rw-r--r--library/std/tests/run-time-detect.rs1
m---------library/stdarch0
-rw-r--r--library/test/src/cli.rs14
-rw-r--r--library/test/src/console.rs3
-rw-r--r--library/test/src/formatters/junit.rs174
-rw-r--r--library/test/src/formatters/mod.rs2
-rw-r--r--library/test/src/lib.rs2
-rw-r--r--library/test/src/options.rs2
-rw-r--r--library/unwind/Cargo.toml9
-rw-r--r--library/unwind/build.rs160
-rw-r--r--library/unwind/src/lib.rs21
-rw-r--r--src/bootstrap/Cargo.toml2
-rw-r--r--src/bootstrap/bin/rustc.rs2
-rw-r--r--src/bootstrap/builder.rs13
-rw-r--r--src/bootstrap/compile.rs3
-rw-r--r--src/bootstrap/doc.rs3
-rw-r--r--src/bootstrap/mk/Makefile.in4
-rw-r--r--src/bootstrap/native.rs68
-rw-r--r--src/bootstrap/sanity.rs5
-rw-r--r--src/bootstrap/test.rs124
-rw-r--r--src/bootstrap/tool.rs19
-rw-r--r--src/bootstrap/util.rs1
-rw-r--r--src/ci/docker/host-x86_64/dist-various-1/Dockerfile6
-rw-r--r--src/ci/docker/host-x86_64/dist-various-2/Dockerfile10
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh14
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile24
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile58
-rwxr-xr-xsrc/ci/scripts/should-skip-this.sh6
m---------src/doc/edition-guide0
m---------src/doc/embedded-book0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
m---------src/doc/rustc-dev-guide0
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md4
-rw-r--r--src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md56
-rw-r--r--src/doc/rustdoc/README.md5
-rw-r--r--src/doc/rustdoc/src/how-to-write-documentation.md10
-rw-r--r--src/doc/rustdoc/src/lints.md44
-rw-r--r--src/doc/rustdoc/src/the-doc-attribute.md7
-rw-r--r--src/doc/unstable-book/src/compiler-flags/force-warns.md21
-rw-r--r--src/doc/unstable-book/src/language-features/member-constraints.md29
-rw-r--r--src/etc/natvis/intrinsic.natvis53
-rw-r--r--src/etc/natvis/libcore.natvis17
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/clean/auto_trait.rs2
-rw-r--r--src/librustdoc/clean/inline.rs3
-rw-r--r--src/librustdoc/clean/mod.rs14
-rw-r--r--src/librustdoc/clean/types.rs4
-rw-r--r--src/librustdoc/clean/utils.rs3
-rw-r--r--src/librustdoc/config.rs25
-rw-r--r--src/librustdoc/html/format.rs9
-rw-r--r--src/librustdoc/html/layout.rs3
-rw-r--r--src/librustdoc/html/render/context.rs9
-rw-r--r--src/librustdoc/html/render/mod.rs146
-rw-r--r--src/librustdoc/html/render/print_item.rs25
-rw-r--r--src/librustdoc/html/render/write_shared.rs5
-rw-r--r--src/librustdoc/html/static/main.js305
-rw-r--r--src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt93
-rw-r--r--src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woffbin0 -> 287068 bytes
-rw-r--r--src/librustdoc/html/static/rustdoc.css179
-rw-r--r--src/librustdoc/html/static/search.js254
-rw-r--r--src/librustdoc/html/static/sidebar-items.js1
-rw-r--r--src/librustdoc/html/static/themes/ayu.css81
-rw-r--r--src/librustdoc/html/static/themes/dark.css79
-rw-r--r--src/librustdoc/html/static/themes/light.css75
-rw-r--r--src/librustdoc/html/static_files.rs14
-rw-r--r--src/librustdoc/json/conversions.rs2
-rw-r--r--src/librustdoc/lib.rs12
-rw-r--r--src/librustdoc/lint.rs13
-rw-r--r--src/librustdoc/passes/check_code_block_syntax.rs114
-rw-r--r--src/librustdoc/visit_ast.rs3
-rw-r--r--src/stage0.txt2
-rw-r--r--src/test/assembly/static-relocation-model.rs50
-rw-r--r--src/test/codegen/async-fn-debug-msvc.rs16
-rw-r--r--src/test/codegen/auxiliary/thread_local_aux.rs6
-rw-r--r--src/test/codegen/generator-debug-msvc.rs16
-rw-r--r--src/test/codegen/thread-local.rs50
-rw-r--r--src/test/codegen/try_identity.rs21
-rw-r--r--src/test/debuginfo/msvc-pretty-enums.rs97
-rw-r--r--src/test/debuginfo/pretty-std.rs7
-rw-r--r--src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs10
-rw-r--r--src/test/incremental/callee_caller_cross_crate/b.rs4
-rw-r--r--src/test/incremental/change_add_field/struct_point.rs14
-rw-r--r--src/test/incremental/change_private_fn/struct_point.rs10
-rw-r--r--src/test/incremental/change_private_fn_cc/struct_point.rs10
-rw-r--r--src/test/incremental/change_private_impl_method/struct_point.rs10
-rw-r--r--src/test/incremental/change_private_impl_method_cc/struct_point.rs10
-rw-r--r--src/test/incremental/change_pub_inherent_method_body/struct_point.rs10
-rw-r--r--src/test/incremental/change_pub_inherent_method_sig/struct_point.rs10
-rw-r--r--src/test/incremental/crate_hash_reorder.rs4
-rw-r--r--src/test/incremental/dirty_clean.rs15
-rw-r--r--src/test/incremental/hashes/call_expressions.rs8
-rw-r--r--src/test/incremental/hashes/enum_defs.rs20
-rw-r--r--src/test/incremental/hashes/extern_mods.rs26
-rw-r--r--src/test/incremental/hashes/indexing_expressions.rs42
-rw-r--r--src/test/incremental/hashes/inherent_impls.rs5
-rw-r--r--src/test/incremental/hashes/struct_defs.rs252
-rw-r--r--src/test/incremental/hashes/trait_defs.rs426
-rw-r--r--src/test/incremental/hashes/trait_impls.rs161
-rw-r--r--src/test/incremental/hello_world.rs4
-rw-r--r--src/test/incremental/hygiene/auxiliary/cached_hygiene.rs2
-rw-r--r--src/test/incremental/ich_method_call_trait_scope.rs8
-rw-r--r--src/test/incremental/ich_nested_items.rs6
-rw-r--r--src/test/incremental/ich_resolve_results.rs12
-rw-r--r--src/test/incremental/link_order/auxiliary/my_lib.rs3
-rw-r--r--src/test/incremental/link_order/main.rs12
-rw-r--r--src/test/incremental/rlib_cross_crate/b.rs8
-rw-r--r--src/test/incremental/source_loc_macros.rs15
-rw-r--r--src/test/incremental/span_hash_stable/auxiliary/sub1.rs2
-rw-r--r--src/test/incremental/span_hash_stable/auxiliary/sub2.rs2
-rw-r--r--src/test/incremental/spans_significant_w_debuginfo.rs3
-rw-r--r--src/test/incremental/spans_significant_w_panic.rs2
-rw-r--r--src/test/incremental/string_constant.rs9
-rw-r--r--src/test/incremental/struct_add_field.rs6
-rw-r--r--src/test/incremental/struct_change_field_name.rs6
-rw-r--r--src/test/incremental/struct_change_field_type.rs6
-rw-r--r--src/test/incremental/struct_change_field_type_cross_crate/b.rs6
-rw-r--r--src/test/incremental/struct_change_nothing.rs6
-rw-r--r--src/test/incremental/struct_remove_field.rs6
-rw-r--r--src/test/incremental/type_alias_cross_crate/b.rs8
-rw-r--r--src/test/incremental/unchecked_dirty_clean.rs18
-rw-r--r--src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff2
-rw-r--r--src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff2
-rw-r--r--src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff2
-rw-r--r--src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff2
-rw-r--r--src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff2
-rw-r--r--src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir4
-rw-r--r--src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir70
-rw-r--r--src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff2
-rw-r--r--src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff2
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff2
-rw-r--r--src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff2
-rw-r--r--src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff6
-rw-r--r--src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir2
-rw-r--r--src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff25
-rw-r--r--src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir2
-rw-r--r--src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir4
-rw-r--r--src/test/mir-opt/simplify-arm.rs17
-rw-r--r--src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff140
-rw-r--r--src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff91
-rw-r--r--src/test/mir-opt/simplify_try.rs18
-rw-r--r--src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff93
-rw-r--r--src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff136
-rw-r--r--src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir75
-rw-r--r--src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir34
-rw-r--r--src/test/pretty/anonymous-types.rs24
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt1
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt8
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt4
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt10
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt32
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt28
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt38
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt2
-rw-r--r--src/test/run-make-fulldeps/coverage/conditions.rs4
-rw-r--r--src/test/run-make-fulldeps/coverage/generator.rs30
-rw-r--r--src/test/run-make-fulldeps/coverage/generics.rs10
-rw-r--r--src/test/run-make-fulldeps/coverage/loops_branches.rs8
-rw-r--r--src/test/run-make-fulldeps/issue-47551/Makefile9
-rw-r--r--src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs23
-rw-r--r--src/test/run-make-fulldeps/link-dedup/Makefile12
-rw-r--r--src/test/run-make-fulldeps/link-dedup/depa.rs7
-rw-r--r--src/test/run-make-fulldeps/link-dedup/depb.rs8
-rw-r--r--src/test/run-make-fulldeps/link-dedup/depc.rs4
-rw-r--r--src/test/run-make-fulldeps/link-dedup/empty.rs5
-rw-r--r--src/test/run-make-fulldeps/print-unversioned-files/Makefile4
-rw-r--r--src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt16
-rw-r--r--src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile9
-rw-r--r--src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs2
-rw-r--r--src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs3
-rw-r--r--src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json39
-rw-r--r--src/test/run-make/emit-named-files/Makefile33
-rw-r--r--src/test/run-make/emit-named-files/foo.rs1
-rw-r--r--src/test/run-make/incremental-session-fail/Makefile14
-rw-r--r--src/test/run-make/incremental-session-fail/foo.rs1
-rw-r--r--src/test/run-make/unstable-flag-required/Makefile1
-rw-r--r--src/test/run-make/unstable-flag-required/force-warns.stderr2
-rw-r--r--src/test/rustdoc-gui/escape-key.goml34
-rw-r--r--src/test/rustdoc-gui/search-result-colors.goml14
-rw-r--r--src/test/rustdoc-gui/search-result-display.goml12
-rw-r--r--src/test/rustdoc-gui/search-result-keyword.goml10
-rw-r--r--src/test/rustdoc-gui/sidebar.goml56
-rw-r--r--src/test/rustdoc-gui/src/lib.rs5
-rw-r--r--src/test/rustdoc-gui/src/lib2.rs11
-rw-r--r--src/test/rustdoc-ui/ignore-block-help.rs5
-rw-r--r--src/test/rustdoc-ui/ignore-block-help.stderr10
-rw-r--r--src/test/rustdoc-ui/invalid-syntax.rs2
-rw-r--r--src/test/rustdoc-ui/invalid-syntax.stderr3
-rw-r--r--src/test/rustdoc/assoc-consts.rs6
-rw-r--r--src/test/rustdoc/async-fn.rs6
-rw-r--r--src/test/rustdoc/auto_aliases.rs2
-rw-r--r--src/test/rustdoc/blanket-reexport-item.rs2
-rw-r--r--src/test/rustdoc/const-display.rs4
-rw-r--r--src/test/rustdoc/const-fn.rs2
-rw-r--r--src/test/rustdoc/const-generics/add-impl.rs2
-rw-r--r--src/test/rustdoc/const-generics/const-generic-slice.rs2
-rw-r--r--src/test/rustdoc/const-generics/const-generics-docs.rs4
-rw-r--r--src/test/rustdoc/const-generics/const-impl.rs10
-rw-r--r--src/test/rustdoc/doc-assoc-item.rs2
-rw-r--r--src/test/rustdoc/duplicate_impls/issue-33054.rs4
-rw-r--r--src/test/rustdoc/empty-impls.rs6
-rw-r--r--src/test/rustdoc/ensure-src-link.rs2
-rw-r--r--src/test/rustdoc/external-doc.rs1
-rw-r--r--src/test/rustdoc/generic-impl.rs4
-rw-r--r--src/test/rustdoc/impl-parts.rs2
-rw-r--r--src/test/rustdoc/inline_cross/assoc-items.rs9
-rw-r--r--src/test/rustdoc/inline_cross/impl-inline-without-trait.rs3
-rw-r--r--src/test/rustdoc/inline_cross/issue-31948-1.rs4
-rw-r--r--src/test/rustdoc/inline_cross/issue-31948-2.rs6
-rw-r--r--src/test/rustdoc/inline_cross/issue-31948.rs6
-rw-r--r--src/test/rustdoc/issue-21474.rs2
-rw-r--r--src/test/rustdoc/issue-29503.rs2
-rw-r--r--src/test/rustdoc/issue-33302.rs6
-rw-r--r--src/test/rustdoc/issue-45584.rs8
-rw-r--r--src/test/rustdoc/issue-50159.rs2
-rw-r--r--src/test/rustdoc/issue-51236.rs4
-rw-r--r--src/test/rustdoc/issue-53812.rs11
-rw-r--r--src/test/rustdoc/issue-54705.rs8
-rw-r--r--src/test/rustdoc/issue-55321.rs14
-rw-r--r--src/test/rustdoc/issue-56822.rs4
-rw-r--r--src/test/rustdoc/issue-60726.rs8
-rw-r--r--src/test/rustdoc/issue-76501.rs3
-rw-r--r--src/test/rustdoc/issue-78673.rs8
-rw-r--r--src/test/rustdoc/issue-85454.rs17
-rw-r--r--src/test/rustdoc/keyword.rs3
-rw-r--r--src/test/rustdoc/manual_impl.rs21
-rw-r--r--src/test/rustdoc/mut-params.rs2
-rw-r--r--src/test/rustdoc/negative-impl.rs6
-rw-r--r--src/test/rustdoc/primitive-generic-impl.rs2
-rw-r--r--src/test/rustdoc/pub-method.rs4
-rw-r--r--src/test/rustdoc/sidebar-links-to-foreign-impl.rs4
-rw-r--r--src/test/rustdoc/sized_trait.rs6
-rw-r--r--src/test/rustdoc/spotlight-from-dependency.rs2
-rw-r--r--src/test/rustdoc/src-links-auto-impls.rs12
-rw-r--r--src/test/rustdoc/synthetic_auto/basic.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/complex.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/lifetimes.rs8
-rw-r--r--src/test/rustdoc/synthetic_auto/manual.rs10
-rw-r--r--src/test/rustdoc/synthetic_auto/negative.rs8
-rw-r--r--src/test/rustdoc/synthetic_auto/nested.rs6
-rw-r--r--src/test/rustdoc/synthetic_auto/no-redundancy.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/project.rs9
-rw-r--r--src/test/rustdoc/synthetic_auto/self-referential.rs4
-rw-r--r--src/test/rustdoc/synthetic_auto/static-region.rs4
-rw-r--r--src/test/rustdoc/toggle-item-contents.rs (renamed from src/test/rustdoc/item-hide-threshold.rs)22
-rw-r--r--src/test/rustdoc/toggle-method.rs18
-rw-r--r--src/test/rustdoc/toggle-trait-fn.rs23
-rw-r--r--src/test/rustdoc/trait-attributes.rs6
-rw-r--r--src/test/rustdoc/trait-impl-items-links-and-anchors.rs68
-rw-r--r--src/test/rustdoc/typedef.rs4
-rw-r--r--src/test/rustdoc/where.rs6
-rw-r--r--src/test/ui/async-await/async-await.rs3
-rw-r--r--src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs4
-rw-r--r--src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr18
-rw-r--r--src/test/ui/async-await/issue-61076.rs4
-rw-r--r--src/test/ui/async-await/issue-61076.stderr4
-rw-r--r--src/test/ui/async-await/issue-73741-type-err.rs14
-rw-r--r--src/test/ui/async-await/issue-73741-type-err.stderr11
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs7
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs20
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr43
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr2
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs2
-rw-r--r--src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr2
-rw-r--r--src/test/ui/async-await/try-on-option-in-async.stderr30
-rw-r--r--src/test/ui/attributes/key-value-expansion-on-mac.rs1
-rw-r--r--src/test/ui/attributes/key-value-expansion-on-mac.stderr2
-rw-r--r--src/test/ui/cast/cast-ptr-to-int-const.mir.stderr (renamed from src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr)4
-rw-r--r--src/test/ui/cast/cast-ptr-to-int-const.rs20
-rw-r--r--src/test/ui/cast/cast-ptr-to-int-const.thir.stderr19
-rw-r--r--src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs13
-rw-r--r--src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.stderr (renamed from src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr)17
-rw-r--r--src/test/ui/cast/issue-84213.stderr4
-rw-r--r--src/test/ui/command/command-pre-exec.rs2
-rw-r--r--src/test/ui/confuse-field-and-method/issue-18343.stderr2
-rw-r--r--src/test/ui/confuse-field-and-method/issue-2392.stderr12
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs1
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr12
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs22
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs2
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr2
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr6
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr2
-rw-r--r--src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs5
-rw-r--r--src/test/ui/const-generics/defaults/const-param-as-default-value.rs1
-rw-r--r--src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs1
-rw-r--r--src/test/ui/const-generics/defaults/default-param-wf-concrete.rs1
-rw-r--r--src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr2
-rw-r--r--src/test/ui/const-generics/defaults/forward-declared.rs15
-rw-r--r--src/test/ui/const-generics/defaults/forward-declared.stderr27
-rw-r--r--src/test/ui/const-generics/defaults/pretty-printing-ast.rs1
-rw-r--r--src/test/ui/const-generics/defaults/pretty-printing-ast.stdout1
-rw-r--r--src/test/ui/const-generics/defaults/repr-c-issue-82792.rs1
-rw-r--r--src/test/ui/const-generics/issues/issue-62504.full.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-62504.rs2
-rw-r--r--src/test/ui/const-generics/min_const_generics/default_function_param.rs1
-rw-r--r--src/test/ui/const-generics/min_const_generics/default_function_param.stderr2
-rw-r--r--src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs20
-rw-r--r--src/test/ui/consts/const-eval/const_panic.rs10
-rw-r--r--src/test/ui/consts/const-eval/const_panic.stderr78
-rw-r--r--src/test/ui/consts/const-eval/const_panic_libcore_bin.rs3
-rw-r--r--src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr22
-rw-r--r--src/test/ui/consts/const-eval/issue-50814-2.stderr2
-rw-r--r--src/test/ui/consts/const-eval/issue-50814.stderr2
-rw-r--r--src/test/ui/consts/const-eval/issue-85155.rs21
-rw-r--r--src/test/ui/consts/const-eval/issue-85155.stderr15
-rw-r--r--src/test/ui/consts/const-eval/panic-assoc-never-type.rs3
-rw-r--r--src/test/ui/consts/const-eval/panic-assoc-never-type.stderr15
-rw-r--r--src/test/ui/consts/const-eval/panic-never-type.rs6
-rw-r--r--src/test/ui/consts/const-eval/panic-never-type.stderr23
-rw-r--r--src/test/ui/consts/const-eval/unwind-abort.rs3
-rw-r--r--src/test/ui/consts/const-eval/unwind-abort.stderr8
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs2
-rw-r--r--src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr10
-rw-r--r--src/test/ui/consts/const-unwrap.stderr6
-rw-r--r--src/test/ui/consts/const_fn_unsize.gated.stderr8
-rw-r--r--src/test/ui/consts/const_fn_unsize.rs23
-rw-r--r--src/test/ui/consts/const_fn_unsize.stock.stderr12
-rw-r--r--src/test/ui/consts/control-flow/assert.const_panic.stderr6
-rw-r--r--src/test/ui/consts/control-flow/assert.rs1
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.rs6
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn.stderr34
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs2
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr6
-rw-r--r--src/test/ui/consts/miri_unleashed/tls.stderr4
-rw-r--r--src/test/ui/consts/unsizing-cast-non-null.rs10
-rw-r--r--src/test/ui/consts/unsizing-cast-non-null.stderr12
-rw-r--r--src/test/ui/dep-graph/dep-graph-check-attr.rs2
-rw-r--r--src/test/ui/dep-graph/dep-graph-check-attr.stderr2
-rw-r--r--src/test/ui/deprecation/deprecation-lint.stderr108
-rw-r--r--src/test/ui/deprecation/suggestion.fixed17
-rw-r--r--src/test/ui/deprecation/suggestion.rs17
-rw-r--r--src/test/ui/deprecation/suggestion.stderr18
-rw-r--r--src/test/ui/derives/derive-macro-const-default.rs1
-rw-r--r--src/test/ui/error-codes/E0107.rs26
-rw-r--r--src/test/ui/error-codes/E0107.stderr94
-rw-r--r--src/test/ui/error-codes/E0605.stderr7
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr44
-rw-r--r--src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs8
-rw-r--r--src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr39
-rw-r--r--src/test/ui/feature-gates/feature-gate-member-constraints.rs10
-rw-r--r--src/test/ui/feature-gates/feature-gate-member-constraints.stderr18
-rw-r--r--src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr (renamed from src/test/ui/generator/issue-45729-unsafe-in-generator.stderr)2
-rw-r--r--src/test/ui/generator/issue-45729-unsafe-in-generator.rs3
-rw-r--r--src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr11
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-1.stderr10
-rw-r--r--src/test/ui/generator/static-mut-reference-across-yield.rs3
-rw-r--r--src/test/ui/generics/wrong-number-of-args.rs6
-rw-r--r--src/test/ui/generics/wrong-number-of-args.stderr204
-rw-r--r--src/test/ui/impl-trait/example-calendar.rs3
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr4
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs1
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs8
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs7
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs8
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr4
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr2
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs4
-rw-r--r--src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr4
-rw-r--r--src/test/ui/impl-trait/needs_least_region_or_bound.rs2
-rw-r--r--src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs4
-rw-r--r--src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr11
-rw-r--r--src/test/ui/inference/cannot-infer-async.rs4
-rw-r--r--src/test/ui/inference/cannot-infer-async.stderr9
-rw-r--r--src/test/ui/inference/cannot-infer-closure-circular.stderr2
-rw-r--r--src/test/ui/inference/cannot-infer-closure.rs4
-rw-r--r--src/test/ui/inference/cannot-infer-closure.stderr7
-rw-r--r--src/test/ui/inference/cannot-infer-partial-try-return.stderr3
-rw-r--r--src/test/ui/intrinsics/issue-28575.mir.stderr (renamed from src/test/ui/intrinsics/issue-28575.stderr)2
-rw-r--r--src/test/ui/intrinsics/issue-28575.rs3
-rw-r--r--src/test/ui/intrinsics/issue-28575.thir.stderr11
-rw-r--r--src/test/ui/intrinsics/panic-uninitialized-zeroed.rs2
-rw-r--r--src/test/ui/issues/issue-11740.rs2
-rw-r--r--src/test/ui/issues/issue-14227.mir.stderr (renamed from src/test/ui/issues/issue-14227.stderr)2
-rw-r--r--src/test/ui/issues/issue-14227.rs3
-rw-r--r--src/test/ui/issues/issue-14227.thir.stderr11
-rw-r--r--src/test/ui/issues/issue-16538.mir.stderr (renamed from src/test/ui/issues/issue-16538.stderr)6
-rw-r--r--src/test/ui/issues/issue-16538.rs3
-rw-r--r--src/test/ui/issues/issue-16538.thir.stderr27
-rw-r--r--src/test/ui/issues/issue-22289.stderr2
-rw-r--r--src/test/ui/issues/issue-22312.stderr2
-rw-r--r--src/test/ui/issues/issue-28324.mir.stderr (renamed from src/test/ui/issues/issue-28324.stderr)2
-rw-r--r--src/test/ui/issues/issue-28324.rs3
-rw-r--r--src/test/ui/issues/issue-28324.thir.stderr11
-rw-r--r--src/test/ui/issues/issue-2995.stderr7
-rw-r--r--src/test/ui/issues/issue-30123.stderr3
-rw-r--r--src/test/ui/issues/issue-32709.stderr3
-rw-r--r--src/test/ui/issues/issue-39367.rs3
-rw-r--r--src/test/ui/issues/issue-41880.stderr2
-rw-r--r--src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr (renamed from src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr)8
-rw-r--r--src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs3
-rw-r--r--src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr35
-rw-r--r--src/test/ui/issues/issue-47412.mir.stderr (renamed from src/test/ui/issues/issue-47412.stderr)4
-rw-r--r--src/test/ui/issues/issue-47412.rs6
-rw-r--r--src/test/ui/issues/issue-47412.thir.stderr11
-rw-r--r--src/test/ui/lang-items/lang-item-missing-generator.rs (renamed from src/test/ui/lang-item-missing-generator.rs)0
-rw-r--r--src/test/ui/lang-items/lang-item-missing-generator.stderr (renamed from src/test/ui/lang-item-missing-generator.stderr)0
-rw-r--r--src/test/ui/lang-items/lang-item-missing.rs (renamed from src/test/ui/lang-item-missing.rs)0
-rw-r--r--src/test/ui/lang-items/lang-item-missing.stderr (renamed from src/test/ui/lang-item-missing.stderr)0
-rw-r--r--src/test/ui/lang-items/wrong-number-generic-args-add.rs20
-rw-r--r--src/test/ui/lang-items/wrong-number-generic-args-add.stderr20
-rw-r--r--src/test/ui/lang-items/wrong-number-generic-args-index.rs19
-rw-r--r--src/test/ui/lang-items/wrong-number-generic-args-index.stderr18
-rw-r--r--src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs11
-rw-r--r--src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr10
-rw-r--r--src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs9
-rw-r--r--src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr14
-rw-r--r--src/test/ui/lint/force-warn/force-allowed-warning.rs9
-rw-r--r--src/test/ui/lint/force-warn/force-allowed-warning.stderr10
-rw-r--r--src/test/ui/lint/force-warn/force-deny-by-default-lint.rs8
-rw-r--r--src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr14
-rw-r--r--src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs9
-rw-r--r--src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr10
-rw-r--r--src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs9
-rw-r--r--src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr10
-rw-r--r--src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs12
-rw-r--r--src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr12
-rw-r--r--src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs12
-rw-r--r--src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr12
-rw-r--r--src/test/ui/lint/force-warn/force-warn-group.rs12
-rw-r--r--src/test/ui/lint/force-warn/force-warn-group.stderr12
-rw-r--r--src/test/ui/lint/lint-stability-deprecated.stderr112
-rw-r--r--src/test/ui/lto-duplicate-symbols.stderr2
-rw-r--r--src/test/ui/lto-still-runs-thread-dtors.rs2
-rw-r--r--src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs11
-rw-r--r--src/test/ui/macros/cross-crate-pat-span.rs12
-rw-r--r--src/test/ui/macros/issue-84429-matches-edition.rs9
-rw-r--r--src/test/ui/matches2021.rs12
-rw-r--r--src/test/ui/methods/method-not-found-generic-arg-elision.rs106
-rw-r--r--src/test/ui/methods/method-not-found-generic-arg-elision.stderr97
-rw-r--r--src/test/ui/mir/issue-80742.stderr4
-rw-r--r--src/test/ui/mismatched_types/cast-rfc0401.stderr7
-rw-r--r--src/test/ui/no-stdio.rs2
-rw-r--r--src/test/ui/option-to-result.stderr35
-rw-r--r--src/test/ui/parser/fn-field-parse-error-ice.rs10
-rw-r--r--src/test/ui/parser/fn-field-parse-error-ice.stderr24
-rw-r--r--src/test/ui/prelude2021.rs7
-rw-r--r--src/test/ui/proc-macro/auxiliary/api/cmp.rs (renamed from library/proc_macro/tests/test.rs)17
-rw-r--r--src/test/ui/proc-macro/auxiliary/api/mod.rs24
-rw-r--r--src/test/ui/proc-macro/auxiliary/api/parse.rs23
-rw-r--r--src/test/ui/proc-macro/test.rs12
-rw-r--r--src/test/ui/question-mark-type-infer.stderr7
-rw-r--r--src/test/ui/resolve/issue-85348.rs12
-rw-r--r--src/test/ui/resolve/issue-85348.stderr25
-rw-r--r--src/test/ui/resolve/shadow-const-param.rs20
-rw-r--r--src/test/ui/resolve/shadow-const-param.stderr20
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr42
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs2
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs2
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr (renamed from src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr)2
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs2
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr18
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr (renamed from src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr)20
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs2
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr83
-rw-r--r--src/test/ui/running-with-no-runtime.rs2
-rw-r--r--src/test/ui/safe-extern-statics-mut.mir.stderr (renamed from src/test/ui/safe-extern-statics-mut.stderr)8
-rw-r--r--src/test/ui/safe-extern-statics-mut.rs2
-rw-r--r--src/test/ui/safe-extern-statics-mut.thir.stderr35
-rw-r--r--src/test/ui/safe-extern-statics.mir.stderr (renamed from src/test/ui/safe-extern-statics.stderr)8
-rw-r--r--src/test/ui/safe-extern-statics.rs2
-rw-r--r--src/test/ui/safe-extern-statics.thir.stderr35
-rw-r--r--src/test/ui/sanitize/crt-static.rs5
-rw-r--r--src/test/ui/sanitize/crt-static.stderr4
-rw-r--r--src/test/ui/simd/simd-intrinsic-generic-comparison.rs2
-rw-r--r--src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr24
-rw-r--r--src/test/ui/span/lint-unused-unsafe.mir.stderr (renamed from src/test/ui/span/lint-unused-unsafe.stderr)18
-rw-r--r--src/test/ui/span/lint-unused-unsafe.rs3
-rw-r--r--src/test/ui/span/lint-unused-unsafe.thir.stderr66
-rw-r--r--src/test/ui/specialization/min_specialization/repeated_projection_type.stderr2
-rw-r--r--src/test/ui/stability-attribute/generics-default-stability.stderr16
-rw-r--r--src/test/ui/static/static-mut-foreign-requires-unsafe.mir.stderr (renamed from src/test/ui/static/static-mut-foreign-requires-unsafe.stderr)6
-rw-r--r--src/test/ui/static/static-mut-foreign-requires-unsafe.rs3
-rw-r--r--src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr27
-rw-r--r--src/test/ui/static/static-mut-requires-unsafe.mir.stderr (renamed from src/test/ui/static/static-mut-requires-unsafe.stderr)6
-rw-r--r--src/test/ui/static/static-mut-requires-unsafe.rs3
-rw-r--r--src/test/ui/static/static-mut-requires-unsafe.thir.stderr27
-rw-r--r--src/test/ui/suffixed-literal-meta.rs2
-rw-r--r--src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs18
-rw-r--r--src/test/ui/suggestions/imm-ref-trait-object-literal.stderr8
-rw-r--r--src/test/ui/suggestions/issue-72766.stderr2
-rw-r--r--src/test/ui/suggestions/issue-84973-2.rs13
-rw-r--r--src/test/ui/suggestions/issue-84973-2.stderr15
-rw-r--r--src/test/ui/suggestions/issue-84973-blacklist.rs29
-rw-r--r--src/test/ui/suggestions/issue-84973-blacklist.stderr64
-rw-r--r--src/test/ui/suggestions/issue-84973-negative.rs12
-rw-r--r--src/test/ui/suggestions/issue-84973-negative.stderr24
-rw-r--r--src/test/ui/suggestions/issue-84973.rs33
-rw-r--r--src/test/ui/suggestions/issue-84973.stderr15
-rw-r--r--src/test/ui/suggestions/issue-85347.rs10
-rw-r--r--src/test/ui/suggestions/issue-85347.stderr19
-rw-r--r--src/test/ui/suggestions/mut-borrow-needed-by-trait.rs1
-rw-r--r--src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr17
-rw-r--r--src/test/ui/suggestions/suggest-ref-macro.rs29
-rw-r--r--src/test/ui/suggestions/suggest-ref-macro.stderr34
-rw-r--r--src/test/ui/symbol-names/basic.legacy.stderr4
-rw-r--r--src/test/ui/symbol-names/basic.rs4
-rw-r--r--src/test/ui/symbol-names/basic.v0.stderr4
-rw-r--r--src/test/ui/symbol-names/const-generics-demangling.rs16
-rw-r--r--src/test/ui/symbol-names/const-generics-demangling.stderr16
-rw-r--r--src/test/ui/symbol-names/impl1.rs12
-rw-r--r--src/test/ui/symbol-names/impl1.v0.stderr12
-rw-r--r--src/test/ui/symbol-names/issue-60925.legacy.stderr4
-rw-r--r--src/test/ui/symbol-names/issue-60925.rs4
-rw-r--r--src/test/ui/symbol-names/issue-60925.v0.stderr4
-rw-r--r--src/test/ui/symbol-names/issue-75326.rs4
-rw-r--r--src/test/ui/symbol-names/issue-75326.v0.stderr4
-rw-r--r--src/test/ui/symbol-names/trait-objects.rs48
-rw-r--r--src/test/ui/symbol-names/trait-objects.v0.stderr56
-rw-r--r--src/test/ui/target-feature/wasm-safe.rs44
-rw-r--r--src/test/ui/thread-local-static.rs16
-rw-r--r--src/test/ui/thread-local-static.stderr44
-rw-r--r--src/test/ui/traits/alias/style_lint.rs8
-rw-r--r--src/test/ui/traits/alias/style_lint.stderr10
-rw-r--r--src/test/ui/traits/inductive-overflow/lifetime.rs2
-rw-r--r--src/test/ui/traits/inductive-overflow/lifetime.stderr4
-rw-r--r--src/test/ui/traits/safety-fn-body.mir.stderr (renamed from src/test/ui/traits/safety-fn-body.stderr)2
-rw-r--r--src/test/ui/traits/safety-fn-body.rs3
-rw-r--r--src/test/ui/traits/safety-fn-body.thir.stderr11
-rw-r--r--src/test/ui/try-block/try-block-bad-type.rs5
-rw-r--r--src/test/ui/try-block/try-block-bad-type.stderr31
-rw-r--r--src/test/ui/try-block/try-block-in-while.rs2
-rw-r--r--src/test/ui/try-block/try-block-in-while.stderr7
-rw-r--r--src/test/ui/try-block/try-block-type-error.stderr4
-rw-r--r--src/test/ui/try-on-option.stderr33
-rw-r--r--src/test/ui/try-operator-custom.rs63
-rw-r--r--src/test/ui/try-trait/bad-interconversion.rs48
-rw-r--r--src/test/ui/try-trait/bad-interconversion.stderr113
-rw-r--r--src/test/ui/try-trait/option-to-result.rs (renamed from src/test/ui/option-to-result.rs)4
-rw-r--r--src/test/ui/try-trait/option-to-result.stderr31
-rw-r--r--src/test/ui/try-trait/try-as-monad.rs24
-rw-r--r--src/test/ui/try-trait/try-on-option-diagnostics.rs (renamed from src/test/ui/try-on-option-diagnostics.rs)0
-rw-r--r--src/test/ui/try-trait/try-on-option-diagnostics.stderr (renamed from src/test/ui/try-on-option-diagnostics.stderr)40
-rw-r--r--src/test/ui/try-trait/try-on-option.rs (renamed from src/test/ui/try-on-option.rs)2
-rw-r--r--src/test/ui/try-trait/try-on-option.stderr31
-rw-r--r--src/test/ui/try-trait/try-operator-custom.rs91
-rw-r--r--src/test/ui/try-trait/try-operator-on-main.rs (renamed from src/test/ui/try-operator-on-main.rs)7
-rw-r--r--src/test/ui/try-trait/try-operator-on-main.stderr (renamed from src/test/ui/try-operator-on-main.stderr)38
-rw-r--r--src/test/ui/try-trait/try-poll.rs (renamed from src/test/ui/try-poll.rs)0
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr6
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr4
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-74761.rs1
-rw-r--r--src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr (renamed from src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr)2
-rw-r--r--src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs3
-rw-r--r--src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr11
-rw-r--r--src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs27
-rw-r--r--src/test/ui/unsafe/ranged_ints.mir.stderr (renamed from src/test/ui/unsafe/ranged_ints.stderr)2
-rw-r--r--src/test/ui/unsafe/ranged_ints.rs3
-rw-r--r--src/test/ui/unsafe/ranged_ints.thir.stderr11
-rw-r--r--src/test/ui/unsafe/ranged_ints_const.mir.stderr (renamed from src/test/ui/unsafe/ranged_ints_const.stderr)2
-rw-r--r--src/test/ui/unsafe/ranged_ints_const.rs3
-rw-r--r--src/test/ui/unsafe/ranged_ints_const.thir.stderr11
-rw-r--r--src/test/ui/unsafe/ranged_ints_macro.rs3
-rw-r--r--src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr (renamed from src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr)32
-rw-r--r--src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs3
-rw-r--r--src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr122
-rw-r--r--src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.mir.stderr (renamed from src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr)2
-rw-r--r--src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs3
-rw-r--r--src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr11
-rw-r--r--src/test/ui/unsafe/unsafe-fn-deref-ptr.mir.stderr (renamed from src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr)2
-rw-r--r--src/test/ui/unsafe/unsafe-fn-deref-ptr.rs3
-rw-r--r--src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr11
-rw-r--r--src/test/ui/unsafe/unsafe-unstable-const-fn.mir.stderr (renamed from src/test/ui/unsafe/unsafe-unstable-const-fn.stderr)2
-rw-r--r--src/test/ui/unsafe/unsafe-unstable-const-fn.rs3
-rw-r--r--src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr11
-rw-r--r--src/test/ui/wf/wf-static-method.nll.stderr2
-rw-r--r--src/test/ui/wf/wf-static-method.rs3
-rw-r--r--src/test/ui/wf/wf-static-method.stderr29
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/.cargo/config1
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml5
-rw-r--r--src/tools/clippy/CHANGELOG.md201
-rw-r--r--src/tools/clippy/COPYRIGHT2
-rw-r--r--src/tools/clippy/Cargo.toml5
-rw-r--r--src/tools/clippy/LICENSE-APACHE2
-rw-r--r--src/tools/clippy/LICENSE-MIT2
-rw-r--r--src/tools/clippy/README.md3
-rw-r--r--src/tools/clippy/build.rs2
-rw-r--r--src/tools/clippy/clippy.toml1
-rw-r--r--src/tools/clippy/clippy_dev/src/lib.rs4
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs2
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/bit_mask.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_if.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/comparison_chain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/consts.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/deprecated_lints.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/double_comparison.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/duration_subsec.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_variants.rs80
-rw-r--r--src/tools/clippy/clippy_lints/src/eq_op.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/erasing_op.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/eval_order_dependence.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/identity_op.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_impl.rs134
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs643
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_collect.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs445
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/map_clone.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_discriminant.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs99
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs135
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs56
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrow.rs219
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs112
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_multiply.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/open_options.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/repeat_once.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/single_component_path_imports.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/transmuting_null.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/try_err.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unicode.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs92
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs293
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/verbose_file_reads.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_div_zero.rs2
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml1
-rw-r--r--src/tools/clippy/clippy_utils/src/attrs.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs22
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs36
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs267
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs124
-rw-r--r--src/tools/clippy/clippy_utils/src/msrvs.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/numeric_literal.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ptr.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs31
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs48
-rw-r--r--src/tools/clippy/clippy_utils/src/usage.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs77
-rw-r--r--src/tools/clippy/doc/basics.md2
-rw-r--r--src/tools/clippy/doc/release.md2
-rw-r--r--src/tools/clippy/mini-macro/Cargo.toml14
-rw-r--r--src/tools/clippy/mini-macro/src/lib.rs29
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/rustc_tools_util/src/lib.rs12
-rw-r--r--src/tools/clippy/tests/clippy.toml1
-rw-r--r--src/tools/clippy/tests/compile-test.rs42
-rw-r--r--src/tools/clippy/tests/dogfood.rs97
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs19
-rw-r--r--src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs14
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7231.rs10
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-7272.rs12
-rw-r--r--src/tools/clippy/tests/ui/crashes/procedural_macro.rs11
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.rs2
-rw-r--r--src/tools/clippy/tests/ui/deprecated.rs2
-rw-r--r--src/tools/clippy/tests/ui/deprecated.stderr14
-rw-r--r--src/tools/clippy/tests/ui/enum_variants.rs7
-rw-r--r--src/tools/clippy/tests/ui/enum_variants.stderr37
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed3
-rw-r--r--src/tools/clippy/tests/ui/eta.rs3
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr16
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powi.fixed5
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powi.rs5
-rw-r--r--src/tools/clippy/tests/ui/floating_point_powi.stderr34
-rw-r--r--src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed14
-rw-r--r--src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs14
-rw-r--r--src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr40
-rw-r--r--src/tools/clippy/tests/ui/functions.stderr18
-rw-r--r--src/tools/clippy/tests/ui/impl.rs31
-rw-r--r--src/tools/clippy/tests/ui/impl.stderr30
-rw-r--r--src/tools/clippy/tests/ui/macro_use_imports.fixed3
-rw-r--r--src/tools/clippy/tests/ui/macro_use_imports.rs3
-rw-r--r--src/tools/clippy/tests/ui/macro_use_imports.stderr14
-rw-r--r--src/tools/clippy/tests/ui/manual_str_repeat.fixed66
-rw-r--r--src/tools/clippy/tests/ui/manual_str_repeat.rs66
-rw-r--r--src/tools/clippy/tests/ui/manual_str_repeat.stderr64
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or.fixed15
-rw-r--r--src/tools/clippy/tests/ui/manual_unwrap_or.rs15
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.fixed5
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.rs10
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.stderr13
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding2.fixed16
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding2.rs18
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding2.stderr36
-rw-r--r--src/tools/clippy/tests/ui/missing-doc-impl.rs5
-rw-r--r--src/tools/clippy/tests/ui/missing-doc-impl.stderr8
-rw-r--r--src/tools/clippy/tests/ui/module_name_repetitions.rs8
-rw-r--r--src/tools/clippy/tests/ui/needless_bitwise_bool.fixed40
-rw-r--r--src/tools/clippy/tests/ui/needless_bitwise_bool.rs40
-rw-r--r--src/tools/clippy/tests/ui/needless_bitwise_bool.stderr10
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed17
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs17
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.stderr16
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow_pat.rs151
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow_pat.stderr112
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.fixed19
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.rs17
-rw-r--r--src/tools/clippy/tests/ui/needless_collect.stderr50
-rw-r--r--src/tools/clippy/tests/ui/needless_collect_indirect.rs8
-rw-r--r--src/tools/clippy/tests/ui/needless_question_mark.fixed5
-rw-r--r--src/tools/clippy/tests/ui/needless_question_mark.rs5
-rw-r--r--src/tools/clippy/tests/ui/needless_question_mark.stderr2
-rw-r--r--src/tools/clippy/tests/ui/no_effect.rs3
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed6
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr13
-rw-r--r--src/tools/clippy/tests/ui/ref_binding_to_reference.rs76
-rw-r--r--src/tools/clippy/tests/ui/ref_binding_to_reference.stderr88
-rw-r--r--src/tools/clippy/tests/ui/similar_names.rs4
-rw-r--r--src/tools/clippy/tests/ui/similar_names.stderr4
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.fixed4
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.rs4
-rw-r--r--src/tools/clippy/tests/ui/single_char_pattern.stderr4
-rw-r--r--src/tools/clippy/tests/ui/suspicious_splitn.rs20
-rw-r--r--src/tools/clippy/tests/ui/suspicious_splitn.stderr75
-rw-r--r--src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_wraps.rs2
-rw-r--r--src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed3
-rw-r--r--src/tools/clippy/tests/ui/unseparated_prefix_literals.rs3
-rw-r--r--src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr18
-rw-r--r--src/tools/clippy/tests/ui/unused_async.rs15
-rw-r--r--src/tools/clippy/tests/ui/unused_async.stderr13
-rw-r--r--src/tools/clippy/tests/ui/use_self.fixed30
-rw-r--r--src/tools/clippy/tests/ui/use_self.rs30
-rw-r--r--src/tools/clippy/tests/ui/use_self.stderr8
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.fixed19
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.rs19
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion.stderr20
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.fixed175
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.rs175
-rw-r--r--src/tools/clippy/tests/ui/while_let_on_iterator.stderr78
-rw-r--r--src/tools/clippy/tests/ui/write_with_newline.stderr4
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention.rs1
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention.stderr48
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention2.rs30
-rw-r--r--src/tools/clippy/tests/ui/wrong_self_convention2.stderr18
-rwxr-xr-xsrc/tools/clippy/util/cov.sh37
-rw-r--r--src/tools/compiletest/src/runtest.rs6
-rw-r--r--src/tools/jsondocck/Cargo.toml5
-rw-r--r--src/tools/jsondocck/src/main.rs12
-rwxr-xr-xsrc/tools/linkchecker/linkcheck.sh10
-rw-r--r--src/tools/linkchecker/main.rs547
-rw-r--r--src/tools/linkchecker/tests/basic_broken/foo.html5
-rw-r--r--src/tools/linkchecker/tests/broken_fragment_local/foo.html5
-rw-r--r--src/tools/linkchecker/tests/broken_fragment_remote/bar.html4
-rw-r--r--src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html5
-rw-r--r--src/tools/linkchecker/tests/broken_redir/foo.html5
-rw-r--r--src/tools/linkchecker/tests/broken_redir/redir-bad.html10
-rw-r--r--src/tools/linkchecker/tests/checks.rs77
-rw-r--r--src/tools/linkchecker/tests/directory_link/foo.html5
-rw-r--r--src/tools/linkchecker/tests/directory_link/somedir/index.html4
-rw-r--r--src/tools/linkchecker/tests/redirect_loop/foo.html5
-rw-r--r--src/tools/linkchecker/tests/redirect_loop/redir-bad.html10
-rw-r--r--src/tools/linkchecker/tests/valid/inner/bar.html7
-rw-r--r--src/tools/linkchecker/tests/valid/inner/foo.html14
-rw-r--r--src/tools/linkchecker/tests/valid/inner/redir-bad.html11
-rw-r--r--src/tools/linkchecker/tests/valid/inner/redir-target.html5
-rw-r--r--src/tools/linkchecker/tests/valid/inner/redir.html10
-rw-r--r--src/tools/linkchecker/tests/valid/outer.html5
m---------src/tools/miri18
m---------src/tools/rls0
m---------src/tools/rust-analyzer34
-rw-r--r--src/tools/rustdoc-gui/tester.js7
-rw-r--r--src/tools/tidy/src/deps.rs10
-rw-r--r--src/tools/tidy/src/error_codes_check.rs27
-rw-r--r--src/tools/tidy/src/ui_tests.rs4
-rw-r--r--src/tools/tier-check/src/main.rs2
-rw-r--r--triagebot.toml2
1295 files changed, 19345 insertions, 11011 deletions
diff --git a/.mailmap b/.mailmap
index cd617ca2f42..213aa6eff66 100644
--- a/.mailmap
+++ b/.mailmap
@@ -43,6 +43,7 @@ Brian Anderson <banderson@mozilla.com> <andersrb@gmail.com>
 Brian Anderson <banderson@mozilla.com> <banderson@mozilla.org>
 Brian Dawn <brian.t.dawn@gmail.com>
 Brian Leibig <brian@brianleibig.com> Brian Leibig <brian.leibig@gmail.com>
+Noah Lev <camelidcamel@gmail.com>
 Noah Lev <camelidcamel@gmail.com> <37223377+camelid@users.noreply.github.com>
 Carl-Anton Ingmarsson <mail@carlanton.se> <ca.ingmarsson@gmail.com>
 Carol (Nichols || Goulding) <carol.nichols@gmail.com> <193874+carols10cents@users.noreply.github.com>
diff --git a/Cargo.lock b/Cargo.lock
index da65b376d19..5c1736c692e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -278,6 +278,7 @@ dependencies = [
  "humantime 2.0.1",
  "ignore",
  "im-rc",
+ "itertools 0.10.0",
  "jobserver",
  "lazy_static",
  "lazycell",
@@ -293,7 +294,7 @@ dependencies = [
  "rand 0.8.3",
  "rustc-workspace-hack",
  "rustfix",
- "semver 0.10.0",
+ "semver 1.0.1",
  "serde",
  "serde_ignored",
  "serde_json",
@@ -441,9 +442,9 @@ version = "0.1.0"
 
 [[package]]
 name = "cc"
-version = "1.0.67"
+version = "1.0.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
+checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
 dependencies = [
  "jobserver",
 ]
@@ -551,10 +552,10 @@ name = "clippy"
 version = "0.1.54"
 dependencies = [
  "cargo_metadata 0.12.0",
- "clippy-mini-macro-test",
  "clippy_lints",
  "compiletest_rs",
  "derive-new",
+ "filetime",
  "quote",
  "regex",
  "rustc-workspace-hack",
@@ -567,10 +568,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "clippy-mini-macro-test"
-version = "0.2.0"
-
-[[package]]
 name = "clippy_dev"
 version = "0.0.1"
 dependencies = [
@@ -655,9 +652,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.43"
+version = "0.1.45"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65af2dcae4779003dfa91aedc6ade7bdc7ba685944e50a8b4f9380df376a4466"
+checksum = "787187ae221adfcda34b03006f1617099e4ae26b50e5a4db282496014ab75837"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
@@ -1716,6 +1713,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "itertools"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
+dependencies = [
+ "either",
+]
+
+[[package]]
 name = "itoa"
 version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1743,11 +1749,10 @@ dependencies = [
  "fs-err",
  "getopts",
  "jsonpath_lib",
- "lazy_static",
+ "once_cell",
  "regex",
- "serde",
  "serde_json",
- "shlex 0.1.1",
+ "shlex",
 ]
 
 [[package]]
@@ -2128,16 +2133,16 @@ dependencies = [
  "serde",
  "serde_derive",
  "serde_json",
- "shlex 1.0.0",
+ "shlex",
  "tempfile",
  "toml",
 ]
 
 [[package]]
 name = "measureme"
-version = "9.1.1"
+version = "9.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49cf14eb7d2eea897d9949b68f19e165638755e3a1a3c0941b6b6c3e00141f2c"
+checksum = "78f7a41bc6f856a2cf0e95094ad5121f82500e2d9a0f3c0171d98f6566d8117d"
 dependencies = [
  "log",
  "memmap2",
@@ -2195,9 +2200,9 @@ dependencies = [
 
 [[package]]
 name = "minifier"
-version = "0.0.39"
+version = "0.0.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6cdf618de5c9c98d4a7b2e0d1f1e44f82a19196cfd94040bb203621c25d28d98"
+checksum = "5594542d20834f2b974f5e5fb8e0cf1c67a2119dcadc29ef5d93a081fb30cc08"
 dependencies = [
  "macro-utils",
 ]
@@ -2289,6 +2294,7 @@ dependencies = [
  "hex 0.4.2",
  "libc",
  "log",
+ "measureme",
  "rand 0.8.3",
  "rustc-workspace-hack",
  "rustc_version",
@@ -2845,9 +2851,9 @@ dependencies = [
 
 [[package]]
 name = "racer"
-version = "2.1.46"
+version = "2.1.47"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7cbda48a9124ed2e83766d2c15e3725710d344abca35fad8cf52341a55883b1"
+checksum = "513c70e67444a0d62fdc581dffa521c6820942a5f08300d0864863f8d0e750e3"
 dependencies = [
  "bitflags",
  "clap",
@@ -3876,6 +3882,7 @@ dependencies = [
  "rand 0.7.3",
  "rustc_ast",
  "rustc_data_structures",
+ "rustc_errors",
  "rustc_fs_util",
  "rustc_graphviz",
  "rustc_hir",
@@ -4673,6 +4680,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "semver"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d023dabf011d5dcb5ac64e3685d97d3b0ef412911077a2851455c6098524a723"
+dependencies = [
+ "serde",
+]
+
+[[package]]
 name = "semver-parser"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4794,12 +4810,6 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
 
 [[package]]
 name = "shlex"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
-
-[[package]]
-name = "shlex"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d"
@@ -5031,9 +5041,9 @@ dependencies = [
 
 [[package]]
 name = "tar"
-version = "0.4.33"
+version = "0.4.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0bcfbd6a598361fda270d82469fff3d65089dc33e175c9a131f7b4cd395f228"
+checksum = "7d779dc6aeff029314570f666ec83f19df7280bb36ef338442cfa8c604021b80"
 dependencies = [
  "filetime",
  "libc",
diff --git a/README.md b/README.md
index 5ec94e189f8..af6a4090a27 100644
--- a/README.md
+++ b/README.md
@@ -19,8 +19,28 @@ Read ["Installation"] from [The Book].
 ## Installing from Source
 
 The Rust build system uses a Python script called `x.py` to build the compiler,
-which manages the bootstrapping process. More information about it can be found
-by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild].
+which manages the bootstrapping process. It lives in the root of the project.
+
+The `x.py` command can be run directly on most systems in the following format: 
+
+```sh
+./x.py <subcommand> [flags]
+```
+
+This is how the documentation and examples assume you are running `x.py`.
+
+Systems such as Ubuntu 20.04 LTS do not create the necessary `python` command by default when Python is installed that allows `x.py` to be run directly. In that case you can either create a symlink for `python` (Ubuntu provides the `python-is-python3` package for this), or run `x.py` using Python itself:
+
+```sh
+# Python 3
+python3 x.py <subcommand> [flags]
+
+# Python 2.7
+python2.7 x.py <subcommand> [flags]
+```
+
+More information about `x.py` can be found
+by running it with the `--help` flag or reading the [rustc dev guide][rustcguidebuild].
 
 [gettingstarted]: https://rustc-dev-guide.rust-lang.org/getting-started.html
 [rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html
diff --git a/RELEASES.md b/RELEASES.md
index 92312d8d556..60b3359c1b6 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,24 @@
+Version 1.52.1 (2021-05-10)
+============================
+
+This release disables incremental compilation, unless the user has explicitly
+opted in via the newly added RUSTC_FORCE_INCREMENTAL=1 environment variable.
+
+This is due to the widespread, and frequently occuring, breakage encountered by
+Rust users due to newly enabled incremental verification in 1.52.0. Notably,
+Rust users **should** upgrade to 1.52.0 or 1.52.1: the bugs that are detected by
+newly added incremental verification are still present in past stable versions,
+and are not yet fixed on any channel. These bugs can lead to miscompilation of
+Rust binaries.
+
+These problems only affect incremental builds, so release builds with Cargo
+should not be affected unless the user has explicitly opted into incremental.
+Debug and check builds are affected.
+
+See [84970] for more details.
+
+[84970]: https://github.com/rust-lang/rust/issues/84970
+
 Version 1.52.0 (2021-05-06)
 ============================
 
diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs
index c648147d108..7eeec4aa86b 100644
--- a/compiler/rustc_apfloat/src/lib.rs
+++ b/compiler/rustc_apfloat/src/lib.rs
@@ -35,7 +35,6 @@
 #![forbid(unsafe_code)]
 #![feature(iter_zip)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 
 #[macro_use]
 extern crate alloc;
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index ffec28a395f..7c79b4aab3c 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -10,15 +10,13 @@
 )]
 #![feature(box_syntax)]
 #![feature(box_patterns)]
-#![cfg_attr(bootstrap, feature(const_fn))] // For the `transmute` in `P::new`
-#![cfg_attr(not(bootstrap), feature(const_fn_unsize))] // For the `transmute` in `P::new`
+#![cfg_attr(bootstrap, feature(const_fn_unsize))]
 #![feature(const_fn_transmute)]
-#![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
 #![feature(iter_zip)]
 #![feature(label_break_value)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
+#![feature(min_specialization)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 483135ed3a3..866f2180bb6 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -560,8 +560,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
         )
     }
 
-    /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`,
-    /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_ok(()) }`
+    /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`,
+    /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }`
     /// and save the block id to use it as a break target for desugaring of the `?` operator.
     fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> {
         self.with_catch_scope(body.id, |this| {
@@ -590,9 +590,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
             let ok_wrapped_span =
                 this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None);
 
-            // `::std::ops::Try::from_ok($tail_expr)`
+            // `::std::ops::Try::from_output($tail_expr)`
             block.expr = Some(this.wrap_in_try_constructor(
-                hir::LangItem::TryFromOk,
+                hir::LangItem::TryTraitFromOutput,
                 try_span,
                 tail_expr,
                 ok_wrapped_span,
@@ -1579,14 +1579,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
             self.allow_try_trait.clone(),
         );
 
-        // `Try::into_result(<expr>)`
+        // `Try::branch(<expr>)`
         let scrutinee = {
             // expand <expr>
             let sub_expr = self.lower_expr_mut(sub_expr);
 
             self.expr_call_lang_item_fn(
                 unstable_span,
-                hir::LangItem::TryIntoResult,
+                hir::LangItem::TryTraitBranch,
                 arena_vec![self; sub_expr],
             )
         };
@@ -1604,8 +1604,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
         };
         let attrs = vec![attr];
 
-        // `Ok(val) => #[allow(unreachable_code)] val,`
-        let ok_arm = {
+        // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,`
+        let continue_arm = {
             let val_ident = Ident::with_dummy_span(sym::val);
             let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
             let val_expr = self.arena.alloc(self.expr_ident_with_attrs(
@@ -1614,27 +1614,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 val_pat_nid,
                 ThinVec::from(attrs.clone()),
             ));
-            let ok_pat = self.pat_ok(span, val_pat);
-            self.arm(ok_pat, val_expr)
+            let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
+            self.arm(continue_pat, val_expr)
         };
 
-        // `Err(err) => #[allow(unreachable_code)]
-        //              return Try::from_error(From::from(err)),`
-        let err_arm = {
-            let err_ident = Ident::with_dummy_span(sym::err);
-            let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident);
-            let from_expr = {
-                let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid);
-                self.expr_call_lang_item_fn(
-                    try_span,
-                    hir::LangItem::FromFrom,
-                    arena_vec![self; err_expr],
-                )
-            };
-            let from_err_expr = self.wrap_in_try_constructor(
-                hir::LangItem::TryFromError,
-                unstable_span,
-                from_expr,
+        // `ControlFlow::Break(residual) =>
+        //     #[allow(unreachable_code)]
+        //     return Try::from_residual(residual),`
+        let break_arm = {
+            let residual_ident = Ident::with_dummy_span(sym::residual);
+            let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident);
+            let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid);
+            let from_residual_expr = self.wrap_in_try_constructor(
+                hir::LangItem::TryTraitFromResidual,
+                try_span,
+                self.arena.alloc(residual_expr),
                 unstable_span,
             );
             let thin_attrs = ThinVec::from(attrs);
@@ -1645,25 +1639,25 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     try_span,
                     hir::ExprKind::Break(
                         hir::Destination { label: None, target_id },
-                        Some(from_err_expr),
+                        Some(from_residual_expr),
                     ),
                     thin_attrs,
                 ))
             } else {
                 self.arena.alloc(self.expr(
                     try_span,
-                    hir::ExprKind::Ret(Some(from_err_expr)),
+                    hir::ExprKind::Ret(Some(from_residual_expr)),
                     thin_attrs,
                 ))
             };
 
-            let err_pat = self.pat_err(try_span, err_local);
-            self.arm(err_pat, ret_expr)
+            let break_pat = self.pat_cf_break(try_span, residual_local);
+            self.arm(break_pat, ret_expr)
         };
 
         hir::ExprKind::Match(
             scrutinee,
-            arena_vec![self; err_arm, ok_arm],
+            arena_vec![self; break_arm, continue_arm],
             hir::MatchSource::TryDesugar,
         )
     }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 740dfc65df8..0ff1efd8165 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -31,7 +31,6 @@
 //! in the HIR, especially for multiple identifiers.
 
 #![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(box_patterns)]
 #![feature(iter_zip)]
 #![recursion_limit = "256"]
@@ -44,7 +43,7 @@ use rustc_ast::walk_list;
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
@@ -199,7 +198,7 @@ pub trait ResolverAstLowering {
 
     fn next_node_id(&mut self) -> NodeId;
 
-    fn trait_map(&self) -> &NodeMap<Vec<hir::TraitCandidate>>;
+    fn take_trait_map(&mut self) -> NodeMap<Vec<hir::TraitCandidate>>;
 
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>;
 
@@ -332,7 +331,7 @@ pub fn lower_crate<'a, 'hir>(
         lifetimes_to_define: Vec::new(),
         is_collecting_in_band_lifetimes: false,
         in_scope_lifetimes: Vec::new(),
-        allow_try_trait: Some([sym::try_trait][..].into()),
+        allow_try_trait: Some([sym::control_flow_enum, sym::try_trait_v2][..].into()),
         allow_gen_future: Some([sym::gen_future][..].into()),
     }
     .lower_crate(krate)
@@ -502,14 +501,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let proc_macros =
             c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect();
 
-        let trait_map = self
-            .resolver
-            .trait_map()
-            .iter()
-            .filter_map(|(&k, v)| {
-                self.node_id_to_hir_id.get(k).and_then(|id| id.as_ref()).map(|id| (*id, v.clone()))
-            })
-            .collect();
+        let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
+        for (k, v) in self.resolver.take_trait_map().into_iter() {
+            if let Some(Some(hir_id)) = self.node_id_to_hir_id.get(k) {
+                let map = trait_map.entry(hir_id.owner).or_default();
+                map.insert(hir_id.local_id, v.into_boxed_slice());
+            }
+        }
 
         let mut def_id_to_hir_id = IndexVec::default();
 
@@ -2490,14 +2488,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.pat(span, hir::PatKind::Lit(expr))
     }
 
-    fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
+    fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
         let field = self.single_pat_field(span, pat);
-        self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field)
+        self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field)
     }
 
-    fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
+    fn pat_cf_break(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
         let field = self.single_pat_field(span, pat);
-        self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field)
+        self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field)
     }
 
     fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> {
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 4215d5c55a0..4996c2195ef 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -713,10 +713,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
     gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
     gate_all!(inline_const, "inline-const is experimental");
     gate_all!(
-        extended_key_value_attributes,
-        "arbitrary expressions in key-value attributes are unstable"
-    );
-    gate_all!(
         const_generics_defaults,
         "default values for const generic parameters are experimental"
     );
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index c9e2d202da9..26da18b571c 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -6,7 +6,6 @@
 
 #![feature(bindings_after_at)]
 #![feature(iter_is_partitioned)]
-#![feature(box_syntax)]
 #![feature(box_patterns)]
 #![recursion_limit = "256"]
 
diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs
index 67b66284f66..6bd543ff150 100644
--- a/compiler/rustc_ast_pretty/src/lib.rs
+++ b/compiler/rustc_ast_pretty/src/lib.rs
@@ -1,6 +1,5 @@
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(box_patterns)]
 #![recursion_limit = "256"]
 
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index da9d89745a8..b7bb896f318 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -955,12 +955,12 @@ impl<'a> State<'a> {
                 self.pclose();
             }
             ast::TyKind::AnonymousStruct(ref fields, ..) => {
-                self.s.word("struct");
-                self.print_record_struct_body(fields, ty.span);
+                self.head("struct");
+                self.print_record_struct_body(&fields, ty.span);
             }
             ast::TyKind::AnonymousUnion(ref fields, ..) => {
-                self.s.word("union");
-                self.print_record_struct_body(fields, ty.span);
+                self.head("union");
+                self.print_record_struct_body(&fields, ty.span);
             }
             ast::TyKind::Paren(ref typ) => {
                 self.popen();
@@ -1397,12 +1397,7 @@ impl<'a> State<'a> {
         }
     }
 
-    crate fn print_record_struct_body(
-        &mut self,
-        fields: &Vec<ast::FieldDef>,
-        span: rustc_span::Span,
-    ) {
-        self.nbsp();
+    crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
         self.bopen();
         self.hardbreak_if_not_bol();
 
@@ -1451,6 +1446,7 @@ impl<'a> State<'a> {
             }
             ast::VariantData::Struct(ref fields, ..) => {
                 self.print_where_clause(&generics.where_clause);
+                self.nbsp();
                 self.print_record_struct_body(fields, span);
             }
         }
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index ab68d24e4b3..3fb11f77872 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -4,8 +4,6 @@
 //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
 //! to this crate.
 
-#![cfg_attr(bootstrap, feature(or_patterns))]
-
 #[macro_use]
 extern crate rustc_macros;
 
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 17b7793c7dd..2393e0b9ebf 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -9,7 +9,6 @@
 #![feature(decl_macro)]
 #![feature(iter_zip)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_quote)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index e6792def567..a6f5925149b 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -26,12 +26,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
 
 [[package]]
-name = "byteorder"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
-
-[[package]]
 name = "cfg-if"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -39,18 +33,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
- "byteorder",
  "cranelift-bforest",
  "cranelift-codegen-meta",
  "cranelift-codegen-shared",
@@ -60,13 +53,12 @@ dependencies = [
  "regalloc",
  "smallvec",
  "target-lexicon",
- "thiserror",
 ]
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "cranelift-codegen-shared",
  "cranelift-entity",
@@ -74,18 +66,18 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -95,15 +87,14 @@ dependencies = [
 
 [[package]]
 name = "cranelift-jit"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
  "cranelift-entity",
  "cranelift-module",
  "cranelift-native",
- "errno",
  "libc",
  "log",
  "region",
@@ -113,20 +104,19 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
  "cranelift-entity",
  "log",
- "thiserror",
 ]
 
 [[package]]
 name = "cranelift-native"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "cranelift-codegen",
  "target-lexicon",
@@ -134,8 +124,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.73.0"
-source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36"
+version = "0.74.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -155,37 +145,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "errno"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "winapi",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067"
-dependencies = [
- "gcc",
- "libc",
-]
-
-[[package]]
-name = "gcc"
-version = "0.3.55"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
-
-[[package]]
 name = "gimli"
-version = "0.23.0"
+version = "0.24.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
+checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
 dependencies = [
  "indexmap",
 ]
@@ -242,33 +205,15 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.23.0"
+version = "0.24.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
+checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170"
 dependencies = [
  "crc32fast",
  "indexmap",
 ]
 
 [[package]]
-name = "proc-macro2"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
-dependencies = [
- "unicode-xid",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
 name = "regalloc"
 version = "0.0.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -323,49 +268,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
 
 [[package]]
-name = "syn"
-version = "1.0.60"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-xid",
-]
-
-[[package]]
 name = "target-lexicon"
 version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834"
 
 [[package]]
-name = "thiserror"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "1.0.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
-
-[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 2789207c655..fd149af4547 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -9,15 +9,15 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] }
-cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
-cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true }
-cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" }
+cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", features = ["unwind"] }
+cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
+cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", optional = true }
+cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" }
 target-lexicon = "0.12.0"
-gimli = { version = "0.23.0", default-features = false, features = ["write"]}
-object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
+gimli = { version = "0.24.0", default-features = false, features = ["write"]}
+object = { version = "0.24.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
 
 ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" }
 indexmap = "1.0.2"
@@ -25,11 +25,11 @@ libloading = { version = "0.6.0", optional = true }
 smallvec = "1.6.1"
 
 # Uncomment to use local checkout of cranelift
-#[patch."https://github.com/bytecodealliance/wasmtime/"]
+#[patch."https://github.com/bytecodealliance/wasmtime.git"]
 #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
 #cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
 #cranelift-module = { path = "../wasmtime/cranelift/module" }
-#cranelift-native = { path = ../wasmtime/cranelift/native" }
+#cranelift-native = { path = "../wasmtime/cranelift/native" }
 #cranelift-jit = { path = "../wasmtime/cranelift/jit" }
 #cranelift-object = { path = "../wasmtime/cranelift/object" }
 
@@ -70,13 +70,5 @@ debug = false
 opt-level = 0
 debug = false
 
-[profile.dev.package.syn]
-opt-level = 0
-debug = false
-
-[profile.release.package.syn]
-opt-level = 0
-debug = false
-
 [package.metadata.rust-analyzer]
 rustc_private = true
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
index e058a972ead..923deb9aec4 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
@@ -40,9 +40,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 
 [[package]]
 name = "cc"
-version = "1.0.67"
+version = "1.0.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
+checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
 
 [[package]]
 name = "cfg-if"
@@ -56,7 +56,7 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.40"
+version = "0.1.43"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -132,9 +132,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.94"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e"
+checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -195,9 +195,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.18"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
+checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh
index f7fcef10774..54b7a94750c 100755
--- a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh
@@ -32,7 +32,7 @@ popd
 git clone https://github.com/rust-lang/compiler-builtins.git || echo "rust-lang/compiler-builtins has already been cloned"
 pushd compiler-builtins
 git checkout -- .
-git checkout 0.1.40
+git checkout 0.1.43
 git apply ../../crate_patches/000*-compiler-builtins-*.patch
 popd
 
diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0002-compiler-builtins-Disable-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Disable-128bit-atomic-operations.patch
index 7daea99f579..7daea99f579 100644
--- a/compiler/rustc_codegen_cranelift/crate_patches/0002-compiler-builtins-Disable-128bit-atomic-operations.patch
+++ b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Disable-128bit-atomic-operations.patch
diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch
deleted file mode 100644
index b4acc4f5b73..00000000000
--- a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 7078cca3cb614e1e82da428380b4e16fc3afef46 Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Thu, 21 Jan 2021 14:46:36 +0100
-Subject: [PATCH] Remove rotate_left from Int
-
----
- src/int/mod.rs | 5 -----
- 1 file changed, 5 deletions(-)
-
-diff --git a/src/int/mod.rs b/src/int/mod.rs
-index 06054c8..3bea17b 100644
---- a/src/int/mod.rs
-+++ b/src/int/mod.rs
-@@ -85,7 +85,6 @@ pub trait Int:
-     fn wrapping_sub(self, other: Self) -> Self;
-     fn wrapping_shl(self, other: u32) -> Self;
-     fn wrapping_shr(self, other: u32) -> Self;
--    fn rotate_left(self, other: u32) -> Self;
-     fn overflowing_add(self, other: Self) -> (Self, bool);
-     fn leading_zeros(self) -> u32;
- }
-@@ -209,10 +208,6 @@ macro_rules! int_impl_common {
-             <Self>::wrapping_shr(self, other)
-         }
- 
--        fn rotate_left(self, other: u32) -> Self {
--            <Self>::rotate_left(self, other)
--        }
--
-         fn overflowing_add(self, other: Self) -> (Self, bool) {
-             <Self>::overflowing_add(self, other)
-         }
--- 
-2.26.2.7.g19db9cfb68
-
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index 77ba72df8ef..7d608df9253 100644
--- a/compiler/rustc_codegen_cranelift/example/std_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/std_example.rs
@@ -187,20 +187,6 @@ unsafe fn test_mm_slli_si128() {
     );
     let r = _mm_slli_si128(a, 16);
     assert_eq_m128i(r, _mm_set1_epi8(0));
-
-    #[rustfmt::skip]
-    let a = _mm_setr_epi8(
-        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
-    );
-    let r = _mm_slli_si128(a, -1);
-    assert_eq_m128i(_mm_set1_epi8(0), r);
-
-    #[rustfmt::skip]
-    let a = _mm_setr_epi8(
-        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
-    );
-    let r = _mm_slli_si128(a, -0x80000000);
-    assert_eq_m128i(r, _mm_set1_epi8(0));
 }
 
 #[cfg(target_arch = "x86_64")]
@@ -295,7 +281,7 @@ unsafe fn test_mm_extract_epi8() {
         8, 9, 10, 11, 12, 13, 14, 15
     );
     let r1 = _mm_extract_epi8(a, 0);
-    let r2 = _mm_extract_epi8(a, 19);
+    let r2 = _mm_extract_epi8(a, 3);
     assert_eq!(r1, 0xFF);
     assert_eq!(r2, 3);
 }
diff --git a/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch
index 8cfffe580a1..ba0eaacd828 100644
--- a/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch
+++ b/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch
@@ -39,46 +39,6 @@ index a35897e..f0bf645 100644
  
  pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
      match decode(v).1 {
-diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs
-index 0475aeb..9558198 100644
---- a/library/core/tests/num/int_macros.rs
-+++ b/library/core/tests/num/int_macros.rs
-@@ -88,6 +88,7 @@ mod tests {
-                 assert_eq!(x.trailing_ones(), 0);
-             }
- 
-+            /*
-             #[test]
-             fn test_rotate() {
-                 assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
-@@ -112,6 +113,7 @@ mod tests {
-                 assert_eq!(B.rotate_left(128), B);
-                 assert_eq!(C.rotate_left(128), C);
-             }
-+            */
- 
-             #[test]
-             fn test_swap_bytes() {
-diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs
-index 04ed14f..a6e372e 100644
---- a/library/core/tests/num/uint_macros.rs
-+++ b/library/core/tests/num/uint_macros.rs
-@@ -52,6 +52,7 @@ mod tests {
-                 assert_eq!(x.trailing_ones(), 0);
-             }
- 
-+            /*
-             #[test]
-             fn test_rotate() {
-                 assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A);
-@@ -76,6 +77,7 @@ mod tests {
-                 assert_eq!(B.rotate_left(128), B);
-                 assert_eq!(C.rotate_left(128), C);
-             }
-+            */
- 
-             #[test]
-             fn test_swap_bytes() {
 diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
 index 1a6be3a..42dbd59 100644
 --- a/library/core/tests/ptr.rs
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 5442e3345aa..9fe6e093a7b 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-04-28"
+channel = "nightly-2021-05-26"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
index 4821a07ac5d..43c4887669c 100644
--- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh
@@ -24,18 +24,6 @@ index 5bd1147cad5..10d68a2ff14 100644
 +
  [patch."https://github.com/rust-lang/rust-clippy"]
  clippy_lints = { path = "src/tools/clippy/clippy_lints" }
-diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
-index 23e689fcae7..5f077b765b6 100644
---- a/compiler/rustc_data_structures/Cargo.toml
-+++ b/compiler/rustc_data_structures/Cargo.toml
-@@ -32,7 +32,6 @@ tempfile = "3.0.5"
-
- [dependencies.parking_lot]
- version = "0.11"
--features = ["nightly"]
-
- [target.'cfg(windows)'.dependencies]
- winapi = { version = "0.3", features = ["fileapi", "psapi"] }
 diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
 index d95b5b7f17f..00b6f0e3635 100644
 --- a/library/alloc/Cargo.toml
@@ -44,11 +32,12 @@ index d95b5b7f17f..00b6f0e3635 100644
 
  [dependencies]
  core = { path = "../core" }
--compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std'] }
-+compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std', 'no-asm'] }
+-compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] }
++compiler_builtins = { version = "0.1.43", features = ['rustc-dep-of-std', 'no-asm'] }
 
  [dev-dependencies]
  rand = "0.7"
+ rand_xorshift = "0.2"
 EOF
 
 cat > config.toml <<EOF
diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh
index 3afcea8f06b..0d99d2c507c 100755
--- a/compiler/rustc_codegen_cranelift/scripts/tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh
@@ -116,6 +116,7 @@ function extended_sysroot_tests() {
     pushd regex
     echo "[TEST] rust-lang/regex example shootout-regex-dna"
     cargo clean
+    export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning
     # Make sure `[codegen mono items] start` doesn't poison the diff
     ../build/cargo.sh build --example shootout-regex-dna --target $TARGET_TRIPLE
     if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs
index fc0823302e0..bd54adc53ee 100644
--- a/compiler/rustc_codegen_cranelift/src/archive.rs
+++ b/compiler/rustc_codegen_cranelift/src/archive.rs
@@ -160,7 +160,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
             };
 
             if !self.no_builtin_ranlib {
-                match object::File::parse(&data) {
+                match object::File::parse(&*data) {
                     Ok(object) => {
                         symbol_table.insert(
                             entry_name.as_bytes().to_vec(),
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 3ec5c14ff17..ec3e17e5b75 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -110,11 +110,6 @@ pub(crate) fn codegen_fn<'tcx>(
     // Verify function
     verify_func(tcx, &clif_comments, &context.func);
 
-    // Perform rust specific optimizations
-    tcx.sess.time("optimize clif ir", || {
-        crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments);
-    });
-
     // If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128`
     // instruction, which doesn't have an encoding.
     context.compute_cfg();
@@ -125,10 +120,14 @@ pub(crate) fn codegen_fn<'tcx>(
     // invalidate it when it would change.
     context.domtree.clear();
 
-    context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
+    // Perform rust specific optimizations
+    tcx.sess.time("optimize clif ir", || {
+        crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments);
+    });
 
     // Define function
     tcx.sess.time("define function", || {
+        context.want_disasm = crate::pretty_clif::should_write_ir(tcx);
         module
             .define_function(func_id, context, &mut NullTrapSink {}, &mut NullStackMapSink {})
             .unwrap()
@@ -870,7 +869,7 @@ pub(crate) fn codegen_operand<'tcx>(
 pub(crate) fn codegen_panic<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, span: Span) {
     let location = fx.get_caller_location(span).load_scalar(fx);
 
-    let msg_ptr = fx.anonymous_str("assert", msg_str);
+    let msg_ptr = fx.anonymous_str(msg_str);
     let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
     let args = [msg_ptr, msg_len, location];
 
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index c12d6d0f141..488ff6e1349 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -347,19 +347,10 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
         self.module.isa().triple()
     }
 
-    pub(crate) fn anonymous_str(&mut self, prefix: &str, msg: &str) -> Value {
-        use std::collections::hash_map::DefaultHasher;
-        use std::hash::{Hash, Hasher};
-
-        let mut hasher = DefaultHasher::new();
-        msg.hash(&mut hasher);
-        let msg_hash = hasher.finish();
+    pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value {
         let mut data_ctx = DataContext::new();
         data_ctx.define(msg.as_bytes().to_vec().into_boxed_slice());
-        let msg_id = self
-            .module
-            .declare_data(&format!("__{}_{:08x}", prefix, msg_hash), Linkage::Local, false, false)
-            .unwrap();
+        let msg_id = self.module.declare_anonymous_data(false, false).unwrap();
 
         // Ignore DuplicateDefinition error, as the data will be the same
         let _ = self.module.define_data(msg_id, &data_ctx);
diff --git a/compiler/rustc_codegen_cranelift/src/config.rs b/compiler/rustc_codegen_cranelift/src/config.rs
index e59a0cb0a23..eef3c8c8d6e 100644
--- a/compiler/rustc_codegen_cranelift/src/config.rs
+++ b/compiler/rustc_codegen_cranelift/src/config.rs
@@ -48,6 +48,12 @@ pub struct BackendConfig {
     /// Can be set using `-Cllvm-args=display_cg_time=...`.
     pub display_cg_time: bool,
 
+    /// The register allocator to use.
+    ///
+    /// Defaults to the value of `CG_CLIF_REGALLOC` or `backtracking` otherwise. Can be set using
+    /// `-Cllvm-args=regalloc=...`.
+    pub regalloc: String,
+
     /// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run
     /// once before passing the clif ir to Cranelift for compilation.
     ///
@@ -74,6 +80,8 @@ impl Default for BackendConfig {
                 args.split(' ').map(|arg| arg.to_string()).collect()
             },
             display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"),
+            regalloc: std::env::var("CG_CLIF_REGALLOC")
+                .unwrap_or_else(|_| "backtracking".to_string()),
             enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
             disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
         }
@@ -93,6 +101,7 @@ impl BackendConfig {
                 match name {
                     "mode" => config.codegen_mode = value.parse()?,
                     "display_cg_time" => config.display_cg_time = parse_bool(name, value)?,
+                    "regalloc" => config.regalloc = value.to_string(),
                     "enable_verifier" => config.enable_verifier = parse_bool(name, value)?,
                     "disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?,
                     _ => return Err(format!("Unknown option `{}`", name)),
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 0a0e02d2639..3ba12c4e96d 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -2,11 +2,13 @@
 
 use rustc_span::DUMMY_SP;
 
+use rustc_ast::Mutability;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::ErrorReported;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::{
-    read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Pointer, Scalar,
+    alloc_range, read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc,
+    Scalar,
 };
 use rustc_middle::ty::ConstKind;
 
@@ -175,9 +177,9 @@ pub(crate) fn codegen_const_value<'tcx>(
                 let mut alloc = Allocation::from_bytes(
                     std::iter::repeat(0).take(size.bytes_usize()).collect::<Vec<u8>>(),
                     align,
+                    Mutability::Not,
                 );
-                let ptr = Pointer::new(AllocId(!0), Size::ZERO); // The alloc id is never used
-                alloc.write_scalar(fx, ptr, x.into(), size).unwrap();
+                alloc.write_scalar(fx, alloc_range(Size::ZERO, size), x.into()).unwrap();
                 let alloc = fx.tcx.intern_const_alloc(alloc);
                 return CValue::by_ref(pointer_for_allocation(fx, alloc), layout);
             }
@@ -374,8 +376,19 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
         data_ctx.set_align(alloc.align.bytes());
 
         if let Some(section_name) = section_name {
-            // FIXME set correct segment for Mach-O files
-            data_ctx.set_segment_section("", &*section_name);
+            let (segment_name, section_name) = if tcx.sess.target.is_like_osx {
+                if let Some(names) = section_name.split_once(',') {
+                    names
+                } else {
+                    tcx.sess.fatal(&format!(
+                        "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma",
+                        section_name
+                    ));
+                }
+            } else {
+                ("", &*section_name)
+            };
+            data_ctx.set_segment_section(segment_name, section_name);
         }
 
         let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec();
@@ -437,12 +450,89 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
     operand: &Operand<'tcx>,
 ) -> Option<ConstValue<'tcx>> {
     match operand {
-        Operand::Copy(_) | Operand::Move(_) => None,
         Operand::Constant(const_) => match const_.literal {
             ConstantKind::Ty(const_) => {
                 fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value()
             }
             ConstantKind::Val(val, _) => Some(val),
         },
+        // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
+        // inside a temporary before being passed to the intrinsic requiring the const argument.
+        // This code tries to find a single constant defining definition of the referenced local.
+        Operand::Copy(place) | Operand::Move(place) => {
+            if !place.projection.is_empty() {
+                return None;
+            }
+            let mut computed_const_val = None;
+            for bb_data in fx.mir.basic_blocks() {
+                for stmt in &bb_data.statements {
+                    match &stmt.kind {
+                        StatementKind::Assign(local_and_rvalue) if &local_and_rvalue.0 == place => {
+                            match &local_and_rvalue.1 {
+                                Rvalue::Cast(CastKind::Misc, operand, ty) => {
+                                    if computed_const_val.is_some() {
+                                        return None; // local assigned twice
+                                    }
+                                    if !matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) {
+                                        return None;
+                                    }
+                                    let const_val = mir_operand_get_const_val(fx, operand)?;
+                                    if fx.layout_of(ty).size
+                                        != const_val.try_to_scalar_int()?.size()
+                                    {
+                                        return None;
+                                    }
+                                    computed_const_val = Some(const_val);
+                                }
+                                Rvalue::Use(operand) => {
+                                    computed_const_val = mir_operand_get_const_val(fx, operand)
+                                }
+                                _ => return None,
+                            }
+                        }
+                        StatementKind::SetDiscriminant { place: stmt_place, variant_index: _ }
+                            if &**stmt_place == place =>
+                        {
+                            return None;
+                        }
+                        StatementKind::LlvmInlineAsm(_) | StatementKind::CopyNonOverlapping(_) => {
+                            return None;
+                        } // conservative handling
+                        StatementKind::Assign(_)
+                        | StatementKind::FakeRead(_)
+                        | StatementKind::SetDiscriminant { .. }
+                        | StatementKind::StorageLive(_)
+                        | StatementKind::StorageDead(_)
+                        | StatementKind::Retag(_, _)
+                        | StatementKind::AscribeUserType(_, _)
+                        | StatementKind::Coverage(_)
+                        | StatementKind::Nop => {}
+                    }
+                }
+                match &bb_data.terminator().kind {
+                    TerminatorKind::Goto { .. }
+                    | TerminatorKind::SwitchInt { .. }
+                    | TerminatorKind::Resume
+                    | TerminatorKind::Abort
+                    | TerminatorKind::Return
+                    | TerminatorKind::Unreachable
+                    | TerminatorKind::Drop { .. }
+                    | TerminatorKind::Assert { .. } => {}
+                    TerminatorKind::DropAndReplace { .. }
+                    | TerminatorKind::Yield { .. }
+                    | TerminatorKind::GeneratorDrop
+                    | TerminatorKind::FalseEdge { .. }
+                    | TerminatorKind::FalseUnwind { .. } => unreachable!(),
+                    TerminatorKind::InlineAsm { .. } => return None,
+                    TerminatorKind::Call { destination: Some((call_place, _)), .. }
+                        if call_place == place =>
+                    {
+                        return None;
+                    }
+                    TerminatorKind::Call { .. } => {}
+                }
+            }
+            computed_const_val
+        }
     }
 }
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 24d933728db..9cf51d15c8c 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -73,9 +73,8 @@ fn reuse_workproduct_for_cgu(
     let mut object = None;
     let work_product = cgu.work_product(tcx);
     if let Some(saved_file) = &work_product.saved_file {
-        let obj_out = tcx
-            .output_filenames(())
-            .temp_path(OutputType::Object, Some(&cgu.name().as_str()));
+        let obj_out =
+            tcx.output_filenames(()).temp_path(OutputType::Object, Some(&cgu.name().as_str()));
         object = Some(obj_out.clone());
         let source_file = rustc_incremental::in_incr_comp_dir(&incr_comp_session_dir, &saved_file);
         if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) {
@@ -145,7 +144,13 @@ fn module_codegen(
             }
         }
     }
-    crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut cx.unwind_context, false);
+    crate::main_shim::maybe_create_entry_wrapper(
+        tcx,
+        &mut module,
+        &mut cx.unwind_context,
+        false,
+        cgu.is_primary(),
+    );
 
     let debug_context = cx.debug_context;
     let unwind_context = cx.unwind_context;
@@ -275,9 +280,8 @@ pub(crate) fn run_aot(
                 .as_str()
                 .to_string();
 
-            let tmp_file = tcx
-                .output_filenames(())
-                .temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
+            let tmp_file =
+                tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
 
             let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| {
                 crate::metadata::write_metadata(tcx, object);
@@ -352,8 +356,7 @@ fn codegen_global_asm(tcx: TyCtxt<'_>, cgu_name: &str, global_asm: &str) {
         .collect::<Vec<_>>()
         .join("\n");
 
-    let output_object_file =
-        tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name));
+    let output_object_file = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name));
 
     // Assemble `global_asm`
     let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm");
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index 632e86da736..4a99cb727c8 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -45,6 +45,7 @@ fn create_jit_module<'tcx>(
         &mut jit_module,
         &mut cx.unwind_context,
         true,
+        true,
     );
 
     (jit_module, cx)
@@ -206,7 +207,7 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> {
         use object::{Object, ObjectSymbol};
         let lib = libloading::Library::new(&path).unwrap();
         let obj = std::fs::read(path).unwrap();
-        let obj = object::File::parse(&obj).unwrap();
+        let obj = object::File::parse(&*obj).unwrap();
         imported_symbols.extend(obj.dynamic_symbols().filter_map(|symbol| {
             let name = symbol.name().unwrap().to_string();
             if name.is_empty() || !symbol.is_global() || symbol.is_undefined() {
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 4ab4c2957ca..09c5e6031c7 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -24,14 +24,22 @@ pub(crate) fn codegen_inline_asm<'tcx>(
         let true_ = fx.bcx.ins().iconst(types::I32, 1);
         fx.bcx.ins().trapnz(true_, TrapCode::User(1));
         return;
-    } else if template[0] == InlineAsmTemplatePiece::String("mov rsi, rbx".to_string())
-        && template[1] == InlineAsmTemplatePiece::String("\n".to_string())
-        && template[2] == InlineAsmTemplatePiece::String("cpuid".to_string())
-        && template[3] == InlineAsmTemplatePiece::String("\n".to_string())
-        && template[4] == InlineAsmTemplatePiece::String("xchg rsi, rbx".to_string())
+    } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
+        && matches!(
+            template[1],
+            InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
+        )
+        && template[2] == InlineAsmTemplatePiece::String("\n".to_string())
+        && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string())
+        && template[4] == InlineAsmTemplatePiece::String("\n".to_string())
+        && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string())
+        && matches!(
+            template[6],
+            InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
+        )
     {
         assert_eq!(operands.len(), 4);
-        let (leaf, eax_place) = match operands[0] {
+        let (leaf, eax_place) = match operands[1] {
             InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
                 let reg = expect_reg(reg);
                 assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::ax));
@@ -42,10 +50,14 @@ pub(crate) fn codegen_inline_asm<'tcx>(
             }
             _ => unreachable!(),
         };
-        let ebx_place = match operands[1] {
+        let ebx_place = match operands[0] {
             InlineAsmOperand::Out { reg, late: true, place } => {
-                let reg = expect_reg(reg);
-                assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::si));
+                assert_eq!(
+                    reg,
+                    InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
+                        X86InlineAsmRegClass::reg
+                    ))
+                );
                 crate::base::codegen_place(fx, place.unwrap())
             }
             _ => unreachable!(),
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs
index 9de12e759bc..d02dfd93c3e 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs
@@ -12,6 +12,7 @@ pub(crate) fn codegen_cpuid_call<'tcx>(
 ) -> (Value, Value, Value, Value) {
     let leaf_0 = fx.bcx.create_block();
     let leaf_1 = fx.bcx.create_block();
+    let leaf_7 = fx.bcx.create_block();
     let leaf_8000_0000 = fx.bcx.create_block();
     let leaf_8000_0001 = fx.bcx.create_block();
     let unsupported_leaf = fx.bcx.create_block();
@@ -25,6 +26,7 @@ pub(crate) fn codegen_cpuid_call<'tcx>(
     let mut switch = cranelift_frontend::Switch::new();
     switch.set_entry(0, leaf_0);
     switch.set_entry(1, leaf_1);
+    switch.set_entry(7, leaf_7);
     switch.set_entry(0x8000_0000, leaf_8000_0000);
     switch.set_entry(0x8000_0001, leaf_8000_0001);
     switch.emit(&mut fx.bcx, leaf, unsupported_leaf);
@@ -43,6 +45,11 @@ pub(crate) fn codegen_cpuid_call<'tcx>(
     let edx_features = fx.bcx.ins().iconst(types::I32, 1 << 25 /* sse */ | 1 << 26 /* sse2 */);
     fx.bcx.ins().jump(dest, &[cpu_signature, additional_information, ecx_features, edx_features]);
 
+    fx.bcx.switch_to_block(leaf_7);
+    // This leaf technically has subleaves, but we just return zero for all subleaves.
+    let zero = fx.bcx.ins().iconst(types::I32, 0);
+    fx.bcx.ins().jump(dest, &[zero, zero, zero, zero]);
+
     fx.bcx.switch_to_block(leaf_8000_0000);
     let extended_max_basic_leaf = fx.bcx.ins().iconst(types::I32, 0);
     let zero = fx.bcx.ins().iconst(types::I32, 0);
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 435737f3a51..52896fc7127 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -8,8 +8,8 @@ mod simd;
 pub(crate) use cpuid::codegen_cpuid_call;
 pub(crate) use llvm::codegen_llvm_intrinsic_call;
 
-use rustc_span::symbol::{sym, kw};
 use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_span::symbol::{kw, sym};
 
 use crate::prelude::*;
 use cranelift_codegen::ir::AtomicRmwOp;
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 940d2514f74..c2f469fa021 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -86,9 +86,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
 
                 let idx_bytes = match idx_const {
                     ConstValue::ByRef { alloc, offset } => {
-                        let ptr = Pointer::new(AllocId(0 /* dummy */), offset);
                         let size = Size::from_bytes(4 * ret_lane_count /* size_of([u32; ret_lane_count]) */);
-                        alloc.get_bytes(fx, ptr, size).unwrap()
+                        alloc.get_bytes(fx, alloc_range(offset, size)).unwrap()
                     }
                     _ => unreachable!("{:?}", idx_const),
                 };
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index ff6e1856059..4ee887cd5af 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -256,6 +256,8 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
 
     flags_builder.set("enable_llvm_abi_extensions", "true").unwrap();
 
+    flags_builder.set("regalloc", &backend_config.regalloc).unwrap();
+
     use rustc_session::config::OptLevel;
     match sess.opts.optimize {
         OptLevel::No => {
@@ -277,21 +279,23 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
             builder
         }
         Some(value) => {
-            let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+            let mut builder =
+                cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
             if let Err(_) = builder.enable(value) {
                 sess.fatal("The specified target cpu isn't currently supported by Cranelift.");
             }
             builder
         }
         None => {
-            let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
+            let mut builder =
+                cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap();
             // Don't use "haswell" as the default, as it implies `has_lzcnt`.
             // macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
             builder.enable("nehalem").unwrap();
             builder
         }
     };
-    
+
     isa_builder.finish(flags)
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index d1958c5f96b..8fd1e4f5811 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -14,6 +14,7 @@ pub(crate) fn maybe_create_entry_wrapper(
     module: &mut impl Module,
     unwind_context: &mut UnwindContext,
     is_jit: bool,
+    is_primary_cgu: bool,
 ) {
     let (main_def_id, is_main_fn) = match tcx.entry_fn(()) {
         Some((def_id, entry_ty)) => (
@@ -26,8 +27,12 @@ pub(crate) fn maybe_create_entry_wrapper(
         None => return,
     };
 
-    let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
-    if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() {
+    if main_def_id.is_local() {
+        let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
+        if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() {
+            return;
+        }
+    } else if !is_primary_cgu {
         return;
     }
 
diff --git a/compiler/rustc_codegen_cranelift/src/trap.rs b/compiler/rustc_codegen_cranelift/src/trap.rs
index 819c8b51558..21d3e68dbc7 100644
--- a/compiler/rustc_codegen_cranelift/src/trap.rs
+++ b/compiler/rustc_codegen_cranelift/src/trap.rs
@@ -21,7 +21,7 @@ fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) {
     }
 
     let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, fx.symbol_name, msg);
-    let msg_ptr = fx.anonymous_str("trap", &real_msg);
+    let msg_ptr = fx.anonymous_str(&real_msg);
     fx.bcx.ins().call(puts, &[msg_ptr]);
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 9a572c3501f..171f39805f8 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -561,6 +561,7 @@ impl<'tcx> CPlace<'tcx> {
                     dst_align,
                     src_align,
                     true,
+                    MemFlags::trusted(),
                 );
             }
             CValueInner::ByRef(_, Some(_)) => todo!(),
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index bc9d99ed4a1..c8cf0116c64 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -69,6 +69,7 @@ impl abi::HasDataLayout for Builder<'_, '_, '_> {
 }
 
 impl ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
+    #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.cx.tcx
     }
@@ -81,6 +82,7 @@ impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
 }
 
 impl HasTargetSpec for Builder<'_, '_, 'tcx> {
+    #[inline]
     fn target_spec(&self) -> &Target {
         &self.cx.target_spec()
     }
@@ -98,6 +100,7 @@ impl abi::LayoutOf for Builder<'_, '_, 'tcx> {
 impl Deref for Builder<'_, 'll, 'tcx> {
     type Target = CodegenCx<'ll, 'tcx>;
 
+    #[inline]
     fn deref(&self) -> &Self::Target {
         self.cx
     }
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index b26969a5012..bb16c90cd12 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -14,7 +14,6 @@ use tracing::debug;
 
 use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
 use rustc_middle::ty::{self, Instance, TypeFoldable};
-use rustc_target::spec::RelocModel;
 
 /// Codegens a reference to a fn/method item, monomorphizing and
 /// inlining as it goes.
@@ -181,7 +180,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
                 llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
             }
 
-            if cx.tcx.sess.relocation_model() == RelocModel::Static {
+            if cx.should_assume_dso_local(llfn, true) {
                 llvm::LLVMRustSetDSOLocal(llfn, true);
             }
         }
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 99046839973..e50d5506e22 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -282,6 +282,12 @@ impl CodegenCx<'ll, 'tcx> {
             }
         }
 
+        unsafe {
+            if self.should_assume_dso_local(g, true) {
+                llvm::LLVMRustSetDSOLocal(g, true);
+            }
+        }
+
         self.instances.borrow_mut().insert(instance, g);
         g
     }
@@ -363,6 +369,10 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
             set_global_alignment(&self, g, self.align_of(ty));
             llvm::LLVMSetInitializer(g, v);
 
+            if self.should_assume_dso_local(g, true) {
+                llvm::LLVMRustSetDSOLocal(g, true);
+            }
+
             // As an optimization, all shared statics which do not have interior
             // mutability are placed into read-only memory.
             if !is_mutable && self.type_is_freeze(ty) {
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index f5c54b11c08..6aa952462fa 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -765,18 +765,21 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
 }
 
 impl HasDataLayout for CodegenCx<'ll, 'tcx> {
+    #[inline]
     fn data_layout(&self) -> &TargetDataLayout {
         &self.tcx.data_layout
     }
 }
 
 impl HasTargetSpec for CodegenCx<'ll, 'tcx> {
+    #[inline]
     fn target_spec(&self) -> &Target {
         &self.tcx.sess.target
     }
 }
 
 impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> {
+    #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 0db6659f8e2..1e70664e64d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -1457,7 +1457,6 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> {
     enum_type: Ty<'tcx>,
     layout: TyAndLayout<'tcx>,
     tag_type_metadata: Option<&'ll DIType>,
-    containing_scope: &'ll DIScope,
     common_members: Vec<Option<&'ll DIType>>,
     span: Span,
 }
@@ -1486,13 +1485,9 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
             _ => bug!(),
         };
 
-        // This will always find the metadata in the type map.
         let fallback = use_enum_fallback(cx);
-        let self_metadata = if fallback {
-            self.containing_scope
-        } else {
-            type_metadata(cx, self.enum_type, self.span)
-        };
+        // This will always find the metadata in the type map.
+        let self_metadata = type_metadata(cx, self.enum_type, self.span);
 
         match self.layout.variants {
             Variants::Single { index } => {
@@ -1507,7 +1502,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                     cx,
                     self.layout,
                     variant_info,
-                    NoTag,
+                    None,
                     self_metadata,
                     self.span,
                 );
@@ -1539,13 +1534,26 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                 ..
             } => {
                 let tag_info = if fallback {
-                    RegularTag {
+                    // For MSVC, we generate a union of structs for each variant with an explicit
+                    // discriminant field roughly equivalent to the following C:
+                    // ```c
+                    // union enum$<{name}> {
+                    //   struct {variant 0 name} {
+                    //     tag$ variant$;
+                    //     <variant 0 fields>
+                    //   } variant0;
+                    //   <other variant structs>
+                    // }
+                    // ```
+                    // The natvis in `intrinsic.nativs` then matches on `this.variant0.variant$` to
+                    // determine which variant is active and then displays it.
+                    Some(DirectTag {
                         tag_field: Field::from(tag_field),
                         tag_type_metadata: self.tag_type_metadata.unwrap(),
-                    }
+                    })
                 } else {
                     // This doesn't matter in this case.
-                    NoTag
+                    None
                 };
                 variants
                     .iter_enumerated()
@@ -1574,7 +1582,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
 
                         MemberDescription {
                             name: if fallback {
-                                String::new()
+                                format!("variant{}", i.as_u32())
                             } else {
                                 variant_info.variant_name()
                             },
@@ -1599,77 +1607,135 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                 ref variants,
                 tag_field,
             } => {
+                let calculate_niche_value = |i: VariantIdx| {
+                    if i == dataful_variant {
+                        None
+                    } else {
+                        let value = (i.as_u32() as u128)
+                            .wrapping_sub(niche_variants.start().as_u32() as u128)
+                            .wrapping_add(niche_start);
+                        let value = tag.value.size(cx).truncate(value);
+                        // NOTE(eddyb) do *NOT* remove this assert, until
+                        // we pass the full 128-bit value to LLVM, otherwise
+                        // truncation will be silent and remain undetected.
+                        assert_eq!(value as u64 as u128, value);
+                        Some(value as u64)
+                    }
+                };
+
+                // For MSVC, we will generate a union of two fields, one for the dataful variant
+                // and one that just points to the discriminant. We also create an enum that
+                // contains tag values for the non-dataful variants and make the discriminant field
+                // that type. We then use natvis to render the enum type correctly in Windbg/VS.
+                // This will generate debuginfo roughly equivalent to the following C:
+                // ```c
+                // union enum$<{name}, {min niche}, {max niche}, {dataful variant name}> {
+                //   struct <dataful variant name> {
+                //     <fields in dataful variant>
+                //   } dataful_variant;
+                //   enum Discriminant$ {
+                //     <non-dataful variants>
+                //   } discriminant;
+                // }
+                // ```
+                // The natvis in `intrinsic.natvis` matches on the type name `enum$<*, *, *, *>`
+                // and evaluates `this.discriminant`. If the value is between the min niche and max
+                // niche, then the enum is in the dataful variant and `this.dataful_variant` is
+                // rendered. Otherwise, the enum is in one of the non-dataful variants. In that
+                // case, we just need to render the name of the `this.discriminant` enum.
                 if fallback {
-                    let variant = self.layout.for_variant(cx, dataful_variant);
-                    // Create a description of the non-null variant.
-                    let (variant_type_metadata, member_description_factory) = describe_enum_variant(
+                    let dataful_variant_layout = self.layout.for_variant(cx, dataful_variant);
+
+                    let mut discr_enum_ty = tag.value.to_ty(cx.tcx);
+                    // If the niche is the NULL value of a reference, then `discr_enum_ty` will be a RawPtr.
+                    // CodeView doesn't know what to do with enums whose base type is a pointer so we fix this up
+                    // to just be `usize`.
+                    if let ty::RawPtr(_) = discr_enum_ty.kind() {
+                        discr_enum_ty = cx.tcx.types.usize;
+                    }
+
+                    let tags: Vec<_> = variants
+                        .iter_enumerated()
+                        .filter_map(|(variant_idx, _)| {
+                            calculate_niche_value(variant_idx).map(|tag| {
+                                let variant = variant_info_for(variant_idx);
+                                let name = variant.variant_name();
+
+                                Some(unsafe {
+                                    llvm::LLVMRustDIBuilderCreateEnumerator(
+                                        DIB(cx),
+                                        name.as_ptr().cast(),
+                                        name.len(),
+                                        tag as i64,
+                                        !discr_enum_ty.is_signed(),
+                                    )
+                                })
+                            })
+                        })
+                        .collect();
+
+                    let discr_enum = unsafe {
+                        llvm::LLVMRustDIBuilderCreateEnumerationType(
+                            DIB(cx),
+                            self_metadata,
+                            "Discriminant$".as_ptr().cast(),
+                            "Discriminant$".len(),
+                            unknown_file_metadata(cx),
+                            UNKNOWN_LINE_NUMBER,
+                            tag.value.size(cx).bits(),
+                            tag.value.align(cx).abi.bits() as u32,
+                            create_DIArray(DIB(cx), &tags),
+                            type_metadata(cx, discr_enum_ty, self.span),
+                            true,
+                        )
+                    };
+
+                    let variant_info = variant_info_for(dataful_variant);
+                    let (variant_type_metadata, member_desc_factory) = describe_enum_variant(
                         cx,
-                        variant,
-                        variant_info_for(dataful_variant),
-                        OptimizedTag,
-                        self.containing_scope,
+                        dataful_variant_layout,
+                        variant_info,
+                        Some(NicheTag),
+                        self_metadata,
                         self.span,
                     );
 
-                    let variant_member_descriptions =
-                        member_description_factory.create_member_descriptions(cx);
+                    let member_descriptions = member_desc_factory.create_member_descriptions(cx);
 
                     set_members_of_composite_type(
                         cx,
                         self.enum_type,
                         variant_type_metadata,
-                        variant_member_descriptions,
+                        member_descriptions,
                         Some(&self.common_members),
                     );
 
-                    // Encode the information about the null variant in the union
-                    // member's name.
-                    let mut name = String::from("RUST$ENCODED$ENUM$");
-                    // Right now it's not even going to work for `niche_start > 0`,
-                    // and for multiple niche variants it only supports the first.
-                    fn compute_field_path<'a, 'tcx>(
-                        cx: &CodegenCx<'a, 'tcx>,
-                        name: &mut String,
-                        layout: TyAndLayout<'tcx>,
-                        offset: Size,
-                        size: Size,
-                    ) {
-                        for i in 0..layout.fields.count() {
-                            let field_offset = layout.fields.offset(i);
-                            if field_offset > offset {
-                                continue;
-                            }
-                            let inner_offset = offset - field_offset;
-                            let field = layout.field(cx, i);
-                            if inner_offset + size <= field.size {
-                                write!(name, "{}$", i).unwrap();
-                                compute_field_path(cx, name, field, inner_offset, size);
-                            }
-                        }
-                    }
-                    compute_field_path(
-                        cx,
-                        &mut name,
-                        self.layout,
-                        self.layout.fields.offset(tag_field),
-                        self.layout.field(cx, tag_field).size,
-                    );
-                    let variant_info = variant_info_for(*niche_variants.start());
-                    variant_info.map_struct_name(|variant_name| {
-                        name.push_str(variant_name);
-                    });
-
-                    // Create the (singleton) list of descriptions of union members.
-                    vec![MemberDescription {
-                        name,
-                        type_metadata: variant_type_metadata,
-                        offset: Size::ZERO,
-                        size: variant.size,
-                        align: variant.align.abi,
-                        flags: DIFlags::FlagZero,
-                        discriminant: None,
-                        source_info: variant_info.source_info(cx),
-                    }]
+                    let (size, align) =
+                        cx.size_and_align_of(dataful_variant_layout.field(cx, tag_field).ty);
+
+                    vec![
+                        MemberDescription {
+                            // Name the dataful variant so that we can identify it for natvis
+                            name: "dataful_variant".to_string(),
+                            type_metadata: variant_type_metadata,
+                            offset: Size::ZERO,
+                            size: self.layout.size,
+                            align: self.layout.align.abi,
+                            flags: DIFlags::FlagZero,
+                            discriminant: None,
+                            source_info: variant_info.source_info(cx),
+                        },
+                        MemberDescription {
+                            name: "discriminant".into(),
+                            type_metadata: discr_enum,
+                            offset: dataful_variant_layout.fields.offset(tag_field),
+                            size,
+                            align,
+                            flags: DIFlags::FlagZero,
+                            discriminant: None,
+                            source_info: None,
+                        },
+                    ]
                 } else {
                     variants
                         .iter_enumerated()
@@ -1681,7 +1747,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                                     cx,
                                     variant,
                                     variant_info,
-                                    OptimizedTag,
+                                    Some(NicheTag),
                                     self_metadata,
                                     self.span,
                                 );
@@ -1697,19 +1763,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> {
                                 Some(&self.common_members),
                             );
 
-                            let niche_value = if i == dataful_variant {
-                                None
-                            } else {
-                                let value = (i.as_u32() as u128)
-                                    .wrapping_sub(niche_variants.start().as_u32() as u128)
-                                    .wrapping_add(niche_start);
-                                let value = tag.value.size(cx).truncate(value);
-                                // NOTE(eddyb) do *NOT* remove this assert, until
-                                // we pass the full 128-bit value to LLVM, otherwise
-                                // truncation will be silent and remain undetected.
-                                assert_eq!(value as u64 as u128, value);
-                                Some(value as u64)
-                            };
+                            let niche_value = calculate_niche_value(i);
 
                             MemberDescription {
                                 name: variant_info.variant_name(),
@@ -1771,14 +1825,10 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> {
     }
 }
 
-// FIXME: terminology here should be aligned with `abi::TagEncoding`.
-// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`.
-// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead.
 #[derive(Copy, Clone)]
 enum EnumTagInfo<'ll> {
-    RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType },
-    OptimizedTag,
-    NoTag,
+    DirectTag { tag_field: Field, tag_type_metadata: &'ll DIType },
+    NicheTag,
 }
 
 #[derive(Copy, Clone)]
@@ -1859,7 +1909,7 @@ fn describe_enum_variant(
     cx: &CodegenCx<'ll, 'tcx>,
     layout: layout::TyAndLayout<'tcx>,
     variant: VariantInfo<'_, 'tcx>,
-    discriminant_info: EnumTagInfo<'ll>,
+    discriminant_info: Option<EnumTagInfo<'ll>>,
     containing_scope: &'ll DIScope,
     span: Span,
 ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
@@ -1882,12 +1932,11 @@ fn describe_enum_variant(
     let (offsets, args) = if use_enum_fallback(cx) {
         // If this is not a univariant enum, there is also the discriminant field.
         let (discr_offset, discr_arg) = match discriminant_info {
-            RegularTag { tag_field, .. } => {
+            Some(DirectTag { tag_field, .. }) => {
                 // We have the layout of an enum variant, we need the layout of the outer enum
                 let enum_layout = cx.layout_of(layout.ty);
                 let offset = enum_layout.fields.offset(tag_field.as_usize());
-                let args =
-                    ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
+                let args = ("variant$".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty);
                 (Some(offset), Some(args))
             }
             _ => (None, None),
@@ -1918,7 +1967,7 @@ fn describe_enum_variant(
         offsets,
         args,
         tag_type_metadata: match discriminant_info {
-            RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata),
+            Some(DirectTag { tag_type_metadata, .. }) => Some(tag_type_metadata),
             _ => None,
         },
         span,
@@ -2048,9 +2097,9 @@ fn prepare_enum_metadata(
 
     if use_enum_fallback(cx) {
         let discriminant_type_metadata = match layout.variants {
-            Variants::Single { .. }
-            | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None,
-            Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
+            Variants::Single { .. } => None,
+            Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, ref tag, .. }
+            | Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => {
                 Some(discriminant_type_metadata(tag.value))
             }
         };
@@ -2062,7 +2111,7 @@ fn prepare_enum_metadata(
             unsafe {
                 llvm::LLVMRustDIBuilderCreateUnionType(
                     DIB(cx),
-                    containing_scope,
+                    None,
                     enum_name.as_ptr().cast(),
                     enum_name.len(),
                     file_metadata,
@@ -2088,7 +2137,6 @@ fn prepare_enum_metadata(
                 enum_type,
                 layout,
                 tag_type_metadata: discriminant_type_metadata,
-                containing_scope,
                 common_members: vec![],
                 span,
             }),
@@ -2241,7 +2289,6 @@ fn prepare_enum_metadata(
             enum_type,
             layout,
             tag_type_metadata: None,
-            containing_scope,
             common_members: outer_fields,
             span,
         }),
@@ -2437,7 +2484,7 @@ fn create_union_stub(
 
         llvm::LLVMRustDIBuilderCreateUnionType(
             DIB(cx),
-            containing_scope,
+            Some(containing_scope),
             union_type_name.as_ptr().cast(),
             union_type_name.len(),
             unknown_file_metadata(cx),
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 329458773ff..728f1224dd8 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -8,12 +8,11 @@
 #![feature(bool_to_option)]
 #![feature(const_cstr_unchecked)]
 #![feature(crate_visibility_modifier)]
-#![feature(extended_key_value_attributes)]
+#![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
 #![feature(extern_types)]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![recursion_limit = "256"]
 
 use back::write::{create_informational_target_machine, create_target_machine};
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index bf66040a7eb..54ef1a28468 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -54,7 +54,7 @@ pub enum CallConv {
 }
 
 /// LLVMRustLinkage
-#[derive(PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
 #[repr(C)]
 pub enum Linkage {
     ExternalLinkage = 0,
@@ -72,6 +72,7 @@ pub enum Linkage {
 
 // LLVMRustVisibility
 #[repr(C)]
+#[derive(Copy, Clone, PartialEq)]
 pub enum Visibility {
     Default = 0,
     Hidden = 1,
@@ -1034,6 +1035,7 @@ extern "C" {
     pub fn LLVMDeleteGlobal(GlobalVar: &Value);
     pub fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>;
     pub fn LLVMSetInitializer(GlobalVar: &'a Value, ConstantVal: &'a Value);
+    pub fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool;
     pub fn LLVMSetThreadLocal(GlobalVar: &Value, IsThreadLocal: Bool);
     pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode);
     pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool;
@@ -2036,7 +2038,7 @@ extern "C" {
 
     pub fn LLVMRustDIBuilderCreateUnionType(
         Builder: &DIBuilder<'a>,
-        Scope: &'a DIScope,
+        Scope: Option<&'a DIScope>,
         Name: *const c_char,
         NameLen: size_t,
         File: &'a DIFile,
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 6101b90aea6..387062a671d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -152,6 +152,12 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
         ("x86", "avx512vpclmulqdq") => "vpclmulqdq",
         ("aarch64", "fp") => "fp-armv8",
         ("aarch64", "fp16") => "fullfp16",
+        ("aarch64", "fhm") => "fp16fml",
+        ("aarch64", "rcpc2") => "rcpc-immo",
+        ("aarch64", "dpb") => "ccpp",
+        ("aarch64", "dpb2") => "ccdp",
+        ("aarch64", "frintts") => "fptoint",
+        ("aarch64", "fcma") => "complxnum",
         (_, s) => s,
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index fc1f364e9c6..93456443aa0 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -37,7 +37,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         unsafe {
             llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
             llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
-            if self.should_assume_dso_local(linkage, visibility) {
+            if self.should_assume_dso_local(g, false) {
                 llvm::LLVMRustSetDSOLocal(g, true);
             }
         }
@@ -85,7 +85,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         attributes::from_fn_attrs(self, lldecl, instance);
 
         unsafe {
-            if self.should_assume_dso_local(linkage, visibility) {
+            if self.should_assume_dso_local(lldecl, false) {
                 llvm::LLVMRustSetDSOLocal(lldecl, true);
             }
         }
@@ -95,28 +95,48 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 }
 
 impl CodegenCx<'ll, 'tcx> {
-    /// Whether a definition (NB: not declaration!) can be assumed to be local to a group of
+    /// Whether a definition or declaration can be assumed to be local to a group of
     /// libraries that form a single DSO or executable.
     pub(crate) unsafe fn should_assume_dso_local(
         &self,
-        linkage: Linkage,
-        visibility: Visibility,
+        llval: &llvm::Value,
+        is_declaration: bool,
     ) -> bool {
-        if matches!(linkage, Linkage::Internal | Linkage::Private) {
+        let linkage = llvm::LLVMRustGetLinkage(llval);
+        let visibility = llvm::LLVMRustGetVisibility(llval);
+
+        if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) {
             return true;
         }
 
-        if visibility != Visibility::Default && linkage != Linkage::ExternalWeak {
+        if visibility != llvm::Visibility::Default && linkage != llvm::Linkage::ExternalWeakLinkage
+        {
             return true;
         }
 
-        // Static relocation model should force copy relocations everywhere.
-        if self.tcx.sess.relocation_model() == RelocModel::Static {
+        // Symbols from executables can't really be imported any further.
+        let all_exe = self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable);
+        let is_declaration_for_linker =
+            is_declaration || linkage == llvm::Linkage::AvailableExternallyLinkage;
+        if all_exe && !is_declaration_for_linker {
             return true;
         }
 
-        // Symbols from executables can't really be imported any further.
-        if self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) {
+        // PowerPC64 prefers TOC indirection to avoid copy relocations.
+        if matches!(&*self.tcx.sess.target.arch, "powerpc64" | "powerpc64le") {
+            return false;
+        }
+
+        // Thread-local variables generally don't support copy relocations.
+        let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval)
+            .map(|v| llvm::LLVMIsThreadLocal(v) == llvm::True)
+            .unwrap_or(false);
+        if is_thread_local_var {
+            return false;
+        }
+
+        // Static relocation model should force copy relocations everywhere.
+        if self.tcx.sess.relocation_model() == RelocModel::Static {
             return true;
         }
 
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 68f40d5f863..3a677a2437c 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -9,7 +9,7 @@ test = false
 
 [dependencies]
 bitflags = "1.2.1"
-cc = "1.0.67"
+cc = "1.0.68"
 itertools = "0.9"
 tracing = "0.1"
 libc = "0.2.50"
@@ -24,7 +24,7 @@ rustc_middle = { path = "../rustc_middle" }
 rustc_apfloat = { path = "../rustc_apfloat" }
 rustc_attr = { path = "../rustc_attr" }
 rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
-rustc_data_structures = { path = "../rustc_data_structures"}
+rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_hir = { path = "../rustc_hir" }
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index e330b5e703b..32275e9b073 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1805,13 +1805,14 @@ fn add_local_native_libraries(
     let search_path = archive_search_paths(sess);
     let mut last = (NativeLibKind::Unspecified, None);
     for lib in relevant_libs {
-        // Skip if this library is the same as the last.
-        last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
-
         let name = match lib.name {
             Some(l) => l,
             None => continue,
         };
+
+        // Skip if this library is the same as the last.
+        last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
+
         let verbatim = lib.verbatim.unwrap_or(false);
         match lib.kind {
             NativeLibKind::Dylib { as_needed } => {
@@ -2144,9 +2145,6 @@ fn add_upstream_native_libraries(
     let mut last = (NativeLibKind::Unspecified, None);
     for &(cnum, _) in crates {
         for lib in codegen_results.crate_info.native_libraries[&cnum].iter() {
-            // Skip if this library is the same as the last.
-            last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
-
             let name = match lib.name {
                 Some(l) => l,
                 None => continue,
@@ -2154,6 +2152,10 @@ fn add_upstream_native_libraries(
             if !relevant_lib(sess, &lib) {
                 continue;
             }
+
+            // Skip if this library is the same as the last.
+            last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) };
+
             let verbatim = lib.verbatim.unwrap_or(false);
             match lib.kind {
                 NativeLibKind::Dylib { as_needed } => {
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index ea4564c2a6b..4dc9a3f5e41 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -281,8 +281,11 @@ impl<'a> Linker for GccLinker<'a> {
                 }
             }
             LinkOutputKind::DynamicPicExe => {
-                // `-pie` works for both gcc wrapper and ld.
-                self.cmd.arg("-pie");
+                // noop on windows w/ gcc & ld, error w/ lld
+                if !self.sess.target.is_like_windows {
+                    // `-pie` works for both gcc wrapper and ld.
+                    self.cmd.arg("-pie");
+                }
             }
             LinkOutputKind::StaticNoPicExe => {
                 // `-static` works for both gcc wrapper and ld.
@@ -347,7 +350,7 @@ impl<'a> Linker for GccLinker<'a> {
                 // has -needed-l{} / -needed_library {}
                 // but we have no way to detect that here.
                 self.sess.warn("`as-needed` modifier not implemented yet for ld64");
-            } else if self.sess.target.linker_is_gnu {
+            } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
                 self.linker_arg("--no-as-needed");
             } else {
                 self.sess.warn("`as-needed` modifier not supported for current linker");
@@ -358,7 +361,7 @@ impl<'a> Linker for GccLinker<'a> {
         if !as_needed {
             if self.sess.target.is_like_osx {
                 // See above FIXME comment
-            } else if self.sess.target.linker_is_gnu {
+            } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
                 self.linker_arg("--as-needed");
             }
         }
@@ -469,7 +472,7 @@ impl<'a> Linker for GccLinker<'a> {
         // eliminate the metadata. If we're building an executable, however,
         // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
         // reduction.
-        } else if !keep_metadata {
+        } else if self.sess.target.linker_is_gnu && !keep_metadata {
             self.linker_arg("--gc-sections");
         }
     }
@@ -477,9 +480,7 @@ impl<'a> Linker for GccLinker<'a> {
     fn no_gc_sections(&mut self) {
         if self.sess.target.is_like_osx {
             self.linker_arg("-no_dead_strip");
-        } else if self.sess.target.is_like_solaris {
-            self.linker_arg("-zrecord");
-        } else {
+        } else if self.sess.target.linker_is_gnu {
             self.linker_arg("--no-gc-sections");
         }
     }
@@ -692,7 +693,7 @@ impl<'a> Linker for GccLinker<'a> {
     }
 
     fn add_as_needed(&mut self) {
-        if self.sess.target.linker_is_gnu {
+        if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows {
             self.linker_arg("--as-needed");
         } else if self.sess.target.is_like_solaris {
             // -z ignore is the Solaris equivalent to the GNU ld --as-needed option
diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
index 08442c588f8..c1dfe1ef856 100644
--- a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
+++ b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
@@ -28,6 +28,7 @@ pub struct Expression {
 /// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
 /// for a gap area is only used as the line execution count if there are no other regions on a
 /// line."
+#[derive(Debug)]
 pub struct FunctionCoverage<'tcx> {
     instance: Instance<'tcx>,
     source_hash: u64,
@@ -113,6 +114,14 @@ impl<'tcx> FunctionCoverage<'tcx> {
             expression_id, lhs, op, rhs, region
         );
         let expression_index = self.expression_index(u32::from(expression_id));
+        debug_assert!(
+            expression_index.as_usize() < self.expressions.len(),
+            "expression_index {} is out of range for expressions.len() = {}
+            for {:?}",
+            expression_index.as_usize(),
+            self.expressions.len(),
+            self,
+        );
         if let Some(previous_expression) = self.expressions[expression_index].replace(Expression {
             lhs,
             op,
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index d1bbf74307c..7b4b0821c4b 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -3,7 +3,8 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty, TyCtxt};
+use rustc_target::abi::{TagEncoding, Variants};
 
 use std::fmt::Write;
 
@@ -45,8 +46,12 @@ pub fn push_debuginfo_type_name<'tcx>(
         ty::Float(float_ty) => output.push_str(float_ty.name_str()),
         ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
         ty::Adt(def, substs) => {
-            push_item_name(tcx, def.did, qualified, output);
-            push_type_params(tcx, substs, output, visited);
+            if def.is_enum() && cpp_like_names {
+                msvc_enum_fallback(tcx, t, def, substs, output, visited);
+            } else {
+                push_item_name(tcx, def.did, qualified, output);
+                push_type_params(tcx, substs, output, visited);
+            }
         }
         ty::Tuple(component_types) => {
             if cpp_like_names {
@@ -233,6 +238,54 @@ pub fn push_debuginfo_type_name<'tcx>(
         }
     }
 
+    /// MSVC names enums differently than other platforms so that the debugging visualization
+    // format (natvis) is able to understand enums and render the active variant correctly in the
+    // debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and
+    // `EnumMemberDescriptionFactor::create_member_descriptions`.
+    fn msvc_enum_fallback(
+        tcx: TyCtxt<'tcx>,
+        ty: Ty<'tcx>,
+        def: &AdtDef,
+        substs: SubstsRef<'tcx>,
+        output: &mut String,
+        visited: &mut FxHashSet<Ty<'tcx>>,
+    ) {
+        let layout = tcx.layout_of(tcx.param_env(def.did).and(ty)).expect("layout error");
+
+        if let Variants::Multiple {
+            tag_encoding: TagEncoding::Niche { dataful_variant, .. },
+            tag,
+            variants,
+            ..
+        } = &layout.variants
+        {
+            let dataful_variant_layout = &variants[*dataful_variant];
+
+            // calculate the range of values for the dataful variant
+            let dataful_discriminant_range =
+                &dataful_variant_layout.largest_niche.as_ref().unwrap().scalar.valid_range;
+
+            let min = dataful_discriminant_range.start();
+            let min = tag.value.size(&tcx).truncate(*min);
+
+            let max = dataful_discriminant_range.end();
+            let max = tag.value.size(&tcx).truncate(*max);
+
+            output.push_str("enum$<");
+            push_item_name(tcx, def.did, true, output);
+            push_type_params(tcx, substs, output, visited);
+
+            let dataful_variant_name = def.variants[*dataful_variant].ident.as_str();
+
+            output.push_str(&format!(", {}, {}, {}>", min, max, dataful_variant_name));
+        } else {
+            output.push_str("enum$<");
+            push_item_name(tcx, def.did, true, output);
+            push_type_params(tcx, substs, output, visited);
+            output.push('>');
+        }
+    }
+
     fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) {
         if qualified {
             output.push_str(&tcx.crate_name(def_id.krate).as_str());
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 1b53b551901..12da3d9e155 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -1,16 +1,11 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(assert_matches)]
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
-#![feature(drain_filter)]
 #![feature(try_blocks)]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(associated_type_bounds)]
-#![feature(iter_zip)]
 #![recursion_limit = "256"]
-#![feature(box_syntax)]
 
 //! This crate contains codegen code that is used by all codegen backends (LLVM and others).
 //! The backend-agnostic functions of this crate use functions defined in various traits that
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 4e987908b4e..98d550d732f 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -17,6 +17,8 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("neon", Some(sym::arm_target_feature)),
     ("crc", Some(sym::arm_target_feature)),
     ("crypto", Some(sym::arm_target_feature)),
+    ("aes", Some(sym::arm_target_feature)),
+    ("sha2", Some(sym::arm_target_feature)),
     ("v5te", Some(sym::arm_target_feature)),
     ("v6", Some(sym::arm_target_feature)),
     ("v6k", Some(sym::arm_target_feature)),
@@ -33,22 +35,95 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("thumb-mode", Some(sym::arm_target_feature)),
 ];
 
+// Commented features are not available in LLVM 10.0, or have since been renamed
 const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
-    ("fp", Some(sym::aarch64_target_feature)),
+    // FEAT_AdvSimd
     ("neon", Some(sym::aarch64_target_feature)),
+    // FEAT_FP
+    ("fp", Some(sym::aarch64_target_feature)),
+    // FEAT_FP16
+    ("fp16", Some(sym::aarch64_target_feature)),
+    // FEAT_SVE
     ("sve", Some(sym::aarch64_target_feature)),
+    // FEAT_CRC
     ("crc", Some(sym::aarch64_target_feature)),
+    // Cryptographic extension
     ("crypto", Some(sym::aarch64_target_feature)),
+    // FEAT_RAS
     ("ras", Some(sym::aarch64_target_feature)),
+    // FEAT_LSE
     ("lse", Some(sym::aarch64_target_feature)),
+    // FEAT_RDM
     ("rdm", Some(sym::aarch64_target_feature)),
-    ("fp16", Some(sym::aarch64_target_feature)),
+    // FEAT_RCPC
     ("rcpc", Some(sym::aarch64_target_feature)),
+    // FEAT_RCPC2
+    ("rcpc2", Some(sym::aarch64_target_feature)),
+    // FEAT_DotProd
     ("dotprod", Some(sym::aarch64_target_feature)),
+    // FEAT_TME
     ("tme", Some(sym::aarch64_target_feature)),
+    // FEAT_FHM
+    ("fhm", Some(sym::aarch64_target_feature)),
+    // FEAT_DIT
+    ("dit", Some(sym::aarch64_target_feature)),
+    // FEAT_FLAGM
+    // ("flagm", Some(sym::aarch64_target_feature)),
+    // FEAT_SSBS
+    ("ssbs", Some(sym::aarch64_target_feature)),
+    // FEAT_SB
+    ("sb", Some(sym::aarch64_target_feature)),
+    // FEAT_PAUTH
+    // ("pauth", Some(sym::aarch64_target_feature)),
+    // FEAT_DPB
+    ("dpb", Some(sym::aarch64_target_feature)),
+    // FEAT_DPB2
+    ("dpb2", Some(sym::aarch64_target_feature)),
+    // FEAT_SVE2
+    ("sve2", Some(sym::aarch64_target_feature)),
+    // FEAT_SVE2_AES
+    ("sve2-aes", Some(sym::aarch64_target_feature)),
+    // FEAT_SVE2_SM4
+    ("sve2-sm4", Some(sym::aarch64_target_feature)),
+    // FEAT_SVE2_SHA3
+    ("sve2-sha3", Some(sym::aarch64_target_feature)),
+    // FEAT_SVE2_BitPerm
+    ("sve2-bitperm", Some(sym::aarch64_target_feature)),
+    // FEAT_FRINTTS
+    ("frintts", Some(sym::aarch64_target_feature)),
+    // FEAT_I8MM
+    // ("i8mm", Some(sym::aarch64_target_feature)),
+    // FEAT_F32MM
+    // ("f32mm", Some(sym::aarch64_target_feature)),
+    // FEAT_F64MM
+    // ("f64mm", Some(sym::aarch64_target_feature)),
+    // FEAT_BF16
+    // ("bf16", Some(sym::aarch64_target_feature)),
+    // FEAT_RAND
+    ("rand", Some(sym::aarch64_target_feature)),
+    // FEAT_BTI
+    ("bti", Some(sym::aarch64_target_feature)),
+    // FEAT_MTE
+    ("mte", Some(sym::aarch64_target_feature)),
+    // FEAT_JSCVT
+    ("jsconv", Some(sym::aarch64_target_feature)),
+    // FEAT_FCMA
+    ("fcma", Some(sym::aarch64_target_feature)),
+    // FEAT_AES
+    ("aes", Some(sym::aarch64_target_feature)),
+    // FEAT_SHA1 & FEAT_SHA256
+    ("sha2", Some(sym::aarch64_target_feature)),
+    // FEAT_SHA512 & FEAT_SHA3
+    ("sha3", Some(sym::aarch64_target_feature)),
+    // FEAT_SM3 & FEAT_SM4
+    ("sm4", Some(sym::aarch64_target_feature)),
     ("v8.1a", Some(sym::aarch64_target_feature)),
     ("v8.2a", Some(sym::aarch64_target_feature)),
     ("v8.3a", Some(sym::aarch64_target_feature)),
+    ("v8.4a", Some(sym::aarch64_target_feature)),
+    ("v8.5a", Some(sym::aarch64_target_feature)),
+    // ("v8.6a", Some(sym::aarch64_target_feature)),
+    // ("v8.7a", Some(sym::aarch64_target_feature)),
 ];
 
 const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index aa95ecbdaf9..c35a164bb33 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -34,7 +34,7 @@ tempfile = "3.2"
 version = "0.11"
 
 [target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["fileapi", "psapi"] }
+winapi = { version = "0.3", features = ["fileapi", "psapi", "winerror"] }
 
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
 memmap2 = "0.2.1"
diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs
index 9383be474fd..4f5d8d7ea48 100644
--- a/compiler/rustc_data_structures/src/flock.rs
+++ b/compiler/rustc_data_structures/src/flock.rs
@@ -54,6 +54,10 @@ cfg_if! {
                     Ok(Lock { _file: file })
                 }
             }
+
+            pub fn error_unsupported(err: &io::Error) -> bool {
+                matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
+            }
         }
 
         // Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by
@@ -103,6 +107,10 @@ cfg_if! {
                     Ok(Lock { file })
                 }
             }
+
+            pub fn error_unsupported(err: &io::Error) -> bool {
+                matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
+            }
         }
 
         impl Drop for Lock {
@@ -122,6 +130,7 @@ cfg_if! {
         use std::mem;
         use std::os::windows::prelude::*;
 
+        use winapi::shared::winerror::ERROR_INVALID_FUNCTION;
         use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK};
         use winapi::um::fileapi::LockFileEx;
         use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE};
@@ -194,6 +203,10 @@ cfg_if! {
                     Ok(Lock { _file: file })
                 }
             }
+
+            pub fn error_unsupported(err: &io::Error) -> bool {
+                err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32)
+            }
         }
 
         // Note that we don't need a Drop impl on the Windows: The file is unlocked
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index adbb98fa750..a8b9f479f1e 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -10,15 +10,12 @@
 #![feature(array_windows)]
 #![feature(control_flow_enum)]
 #![feature(in_band_lifetimes)]
-#![feature(unboxed_closures)]
 #![feature(generator_trait)]
-#![feature(fn_traits)]
 #![feature(min_specialization)]
 #![feature(auto_traits)]
 #![feature(nll)]
 #![feature(allow_internal_unstable)]
 #![feature(hash_raw_entry)]
-#![feature(stmt_expr_attributes)]
 #![feature(core_intrinsics)]
 #![feature(test)]
 #![feature(associated_type_bounds)]
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 29d685ab530..3aabe94bfc6 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -597,7 +597,7 @@ impl<O: ForestObligation> ObligationForest<O> {
                 Some(rpos) => {
                     // Cycle detected.
                     processor.process_backedge(
-                        stack[rpos..].iter().map(GetObligation(&self.nodes)),
+                        stack[rpos..].iter().map(|&i| &self.nodes[i].obligation),
                         PhantomData,
                     );
                 }
@@ -705,20 +705,3 @@ impl<O: ForestObligation> ObligationForest<O> {
         });
     }
 }
-
-// I need a Clone closure.
-#[derive(Clone)]
-struct GetObligation<'a, O>(&'a [Node<O>]);
-
-impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> {
-    type Output = &'a O;
-    extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O {
-        &self.0[*args.0].obligation
-    }
-}
-
-impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> {
-    extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O {
-        &self.0[*args.0].obligation
-    }
-}
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index ff28784a1dc..18b352cf3b0 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -550,35 +550,3 @@ pub fn hash_stable_hashmap<HCX, K, V, R, SK, F>(
     entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2));
     entries.hash_stable(hcx, hasher);
 }
-
-/// A vector container that makes sure that its items are hashed in a stable
-/// order.
-#[derive(Debug)]
-pub struct StableVec<T>(Vec<T>);
-
-impl<T> StableVec<T> {
-    pub fn new(v: Vec<T>) -> Self {
-        StableVec(v)
-    }
-}
-
-impl<T> ::std::ops::Deref for StableVec<T> {
-    type Target = Vec<T>;
-
-    fn deref(&self) -> &Vec<T> {
-        &self.0
-    }
-}
-
-impl<T, HCX> HashStable<HCX> for StableVec<T>
-where
-    T: HashStable<HCX> + ToStableHashKey<HCX>,
-{
-    fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
-        let StableVec(ref v) = *self;
-
-        let mut sorted: Vec<_> = v.iter().map(|x| x.to_stable_hash_key(hcx)).collect();
-        sorted.sort_unstable();
-        sorted.hash_stable(hcx, hasher);
-    }
-}
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index 26706cd2b1b..722ce6b6367 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -43,49 +43,9 @@ cfg_if! {
         use std::ops::Add;
         use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe};
 
-        /// This is a single threaded variant of AtomicCell provided by crossbeam.
-        /// Unlike `Atomic` this is intended for all `Copy` types,
-        /// but it lacks the explicit ordering arguments.
-        #[derive(Debug)]
-        pub struct AtomicCell<T: Copy>(Cell<T>);
-
-        impl<T: Copy> AtomicCell<T> {
-            #[inline]
-            pub fn new(v: T) -> Self {
-                AtomicCell(Cell::new(v))
-            }
-
-            #[inline]
-            pub fn get_mut(&mut self) -> &mut T {
-                self.0.get_mut()
-            }
-        }
-
-        impl<T: Copy> AtomicCell<T> {
-            #[inline]
-            pub fn into_inner(self) -> T {
-                self.0.into_inner()
-            }
-
-            #[inline]
-            pub fn load(&self) -> T {
-                self.0.get()
-            }
-
-            #[inline]
-            pub fn store(&self, val: T) {
-                self.0.set(val)
-            }
-
-            #[inline]
-            pub fn swap(&self, val: T) -> T {
-                self.0.replace(val)
-            }
-        }
-
         /// This is a single threaded variant of `AtomicU64`, `AtomicUsize`, etc.
-        /// It differs from `AtomicCell` in that it has explicit ordering arguments
-        /// and is only intended for use with the native atomic types.
+        /// It has explicit ordering arguments and is only intended for use with
+        /// the native atomic types.
         /// You should use this type through the `AtomicU64`, `AtomicUsize`, etc, type aliases
         /// as it's not intended to be used separately.
         #[derive(Debug)]
@@ -159,22 +119,6 @@ cfg_if! {
             (oper_a(), oper_b())
         }
 
-        pub struct SerialScope;
-
-        impl SerialScope {
-            pub fn spawn<F>(&self, f: F)
-                where F: FnOnce(&SerialScope)
-            {
-                f(self)
-            }
-        }
-
-        pub fn scope<F, R>(f: F) -> R
-            where F: FnOnce(&SerialScope) -> R
-        {
-            f(&SerialScope)
-        }
-
         #[macro_export]
         macro_rules! parallel {
             ($($blocks:tt),*) => {
@@ -318,8 +262,6 @@ cfg_if! {
 
         pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64};
 
-        pub use crossbeam_utils::atomic::AtomicCell;
-
         pub use std::sync::Arc as Lrc;
         pub use std::sync::Weak as Weak;
 
diff --git a/compiler/rustc_data_structures/src/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs
index cd1e12ca450..324a8624dd0 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr.rs
@@ -90,9 +90,11 @@ pub unsafe trait Tag: Copy {
 
 unsafe impl<T> Pointer for Box<T> {
     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+    #[inline]
     fn into_usize(self) -> usize {
         Box::into_raw(self) as usize
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         Box::from_raw(ptr as *mut T)
     }
@@ -104,9 +106,11 @@ unsafe impl<T> Pointer for Box<T> {
 
 unsafe impl<T> Pointer for Rc<T> {
     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+    #[inline]
     fn into_usize(self) -> usize {
         Rc::into_raw(self) as usize
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         Rc::from_raw(ptr as *const T)
     }
@@ -118,9 +122,11 @@ unsafe impl<T> Pointer for Rc<T> {
 
 unsafe impl<T> Pointer for Arc<T> {
     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+    #[inline]
     fn into_usize(self) -> usize {
         Arc::into_raw(self) as usize
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         Arc::from_raw(ptr as *const T)
     }
@@ -132,9 +138,11 @@ unsafe impl<T> Pointer for Arc<T> {
 
 unsafe impl<'a, T: 'a> Pointer for &'a T {
     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+    #[inline]
     fn into_usize(self) -> usize {
         self as *const T as usize
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         &*(ptr as *const T)
     }
@@ -145,9 +153,11 @@ unsafe impl<'a, T: 'a> Pointer for &'a T {
 
 unsafe impl<'a, T: 'a> Pointer for &'a mut T {
     const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+    #[inline]
     fn into_usize(self) -> usize {
         self as *mut T as usize
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         &mut *(ptr as *mut T)
     }
diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs
index 370ec053cbb..a2b4f3fcf73 100644
--- a/compiler/rustc_driver/src/pretty.rs
+++ b/compiler/rustc_driver/src/pretty.rs
@@ -8,14 +8,12 @@ use rustc_hir_pretty as pprust_hir;
 use rustc_middle::hir::map as hir_map;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_mir::util::{write_mir_graphviz, write_mir_pretty};
-use rustc_mir_build::thir;
 use rustc_session::config::{Input, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
 use rustc_span::FileName;
 
 use std::cell::Cell;
-use std::fmt::Write;
 use std::path::Path;
 
 pub use self::PpMode::*;
@@ -490,18 +488,8 @@ fn print_with_analysis(
         }
 
         ThirTree => {
-            let mut out = String::new();
-            abort_on_err(rustc_typeck::check_crate(tcx), tcx.sess);
-            debug!("pretty printing THIR tree");
-            for did in tcx.body_owners() {
-                let hir = tcx.hir();
-                let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(did)));
-                let arena = thir::Arena::default();
-                let thir =
-                    thir::build_thir(tcx, ty::WithOptConstParam::unknown(did), &arena, &body.value);
-                let _ = writeln!(out, "{:?}:\n{:#?}\n", did, thir);
-            }
-            out
+            // FIXME(rust-lang/project-thir-unsafeck#8)
+            todo!()
         }
 
         _ => unreachable!(),
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index f53ce7ceace..979f2d3b300 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -5,7 +5,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(crate_visibility_modifier)]
 #![feature(backtrace)]
-#![feature(extended_key_value_attributes)]
+#![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
 #![feature(format_args_capture)]
 #![feature(iter_zip)]
 #![feature(nll)]
@@ -715,6 +715,7 @@ impl Handler {
         self.inner.borrow_mut().bug(msg)
     }
 
+    #[inline]
     pub fn err_count(&self) -> usize {
         self.inner.borrow().err_count()
     }
@@ -924,6 +925,7 @@ impl HandlerInner {
         }
     }
 
+    #[inline]
     fn err_count(&self) -> usize {
         self.err_count + self.stashed_diagnostics.len()
     }
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 5fb85867501..f77eac2b068 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -1,9 +1,7 @@
-#![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(destructuring_assignment)]
 #![feature(iter_zip)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(proc_macro_diagnostic)]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_span)]
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 91d4a0f0d65..6608573d720 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -467,6 +467,7 @@ pub fn compile_declarative_macro(
                             &sess.parse_sess,
                             def.id,
                             features,
+                            edition,
                         )
                         .pop()
                         .unwrap();
@@ -492,6 +493,7 @@ pub fn compile_declarative_macro(
                             &sess.parse_sess,
                             def.id,
                             features,
+                            edition,
                         )
                         .pop()
                         .unwrap();
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index aca02ef93f8..fb7479eafc8 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -9,7 +9,8 @@ use rustc_feature::Features;
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::{kw, Ident};
 
-use rustc_span::Span;
+use rustc_span::edition::Edition;
+use rustc_span::{Span, SyntaxContext};
 
 use rustc_data_structures::sync::Lrc;
 
@@ -32,6 +33,7 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
 /// - `sess`: the parsing session. Any errors will be emitted to this session.
 /// - `node_id`: the NodeId of the macro we are parsing.
 /// - `features`: language features so we can do feature gating.
+/// - `edition`: the edition of the crate defining the macro
 ///
 /// # Returns
 ///
@@ -42,6 +44,7 @@ pub(super) fn parse(
     sess: &ParseSess,
     node_id: NodeId,
     features: &Features,
+    edition: Edition,
 ) -> Vec<TokenTree> {
     // Will contain the final collection of `self::TokenTree`
     let mut result = Vec::new();
@@ -52,7 +55,7 @@ pub(super) fn parse(
     while let Some(tree) = trees.next() {
         // Given the parsed tree, if there is a metavar and we are expecting matchers, actually
         // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`).
-        let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features);
+        let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features, edition);
         match tree {
             TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
                 let span = match trees.next() {
@@ -64,7 +67,19 @@ pub(super) fn parse(
 
                                     let kind =
                                         token::NonterminalKind::from_symbol(frag.name, || {
-                                            span.edition()
+                                            // FIXME(#85708) - once we properly decode a foreign
+                                            // crate's `SyntaxContext::root`, then we can replace
+                                            // this with just `span.edition()`. A
+                                            // `SyntaxContext::root()` from the current crate will
+                                            // have the edition of the current crate, and a
+                                            // `SyntaxxContext::root()` from a foreign crate will
+                                            // have the edition of that crate (which we manually
+                                            // retrieve via the `edition` parameter).
+                                            if span.ctxt() == SyntaxContext::root() {
+                                                edition
+                                            } else {
+                                                span.edition()
+                                            }
                                         })
                                         .unwrap_or_else(
                                             || {
@@ -117,6 +132,7 @@ pub(super) fn parse(
 /// - `expect_matchers`: same as for `parse` (see above).
 /// - `sess`: the parsing session. Any errors will be emitted to this session.
 /// - `features`: language features so we can do feature gating.
+/// - `edition` - the edition of the crate defining the macro
 fn parse_tree(
     tree: tokenstream::TokenTree,
     outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>,
@@ -124,6 +140,7 @@ fn parse_tree(
     sess: &ParseSess,
     node_id: NodeId,
     features: &Features,
+    edition: Edition,
 ) -> TokenTree {
     // Depending on what `tree` is, we could be parsing different parts of a macro
     match tree {
@@ -151,7 +168,7 @@ fn parse_tree(
                         sess.span_diagnostic.span_err(span.entire(), &msg);
                     }
                     // Parse the contents of the sequence itself
-                    let sequence = parse(tts, expect_matchers, sess, node_id, features);
+                    let sequence = parse(tts, expect_matchers, sess, node_id, features, edition);
                     // Get the Kleene operator and optional separator
                     let (separator, kleene) =
                         parse_sep_and_kleene_op(&mut trees, span.entire(), sess);
@@ -204,7 +221,7 @@ fn parse_tree(
             span,
             Lrc::new(Delimited {
                 delim,
-                tts: parse(tts, expect_matchers, sess, node_id, features),
+                tts: parse(tts, expect_matchers, sess, node_id, features, edition),
             }),
         ),
     }
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 7bf6502c976..92315c4d4f6 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -1,9 +1,7 @@
 use crate::base::{ExtCtxt, ResolverExpand};
 
 use rustc_ast as ast;
-use rustc_ast::token;
-use rustc_ast::token::Nonterminal;
-use rustc_ast::token::NtIdent;
+use rustc_ast::token::{self, Nonterminal, NtIdent, TokenKind};
 use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens};
 use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing};
 use rustc_ast_pretty::pprust;
@@ -541,6 +539,33 @@ impl server::Ident for Rustc<'_> {
 }
 
 impl server::Literal for Rustc<'_> {
+    fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
+        let override_span = None;
+        let stream = parse_stream_from_source_str(
+            FileName::proc_macro_source_code(s),
+            s.to_owned(),
+            self.sess,
+            override_span,
+        );
+        if stream.len() != 1 {
+            return Err(());
+        }
+        let tree = stream.into_trees().next().unwrap();
+        let token = match tree {
+            tokenstream::TokenTree::Token(token) => token,
+            tokenstream::TokenTree::Delimited { .. } => return Err(()),
+        };
+        let span_data = token.span.data();
+        if (span_data.hi.0 - span_data.lo.0) as usize != s.len() {
+            // There is a comment or whitespace adjacent to the literal.
+            return Err(());
+        }
+        let lit = match token.kind {
+            TokenKind::Literal(lit) => lit,
+            _ => return Err(()),
+        };
+        Ok(Literal { lit, span: self.call_site })
+    }
     fn debug_kind(&mut self, literal: &Self::Literal) -> String {
         format!("{:?}", literal.lit.kind)
     }
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index e8642a52749..95504723e7b 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -281,6 +281,12 @@ declare_features! (
     (accepted, or_patterns, "1.53.0", Some(54883), None),
     /// Allows defining identifiers beyond ASCII.
     (accepted, non_ascii_idents, "1.53.0", Some(55467), None),
+    /// Allows arbitrary expressions in key-value attributes at parse time.
+    (accepted, extended_key_value_attributes, "1.54.0", Some(78835), None),
+    /// Allows unsizing coercions in `const fn`.
+    (accepted, const_fn_unsize, "1.54.0", Some(64992), None),
+    /// Allows `impl Trait` with multiple unrelated lifetimes.
+    (accepted, member_constraints, "1.54.0", Some(61997), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 80fe5bafc6e..a84737e80a0 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -472,9 +472,6 @@ declare_features! (
     /// Allows explicit discriminants on non-unit enum variants.
     (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
 
-    /// Allows `impl Trait` with multiple unrelated lifetimes.
-    (active, member_constraints, "1.37.0", Some(61997), None),
-
     /// Allows `async || body` closures.
     (active, async_closure, "1.37.0", Some(62290), None),
 
@@ -601,9 +598,6 @@ declare_features! (
     /// Allows capturing disjoint fields in a closure/generator (RFC 2229).
     (active, capture_disjoint_fields, "1.49.0", Some(53488), None),
 
-    /// Allows arbitrary expressions in key-value attributes at parse time.
-    (active, extended_key_value_attributes, "1.50.0", Some(78835), None),
-
     /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`).
     (active, const_generics_defaults, "1.51.0", Some(44580), None),
 
@@ -647,9 +641,6 @@ declare_features! (
     /// Allows trait bounds in `const fn`.
     (active, const_fn_trait_bound, "1.53.0", Some(57563), None),
 
-    /// Allows unsizing coercions in `const fn`.
-    (active, const_fn_unsize, "1.53.0", Some(64992), None),
-
     /// Allows `async {}` expressions in const contexts.
     (active, const_async_blocks, "1.53.0", Some(85368), None),
 
@@ -698,14 +689,8 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
     sym::repr128,
     sym::unsized_locals,
     sym::capture_disjoint_fields,
-    sym::const_generics_defaults,
     sym::inherent_associated_types,
     sym::type_alias_impl_trait,
-    sym::native_link_modifiers,
-    sym::native_link_modifiers_bundle,
-    sym::native_link_modifiers_verbatim,
-    sym::native_link_modifiers_whole_archive,
-    sym::native_link_modifiers_as_needed,
     sym::rustc_insignificant_dtor,
     sym::unnamed_fields,
 ];
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index e7e128f8a9b..259a6328a22 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -569,10 +569,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")),
     rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")),
     rustc_attr!(
-        TEST, rustc_dirty, AssumedUsed,
-        template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
-    ),
-    rustc_attr!(
         TEST, rustc_clean, AssumedUsed,
         template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
     ),
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 647d735fb86..fda1ba80952 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -14,7 +14,6 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_index::vec::IndexVec;
-use rustc_span::crate_disambiguator::CrateDisambiguator;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::symbol::{kw, sym, Symbol};
 
@@ -306,6 +305,7 @@ impl Definitions {
         self.table.index_to_key.len()
     }
 
+    #[inline]
     pub fn def_key(&self, id: LocalDefId) -> DefKey {
         self.table.def_key(id.local_def_index)
     }
@@ -338,7 +338,7 @@ impl Definitions {
     }
 
     /// Adds a root definition (no parent) and a few other reserved definitions.
-    pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> Definitions {
+    pub fn new(stable_crate_id: StableCrateId) -> Definitions {
         let key = DefKey {
             parent: None,
             disambiguated_data: DisambiguatedDefPathData {
@@ -347,7 +347,6 @@ impl Definitions {
             },
         };
 
-        let stable_crate_id = StableCrateId::new(crate_name, crate_disambiguator);
         let parent_hash = DefPathHash::new(stable_crate_id, 0);
         let def_path_hash = key.compute_stable_hash(parent_hash);
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 91fd97a0d40..577d43b1c8e 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,7 +1,7 @@
 // ignore-tidy-filelength
 use crate::def::{CtorKind, DefKind, Res};
 use crate::def_id::DefId;
-crate use crate::hir_id::HirId;
+crate use crate::hir_id::{HirId, ItemLocalId};
 use crate::{itemlikevisit, LangItem};
 
 use rustc_ast::util::parser::ExprPrecedence;
@@ -10,6 +10,7 @@ use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, TraitObject
 pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
 pub use rustc_ast::{CaptureBy, Movability, Mutability};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
 use rustc_macros::HashStable_Generic;
 use rustc_span::source_map::Spanned;
@@ -658,7 +659,9 @@ pub struct Crate<'hir> {
     /// they are declared in the static array generated by proc_macro_harness.
     pub proc_macros: Vec<HirId>,
 
-    pub trait_map: BTreeMap<HirId, Vec<TraitCandidate>>,
+    /// Map indicating what traits are in scope for places where this
+    /// is relevant; generated by resolve.
+    pub trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Box<[TraitCandidate]>>>,
 
     /// Collected attributes from HIR nodes.
     pub attrs: BTreeMap<HirId, &'hir [Attribute]>,
@@ -2485,6 +2488,7 @@ pub enum FnRetTy<'hir> {
 }
 
 impl FnRetTy<'_> {
+    #[inline]
     pub fn span(&self) -> Span {
         match *self {
             Self::DefaultReturn(span) => span,
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 7b788b13b9f..0b8535f8ca5 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -308,12 +308,12 @@ language_item_table! {
 
     Termination,             sym::termination,         termination,                Target::Trait;
 
-    Try,                     kw::Try,                  try_trait,                  Target::Trait;
+    Try,                     sym::Try,                 try_trait,                  Target::Trait;
 
     // Language items from AST lowering
-    TryFromError,            sym::from_error,          from_error_fn,              Target::Method(MethodKind::Trait { body: false });
-    TryFromOk,               sym::from_ok,             from_ok_fn,                 Target::Method(MethodKind::Trait { body: false });
-    TryIntoResult,           sym::into_result,         into_result_fn,             Target::Method(MethodKind::Trait { body: false });
+    TryTraitFromResidual,    sym::from_residual,       from_residual_fn,           Target::Method(MethodKind::Trait { body: false });
+    TryTraitFromOutput,      sym::from_output,         from_output_fn,             Target::Method(MethodKind::Trait { body: false });
+    TryTraitBranch,          sym::branch,              branch_fn,                  Target::Method(MethodKind::Trait { body: false });
 
     PollReady,               sym::Ready,               poll_ready_variant,         Target::Variant;
     PollPending,             sym::Pending,             poll_pending_variant,       Target::Variant;
@@ -331,6 +331,9 @@ language_item_table! {
     ResultOk,                sym::Ok,                  result_ok_variant,          Target::Variant;
     ResultErr,               sym::Err,                 result_err_variant,         Target::Variant;
 
+    ControlFlowContinue,     sym::Continue,            cf_continue_variant,        Target::Variant;
+    ControlFlowBreak,        sym::Break,               cf_break_variant,           Target::Variant;
+
     IntoIterIntoIter,        sym::into_iter,           into_iter_fn,               Target::Method(MethodKind::Trait { body: false });
     IteratorNext,            sym::next,                next_fn,                    Target::Method(MethodKind::Trait { body: false});
 
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 65c99535c4e..ad2ecae9233 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -3,11 +3,10 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
 
 #![feature(crate_visibility_modifier)]
-#![feature(const_panic)]
-#![feature(extended_key_value_attributes)]
+#![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
 #![feature(in_band_lifetimes)]
 #![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
+#![feature(min_specialization)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs
index 2aafc6afa23..4636d515249 100644
--- a/compiler/rustc_hir/src/tests.rs
+++ b/compiler/rustc_hir/src/tests.rs
@@ -1,6 +1,4 @@
 use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_span::crate_disambiguator::CrateDisambiguator;
 use rustc_span::def_id::{DefPathHash, StableCrateId};
 
 #[test]
@@ -13,17 +11,16 @@ fn def_path_hash_depends_on_crate_id() {
     // the crate by changing the crate disambiguator (e.g. via bumping the
     // crate's version number).
 
-    let d0 = CrateDisambiguator::from(Fingerprint::new(12, 34));
-    let d1 = CrateDisambiguator::from(Fingerprint::new(56, 78));
+    let id0 = StableCrateId::new("foo", false, vec!["1".to_string()]);
+    let id1 = StableCrateId::new("foo", false, vec!["2".to_string()]);
 
-    let h0 = mk_test_hash("foo", d0);
-    let h1 = mk_test_hash("foo", d1);
+    let h0 = mk_test_hash(id0);
+    let h1 = mk_test_hash(id1);
 
     assert_ne!(h0.stable_crate_id(), h1.stable_crate_id());
     assert_ne!(h0.local_hash(), h1.local_hash());
 
-    fn mk_test_hash(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> DefPathHash {
-        let stable_crate_id = StableCrateId::new(crate_name, crate_disambiguator);
+    fn mk_test_hash(stable_crate_id: StableCrateId) -> DefPathHash {
         let parent_hash = DefPathHash::new(stable_crate_id, 0);
 
         let key = DefKey {
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index fe02cc5de8c..2b932b7c953 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1,4 +1,3 @@
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![recursion_limit = "256"]
 
 use rustc_ast as ast;
diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml
index 049e5b8b722..85bf4dc176b 100644
--- a/compiler/rustc_incremental/Cargo.toml
+++ b/compiler/rustc_incremental/Cargo.toml
@@ -20,3 +20,4 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_span = { path = "../rustc_span" }
 rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_session = { path = "../rustc_session" }
+rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index e7bd488af8e..9abd4eae914 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -1,6 +1,5 @@
-//! Debugging code to test fingerprints computed for query results.
-//! For each node marked with `#[rustc_clean]` or `#[rustc_dirty]`,
-//! we will compare the fingerprint from the current and from the previous
+//! Debugging code to test fingerprints computed for query results.  For each node marked with
+//! `#[rustc_clean]` we will compare the fingerprint from the current and from the previous
 //! compilation session as appropriate:
 //!
 //! - `#[rustc_clean(cfg="rev2", except="typeck")]` if we are
@@ -30,7 +29,6 @@ use std::iter::FromIterator;
 use std::vec::Vec;
 
 const EXCEPT: Symbol = sym::except;
-const LABEL: Symbol = sym::label;
 const CFG: Symbol = sym::cfg;
 
 // Base and Extra labels to build up the labels
@@ -102,6 +100,12 @@ const LABELS_FN_IN_TRAIT: &[&[&str]] =
 const LABELS_HIR_ONLY: &[&[&str]] = &[BASE_HIR];
 
 /// Impl `DepNode`s.
+const LABELS_TRAIT: &[&[&str]] = &[
+    BASE_HIR,
+    &[label_strs::associated_item_def_ids, label_strs::predicates_of, label_strs::generics_of],
+];
+
+/// Impl `DepNode`s.
 const LABELS_IMPL: &[&[&str]] = &[BASE_HIR, BASE_IMPL];
 
 /// Abstract data type (struct, enum, union) `DepNode`s.
@@ -122,22 +126,12 @@ struct Assertion {
     dirty: Labels,
 }
 
-impl Assertion {
-    fn from_clean_labels(labels: Labels) -> Assertion {
-        Assertion { clean: labels, dirty: Labels::default() }
-    }
-
-    fn from_dirty_labels(labels: Labels) -> Assertion {
-        Assertion { clean: Labels::default(), dirty: labels }
-    }
-}
-
 pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
     if !tcx.sess.opts.debugging_opts.query_dep_graph {
         return;
     }
 
-    // can't add `#[rustc_dirty]` etc without opting in to this feature
+    // can't add `#[rustc_clean]` etc without opting in to this feature
     if !tcx.features().rustc_attrs {
         return;
     }
@@ -147,11 +141,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
         let mut dirty_clean_visitor = DirtyCleanVisitor { tcx, checked_attrs: Default::default() };
         krate.visit_all_item_likes(&mut dirty_clean_visitor);
 
-        let mut all_attrs = FindAllAttrs {
-            tcx,
-            attr_names: &[sym::rustc_dirty, sym::rustc_clean],
-            found_attrs: vec![],
-        };
+        let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] };
         intravisit::walk_crate(&mut all_attrs, krate);
 
         // Note that we cannot use the existing "unused attribute"-infrastructure
@@ -169,37 +159,20 @@ pub struct DirtyCleanVisitor<'tcx> {
 impl DirtyCleanVisitor<'tcx> {
     /// Possibly "deserialize" the attribute into a clean/dirty 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) {
-            true
-        } else {
+        if !self.tcx.sess.check_name(attr, sym::rustc_clean) {
             // skip: not rustc_clean/dirty
             return None;
-        };
+        }
         if !check_config(self.tcx, attr) {
             // skip: not the correct `cfg=`
             return None;
         }
-        let assertion = if let Some(labels) = self.labels(attr) {
-            if is_clean {
-                Assertion::from_clean_labels(labels)
-            } else {
-                Assertion::from_dirty_labels(labels)
-            }
-        } else {
-            self.assertion_auto(item_id, attr, is_clean)
-        };
+        let assertion = self.assertion_auto(item_id, attr);
         Some(assertion)
     }
 
     /// Gets the "auto" assertion on pre-validated attr, along with the `except` labels.
-    fn assertion_auto(
-        &mut self,
-        item_id: LocalDefId,
-        attr: &Attribute,
-        is_clean: bool,
-    ) -> Assertion {
+    fn assertion_auto(&mut self, item_id: LocalDefId, attr: &Attribute) -> Assertion {
         let (name, mut auto) = self.auto_labels(item_id, attr);
         let except = self.except(attr);
         for e in except.iter() {
@@ -211,21 +184,7 @@ impl DirtyCleanVisitor<'tcx> {
                 self.tcx.sess.span_fatal(attr.span, &msg);
             }
         }
-        if is_clean {
-            Assertion { clean: auto, dirty: except }
-        } else {
-            Assertion { clean: except, dirty: auto }
-        }
-    }
-
-    fn labels(&self, attr: &Attribute) -> Option<Labels> {
-        for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
-            if item.has_name(LABEL) {
-                let value = expect_associated_value(self.tcx, &item);
-                return Some(self.resolve_labels(&item, value));
-            }
-        }
-        None
+        Assertion { clean: auto, dirty: except }
     }
 
     /// `except=` attribute value
@@ -288,20 +247,7 @@ impl DirtyCleanVisitor<'tcx> {
                     HirItem::Union(..) => ("ItemUnion", LABELS_ADT),
 
                     // Represents a Trait Declaration
-                    // FIXME(michaelwoerister): trait declaration is buggy because sometimes some of
-                    // the depnodes don't exist (because they legitimately didn't need to be
-                    // calculated)
-                    //
-                    // michaelwoerister and vitiral came up with a possible solution,
-                    // to just do this before every query
-                    // ```
-                    // ::rustc_middle::ty::query::plumbing::force_from_dep_node(tcx, dep_node)
-                    // ```
-                    //
-                    // However, this did not seem to work effectively and more bugs were hit.
-                    // Nebie @vitiral gave up :)
-                    //
-                    //HirItem::Trait(..) => ("ItemTrait", LABELS_TRAIT),
+                    HirItem::Trait(..) => ("ItemTrait", LABELS_TRAIT),
 
                     // An implementation, eg `impl<A> Trait for Foo { .. }`
                     HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL),
@@ -434,35 +380,23 @@ impl ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'tcx> {
     }
 }
 
-/// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan
-/// for a `cfg="foo"` attribute and check whether we have a cfg
-/// flag called `foo`.
-///
-/// Also make sure that the `label` and `except` fields do not
-/// both exist.
+/// Given a `#[rustc_clean]` attribute, scan for a `cfg="foo"` attribute and check whether we have
+/// a cfg flag called `foo`.
 fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {
     debug!("check_config(attr={:?})", attr);
     let config = &tcx.sess.parse_sess.config;
     debug!("check_config: config={:?}", config);
-    let (mut cfg, mut except, mut label) = (None, false, false);
+    let mut cfg = None;
     for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
         if item.has_name(CFG) {
             let value = expect_associated_value(tcx, &item);
             debug!("check_config: searching for cfg {:?}", value);
             cfg = Some(config.contains(&(value, None)));
-        }
-        if item.has_name(LABEL) {
-            label = true;
-        }
-        if item.has_name(EXCEPT) {
-            except = true;
+        } else if !item.has_name(EXCEPT) {
+            tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty()));
         }
     }
 
-    if label && except {
-        tcx.sess.span_fatal(attr.span, "must specify only one of: `label`, `except`");
-    }
-
     match cfg {
         None => tcx.sess.span_fatal(attr.span, "no cfg attribute"),
         Some(c) => c,
@@ -483,21 +417,18 @@ fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol {
     }
 }
 
-// A visitor that collects all #[rustc_dirty]/#[rustc_clean] attributes from
+// A visitor that collects all #[rustc_clean] attributes from
 // the HIR. It is used to verify that we really ran checks for all annotated
 // nodes.
-pub struct FindAllAttrs<'a, 'tcx> {
+pub struct FindAllAttrs<'tcx> {
     tcx: TyCtxt<'tcx>,
-    attr_names: &'a [Symbol],
     found_attrs: Vec<&'tcx Attribute>,
 }
 
-impl FindAllAttrs<'_, 'tcx> {
+impl FindAllAttrs<'tcx> {
     fn is_active_attr(&mut self, attr: &Attribute) -> bool {
-        for attr_name in self.attr_names {
-            if self.tcx.sess.check_name(attr, *attr_name) && check_config(self.tcx, attr) {
-                return true;
-            }
+        if self.tcx.sess.check_name(attr, sym::rustc_clean) && check_config(self.tcx, attr) {
+            return true;
         }
 
         false
@@ -506,17 +437,14 @@ impl FindAllAttrs<'_, 'tcx> {
     fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet<ast::AttrId>) {
         for attr in &self.found_attrs {
             if !checked_attrs.contains(&attr.id) {
-                self.tcx.sess.span_err(
-                    attr.span,
-                    "found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute",
-                );
+                self.tcx.sess.span_err(attr.span, "found unchecked `#[rustc_clean]` attribute");
                 checked_attrs.insert(attr.id);
             }
         }
     }
 }
 
-impl intravisit::Visitor<'tcx> for FindAllAttrs<'_, 'tcx> {
+impl intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> {
     type Map = Map<'tcx>;
 
     fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 30c6c408bc7..2ed0539841a 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -106,8 +106,9 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::{base_n, flock};
+use rustc_errors::ErrorReported;
 use rustc_fs_util::{link_or_copy, LinkOrCopy};
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::{Session, StableCrateId};
 
 use std::fs as std_fs;
 use std::io;
@@ -188,10 +189,10 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu
 pub fn prepare_session_directory(
     sess: &Session,
     crate_name: &str,
-    crate_disambiguator: CrateDisambiguator,
-) {
+    stable_crate_id: StableCrateId,
+) -> Result<(), ErrorReported> {
     if sess.opts.incremental.is_none() {
-        return;
+        return Ok(());
     }
 
     let _timer = sess.timer("incr_comp_prepare_session_directory");
@@ -199,11 +200,9 @@ pub fn prepare_session_directory(
     debug!("prepare_session_directory");
 
     // {incr-comp-dir}/{crate-name-and-disambiguator}
-    let crate_dir = crate_path(sess, crate_name, crate_disambiguator);
+    let crate_dir = crate_path(sess, crate_name, stable_crate_id);
     debug!("crate-dir: {}", crate_dir.display());
-    if create_dir(sess, &crate_dir, "crate").is_err() {
-        return;
-    }
+    create_dir(sess, &crate_dir, "crate")?;
 
     // Hack: canonicalize the path *after creating the directory*
     // because, on windows, long paths can cause problems;
@@ -217,7 +216,7 @@ pub fn prepare_session_directory(
                 crate_dir.display(),
                 err
             ));
-            return;
+            return Err(ErrorReported);
         }
     };
 
@@ -232,16 +231,11 @@ pub fn prepare_session_directory(
 
         // Lock the new session directory. If this fails, return an
         // error without retrying
-        let (directory_lock, lock_file_path) = match lock_directory(sess, &session_dir) {
-            Ok(e) => e,
-            Err(_) => return,
-        };
+        let (directory_lock, lock_file_path) = lock_directory(sess, &session_dir)?;
 
         // Now that we have the lock, we can actually create the session
         // directory
-        if create_dir(sess, &session_dir, "session").is_err() {
-            return;
-        }
+        create_dir(sess, &session_dir, "session")?;
 
         // Find a suitable source directory to copy from. Ignore those that we
         // have already tried before.
@@ -257,7 +251,7 @@ pub fn prepare_session_directory(
             );
 
             sess.init_incr_comp_session(session_dir, directory_lock, false);
-            return;
+            return Ok(());
         };
 
         debug!("attempting to copy data from source: {}", source_directory.display());
@@ -278,7 +272,7 @@ pub fn prepare_session_directory(
             }
 
             sess.init_incr_comp_session(session_dir, directory_lock, true);
-            return;
+            return Ok(());
         } else {
             debug!("copying failed - trying next directory");
 
@@ -478,7 +472,7 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf {
     directory_path
 }
 
-fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> {
+fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ErrorReported> {
     match std_fs::create_dir_all(path) {
         Ok(()) => {
             debug!("{} directory created successfully", dir_tag);
@@ -492,13 +486,16 @@ fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> {
                 path.display(),
                 err
             ));
-            Err(())
+            Err(ErrorReported)
         }
     }
 }
 
 /// Allocate the lock-file and lock it.
-fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, PathBuf), ()> {
+fn lock_directory(
+    sess: &Session,
+    session_dir: &Path,
+) -> Result<(flock::Lock, PathBuf), ErrorReported> {
     let lock_file_path = lock_file_path(session_dir);
     debug!("lock_directory() - lock_file: {}", lock_file_path.display());
 
@@ -510,13 +507,36 @@ fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, Pa
     ) {
         // the lock should be exclusive
         Ok(lock) => Ok((lock, lock_file_path)),
-        Err(err) => {
-            sess.err(&format!(
+        Err(lock_err) => {
+            let mut err = sess.struct_err(&format!(
                 "incremental compilation: could not create \
-                               session directory lock file: {}",
-                err
+                 session directory lock file: {}",
+                lock_err
             ));
-            Err(())
+            if flock::Lock::error_unsupported(&lock_err) {
+                err.note(&format!(
+                    "the filesystem for the incremental path at {} \
+                     does not appear to support locking, consider changing the \
+                     incremental path to a filesystem that supports locking \
+                     or disable incremental compilation",
+                    session_dir.display()
+                ));
+                if std::env::var_os("CARGO").is_some() {
+                    err.help(
+                        "incremental compilation can be disabled by setting the \
+                         environment variable CARGO_INCREMENTAL=0 (see \
+                         https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)",
+                    );
+                    err.help(
+                        "the entire build directory can be changed to a different \
+                        filesystem by setting the environment variable CARGO_TARGET_DIR \
+                        to a different path (see \
+                        https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)",
+                    );
+                }
+            }
+            err.emit();
+            Err(ErrorReported)
         }
     }
 }
@@ -628,19 +648,12 @@ fn string_to_timestamp(s: &str) -> Result<SystemTime, ()> {
     Ok(UNIX_EPOCH + duration)
 }
 
-fn crate_path(
-    sess: &Session,
-    crate_name: &str,
-    crate_disambiguator: CrateDisambiguator,
-) -> PathBuf {
+fn crate_path(sess: &Session, crate_name: &str, stable_crate_id: StableCrateId) -> PathBuf {
     let incr_dir = sess.opts.incremental.as_ref().unwrap().clone();
 
-    // The full crate disambiguator is really long. 64 bits of it should be
-    // sufficient.
-    let crate_disambiguator = crate_disambiguator.to_fingerprint().to_smaller_hash();
-    let crate_disambiguator = base_n::encode(crate_disambiguator as u128, INT_ENCODE_BASE);
+    let stable_crate_id = base_n::encode(stable_crate_id.to_u64() as u128, INT_ENCODE_BASE);
 
-    let crate_name = format!("{}-{}", crate_name, crate_disambiguator);
+    let crate_name = format!("{}-{}", crate_name, stable_crate_id);
     incr_dir.join(crate_name)
 }
 
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index bd3b5239f7b..303c39a39a9 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -2,7 +2,7 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::definitions::DefPathTable;
-use rustc_middle::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
+use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId};
 use rustc_middle::ty::query::OnDiskCache;
 use rustc_serialize::opaque::Decoder;
 use rustc_serialize::Decodable;
@@ -22,8 +22,8 @@ pub enum LoadResult<T> {
     Error { message: String },
 }
 
-impl LoadResult<(PreviousDepGraph, WorkProductMap)> {
-    pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) {
+impl LoadResult<(SerializedDepGraph, WorkProductMap)> {
+    pub fn open(self, sess: &Session) -> (SerializedDepGraph, WorkProductMap) {
         match self {
             LoadResult::Error { message } => {
                 sess.warn(&message);
@@ -84,7 +84,7 @@ impl<T> MaybeAsync<T> {
     }
 }
 
-pub type DepGraphFuture = MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>;
+pub type DepGraphFuture = MaybeAsync<LoadResult<(SerializedDepGraph, WorkProductMap)>>;
 
 /// Launch a thread and load the dependency graph in the background.
 pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
@@ -185,7 +185,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
                 let dep_graph = SerializedDepGraph::decode(&mut decoder)
                     .expect("Error reading cached dep-graph");
 
-                LoadResult::Ok { data: (PreviousDepGraph::new(dep_graph), prev_work_products) }
+                LoadResult::Ok { data: (dep_graph, prev_work_products) }
             }
         }
     }))
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index 1484088837a..a8455854ebb 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -1,6 +1,6 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::join;
-use rustc_middle::dep_graph::{DepGraph, PreviousDepGraph, WorkProduct, WorkProductId};
+use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
 use rustc_middle::ty::TyCtxt;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_serialize::Encodable as RustcEncodable;
@@ -186,7 +186,7 @@ fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeR
 
 pub fn build_dep_graph(
     sess: &Session,
-    prev_graph: PreviousDepGraph,
+    prev_graph: SerializedDepGraph,
     prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
 ) -> Option<DepGraph> {
     if sess.opts.incremental.is_none() {
@@ -229,6 +229,7 @@ pub fn build_dep_graph(
     }
 
     Some(DepGraph::new(
+        &sess.prof,
         prev_graph,
         prev_work_products,
         encoder,
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index 4c73b7bf612..0093fa5e562 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -1,6 +1,5 @@
 #![feature(allow_internal_unstable)]
 #![feature(bench_black_box)]
-#![feature(const_panic)]
 #![feature(extend_one)]
 #![feature(iter_zip)]
 #![feature(unboxed_closures)]
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index 1b1a59a254e..246fa28d986 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -65,7 +65,7 @@ impl Idx for u32 {
 /// `u32::MAX`. You can also customize things like the `Debug` impl,
 /// what traits are derived, and so forth via the macro.
 #[macro_export]
-#[allow_internal_unstable(step_trait, step_trait_ext, rustc_attrs)]
+#[allow_internal_unstable(step_trait, rustc_attrs, trusted_step)]
 macro_rules! newtype_index {
     // ---- public rules ----
 
@@ -184,7 +184,7 @@ macro_rules! newtype_index {
             }
         }
 
-        unsafe impl ::std::iter::Step for $type {
+        impl ::std::iter::Step for $type {
             #[inline]
             fn steps_between(start: &Self, end: &Self) -> Option<usize> {
                 <usize as ::std::iter::Step>::steps_between(
@@ -204,6 +204,9 @@ macro_rules! newtype_index {
             }
         }
 
+        // Safety: The implementation of `Step` upholds all invariants.
+        unsafe impl ::std::iter::TrustedStep for $type {}
+
         impl From<$type> for u32 {
             #[inline]
             fn from(v: $type) -> u32 {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 680f6af63f2..fb762d2deba 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -524,7 +524,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             }
 
             fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
-                Ok(vec![self.tcx.original_crate_name(cnum).to_string()])
+                Ok(vec![self.tcx.crate_name(cnum).to_string()])
             }
             fn path_qualified(
                 self,
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 9ffcddfae99..49359130162 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -3,7 +3,6 @@
 use self::CombineMapType::*;
 use self::UndoLog::*;
 
-use super::unify_key;
 use super::{
     InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin,
 };
@@ -12,9 +11,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_data_structures::unify as ut;
-use rustc_data_structures::unify::UnifyKey;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::IndexVec;
+use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
 use rustc_middle::ty::ReStatic;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ReLateBound, ReVar};
@@ -54,7 +53,7 @@ pub struct RegionConstraintStorage<'tcx> {
     /// code is iterating to a fixed point, because otherwise we sometimes
     /// would wind up with a fresh stream of region variables that have been
     /// equated but appear distinct.
-    pub(super) unification_table: ut::UnificationTableStorage<ty::RegionVid>,
+    pub(super) unification_table: ut::UnificationTableStorage<RegionVidKey<'tcx>>,
 
     /// a flag set to true when we perform any unifications; this is used
     /// to micro-optimize `take_and_reset_data`
@@ -407,8 +406,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         // `RegionConstraintData` contains the relationship here.
         if *any_unifications {
             *any_unifications = false;
-            self.unification_table()
-                .reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid });
+            self.unification_table().reset_unifications(|_| UnifiedRegion(None));
         }
 
         data
@@ -435,8 +433,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
     ) -> RegionVid {
         let vid = self.var_infos.push(RegionVariableInfo { origin, universe });
 
-        let u_vid = self.unification_table().new_key(unify_key::RegionVidKey { min_vid: vid });
-        assert_eq!(vid, u_vid);
+        let u_vid = self.unification_table().new_key(UnifiedRegion(None));
+        assert_eq!(vid, u_vid.vid);
         self.undo_log.push(AddVar(vid));
         debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin);
         vid
@@ -498,10 +496,18 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
             self.make_subregion(origin.clone(), sub, sup);
             self.make_subregion(origin, sup, sub);
 
-            if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) {
-                debug!("make_eqregion: uniying {:?} with {:?}", sub, sup);
-                self.unification_table().union(sub, sup);
-                self.any_unifications = true;
+            match (sub, sup) {
+                (&ty::ReVar(sub), &ty::ReVar(sup)) => {
+                    debug!("make_eqregion: unifying {:?} with {:?}", sub, sup);
+                    self.unification_table().union(sub, sup);
+                    self.any_unifications = true;
+                }
+                (&ty::ReVar(vid), value) | (value, &ty::ReVar(vid)) => {
+                    debug!("make_eqregion: unifying {:?} with {:?}", vid, value);
+                    self.unification_table().union_value(vid, UnifiedRegion(Some(value)));
+                    self.any_unifications = true;
+                }
+                (_, _) => {}
             }
         }
     }
@@ -617,8 +623,29 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         }
     }
 
-    pub fn opportunistic_resolve_var(&mut self, rid: RegionVid) -> ty::RegionVid {
-        self.unification_table().probe_value(rid).min_vid
+    /// Resolves the passed RegionVid to the root RegionVid in the unification table
+    pub fn opportunistic_resolve_var(&mut self, rid: ty::RegionVid) -> ty::RegionVid {
+        self.unification_table().find(rid).vid
+    }
+
+    /// If the Region is a `ReVar`, then resolves it either to the root value in
+    /// the unification table, if it exists, or to the root `ReVar` in the table.
+    /// If the Region is not a `ReVar`, just returns the Region itself.
+    pub fn opportunistic_resolve_region(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        region: ty::Region<'tcx>,
+    ) -> ty::Region<'tcx> {
+        match region {
+            ty::ReVar(rid) => {
+                let unified_region = self.unification_table().probe_value(*rid);
+                unified_region.0.unwrap_or_else(|| {
+                    let root = self.unification_table().find(*rid).vid;
+                    tcx.reuse_or_mk_region(region, ty::ReVar(root))
+                })
+            }
+            _ => region,
+        }
     }
 
     fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> {
@@ -673,8 +700,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
         &self,
         value_count: usize,
     ) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) {
-        let range = RegionVid::from_index(value_count as u32)
-            ..RegionVid::from_index(self.unification_table.len() as u32);
+        let range = RegionVid::from(value_count)..RegionVid::from(self.unification_table.len());
         (
             range.clone(),
             (range.start.index()..range.end.index())
@@ -696,7 +722,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
     }
 
     #[inline]
-    fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, ty::RegionVid> {
+    fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>> {
         ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log)
     }
 }
diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs
index f41e872e004..5ad2519a93c 100644
--- a/compiler/rustc_infer/src/infer/undo_log.rs
+++ b/compiler/rustc_infer/src/infer/undo_log.rs
@@ -3,6 +3,7 @@ use std::marker::PhantomData;
 use rustc_data_structures::snapshot_vec as sv;
 use rustc_data_structures::undo_log::{Rollback, UndoLogs};
 use rustc_data_structures::unify as ut;
+use rustc_middle::infer::unify_key::RegionVidKey;
 use rustc_middle::ty;
 
 use crate::{
@@ -22,7 +23,7 @@ pub(crate) enum UndoLog<'tcx> {
     IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
     FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
     RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
-    RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>),
+    RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
     ProjectionCache(traits::UndoLog<'tcx>),
     PushRegionObligation,
 }
@@ -55,7 +56,7 @@ impl_from! {
 
     ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
 
-    RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>),
+    RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
     ProjectionCache(traits::UndoLog<'tcx>),
 }
 
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 15b4a7ed207..ee358c52c2f 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -16,13 +16,12 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_panic)]
 #![feature(extend_one)]
 #![feature(iter_zip)]
 #![feature(never_type)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(in_band_lifetimes)]
 #![feature(control_flow_enum)]
+#![feature(min_specialization)]
 #![recursion_limit = "512"] // For rustdoc
 
 #[macro_use]
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index f2b69da3f86..b5af2bfca35 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,6 +1,5 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 #![feature(internal_output_capture)]
 #![feature(nll)]
 #![feature(generator_trait)]
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index e2220e3b60d..1666754d29a 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
 use rustc_errors::{ErrorReported, PResult};
 use rustc_expand::base::ExtCtxt;
-use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
 use rustc_hir::Crate;
 use rustc_lint::LintStore;
 use rustc_metadata::creader::CStore;
@@ -170,9 +170,13 @@ pub fn register_plugins<'a>(
     let crate_types = util::collect_crate_types(sess, &krate.attrs);
     sess.init_crate_types(crate_types);
 
-    let disambiguator = util::compute_crate_disambiguator(sess);
-    sess.crate_disambiguator.set(disambiguator).expect("not yet initialized");
-    rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator);
+    let stable_crate_id = StableCrateId::new(
+        crate_name,
+        sess.crate_types().contains(&CrateType::Executable),
+        sess.opts.cg.metadata.clone(),
+    );
+    sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized");
+    rustc_incremental::prepare_session_directory(sess, &crate_name, stable_crate_id)?;
 
     if sess.opts.incremental.is_some() {
         sess.time("incr_comp_garbage_collect_session_directories", || {
@@ -795,7 +799,7 @@ pub fn create_global_ctxt<'tcx>(
                 query_result_on_disk_cache,
                 queries.as_dyn(),
                 &crate_name,
-                &outputs,
+                outputs,
             )
         })
     });
@@ -873,9 +877,8 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
 
     sess.time("MIR_effect_checking", || {
         for def_id in tcx.body_owners() {
-            if tcx.sess.opts.debugging_opts.thir_unsafeck {
-                tcx.ensure().thir_check_unsafety(def_id);
-            } else {
+            tcx.ensure().thir_check_unsafety(def_id);
+            if !tcx.sess.opts.debugging_opts.thir_unsafeck {
                 mir::transform::check_unsafety::check_unsafety(tcx, def_id);
             }
 
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 92d05e48068..969b526235b 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -148,7 +148,7 @@ impl<'tcx> Queries<'tcx> {
                 self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
                 krate,
                 &crate_name,
-            );
+            )?;
 
             // Compute the dependency graph (in the background). We want to do
             // this as early as possible, to give the DepGraph maximum time to
@@ -157,7 +157,7 @@ impl<'tcx> Queries<'tcx> {
             // called, which happens within passes::register_plugins().
             self.dep_graph_future().ok();
 
-            result
+            Ok(result)
         })
     }
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index bea7d0fb81f..5d8a6084f2e 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -252,7 +252,8 @@ fn test_lints_tracking_hash_different_construction_order() {
         (String::from("d"), Level::Forbid),
     ];
 
-    assert_same_hash(&v1, &v2);
+    // The hash should be order-dependent
+    assert_different_hash(&v1, &v2);
 }
 
 #[test]
@@ -491,9 +492,10 @@ fn test_native_libs_tracking_hash_different_order() {
         },
     ];
 
-    assert_same_hash(&v1, &v2);
-    assert_same_hash(&v1, &v3);
-    assert_same_hash(&v2, &v3);
+    // The hash should be order-dependent
+    assert_different_hash(&v1, &v2);
+    assert_different_hash(&v1, &v3);
+    assert_different_hash(&v2, &v3);
 }
 
 #[test]
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 7b1660b501b..15cda299208 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -2,11 +2,9 @@ use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *};
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, AttrVec, BlockCheckMode};
 use rustc_codegen_ssa::traits::CodegenBackend;
-use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 #[cfg(parallel_compiler)]
 use rustc_data_structures::jobserver;
-use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::registry::Registry;
 use rustc_metadata::dynamic_lib::DynamicLibrary;
@@ -18,7 +16,6 @@ use rustc_session::config::{self, CrateType};
 use rustc_session::config::{ErrorOutputType, Input, OutputFilenames};
 use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
 use rustc_session::parse::CrateConfig;
-use rustc_session::CrateDisambiguator;
 use rustc_session::{early_error, filesearch, output, DiagnosticOutput, Session};
 use rustc_span::edition::Edition;
 use rustc_span::lev_distance::find_best_match_for_name;
@@ -496,39 +493,6 @@ pub fn get_codegen_sysroot(
     }
 }
 
-pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator {
-    use std::hash::Hasher;
-
-    // The crate_disambiguator is a 128 bit hash. The disambiguator is fed
-    // into various other hashes quite a bit (symbol hashes, incr. comp. hashes,
-    // debuginfo type IDs, etc), so we don't want it to be too wide. 128 bits
-    // should still be safe enough to avoid collisions in practice.
-    let mut hasher = StableHasher::new();
-
-    let mut metadata = session.opts.cg.metadata.clone();
-    // We don't want the crate_disambiguator to dependent on the order
-    // -C metadata arguments, so sort them:
-    metadata.sort();
-    // Every distinct -C metadata value is only incorporated once:
-    metadata.dedup();
-
-    hasher.write(b"metadata");
-    for s in &metadata {
-        // Also incorporate the length of a metadata string, so that we generate
-        // different values for `-Cmetadata=ab -Cmetadata=c` and
-        // `-Cmetadata=a -Cmetadata=bc`
-        hasher.write_usize(s.len());
-        hasher.write(s.as_bytes());
-    }
-
-    // Also incorporate crate type, so that we don't get symbol conflicts when
-    // linking against a library of the same name, if this is an executable.
-    let is_exe = session.crate_types().contains(&CrateType::Executable);
-    hasher.write(if is_exe { b"exe" } else { b"lib" });
-
-    CrateDisambiguator::from(hasher.finish::<Fingerprint>())
-}
-
 pub(crate) fn check_attr_crate_type(
     sess: &Session,
     attrs: &[ast::Attribute],
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index c1d6a4f1de1..a8df1b0952c 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -334,8 +334,14 @@ impl LintStore {
         }
     }
 
-    /// Checks the validity of lint names derived from the command line
-    pub fn check_lint_name_cmdline(&self, sess: &Session, lint_name: &str, level: Level) {
+    /// Checks the validity of lint names derived from the command line. Returns
+    /// true if the lint is valid, false otherwise.
+    pub fn check_lint_name_cmdline(
+        &self,
+        sess: &Session,
+        lint_name: &str,
+        level: Option<Level>,
+    ) -> bool {
         let db = match self.check_lint_name(lint_name, None) {
             CheckLintNameResult::Ok(_) => None,
             CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
@@ -361,18 +367,23 @@ impl LintStore {
         };
 
         if let Some(mut db) = db {
-            let msg = format!(
-                "requested on the command line with `{} {}`",
-                match level {
-                    Level::Allow => "-A",
-                    Level::Warn => "-W",
-                    Level::Deny => "-D",
-                    Level::Forbid => "-F",
-                },
-                lint_name
-            );
-            db.note(&msg);
+            if let Some(level) = level {
+                let msg = format!(
+                    "requested on the command line with `{} {}`",
+                    match level {
+                        Level::Allow => "-A",
+                        Level::Warn => "-W",
+                        Level::Deny => "-D",
+                        Level::Forbid => "-F",
+                    },
+                    lint_name
+                );
+                db.note(&msg);
+            }
             db.emit();
+            false
+        } else {
+            true
         }
     }
 
@@ -922,7 +933,7 @@ impl<'tcx> LateContext<'tcx> {
             }
 
             fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
-                Ok(vec![self.tcx.original_crate_name(cnum)])
+                Ok(vec![self.tcx.crate_name(cnum)])
             }
 
             fn path_qualified(
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 91cdef9b089..0ee434f5fb5 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -88,7 +88,7 @@ impl<'s> LintLevelsBuilder<'s> {
         self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
 
         for &(ref lint_name, level) in &sess.opts.lint_opts {
-            store.check_lint_name_cmdline(sess, &lint_name, level);
+            store.check_lint_name_cmdline(sess, &lint_name, Some(level));
             let orig_level = level;
 
             // If the cap is less than this specified level, e.g., if we've got
@@ -109,6 +109,16 @@ impl<'s> LintLevelsBuilder<'s> {
             }
         }
 
+        for lint_name in &sess.opts.force_warns {
+            let valid = store.check_lint_name_cmdline(sess, lint_name, None);
+            if valid {
+                let lints = store
+                    .find_lints(lint_name)
+                    .unwrap_or_else(|_| bug!("A valid lint failed to produce a lint ids"));
+                self.sets.force_warns.extend(&lints);
+            }
+        }
+
         self.sets.list.push(LintSet::CommandLine { specs });
     }
 
@@ -142,6 +152,9 @@ impl<'s> LintLevelsBuilder<'s> {
                     LintLevelSource::Default => false,
                     LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol),
                     LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
+                    LintLevelSource::ForceWarn(_symbol) => {
+                        bug!("forced warn lint returned a forbid lint level")
+                    }
                 };
                 debug!(
                     "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
@@ -166,6 +179,7 @@ impl<'s> LintLevelsBuilder<'s> {
                         LintLevelSource::CommandLine(_, _) => {
                             diag_builder.note("`forbid` lint level was set on command line");
                         }
+                        _ => bug!("forced warn lint returned a forbid lint level"),
                     }
                     diag_builder.emit();
                 };
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 2f46969b021..4f59460aa82 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -36,9 +36,6 @@
 #![feature(iter_zip)]
 #![feature(never_type)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
-#![feature(half_open_range_patterns)]
-#![feature(exclusive_range_pattern)]
 #![feature(control_flow_enum)]
 #![recursion_limit = "256"]
 
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index be9c6eafb6f..7146dd51aa7 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -176,6 +176,7 @@ impl EarlyLintPass for NonCamelCaseTypes {
             | ast::ItemKind::Struct(..)
             | ast::ItemKind::Union(..) => self.check_case(cx, "type", &it.ident),
             ast::ItemKind::Trait(..) => self.check_case(cx, "trait", &it.ident),
+            ast::ItemKind::TraitAlias(..) => self.check_case(cx, "trait alias", &it.ident),
             _ => (),
         }
     }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 9c94bab04e9..319adf42cf1 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::{is_range_literal, ExprKind, Node};
-use rustc_index::vec::Idx;
 use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
@@ -13,7 +12,7 @@ use rustc_span::source_map;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::Abi;
-use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants};
+use rustc_target::abi::{Integer, LayoutOf, TagEncoding, Variants};
 use rustc_target::spec::abi::Abi as SpecAbi;
 
 use std::cmp;
@@ -783,25 +782,14 @@ crate fn repr_nullable_ptr<'tcx>(
 ) -> Option<Ty<'tcx>> {
     debug!("is_repr_nullable_ptr(cx, ty = {:?})", ty);
     if let ty::Adt(ty_def, substs) = ty.kind() {
-        if ty_def.variants.len() != 2 {
-            return None;
-        }
-
-        let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields;
-        let variant_fields = [get_variant_fields(0), get_variant_fields(1)];
-        let fields = if variant_fields[0].is_empty() {
-            &variant_fields[1]
-        } else if variant_fields[1].is_empty() {
-            &variant_fields[0]
-        } else {
-            return None;
+        let field_ty = match &ty_def.variants.raw[..] {
+            [var_one, var_two] => match (&var_one.fields[..], &var_two.fields[..]) {
+                ([], [field]) | ([field], []) => field.ty(cx.tcx, substs),
+                _ => return None,
+            },
+            _ => return None,
         };
 
-        if fields.len() != 1 {
-            return None;
-        }
-
-        let field_ty = fields[0].ty(cx.tcx, substs);
         if !ty_is_known_nonnull(cx, field_ty, ckind) {
             return None;
         }
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 70475563a4a..f1c4e5fb4a3 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -25,7 +25,11 @@ macro_rules! pluralize {
 /// before applying the suggestion.
 #[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
 pub enum Applicability {
-    /// The suggestion is definitely what the user intended. This suggestion should be
+    /// The suggestion is definitely what the user intended, or maintains the exact meaning of the code.
+    /// This suggestion should be automatically applied.
+    ///
+    /// In case of multiple `MachineApplicable` suggestions (whether as part of
+    /// the same `multipart_suggestion` or not), all of them should be
     /// automatically applied.
     MachineApplicable,
 
diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml
index 7a34788de91..3fca2e1ccb9 100644
--- a/compiler/rustc_llvm/Cargo.toml
+++ b/compiler/rustc_llvm/Cargo.toml
@@ -13,4 +13,4 @@ libc = "0.2.73"
 
 [build-dependencies]
 build_helper = { path = "../../src/build_helper" }
-cc = "1.0.67"
+cc = "1.0.68"
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 99ce13a6ed5..3595e37cf96 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -793,16 +793,23 @@ LLVMRustOptimizeWithNewPassManager(
     PGOOpt = PGOOptions(PGOUsePath, "", "", PGOOptions::IRUse);
   }
 
-#if LLVM_VERSION_GE(12, 0)
+#if LLVM_VERSION_GE(12, 0) && !LLVM_VERSION_GE(13,0)
   PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC);
 #else
   PassBuilder PB(TM, PTO, PGOOpt, &PIC);
 #endif
 
+#if LLVM_VERSION_GE(13, 0)
+  LoopAnalysisManager LAM;
+  FunctionAnalysisManager FAM;
+  CGSCCAnalysisManager CGAM;
+  ModuleAnalysisManager MAM;
+#else
   LoopAnalysisManager LAM(DebugPassManager);
   FunctionAnalysisManager FAM(DebugPassManager);
   CGSCCAnalysisManager CGAM(DebugPassManager);
   ModuleAnalysisManager MAM(DebugPassManager);
+#endif
 
   FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); });
 
@@ -956,7 +963,11 @@ LLVMRustOptimizeWithNewPassManager(
     }
   }
 
+#if LLVM_VERSION_GE(13, 0)
+  ModulePassManager MPM;
+#else
   ModulePassManager MPM(DebugPassManager);
+#endif
   bool NeedThinLTOBufferPasses = UseThinLTOBuffers;
   if (!NoPrepopulatePasses) {
     if (OptLevel == PassBuilder::OptimizationLevel::O0) {
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index e9ae22f8ced..42c32219aba 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -21,7 +21,7 @@ use rustc_session::config::{self, CrateType, ExternLocation};
 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};
+use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -222,10 +222,8 @@ impl<'a> CrateLoader<'a> {
         metadata_loader: &'a MetadataLoaderDyn,
         local_crate_name: &str,
     ) -> Self {
-        let local_crate_stable_id =
-            StableCrateId::new(local_crate_name, sess.local_crate_disambiguator());
         let mut stable_crate_ids = FxHashMap::default();
-        stable_crate_ids.insert(local_crate_stable_id, LOCAL_CRATE);
+        stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE);
 
         CrateLoader {
             sess,
@@ -327,17 +325,14 @@ impl<'a> CrateLoader<'a> {
 
     fn verify_no_symbol_conflicts(&self, root: &CrateRoot<'_>) -> Result<(), CrateError> {
         // Check for (potential) conflicts with the local crate
-        if self.local_crate_name == root.name()
-            && self.sess.local_crate_disambiguator() == root.disambiguator()
-        {
+        if self.sess.local_stable_crate_id() == root.stable_crate_id() {
             return Err(CrateError::SymbolConflictsCurrent(root.name()));
         }
 
         // Check for conflicts with any crate loaded so far
         let mut res = Ok(());
         self.cstore.iter_crate_data(|_, other| {
-            if other.name() == root.name() && // same crate-name
-               other.disambiguator() == root.disambiguator() && // same crate-disambiguator
+            if other.stable_crate_id() == root.stable_crate_id() && // same stable crate id
                other.hash() != root.hash()
             {
                 // but different SVH
@@ -411,7 +406,7 @@ impl<'a> CrateLoader<'a> {
                 None => (&source, &crate_root),
             };
             let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
-            Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator())?)
+            Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.stable_crate_id())?)
         } else {
             None
         };
@@ -664,7 +659,7 @@ impl<'a> CrateLoader<'a> {
     fn dlsym_proc_macros(
         &self,
         path: &Path,
-        disambiguator: CrateDisambiguator,
+        stable_crate_id: StableCrateId,
     ) -> Result<&'static [ProcMacro], CrateError> {
         // Make sure the path contains a / or the linker will search for it.
         let path = env::current_dir().unwrap().join(path);
@@ -673,7 +668,7 @@ impl<'a> CrateLoader<'a> {
             Err(s) => return Err(CrateError::DlOpen(s)),
         };
 
-        let sym = self.sess.generate_proc_macro_decls_symbol(disambiguator);
+        let sym = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
         let decls = unsafe {
             let sym = match lib.symbol(&sym) {
                 Ok(f) => f,
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index c4d9e3f77f0..27842ac7796 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -1,14 +1,11 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(core_intrinsics)]
 #![feature(crate_visibility_modifier)]
 #![feature(drain_filter)]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
 #![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(proc_macro_internals)]
 #![feature(min_specialization)]
-#![feature(stmt_expr_attributes)]
 #![feature(try_blocks)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 6e736095090..b830c6b2481 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -226,7 +226,7 @@ use rustc_session::config::{self, CrateType};
 use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::CanonicalizedPath;
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::{Session, StableCrateId};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use rustc_target::spec::{Target, TargetTriple};
@@ -787,7 +787,7 @@ pub fn find_plugin_registrar(
     metadata_loader: &dyn MetadataLoader,
     span: Span,
     name: Symbol,
-) -> (PathBuf, CrateDisambiguator) {
+) -> (PathBuf, StableCrateId) {
     match find_plugin_registrar_impl(sess, metadata_loader, name) {
         Ok(res) => res,
         // `core` is always available if we got as far as loading plugins.
@@ -799,7 +799,7 @@ fn find_plugin_registrar_impl<'a>(
     sess: &'a Session,
     metadata_loader: &dyn MetadataLoader,
     name: Symbol,
-) -> Result<(PathBuf, CrateDisambiguator), CrateError> {
+) -> Result<(PathBuf, StableCrateId), CrateError> {
     info!("find plugin registrar `{}`", name);
     let mut locator = CrateLocator::new(
         sess,
@@ -816,7 +816,7 @@ fn find_plugin_registrar_impl<'a>(
 
     match locator.maybe_load_library_crate()? {
         Some(library) => match library.source.dylib {
-            Some(dylib) => Ok((dylib.0, library.metadata.get_root().disambiguator())),
+            Some(dylib) => Ok((dylib.0, library.metadata.get_root().stable_crate_id())),
             None => Err(CrateError::NonDylibPlugin(name)),
         },
         None => Err(locator.into_error()),
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index b27eef376c4..59fec58f0a1 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -300,7 +300,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
     {
         let tcx = self.tcx();
 
-        let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand };
+        let key = ty::CReaderCacheKey { cnum: Some(self.cdata().cnum), pos: shorthand };
 
         if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) {
             return Ok(ty);
@@ -620,10 +620,6 @@ impl CrateRoot<'_> {
         self.name
     }
 
-    crate fn disambiguator(&self) -> CrateDisambiguator {
-        self.disambiguator
-    }
-
     crate fn hash(&self) -> Svh {
         self.hash
     }
@@ -1927,14 +1923,18 @@ impl CrateMetadata {
         self.root.name
     }
 
-    crate fn disambiguator(&self) -> CrateDisambiguator {
-        self.root.disambiguator
+    crate fn stable_crate_id(&self) -> StableCrateId {
+        self.root.stable_crate_id
     }
 
     crate fn hash(&self) -> Svh {
         self.root.hash
     }
 
+    fn num_def_ids(&self) -> usize {
+        self.root.tables.def_keys.size()
+    }
+
     fn local_def_id(&self, index: DefIndex) -> DefId {
         DefId { krate: self.cnum, index }
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index e25b22c8331..9e615e48a3c 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -19,7 +19,7 @@ use rustc_middle::middle::stability::DeprecationEntry;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, Visibility};
 use rustc_session::utils::NativeLibKind;
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::{Session, StableCrateId};
 use rustc_span::source_map::{Span, Spanned};
 use rustc_span::symbol::Symbol;
 
@@ -155,6 +155,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
 
     dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
+    is_private_dep => { cdata.private_dep }
     is_panic_runtime => { cdata.root.panic_runtime }
     is_compiler_builtins => { cdata.root.compiler_builtins }
     has_global_allocator => { cdata.root.has_global_allocator }
@@ -185,10 +186,9 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     }
     native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess)) }
     foreign_modules => { cdata.get_foreign_modules(tcx) }
-    crate_disambiguator => { cdata.root.disambiguator }
     crate_hash => { cdata.root.hash }
     crate_host_hash => { cdata.host_hash }
-    original_crate_name => { cdata.root.name }
+    crate_name => { cdata.root.name }
 
     extra_filename => { cdata.root.extra_filename.clone() }
 
@@ -205,7 +205,6 @@ provide! { <'tcx> tcx, def_id, other, cdata,
         let r = *cdata.dep_kind.lock();
         r
     }
-    crate_name => { cdata.root.name }
     item_children => {
         let mut result = SmallVec::<[_; 8]>::new();
         cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess);
@@ -251,6 +250,10 @@ pub fn provide(providers: &mut Providers) {
         is_statically_included_foreign_item: |tcx, id| {
             matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. }))
         },
+        is_private_dep: |_tcx, cnum| {
+            assert_eq!(cnum, LOCAL_CRATE);
+            false
+        },
         native_library_kind: |tcx, id| {
             tcx.native_libraries(id.krate)
                 .iter()
@@ -455,6 +458,13 @@ impl CStore {
         self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
     }
 
+    /// Only public-facing way to traverse all the definitions in a non-local crate.
+    /// Critically useful for this third-party project: <https://github.com/hacspec/hacspec>.
+    /// See <https://github.com/rust-lang/rust/pull/85889> for context.
+    pub fn num_def_ids_untracked(&self, cnum: CrateNum) -> usize {
+        self.get_crate_data(cnum).num_def_ids()
+    }
+
     pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
         self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect()
     }
@@ -478,12 +488,8 @@ impl CrateStore for CStore {
         self.get_crate_data(cnum).root.name
     }
 
-    fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool {
-        self.get_crate_data(cnum).private_dep
-    }
-
-    fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator {
-        self.get_crate_data(cnum).root.disambiguator
+    fn stable_crate_id_untracked(&self, cnum: CrateNum) -> StableCrateId {
+        self.get_crate_data(cnum).root.stable_crate_id
     }
 
     fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 0c31430598a..2fd9a46cf42 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -671,7 +671,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             extra_filename: tcx.sess.opts.cg.extra_filename.clone(),
             triple: tcx.sess.opts.target_triple.clone(),
             hash: tcx.crate_hash(LOCAL_CRATE),
-            disambiguator: tcx.sess.local_crate_disambiguator(),
             stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(),
             panic_strategy: tcx.sess.panic_strategy(),
             edition: tcx.sess.edition(),
@@ -1674,7 +1673,7 @@ impl EncodeContext<'a, 'tcx> {
             .iter()
             .map(|&cnum| {
                 let dep = CrateDep {
-                    name: self.tcx.original_crate_name(cnum),
+                    name: self.tcx.crate_name(cnum),
                     hash: self.tcx.crate_hash(cnum),
                     host_hash: self.tcx.crate_host_hash(cnum),
                     kind: self.tcx.dep_kind(cnum),
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 04fe5cf5890..9a3a6284c36 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -18,7 +18,6 @@ use rustc_middle::mir;
 use rustc_middle::ty::{self, ReprOptions, Ty};
 use rustc_serialize::opaque::Encoder;
 use rustc_session::config::SymbolManglingVersion;
-use rustc_session::CrateDisambiguator;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{Ident, Symbol};
@@ -202,7 +201,6 @@ crate struct CrateRoot<'tcx> {
     triple: TargetTriple,
     extra_filename: String,
     hash: Svh,
-    disambiguator: CrateDisambiguator,
     stable_crate_id: StableCrateId,
     panic_strategy: PanicStrategy,
     edition: Edition,
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index d5697513eef..a89d00e26ac 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -14,6 +14,7 @@ macro_rules! arena_types {
             [] layouts: rustc_target::abi::Layout,
             // AdtDef are interned and compared by address
             [] adt_def: rustc_middle::ty::AdtDef,
+            [] steal_thir: rustc_data_structures::steal::Steal<rustc_middle::thir::Thir<$tcx>>,
             [] steal_mir: rustc_data_structures::steal::Steal<rustc_middle::mir::Body<$tcx>>,
             [decode] mir: rustc_middle::mir::Body<$tcx>,
             [] steal_promoted:
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index 31bea832958..aa61219ad78 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -18,7 +18,6 @@ crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
 pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
 pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
 pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
-pub type PreviousDepGraph = rustc_query_system::dep_graph::PreviousDepGraph<DepKind>;
 pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
 pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
 
diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs
index 342cc9a7397..8ffd98326f1 100644
--- a/compiler/rustc_middle/src/hir/map/collector.rs
+++ b/compiler/rustc_middle/src/hir/map/collector.rs
@@ -1,6 +1,6 @@
 use crate::arena::Arena;
-use crate::hir::map::{HirOwnerData, Map};
-use crate::hir::{IndexedHir, Owner, OwnerNodes, ParentedNode};
+use crate::hir::map::Map;
+use crate::hir::{IndexedHir, OwnerNodes, ParentedNode};
 use crate::ich::StableHashingContext;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
@@ -28,7 +28,7 @@ pub(super) struct NodeCollector<'a, 'hir> {
     /// Source map
     source_map: &'a SourceMap,
 
-    map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+    map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
     parenting: FxHashMap<LocalDefId, HirId>,
 
     /// The parent of this node
@@ -107,9 +107,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
             current_dep_node_owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
             definitions,
             hcx,
-            map: (0..definitions.def_index_count())
-                .map(|_| HirOwnerData { signature: None, with_bodies: None })
-                .collect(),
+            map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()),
             parenting: FxHashMap::default(),
         };
         collector.insert_entry(
@@ -124,7 +122,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
     pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> {
         // Insert bodies into the map
         for (id, body) in self.krate.bodies.iter() {
-            let bodies = &mut self.map[id.hir_id.owner].with_bodies.as_mut().unwrap().bodies;
+            let bodies = &mut self.map[id.hir_id.owner].as_mut().unwrap().bodies;
             assert!(bodies.insert(id.hir_id.local_id, body).is_none());
         }
         IndexedHir { map: self.map, parenting: self.parenting }
@@ -137,22 +135,13 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
 
         let data = &mut self.map[id.owner];
 
-        if data.with_bodies.is_none() {
-            data.with_bodies = Some(arena.alloc(OwnerNodes {
+        if i == 0 {
+            debug_assert!(data.is_none());
+            *data = Some(arena.alloc(OwnerNodes {
                 hash,
                 nodes: IndexVec::new(),
                 bodies: FxHashMap::default(),
             }));
-        }
-
-        let nodes = data.with_bodies.as_mut().unwrap();
-
-        if i == 0 {
-            // Overwrite the dummy hash with the real HIR owner hash.
-            nodes.hash = hash;
-
-            debug_assert!(data.signature.is_none());
-            data.signature = Some(self.arena.alloc(Owner { node: entry.node }));
 
             let dk_parent = self.definitions.def_key(id.owner).parent;
             if let Some(dk_parent) = dk_parent {
@@ -168,13 +157,16 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
                 debug_assert_eq!(self.parenting.get(&id.owner), Some(&entry.parent));
             }
         } else {
-            assert_eq!(entry.parent.owner, id.owner);
-            insert_vec_map(
-                &mut nodes.nodes,
-                id.local_id,
-                ParentedNode { parent: entry.parent.local_id, node: entry.node },
-            );
+            debug_assert_eq!(entry.parent.owner, id.owner);
         }
+
+        let data = data.as_mut().unwrap();
+
+        insert_vec_map(
+            &mut data.nodes,
+            id.local_id,
+            ParentedNode { parent: entry.parent.local_id, node: entry.node },
+        );
     }
 
     fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) {
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index d154b7804f0..07b39c97c49 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,6 +1,6 @@
 use self::collector::NodeCollector;
 
-use crate::hir::{AttributeMap, HirOwnerData, IndexedHir};
+use crate::hir::{AttributeMap, IndexedHir};
 use crate::middle::cstore::CrateStore;
 use crate::ty::TyCtxt;
 use rustc_ast as ast;
@@ -15,6 +15,7 @@ use rustc_hir::intravisit::Visitor;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::*;
 use rustc_index::vec::Idx;
+use rustc_span::def_id::StableCrateId;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, Ident, Symbol};
@@ -952,7 +953,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
         .filter_map(|(def_id, hod)| {
             let def_path_hash = tcx.definitions.def_path_hash(def_id);
             let mut hasher = StableHasher::new();
-            hod.with_bodies.as_ref()?.hash_stable(&mut hcx, &mut hasher);
+            hod.as_ref()?.hash_stable(&mut hcx, &mut hasher);
             AttributeMap { map: &tcx.untracked_crate.attrs, prefix: def_id }
                 .hash_stable(&mut hcx, &mut hasher);
             Some((def_path_hash, hasher.finish()))
@@ -990,25 +991,24 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh {
     upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
     source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
     tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
-    tcx.sess.local_crate_disambiguator().to_fingerprint().hash_stable(&mut hcx, &mut stable_hasher);
+    tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher);
     tcx.untracked_crate.non_exported_macro_attrs.hash_stable(&mut hcx, &mut stable_hasher);
 
     let crate_hash: Fingerprint = stable_hasher.finish();
     Svh::new(crate_hash.to_smaller_hash())
 }
 
-fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> {
+fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(StableCrateId, Svh)> {
     let mut upstream_crates: Vec<_> = cstore
         .crates_untracked()
         .iter()
         .map(|&cnum| {
-            let name = cstore.crate_name_untracked(cnum);
-            let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint();
+            let stable_crate_id = cstore.stable_crate_id_untracked(cnum);
             let hash = cstore.crate_hash_untracked(cnum);
-            (name, disambiguator, hash)
+            (stable_crate_id, hash)
         })
         .collect();
-    upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis));
+    upstream_crates.sort_unstable_by_key(|&(stable_crate_id, _)| stable_crate_id);
     upstream_crates
 }
 
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 879372c65ea..b8407833c90 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -15,23 +15,25 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::*;
-use rustc_index::vec::IndexVec;
+use rustc_index::vec::{Idx, IndexVec};
 use rustc_span::DUMMY_SP;
 use std::collections::BTreeMap;
 
-#[derive(Debug)]
-struct HirOwnerData<'hir> {
-    signature: Option<&'hir Owner<'hir>>,
-    with_bodies: Option<&'hir mut OwnerNodes<'hir>>,
-}
-
+/// Result of HIR indexing.
 #[derive(Debug)]
 pub struct IndexedHir<'hir> {
-    map: IndexVec<LocalDefId, HirOwnerData<'hir>>,
+    /// Contents of the HIR owned by each definition. None for definitions that are not HIR owners.
+    // The `mut` comes from construction time, and is harmless since we only ever hand out
+    // immutable refs to IndexedHir.
+    map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>,
+    /// Map from each owner to its parent's HirId inside another owner.
+    // This map is separate from `map` to eventually allow for per-owner indexing.
     parenting: FxHashMap<LocalDefId, HirId>,
 }
 
-#[derive(Debug)]
+/// Top-level HIR node for current owner. This only contains the node for which
+/// `HirId::local_id == 0`, and excludes bodies.
+#[derive(Copy, Clone, Debug)]
 pub struct Owner<'tcx> {
     node: Node<'tcx>,
 }
@@ -43,6 +45,9 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> {
     }
 }
 
+/// HIR node coupled with its parent's id in the same HIR owner.
+///
+/// The parent is trash when the node is a HIR owner.
 #[derive(Clone, Debug)]
 pub struct ParentedNode<'tcx> {
     parent: ItemLocalId,
@@ -51,8 +56,12 @@ pub struct ParentedNode<'tcx> {
 
 #[derive(Debug)]
 pub struct OwnerNodes<'tcx> {
+    /// Pre-computed hash of the full HIR.
     hash: Fingerprint,
+    /// Full HIR for the current owner.
+    // The zeroth node's parent is trash, but is never accessed.
     nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
+    /// Content of local bodies.
     bodies: FxHashMap<ItemLocalId, &'tcx Body<'tcx>>,
 }
 
@@ -65,6 +74,8 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OwnerNodes<'tcx> {
     }
 }
 
+/// Attributes owner by a HIR owner. It is build as a slice inside the attributes map, restricted
+/// to the nodes whose `HirId::owner` is `prefix`.
 #[derive(Copy, Clone)]
 pub struct AttributeMap<'tcx> {
     map: &'tcx BTreeMap<HirId, &'tcx [Attribute]>,
@@ -127,8 +138,12 @@ pub fn provide(providers: &mut Providers) {
     providers.index_hir = map::index_hir;
     providers.crate_hash = map::crate_hash;
     providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id];
-    providers.hir_owner = |tcx, id| tcx.index_hir(()).map[id].signature;
-    providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].with_bodies.as_deref();
+    providers.hir_owner = |tcx, id| {
+        let owner = tcx.index_hir(()).map[id].as_ref()?;
+        let node = owner.nodes[ItemLocalId::new(0)].as_ref()?.node;
+        Some(Owner { node })
+    };
+    providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref();
     providers.hir_owner_parent = |tcx, id| {
         let index = tcx.index_hir(());
         index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID)
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 5df2f91f09f..d764d45ba7e 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -294,6 +294,7 @@ TrivialTypeFoldableImpls! {
 }
 
 impl<'tcx> CanonicalVarValues<'tcx> {
+    #[inline]
     pub fn len(&self) -> usize {
         self.var_values.len()
     }
diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs
index 641cf23781e..0b05dd5c0ba 100644
--- a/compiler/rustc_middle/src/infer/unify_key.rs
+++ b/compiler/rustc_middle/src/infer/unify_key.rs
@@ -16,37 +16,48 @@ pub trait ToType {
 }
 
 #[derive(PartialEq, Copy, Clone, Debug)]
-pub struct RegionVidKey {
-    /// The minimum region vid in the unification set. This is needed
-    /// to have a canonical name for a type to prevent infinite
-    /// recursion.
-    pub min_vid: ty::RegionVid,
-}
-
-impl UnifyValue for RegionVidKey {
-    type Error = NoError;
+pub struct UnifiedRegion<'tcx>(pub Option<ty::Region<'tcx>>);
 
-    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
-        let min_vid = if value1.min_vid.index() < value2.min_vid.index() {
-            value1.min_vid
-        } else {
-            value2.min_vid
-        };
+#[derive(PartialEq, Copy, Clone, Debug)]
+pub struct RegionVidKey<'tcx> {
+    pub vid: ty::RegionVid,
+    pub phantom: PhantomData<UnifiedRegion<'tcx>>,
+}
 
-        Ok(RegionVidKey { min_vid })
+impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> {
+    fn from(vid: ty::RegionVid) -> Self {
+        RegionVidKey { vid, phantom: PhantomData }
     }
 }
 
-impl UnifyKey for ty::RegionVid {
-    type Value = RegionVidKey;
+impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
+    type Value = UnifiedRegion<'tcx>;
     fn index(&self) -> u32 {
-        u32::from(*self)
+        self.vid.as_u32()
     }
-    fn from_index(i: u32) -> ty::RegionVid {
-        ty::RegionVid::from(i)
+    fn from_index(i: u32) -> Self {
+        RegionVidKey::from(ty::RegionVid::from_u32(i))
     }
     fn tag() -> &'static str {
-        "RegionVid"
+        "RegionVidKey"
+    }
+}
+
+impl<'tcx> UnifyValue for UnifiedRegion<'tcx> {
+    type Error = NoError;
+
+    fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
+        Ok(match (value1.0, value2.0) {
+            // Here we can just pick one value, because the full constraints graph
+            // will be handled later. Ideally, we might want a `MultipleValues`
+            // variant or something. For now though, this is fine.
+            (Some(_), Some(_)) => *value1,
+
+            (Some(_), _) => *value1,
+            (_, Some(_)) => *value2,
+
+            (None, None) => *value1,
+        })
     }
 }
 
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 597a4fd0f52..e1d7bc4be53 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -29,14 +29,12 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_panic)]
 #![feature(core_intrinsics)]
 #![feature(discriminant_kind)]
 #![feature(never_type)]
 #![feature(extern_types)]
 #![feature(nll)]
 #![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(min_specialization)]
 #![feature(trusted_len)]
 #![feature(test)]
@@ -83,6 +81,7 @@ pub mod infer;
 pub mod lint;
 pub mod middle;
 pub mod mir;
+pub mod thir;
 pub mod traits;
 pub mod ty;
 
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 38d0793a682..4c7ea937ceb 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -1,7 +1,7 @@
 use std::cmp;
 
 use crate::ich::StableHashingContext;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::{DiagnosticBuilder, DiagnosticId};
 use rustc_hir::HirId;
@@ -28,6 +28,9 @@ pub enum LintLevelSource {
     /// The provided `Level` is the level specified on the command line.
     /// (The actual level may be lower due to `--cap-lints`.)
     CommandLine(Symbol, Level),
+
+    /// Lint is being forced to warn no matter what.
+    ForceWarn(Symbol),
 }
 
 impl LintLevelSource {
@@ -36,6 +39,7 @@ impl LintLevelSource {
             LintLevelSource::Default => symbol::kw::Default,
             LintLevelSource::Node(name, _, _) => name,
             LintLevelSource::CommandLine(name, _) => name,
+            LintLevelSource::ForceWarn(name) => name,
         }
     }
 
@@ -44,6 +48,7 @@ impl LintLevelSource {
             LintLevelSource::Default => DUMMY_SP,
             LintLevelSource::Node(_, span, _) => span,
             LintLevelSource::CommandLine(_, _) => DUMMY_SP,
+            LintLevelSource::ForceWarn(_) => DUMMY_SP,
         }
     }
 }
@@ -55,6 +60,7 @@ pub type LevelAndSource = (Level, LintLevelSource);
 pub struct LintLevelSets {
     pub list: Vec<LintSet>,
     pub lint_cap: Level,
+    pub force_warns: FxHashSet<LintId>,
 }
 
 #[derive(Debug)]
@@ -73,7 +79,11 @@ pub enum LintSet {
 
 impl LintLevelSets {
     pub fn new() -> Self {
-        LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
+        LintLevelSets {
+            list: Vec::new(),
+            lint_cap: Level::Forbid,
+            force_warns: FxHashSet::default(),
+        }
     }
 
     pub fn get_lint_level(
@@ -83,6 +93,11 @@ impl LintLevelSets {
         aux: Option<&FxHashMap<LintId, LevelAndSource>>,
         sess: &Session,
     ) -> LevelAndSource {
+        // Check whether we should always warn
+        if self.force_warns.contains(&LintId::of(lint)) {
+            return (Level::Warn, LintLevelSource::ForceWarn(Symbol::intern(lint.name)));
+        }
+
         let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
 
         // If `level` is none then we actually assume the default level for this
@@ -176,11 +191,11 @@ impl LintLevelMap {
 impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
     #[inline]
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let LintLevelMap { ref sets, ref id_to_set } = *self;
+        let LintLevelMap { ref sets, ref id_to_set, .. } = *self;
 
         id_to_set.hash_stable(hcx, hasher);
 
-        let LintLevelSets { ref list, lint_cap } = *sets;
+        let LintLevelSets { ref list, lint_cap, .. } = *sets;
 
         lint_cap.hash_stable(hcx, hasher);
 
@@ -346,6 +361,13 @@ pub fn struct_lint_level<'s, 'd>(
                     );
                 }
             }
+            LintLevelSource::ForceWarn(_) => {
+                sess.diag_note_once(
+                    &mut err,
+                    DiagnosticMessageId::from(lint),
+                    "warning forced by `force-warns` commandline option",
+                );
+            }
         }
 
         err.code(DiagnosticId::Lint { name, has_future_breakage });
diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs
index d63116e29c8..dd3b0a40d69 100644
--- a/compiler/rustc_middle/src/middle/cstore.rs
+++ b/compiler/rustc_middle/src/middle/cstore.rs
@@ -14,7 +14,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_macros::HashStable;
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::NativeLibKind;
-use rustc_session::CrateDisambiguator;
+use rustc_session::StableCrateId;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 use rustc_target::spec::Target;
@@ -199,8 +199,7 @@ pub trait CrateStore {
 
     // "queries" used in resolve that aren't tracked for incremental compilation
     fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol;
-    fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool;
-    fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
+    fn stable_crate_id_untracked(&self, cnum: CrateNum) -> StableCrateId;
     fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
 
     // This is basically a 1-based range of ints, which is a little
diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs
index 276e45ce99b..5ea78e087f8 100644
--- a/compiler/rustc_middle/src/middle/exported_symbols.rs
+++ b/compiler/rustc_middle/src/middle/exported_symbols.rs
@@ -48,8 +48,8 @@ impl<'tcx> ExportedSymbol<'tcx> {
 
 pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String {
     format!(
-        "rust_metadata_{}_{}",
-        tcx.original_crate_name(LOCAL_CRATE),
-        tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex()
+        "rust_metadata_{}_{:08x}",
+        tcx.crate_name(LOCAL_CRATE),
+        tcx.sess.local_stable_crate_id().to_u64(),
     )
 }
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 929818bd1ee..ee3902991e9 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -4,16 +4,22 @@ use std::borrow::Cow;
 use std::convert::TryFrom;
 use std::iter;
 use std::ops::{Deref, DerefMut, Range};
+use std::ptr;
 
 use rustc_ast::Mutability;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_target::abi::{Align, HasDataLayout, Size};
 
 use super::{
-    read_target_uint, write_target_uint, AllocId, InterpResult, Pointer, Scalar, ScalarMaybeUninit,
-    UninitBytesAccess,
+    read_target_uint, write_target_uint, AllocId, InterpError, Pointer, Scalar, ScalarMaybeUninit,
+    UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
 };
 
+/// This type represents an Allocation in the Miri/CTFE core engine.
+///
+/// Its public API is rather low-level, working directly with allocation offsets and a custom error
+/// type to account for the lack of an AllocId on this level. The Miri/CTFE core engine `memory`
+/// module provides higher-level access.
 #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub struct Allocation<Tag = (), Extra = ()> {
@@ -38,54 +44,67 @@ pub struct Allocation<Tag = (), Extra = ()> {
     pub extra: Extra,
 }
 
-pub trait AllocationExtra<Tag>: std::fmt::Debug + Clone {
-    // There is no constructor in here because the constructor's type depends
-    // on `MemoryKind`, and making things sufficiently generic leads to painful
-    // inference failure.
+/// We have our own error type that does not know about the `AllocId`; that information
+/// is added when converting to `InterpError`.
+#[derive(Debug)]
+pub enum AllocError {
+    /// Encountered a pointer where we needed raw bytes.
+    ReadPointerAsBytes,
+    /// Using uninitialized data where it is not allowed.
+    InvalidUninitBytes(Option<UninitBytesAccess>),
+}
+pub type AllocResult<T = ()> = Result<T, AllocError>;
 
-    /// Hook for performing extra checks on a memory read access.
-    ///
-    /// Takes read-only access to the allocation so we can keep all the memory read
-    /// operations take `&self`. Use a `RefCell` in `AllocExtra` if you
-    /// need to mutate.
-    #[inline(always)]
-    fn memory_read(
-        _alloc: &Allocation<Tag, Self>,
-        _ptr: Pointer<Tag>,
-        _size: Size,
-    ) -> InterpResult<'tcx> {
-        Ok(())
+impl AllocError {
+    pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpError<'tcx> {
+        match self {
+            AllocError::ReadPointerAsBytes => {
+                InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes)
+            }
+            AllocError::InvalidUninitBytes(info) => InterpError::UndefinedBehavior(
+                UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))),
+            ),
+        }
     }
+}
+
+/// The information that makes up a memory access: offset and size.
+#[derive(Copy, Clone, Debug)]
+pub struct AllocRange {
+    pub start: Size,
+    pub size: Size,
+}
+
+/// Free-starting constructor for less syntactic overhead.
+#[inline(always)]
+pub fn alloc_range(start: Size, size: Size) -> AllocRange {
+    AllocRange { start, size }
+}
 
-    /// Hook for performing extra checks on a memory write access.
+impl AllocRange {
     #[inline(always)]
-    fn memory_written(
-        _alloc: &mut Allocation<Tag, Self>,
-        _ptr: Pointer<Tag>,
-        _size: Size,
-    ) -> InterpResult<'tcx> {
-        Ok(())
+    pub fn end(self) -> Size {
+        self.start + self.size // This does overflow checking.
     }
 
-    /// Hook for performing extra checks on a memory deallocation.
-    /// `size` will be the size of the allocation.
-    #[inline(always)]
-    fn memory_deallocated(
-        _alloc: &mut Allocation<Tag, Self>,
-        _ptr: Pointer<Tag>,
-        _size: Size,
-    ) -> InterpResult<'tcx> {
-        Ok(())
+    /// Returns the `subrange` within this range; panics if it is not a subrange.
+    #[inline]
+    pub fn subrange(self, subrange: AllocRange) -> AllocRange {
+        let sub_start = self.start + subrange.start;
+        let range = alloc_range(sub_start, subrange.size);
+        assert!(range.end() <= self.end(), "access outside the bounds for given AllocRange");
+        range
     }
 }
 
-// For `Tag = ()` and no extra state, we have a trivial implementation.
-impl AllocationExtra<()> for () {}
-
 // The constructors are all without extra; the extra gets added by a machine hook later.
 impl<Tag> Allocation<Tag> {
-    /// Creates a read-only allocation initialized by the given bytes
-    pub fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self {
+    /// Creates an allocation initialized by the given bytes
+    pub fn from_bytes<'a>(
+        slice: impl Into<Cow<'a, [u8]>>,
+        align: Align,
+        mutability: Mutability,
+    ) -> Self {
         let bytes = slice.into().into_owned();
         let size = Size::from_bytes(bytes.len());
         Self {
@@ -93,13 +112,13 @@ impl<Tag> Allocation<Tag> {
             relocations: Relocations::new(),
             init_mask: InitMask::new(size, true),
             align,
-            mutability: Mutability::Not,
+            mutability,
             extra: (),
         }
     }
 
-    pub fn from_byte_aligned_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>) -> Self {
-        Allocation::from_bytes(slice, Align::from_bytes(1).unwrap())
+    pub fn from_bytes_byte_aligned_immutable<'a>(slice: impl Into<Cow<'a, [u8]>>) -> Self {
+        Allocation::from_bytes(slice, Align::ONE, Mutability::Not)
     }
 
     pub fn uninit(size: Size, align: Align) -> Self {
@@ -114,7 +133,7 @@ impl<Tag> Allocation<Tag> {
     }
 }
 
-impl Allocation<(), ()> {
+impl Allocation<()> {
     /// Add Tag and Extra fields
     pub fn with_tags_and_extra<T, E>(
         self,
@@ -154,7 +173,7 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
 
     /// Looks at a slice which may describe uninitialized bytes or describe a relocation. This differs
     /// from `get_bytes_with_uninit_and_ptr` in that it does no relocation checks (even on the
-    /// edges) at all. It further ignores `AllocationExtra` callbacks.
+    /// edges) at all.
     /// This must not be used for reads affecting the interpreter execution.
     pub fn inspect_with_uninit_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] {
         &self.bytes[range]
@@ -172,23 +191,7 @@ impl<Tag, Extra> Allocation<Tag, Extra> {
 }
 
 /// Byte accessors.
-impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
-    /// Just a small local helper function to avoid a bit of code repetition.
-    /// Returns the range of this allocation that was meant.
-    #[inline]
-    fn check_bounds(&self, offset: Size, size: Size) -> Range<usize> {
-        let end = offset + size; // This does overflow checking.
-        let end = usize::try_from(end.bytes()).expect("access too big for this host architecture");
-        assert!(
-            end <= self.len(),
-            "Out-of-bounds access at offset {}, size {} in allocation of size {}",
-            offset.bytes(),
-            size.bytes(),
-            self.len()
-        );
-        offset.bytes_usize()..end
-    }
-
+impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// The last argument controls whether we error out when there are uninitialized
     /// or pointer bytes. You should never call this, call `get_bytes` or
     /// `get_bytes_with_uninit_and_ptr` instead,
@@ -201,23 +204,18 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     fn get_bytes_internal(
         &self,
         cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        size: Size,
+        range: AllocRange,
         check_init_and_ptr: bool,
-    ) -> InterpResult<'tcx, &[u8]> {
-        let range = self.check_bounds(ptr.offset, size);
-
+    ) -> AllocResult<&[u8]> {
         if check_init_and_ptr {
-            self.check_init(ptr, size)?;
-            self.check_relocations(cx, ptr, size)?;
+            self.check_init(range)?;
+            self.check_relocations(cx, range)?;
         } else {
             // We still don't want relocations on the *edges*.
-            self.check_relocation_edges(cx, ptr, size)?;
+            self.check_relocation_edges(cx, range)?;
         }
 
-        AllocationExtra::memory_read(self, ptr, size)?;
-
-        Ok(&self.bytes[range])
+        Ok(&self.bytes[range.start.bytes_usize()..range.end().bytes_usize()])
     }
 
     /// Checks that these bytes are initialized and not pointer bytes, and then return them
@@ -227,13 +225,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
     /// on `InterpCx` instead.
     #[inline]
-    pub fn get_bytes(
-        &self,
-        cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        size: Size,
-    ) -> InterpResult<'tcx, &[u8]> {
-        self.get_bytes_internal(cx, ptr, size, true)
+    pub fn get_bytes(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult<&[u8]> {
+        self.get_bytes_internal(cx, range, true)
     }
 
     /// It is the caller's responsibility to handle uninitialized and pointer bytes.
@@ -244,10 +237,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     pub fn get_bytes_with_uninit_and_ptr(
         &self,
         cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        size: Size,
-    ) -> InterpResult<'tcx, &[u8]> {
-        self.get_bytes_internal(cx, ptr, size, false)
+        range: AllocRange,
+    ) -> AllocResult<&[u8]> {
+        self.get_bytes_internal(cx, range, false)
     }
 
     /// Just calling this already marks everything as defined and removes relocations,
@@ -256,69 +248,46 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     /// It is the caller's responsibility to check bounds and alignment beforehand.
     /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods
     /// on `InterpCx` instead.
-    pub fn get_bytes_mut(
-        &mut self,
-        cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        size: Size,
-    ) -> InterpResult<'tcx, &mut [u8]> {
-        let range = self.check_bounds(ptr.offset, size);
+    pub fn get_bytes_mut(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> &mut [u8] {
+        self.mark_init(range, true);
+        self.clear_relocations(cx, range);
 
-        self.mark_init(ptr, size, true);
-        self.clear_relocations(cx, ptr, size);
+        &mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]
+    }
 
-        AllocationExtra::memory_written(self, ptr, size)?;
+    /// A raw pointer variant of `get_bytes_mut` that avoids invalidating existing aliases into this memory.
+    pub fn get_bytes_mut_ptr(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> *mut [u8] {
+        self.mark_init(range, true);
+        self.clear_relocations(cx, range);
 
-        Ok(&mut self.bytes[range])
+        assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check
+        let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize());
+        let len = range.end().bytes_usize() - range.start.bytes_usize();
+        ptr::slice_from_raw_parts_mut(begin_ptr, len)
     }
 }
 
 /// Reading and writing.
-impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
+impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
     /// relocation. If `allow_uninit_and_ptr` is `false`, also enforces that the memory in the
     /// given range contains neither relocations nor uninitialized bytes.
     pub fn check_bytes(
         &self,
         cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        size: Size,
+        range: AllocRange,
         allow_uninit_and_ptr: bool,
-    ) -> InterpResult<'tcx> {
+    ) -> AllocResult {
         // Check bounds and relocations on the edges.
-        self.get_bytes_with_uninit_and_ptr(cx, ptr, size)?;
+        self.get_bytes_with_uninit_and_ptr(cx, range)?;
         // Check uninit and ptr.
         if !allow_uninit_and_ptr {
-            self.check_init(ptr, size)?;
-            self.check_relocations(cx, ptr, size)?;
+            self.check_init(range)?;
+            self.check_relocations(cx, range)?;
         }
         Ok(())
     }
 
-    /// Writes `src` to the memory starting at `ptr.offset`.
-    ///
-    /// It is the caller's responsibility to check bounds and alignment beforehand.
-    /// Most likely, you want to call `Memory::write_bytes` instead of this method.
-    pub fn write_bytes(
-        &mut self,
-        cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        src: impl IntoIterator<Item = u8>,
-    ) -> InterpResult<'tcx> {
-        let mut src = src.into_iter();
-        let (lower, upper) = src.size_hint();
-        let len = upper.expect("can only write bounded iterators");
-        assert_eq!(lower, len, "can only write iterators with a precise length");
-        let bytes = self.get_bytes_mut(cx, ptr, Size::from_bytes(len))?;
-        // `zip` would stop when the first iterator ends; we want to definitely
-        // cover all of `bytes`.
-        for dest in bytes {
-            *dest = src.next().expect("iterator was shorter than it said it would be");
-        }
-        assert_matches!(src.next(), None, "iterator was longer than it said it would be");
-        Ok(())
-    }
-
     /// Reads a *non-ZST* scalar.
     ///
     /// ZSTs can't be read because in order to obtain a `Pointer`, we need to check
@@ -329,14 +298,13 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     pub fn read_scalar(
         &self,
         cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        size: Size,
-    ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+        range: AllocRange,
+    ) -> AllocResult<ScalarMaybeUninit<Tag>> {
         // `get_bytes_unchecked` tests relocation edges.
-        let bytes = self.get_bytes_with_uninit_and_ptr(cx, ptr, size)?;
+        let bytes = self.get_bytes_with_uninit_and_ptr(cx, range)?;
         // Uninit check happens *after* we established that the alignment is correct.
         // We must not return `Ok()` for unaligned pointers!
-        if self.is_init(ptr, size).is_err() {
+        if self.is_init(range).is_err() {
             // This inflates uninitialized bytes to the entire scalar, even if only a few
             // bytes are uninitialized.
             return Ok(ScalarMaybeUninit::Uninit);
@@ -344,29 +312,19 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
         // Now we do the actual reading.
         let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap();
         // See if we got a pointer.
-        if size != cx.data_layout().pointer_size {
+        if range.size != cx.data_layout().pointer_size {
+            // Not a pointer.
             // *Now*, we better make sure that the inside is free of relocations too.
-            self.check_relocations(cx, ptr, size)?;
+            self.check_relocations(cx, range)?;
         } else {
-            if let Some(&(tag, alloc_id)) = self.relocations.get(&ptr.offset) {
+            // Maybe a pointer.
+            if let Some(&(tag, alloc_id)) = self.relocations.get(&range.start) {
                 let ptr = Pointer::new_with_tag(alloc_id, Size::from_bytes(bits), tag);
                 return Ok(ScalarMaybeUninit::Scalar(ptr.into()));
             }
         }
         // We don't. Just return the bits.
-        Ok(ScalarMaybeUninit::Scalar(Scalar::from_uint(bits, size)))
-    }
-
-    /// Reads a pointer-sized scalar.
-    ///
-    /// It is the caller's responsibility to check bounds and alignment beforehand.
-    /// Most likely, you want to call `InterpCx::read_scalar` instead of this method.
-    pub fn read_ptr_sized(
-        &self,
-        cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-    ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
-        self.read_scalar(cx, ptr, cx.data_layout().pointer_size)
+        Ok(ScalarMaybeUninit::Scalar(Scalar::from_uint(bits, range.size)))
     }
 
     /// Writes a *non-ZST* scalar.
@@ -379,78 +337,56 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
     pub fn write_scalar(
         &mut self,
         cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
+        range: AllocRange,
         val: ScalarMaybeUninit<Tag>,
-        type_size: Size,
-    ) -> InterpResult<'tcx> {
+    ) -> AllocResult {
         let val = match val {
             ScalarMaybeUninit::Scalar(scalar) => scalar,
             ScalarMaybeUninit::Uninit => {
-                self.mark_init(ptr, type_size, false);
+                self.mark_init(range, false);
                 return Ok(());
             }
         };
 
-        let bytes = match val.to_bits_or_ptr(type_size, cx) {
+        let bytes = match val.to_bits_or_ptr(range.size, cx) {
             Err(val) => u128::from(val.offset.bytes()),
             Ok(data) => data,
         };
 
         let endian = cx.data_layout().endian;
-        let dst = self.get_bytes_mut(cx, ptr, type_size)?;
+        let dst = self.get_bytes_mut(cx, range);
         write_target_uint(endian, dst, bytes).unwrap();
 
         // See if we have to also write a relocation.
         if let Scalar::Ptr(val) = val {
-            self.relocations.insert(ptr.offset, (val.tag, val.alloc_id));
+            self.relocations.insert(range.start, (val.tag, val.alloc_id));
         }
 
         Ok(())
     }
-
-    /// Writes a pointer-sized scalar.
-    ///
-    /// It is the caller's responsibility to check bounds and alignment beforehand.
-    /// Most likely, you want to call `InterpCx::write_scalar` instead of this method.
-    pub fn write_ptr_sized(
-        &mut self,
-        cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        val: ScalarMaybeUninit<Tag>,
-    ) -> InterpResult<'tcx> {
-        let ptr_size = cx.data_layout().pointer_size;
-        self.write_scalar(cx, ptr, val, ptr_size)
-    }
 }
 
 /// Relocations.
-impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
+impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// Returns all relocations overlapping with the given pointer-offset pair.
     pub fn get_relocations(
         &self,
         cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        size: Size,
+        range: AllocRange,
     ) -> &[(Size, (Tag, AllocId))] {
         // We have to go back `pointer_size - 1` bytes, as that one would still overlap with
         // the beginning of this range.
-        let start = ptr.offset.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1);
-        let end = ptr.offset + size; // This does overflow checking.
-        self.relocations.range(Size::from_bytes(start)..end)
+        let start = range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1);
+        self.relocations.range(Size::from_bytes(start)..range.end())
     }
 
     /// Checks that there are no relocations overlapping with the given range.
     #[inline(always)]
-    fn check_relocations(
-        &self,
-        cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        size: Size,
-    ) -> InterpResult<'tcx> {
-        if self.get_relocations(cx, ptr, size).is_empty() {
+    fn check_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
+        if self.get_relocations(cx, range).is_empty() {
             Ok(())
         } else {
-            throw_unsup!(ReadPointerAsBytes)
+            Err(AllocError::ReadPointerAsBytes)
         }
     }
 
@@ -460,11 +396,11 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// uninitialized. This is a somewhat odd "spooky action at a distance",
     /// but it allows strictly more code to run than if we would just error
     /// immediately in that case.
-    fn clear_relocations(&mut self, cx: &impl HasDataLayout, ptr: Pointer<Tag>, size: Size) {
+    fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) {
         // Find the start and end of the given range and its outermost relocations.
         let (first, last) = {
             // Find all relocations overlapping the given range.
-            let relocations = self.get_relocations(cx, ptr, size);
+            let relocations = self.get_relocations(cx, range);
             if relocations.is_empty() {
                 return;
             }
@@ -474,8 +410,8 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
                 relocations.last().unwrap().0 + cx.data_layout().pointer_size,
             )
         };
-        let start = ptr.offset;
-        let end = start + size; // `Size` addition
+        let start = range.start;
+        let end = range.end();
 
         // Mark parts of the outermost relocations as uninitialized if they partially fall outside the
         // given range.
@@ -493,46 +429,41 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// Errors if there are relocations overlapping with the edges of the
     /// given memory range.
     #[inline]
-    fn check_relocation_edges(
-        &self,
-        cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        size: Size,
-    ) -> InterpResult<'tcx> {
-        self.check_relocations(cx, ptr, Size::ZERO)?;
-        self.check_relocations(cx, ptr.offset(size, cx)?, Size::ZERO)?;
+    fn check_relocation_edges(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult {
+        self.check_relocations(cx, alloc_range(range.start, Size::ZERO))?;
+        self.check_relocations(cx, alloc_range(range.end(), Size::ZERO))?;
         Ok(())
     }
 }
 
 /// Uninitialized bytes.
-impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
+impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// Checks whether the given range  is entirely initialized.
     ///
     /// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte
     /// indexes of the first contiguous uninitialized access.
-    fn is_init(&self, ptr: Pointer<Tag>, size: Size) -> Result<(), Range<Size>> {
-        self.init_mask.is_range_initialized(ptr.offset, ptr.offset + size) // `Size` addition
+    fn is_init(&self, range: AllocRange) -> Result<(), Range<Size>> {
+        self.init_mask.is_range_initialized(range.start, range.end()) // `Size` addition
     }
 
     /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes`
     /// error which will report the first range of bytes which is uninitialized.
-    fn check_init(&self, ptr: Pointer<Tag>, size: Size) -> InterpResult<'tcx> {
-        self.is_init(ptr, size).or_else(|idx_range| {
-            throw_ub!(InvalidUninitBytes(Some(UninitBytesAccess {
-                access_ptr: ptr.erase_tag(),
-                access_size: size,
-                uninit_ptr: Pointer::new(ptr.alloc_id, idx_range.start),
+    fn check_init(&self, range: AllocRange) -> AllocResult {
+        self.is_init(range).or_else(|idx_range| {
+            Err(AllocError::InvalidUninitBytes(Some(UninitBytesAccess {
+                access_offset: range.start,
+                access_size: range.size,
+                uninit_offset: idx_range.start,
                 uninit_size: idx_range.end - idx_range.start, // `Size` subtraction
             })))
         })
     }
 
-    pub fn mark_init(&mut self, ptr: Pointer<Tag>, size: Size, is_init: bool) {
-        if size.bytes() == 0 {
+    pub fn mark_init(&mut self, range: AllocRange, is_init: bool) {
+        if range.size.bytes() == 0 {
             return;
         }
-        self.init_mask.set_range(ptr.offset, ptr.offset + size, is_init);
+        self.init_mask.set_range(range.start, range.end(), is_init);
     }
 }
 
@@ -667,25 +598,25 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
     pub fn prepare_relocation_copy(
         &self,
         cx: &impl HasDataLayout,
-        src: Pointer<Tag>,
-        size: Size,
-        dest: Pointer<Tag>,
-        length: u64,
+        src: AllocRange,
+        dest: Size,
+        count: u64,
     ) -> AllocationRelocations<Tag> {
-        let relocations = self.get_relocations(cx, src, size);
+        let relocations = self.get_relocations(cx, src);
         if relocations.is_empty() {
             return AllocationRelocations { relative_relocations: Vec::new() };
         }
 
-        let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize));
+        let size = src.size;
+        let mut new_relocations = Vec::with_capacity(relocations.len() * (count as usize));
 
-        for i in 0..length {
+        for i in 0..count {
             new_relocations.extend(relocations.iter().map(|&(offset, reloc)| {
                 // compute offset for current repetition
-                let dest_offset = dest.offset + size * i; // `Size` operations
+                let dest_offset = dest + size * i; // `Size` operations
                 (
                     // shift offsets from source allocation to destination allocation
-                    (offset + dest_offset) - src.offset, // `Size` operations
+                    (offset + dest_offset) - src.start, // `Size` operations
                     reloc,
                 )
             }));
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 9c3bed6ec0a..65d9c1dd90e 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -198,11 +198,11 @@ impl fmt::Display for CheckInAllocMsg {
 #[derive(Debug)]
 pub struct UninitBytesAccess {
     /// Location of the original memory access.
-    pub access_ptr: Pointer,
+    pub access_offset: Size,
     /// Size of the original memory access.
     pub access_size: Size,
     /// Location of the first uninitialized byte that was accessed.
-    pub uninit_ptr: Pointer,
+    pub uninit_offset: Size,
     /// Number of consecutive uninitialized bytes that were accessed.
     pub uninit_size: Size,
 }
@@ -264,7 +264,7 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     /// Using a string that is not valid UTF-8,
     InvalidStr(std::str::Utf8Error),
     /// Using uninitialized data where it is not allowed.
-    InvalidUninitBytes(Option<UninitBytesAccess>),
+    InvalidUninitBytes(Option<(AllocId, UninitBytesAccess)>),
     /// Working with a local that is not currently live.
     DeadLocal,
     /// Data size is not equal to target size.
@@ -335,18 +335,18 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
                 write!(f, "using {} as function pointer but it does not point to a function", p)
             }
             InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err),
-            InvalidUninitBytes(Some(access)) => write!(
+            InvalidUninitBytes(Some((alloc, access))) => write!(
                 f,
                 "reading {} byte{} of memory starting at {}, \
                  but {} byte{} {} uninitialized starting at {}, \
                  and this operation requires initialized memory",
                 access.access_size.bytes(),
                 pluralize!(access.access_size.bytes()),
-                access.access_ptr,
+                Pointer::new(*alloc, access.access_offset),
                 access.uninit_size.bytes(),
                 pluralize!(access.uninit_size.bytes()),
                 if access.uninit_size.bytes() != 1 { "are" } else { "is" },
-                access.uninit_ptr,
+                Pointer::new(*alloc, access.uninit_offset),
             ),
             InvalidUninitBytes(None) => write!(
                 f,
@@ -435,8 +435,12 @@ impl<T: Any> AsAny for T {
 }
 
 /// A trait for machine-specific errors (or other "machine stop" conditions).
-pub trait MachineStopType: AsAny + fmt::Display + Send {}
-impl MachineStopType for String {}
+pub trait MachineStopType: AsAny + fmt::Display + Send {
+    /// If `true`, emit a hard error instead of going through the `CONST_ERR` lint
+    fn is_hard_err(&self) -> bool {
+        false
+    }
+}
 
 impl dyn MachineStopType {
     #[inline(always)]
@@ -446,7 +450,7 @@ impl dyn MachineStopType {
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(InterpError<'_>, 72);
+static_assert_size!(InterpError<'_>, 64);
 
 pub enum InterpError<'tcx> {
     /// The program caused undefined behavior.
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 55fe5f971e7..14bdb0a5a2d 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -125,7 +125,7 @@ pub use self::error::{
 
 pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit};
 
-pub use self::allocation::{Allocation, AllocationExtra, InitMask, Relocations};
+pub use self::allocation::{alloc_range, AllocRange, Allocation, InitMask, Relocations};
 
 pub use self::pointer::{Pointer, PointerArithmetic};
 
@@ -246,6 +246,7 @@ pub struct AllocDecodingState {
 }
 
 impl AllocDecodingState {
+    #[inline]
     pub fn new_decoding_session(&self) -> AllocDecodingSession<'_> {
         static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0);
         let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst);
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 888777a9418..66ff6990e8c 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -10,7 +10,7 @@ use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
 
 use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt};
 
-use super::{AllocId, Allocation, InterpResult, Pointer, PointerArithmetic};
+use super::{AllocId, AllocRange, Allocation, InterpResult, Pointer, PointerArithmetic};
 
 /// Represents the result of const evaluation via the `eval_to_allocation` query.
 #[derive(Copy, Clone, HashStable, TyEncodable, TyDecodable, Debug, Hash, Eq, PartialEq)]
@@ -661,9 +661,7 @@ pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) ->
         let len = end - start;
         data.get_bytes(
             cx,
-            // invent a pointer, only the offset is relevant anyway
-            Pointer::new(AllocId(0), Size::from_bytes(start)),
-            Size::from_bytes(len),
+            AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) },
         )
         .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err))
     } else {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 1cc7f235d7d..7ae7eab6e5a 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1249,10 +1249,12 @@ impl<'tcx> BasicBlockData<'tcx> {
     ///
     /// Terminator may not be None after construction of the basic block is complete. This accessor
     /// provides a convenience way to reach the terminator.
+    #[inline]
     pub fn terminator(&self) -> &Terminator<'tcx> {
         self.terminator.as_ref().expect("invalid terminator state")
     }
 
+    #[inline]
     pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> {
         self.terminator.as_mut().expect("invalid terminator state")
     }
@@ -1870,6 +1872,7 @@ impl<'tcx> PlaceRef<'tcx> {
 
     /// If this place represents a local variable like `_X` with no
     /// projections, return `Some(_X)`.
+    #[inline]
     pub fn as_local(&self) -> Option<Local> {
         match *self {
             PlaceRef { local, projection: [] } => Some(local),
@@ -1877,6 +1880,7 @@ impl<'tcx> PlaceRef<'tcx> {
         }
     }
 
+    #[inline]
     pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> {
         if let &[ref proj_base @ .., elem] = self.projection {
             Some((PlaceRef { local: self.local, projection: proj_base }, elem))
@@ -2464,12 +2468,14 @@ impl Constant<'tcx> {
             _ => None,
         }
     }
+    #[inline]
     pub fn ty(&self) -> Ty<'tcx> {
         self.literal.ty()
     }
 }
 
 impl From<&'tcx ty::Const<'tcx>> for ConstantKind<'tcx> {
+    #[inline]
     fn from(ct: &'tcx ty::Const<'tcx>) -> Self {
         Self::Ty(ct)
     }
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index edf2e539765..c354cdd985b 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -186,6 +186,15 @@ impl<'tcx> MonoItem<'tcx> {
     pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode {
         crate::dep_graph::make_compile_mono_item(tcx, self)
     }
+
+    /// Returns the item's `CrateNum`
+    pub fn krate(&self) -> CrateNum {
+        match self {
+            MonoItem::Fn(ref instance) => instance.def_id().krate,
+            MonoItem::Static(def_id) => def_id.krate,
+            MonoItem::GlobalAsm(..) => LOCAL_CRATE,
+        }
+    }
 }
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
@@ -258,6 +267,7 @@ pub enum Visibility {
 }
 
 impl<'tcx> CodegenUnit<'tcx> {
+    #[inline]
     pub fn new(name: Symbol) -> CodegenUnit<'tcx> {
         CodegenUnit { name, items: Default::default(), size_estimate: None, primary: false }
     }
@@ -302,6 +312,7 @@ impl<'tcx> CodegenUnit<'tcx> {
         self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum());
     }
 
+    #[inline]
     pub fn size_estimate(&self) -> usize {
         // Should only be called if `estimate_size` has previously been called.
         self.size_estimate.expect("estimate_size must be called before getting a size_estimate")
@@ -479,15 +490,18 @@ impl CodegenUnitNameBuilder<'tcx> {
             // local crate's ID. Otherwise there can be collisions between CGUs
             // instantiating stuff for upstream crates.
             let local_crate_id = if cnum != LOCAL_CRATE {
-                let local_crate_disambiguator = format!("{}", tcx.crate_disambiguator(LOCAL_CRATE));
-                format!("-in-{}.{}", tcx.crate_name(LOCAL_CRATE), &local_crate_disambiguator[0..8])
+                let local_stable_crate_id = tcx.sess.local_stable_crate_id();
+                format!(
+                    "-in-{}.{:08x}",
+                    tcx.crate_name(LOCAL_CRATE),
+                    local_stable_crate_id.to_u64()
+                )
             } else {
                 String::new()
             };
 
-            let crate_disambiguator = tcx.crate_disambiguator(cnum).to_string();
-            // Using a shortened disambiguator of about 40 bits
-            format!("{}.{}{}", tcx.crate_name(cnum), &crate_disambiguator[0..8], local_crate_id)
+            let stable_crate_id = tcx.sess.local_stable_crate_id();
+            format!("{}.{:08x}{}", tcx.crate_name(cnum), stable_crate_id.to_u64(), local_crate_id)
         });
 
         write!(cgu_name, "{}", crate_prefix).unwrap();
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index a80aa6ad3d8..0edb79fdbc8 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -32,7 +32,6 @@ pub enum UnsafetyViolationDetails {
     UseOfInlineAssembly,
     InitializingTypeWith,
     CastOfPointerToInt,
-    BorrowOfPackedField,
     UseOfMutableStatic,
     UseOfExternStatic,
     DerefOfRawPointer,
@@ -64,11 +63,6 @@ impl UnsafetyViolationDetails {
             CastOfPointerToInt => {
                 ("cast of pointer to int", "casting pointers to integers in constants")
             }
-            BorrowOfPackedField => (
-                "borrow of packed field",
-                "fields of packed structs might be misaligned: dereferencing a misaligned pointer \
-                 or even just creating a misaligned reference is undefined behavior",
-            ),
             UseOfMutableStatic => (
                 "use of mutable static",
                 "mutable statics can be mutated by multiple threads: aliasing violations or data \
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 70f70788bca..f65dfea04eb 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -47,7 +47,7 @@ rustc_queries! {
     ///
     /// This can be conveniently accessed by methods on `tcx.hir()`.
     /// Avoid calling this query directly.
-    query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> {
+    query hir_owner(key: LocalDefId) -> Option<crate::hir::Owner<'tcx>> {
         eval_always
         desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
     }
@@ -220,6 +220,13 @@ rustc_queries! {
         desc { "checking if the crate is_panic_runtime" }
     }
 
+    /// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
+    query thir_body(key: ty::WithOptConstParam<LocalDefId>) -> (&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId) {
+        // Perf tests revealed that hashing THIR is inefficient (see #85729).
+        no_hash
+        desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+    }
+
     /// Set of all the `DefId`s in this crate that have MIR associated with
     /// them. This includes all the body owners, but also things like struct
     /// constructors.
@@ -1120,8 +1127,7 @@ rustc_queries! {
         desc { "computing whether impls specialize one another" }
     }
     query in_scope_traits_map(_: LocalDefId)
-        -> Option<&'tcx FxHashMap<ItemLocalId, StableVec<TraitCandidate>>> {
-        eval_always
+        -> Option<&'tcx FxHashMap<ItemLocalId, Box<[TraitCandidate]>>> {
         desc { "traits in scope at a block" }
     }
 
@@ -1231,10 +1237,6 @@ rustc_queries! {
     query proc_macro_decls_static(_: ()) -> Option<LocalDefId> {
         desc { "looking up the derive registrar for a crate" }
     }
-    query crate_disambiguator(_: CrateNum) -> CrateDisambiguator {
-        eval_always
-        desc { "looking up the disambiguator a crate" }
-    }
     // The macro which defines `rustc_metadata::provide_extern` depends on this query's name.
     // Changing the name should cause a compiler error, but in case that changes, be aware.
     query crate_hash(_: CrateNum) -> Svh {
@@ -1245,10 +1247,6 @@ rustc_queries! {
         eval_always
         desc { "looking up the hash of a host version of a crate" }
     }
-    query original_crate_name(_: CrateNum) -> Symbol {
-        eval_always
-        desc { "looking up the original name a crate" }
-    }
     query extra_filename(_: CrateNum) -> String {
         eval_always
         desc { "looking up the extra filename for a crate" }
@@ -1412,6 +1410,12 @@ rustc_queries! {
         eval_always
         desc { "generating a postorder list of CrateNums" }
     }
+    /// Returns whether or not the crate with CrateNum 'cnum'
+    /// is marked as a private dependency
+    query is_private_dep(c: CrateNum) -> bool {
+        eval_always
+        desc { "check whether crate {} is a private dependency", c }
+    }
 
     query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
         desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
new file mode 100644
index 00000000000..a5069113702
--- /dev/null
+++ b/compiler/rustc_middle/src/thir.rs
@@ -0,0 +1,747 @@
+use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_hir as hir;
+use rustc_hir::def::CtorKind;
+use rustc_hir::def_id::DefId;
+use rustc_hir::RangeEnd;
+use rustc_index::newtype_index;
+use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::infer::canonical::Canonical;
+use rustc_middle::middle::region;
+use rustc_middle::mir::{
+    BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
+};
+use rustc_middle::ty::adjustment::PointerCast;
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType};
+use rustc_middle::ty::{
+    CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
+};
+use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_target::abi::VariantIdx;
+use rustc_target::asm::InlineAsmRegOrRegClass;
+
+use std::fmt;
+use std::ops::Index;
+
+newtype_index! {
+    #[derive(HashStable)]
+    pub struct ArmId {
+        DEBUG_FORMAT = "a{}"
+    }
+}
+
+newtype_index! {
+    #[derive(HashStable)]
+    pub struct ExprId {
+        DEBUG_FORMAT = "e{}"
+    }
+}
+
+newtype_index! {
+    #[derive(HashStable)]
+    pub struct StmtId {
+        DEBUG_FORMAT = "s{}"
+    }
+}
+
+macro_rules! thir_with_elements {
+    ($($name:ident: $id:ty => $value:ty,)*) => {
+        #[derive(Debug, HashStable)]
+        pub struct Thir<'tcx> {
+            $(
+                pub $name: IndexVec<$id, $value>,
+            )*
+        }
+
+        impl<'tcx> Thir<'tcx> {
+            pub fn new() -> Thir<'tcx> {
+                Thir {
+                    $(
+                        $name: IndexVec::new(),
+                    )*
+                }
+            }
+        }
+
+        $(
+            impl<'tcx> Index<$id> for Thir<'tcx> {
+                type Output = $value;
+                fn index(&self, index: $id) -> &Self::Output {
+                    &self.$name[index]
+                }
+            }
+        )*
+    }
+}
+
+thir_with_elements! {
+    arms: ArmId => Arm<'tcx>,
+    exprs: ExprId => Expr<'tcx>,
+    stmts: StmtId => Stmt<'tcx>,
+}
+
+#[derive(Copy, Clone, Debug, HashStable)]
+pub enum LintLevel {
+    Inherited,
+    Explicit(hir::HirId),
+}
+
+#[derive(Debug, HashStable)]
+pub struct Block {
+    pub targeted_by_break: bool,
+    pub region_scope: region::Scope,
+    pub opt_destruction_scope: Option<region::Scope>,
+    pub span: Span,
+    pub stmts: Box<[StmtId]>,
+    pub expr: Option<ExprId>,
+    pub safety_mode: BlockSafety,
+}
+
+#[derive(Copy, Clone, Debug, HashStable)]
+pub enum BlockSafety {
+    Safe,
+    ExplicitUnsafe(hir::HirId),
+    PushUnsafe,
+    PopUnsafe,
+}
+
+#[derive(Debug, HashStable)]
+pub struct Stmt<'tcx> {
+    pub kind: StmtKind<'tcx>,
+    pub opt_destruction_scope: Option<region::Scope>,
+}
+
+#[derive(Debug, HashStable)]
+pub enum StmtKind<'tcx> {
+    Expr {
+        /// scope for this statement; may be used as lifetime of temporaries
+        scope: region::Scope,
+
+        /// expression being evaluated in this statement
+        expr: ExprId,
+    },
+
+    Let {
+        /// scope for variables bound in this let; covers this and
+        /// remaining statements in block
+        remainder_scope: region::Scope,
+
+        /// scope for the initialization itself; might be used as
+        /// lifetime of temporaries
+        init_scope: region::Scope,
+
+        /// `let <PAT> = ...`
+        ///
+        /// if a type is included, it is added as an ascription pattern
+        pattern: Pat<'tcx>,
+
+        /// let pat: ty = <INIT> ...
+        initializer: Option<ExprId>,
+
+        /// the lint level for this let-statement
+        lint_level: LintLevel,
+    },
+}
+
+// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Expr<'_>, 144);
+
+/// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`)
+/// into instances of this `Expr` enum. This lowering can be done
+/// basically as lazily or as eagerly as desired: every recursive
+/// reference to an expression in this enum is an `ExprId`, which
+/// may in turn be another instance of this enum (boxed), or else an
+/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
+/// short-lived. They are created by `Thir::to_expr`, analyzed and
+/// converted into MIR, and then discarded.
+///
+/// If you compare `Expr` to the full compiler AST, you will see it is
+/// a good bit simpler. In fact, a number of the more straight-forward
+/// MIR simplifications are already done in the impl of `Thir`. For
+/// example, method calls and overloaded operators are absent: they are
+/// expected to be converted into `Expr::Call` instances.
+#[derive(Debug, HashStable)]
+pub struct Expr<'tcx> {
+    /// type of this expression
+    pub ty: Ty<'tcx>,
+
+    /// lifetime of this expression if it should be spilled into a
+    /// temporary; should be None only if in a constant context
+    pub temp_lifetime: Option<region::Scope>,
+
+    /// span of the expression in the source
+    pub span: Span,
+
+    /// kind of expression
+    pub kind: ExprKind<'tcx>,
+}
+
+#[derive(Debug, HashStable)]
+pub enum ExprKind<'tcx> {
+    Scope {
+        region_scope: region::Scope,
+        lint_level: LintLevel,
+        value: ExprId,
+    },
+    Box {
+        value: ExprId,
+    },
+    If {
+        cond: ExprId,
+        then: ExprId,
+        else_opt: Option<ExprId>,
+    },
+    Call {
+        ty: Ty<'tcx>,
+        fun: ExprId,
+        args: Box<[ExprId]>,
+        /// Whether this is from a call in HIR, rather than from an overloaded
+        /// operator. `true` for overloaded function call.
+        from_hir_call: bool,
+        /// This `Span` is the span of the function, without the dot and receiver
+        /// (e.g. `foo(a, b)` in `x.foo(a, b)`
+        fn_span: Span,
+    },
+    Deref {
+        arg: ExprId,
+    }, // NOT overloaded!
+    Binary {
+        op: BinOp,
+        lhs: ExprId,
+        rhs: ExprId,
+    }, // NOT overloaded!
+    LogicalOp {
+        op: LogicalOp,
+        lhs: ExprId,
+        rhs: ExprId,
+    }, // NOT overloaded!
+    // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
+    Unary {
+        op: UnOp,
+        arg: ExprId,
+    }, // NOT overloaded!
+    Cast {
+        source: ExprId,
+    },
+    Use {
+        source: ExprId,
+    }, // Use a lexpr to get a vexpr.
+    NeverToAny {
+        source: ExprId,
+    },
+    Pointer {
+        cast: PointerCast,
+        source: ExprId,
+    },
+    Loop {
+        body: ExprId,
+    },
+    Match {
+        scrutinee: ExprId,
+        arms: Box<[ArmId]>,
+    },
+    Block {
+        body: Block,
+    },
+    Assign {
+        lhs: ExprId,
+        rhs: ExprId,
+    },
+    AssignOp {
+        op: BinOp,
+        lhs: ExprId,
+        rhs: ExprId,
+    },
+    Field {
+        lhs: ExprId,
+        name: Field,
+    },
+    Index {
+        lhs: ExprId,
+        index: ExprId,
+    },
+    VarRef {
+        id: hir::HirId,
+    },
+    /// Used to represent upvars mentioned in a closure/generator
+    UpvarRef {
+        /// DefId of the closure/generator
+        closure_def_id: DefId,
+
+        /// HirId of the root variable
+        var_hir_id: hir::HirId,
+    },
+    Borrow {
+        borrow_kind: BorrowKind,
+        arg: ExprId,
+    },
+    /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
+    AddressOf {
+        mutability: hir::Mutability,
+        arg: ExprId,
+    },
+    Break {
+        label: region::Scope,
+        value: Option<ExprId>,
+    },
+    Continue {
+        label: region::Scope,
+    },
+    Return {
+        value: Option<ExprId>,
+    },
+    ConstBlock {
+        value: &'tcx Const<'tcx>,
+    },
+    Repeat {
+        value: ExprId,
+        count: &'tcx Const<'tcx>,
+    },
+    Array {
+        fields: Box<[ExprId]>,
+    },
+    Tuple {
+        fields: Box<[ExprId]>,
+    },
+    Adt {
+        adt_def: &'tcx AdtDef,
+        variant_index: VariantIdx,
+        substs: SubstsRef<'tcx>,
+
+        /// Optional user-given substs: for something like `let x =
+        /// Bar::<T> { ... }`.
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+
+        fields: Box<[FieldExpr]>,
+        base: Option<FruInfo<'tcx>>,
+    },
+    PlaceTypeAscription {
+        source: ExprId,
+        /// Type that the user gave to this expression
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+    },
+    ValueTypeAscription {
+        source: ExprId,
+        /// Type that the user gave to this expression
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+    },
+    Closure {
+        closure_id: DefId,
+        substs: UpvarSubsts<'tcx>,
+        upvars: Box<[ExprId]>,
+        movability: Option<hir::Movability>,
+        fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>,
+    },
+    Literal {
+        literal: &'tcx Const<'tcx>,
+        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
+        /// The `DefId` of the `const` item this literal
+        /// was produced from, if this is not a user-written
+        /// literal value.
+        const_id: Option<DefId>,
+    },
+    /// A literal containing the address of a `static`.
+    ///
+    /// This is only distinguished from `Literal` so that we can register some
+    /// info for diagnostics.
+    StaticRef {
+        literal: &'tcx Const<'tcx>,
+        def_id: DefId,
+    },
+    InlineAsm {
+        template: &'tcx [InlineAsmTemplatePiece],
+        operands: Box<[InlineAsmOperand<'tcx>]>,
+        options: InlineAsmOptions,
+        line_spans: &'tcx [Span],
+    },
+    /// An expression taking a reference to a thread local.
+    ThreadLocalRef(DefId),
+    LlvmInlineAsm {
+        asm: &'tcx hir::LlvmInlineAsmInner,
+        outputs: Box<[ExprId]>,
+        inputs: Box<[ExprId]>,
+    },
+    Yield {
+        value: ExprId,
+    },
+}
+
+#[derive(Debug, HashStable)]
+pub struct FieldExpr {
+    pub name: Field,
+    pub expr: ExprId,
+}
+
+#[derive(Debug, HashStable)]
+pub struct FruInfo<'tcx> {
+    pub base: ExprId,
+    pub field_types: Box<[Ty<'tcx>]>,
+}
+
+#[derive(Debug, HashStable)]
+pub struct Arm<'tcx> {
+    pub pattern: Pat<'tcx>,
+    pub guard: Option<Guard<'tcx>>,
+    pub body: ExprId,
+    pub lint_level: LintLevel,
+    pub scope: region::Scope,
+    pub span: Span,
+}
+
+#[derive(Debug, HashStable)]
+pub enum Guard<'tcx> {
+    If(ExprId),
+    IfLet(Pat<'tcx>, ExprId),
+}
+
+#[derive(Copy, Clone, Debug, HashStable)]
+pub enum LogicalOp {
+    And,
+    Or,
+}
+
+#[derive(Debug, HashStable)]
+pub enum InlineAsmOperand<'tcx> {
+    In {
+        reg: InlineAsmRegOrRegClass,
+        expr: ExprId,
+    },
+    Out {
+        reg: InlineAsmRegOrRegClass,
+        late: bool,
+        expr: Option<ExprId>,
+    },
+    InOut {
+        reg: InlineAsmRegOrRegClass,
+        late: bool,
+        expr: ExprId,
+    },
+    SplitInOut {
+        reg: InlineAsmRegOrRegClass,
+        late: bool,
+        in_expr: ExprId,
+        out_expr: Option<ExprId>,
+    },
+    Const {
+        value: &'tcx Const<'tcx>,
+        span: Span,
+    },
+    SymFn {
+        expr: ExprId,
+    },
+    SymStatic {
+        def_id: DefId,
+    },
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+pub enum BindingMode {
+    ByValue,
+    ByRef(BorrowKind),
+}
+
+#[derive(Clone, Debug, PartialEq, HashStable)]
+pub struct FieldPat<'tcx> {
+    pub field: Field,
+    pub pattern: Pat<'tcx>,
+}
+
+#[derive(Clone, Debug, PartialEq, HashStable)]
+pub struct Pat<'tcx> {
+    pub ty: Ty<'tcx>,
+    pub span: Span,
+    pub kind: Box<PatKind<'tcx>>,
+}
+
+impl<'tcx> Pat<'tcx> {
+    pub fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
+        Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+pub struct PatTyProj<'tcx> {
+    pub user_ty: CanonicalUserType<'tcx>,
+}
+
+impl<'tcx> PatTyProj<'tcx> {
+    pub fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
+        Self { user_ty: user_annotation }
+    }
+
+    pub fn user_ty(
+        self,
+        annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
+        inferred_ty: Ty<'tcx>,
+        span: Span,
+    ) -> UserTypeProjection {
+        UserTypeProjection {
+            base: annotations.push(CanonicalUserTypeAnnotation {
+                span,
+                user_ty: self.user_ty,
+                inferred_ty,
+            }),
+            projs: Vec::new(),
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+pub struct Ascription<'tcx> {
+    pub user_ty: PatTyProj<'tcx>,
+    /// Variance to use when relating the type `user_ty` to the **type of the value being
+    /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
+    /// have a type that is some subtype of the ascribed type.
+    ///
+    /// Note that this variance does not apply for any bindings within subpatterns. The type
+    /// assigned to those bindings must be exactly equal to the `user_ty` given here.
+    ///
+    /// The only place where this field is not `Covariant` is when matching constants, where
+    /// we currently use `Contravariant` -- this is because the constant type just needs to
+    /// be "comparable" to the type of the input value. So, for example:
+    ///
+    /// ```text
+    /// match x { "foo" => .. }
+    /// ```
+    ///
+    /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
+    /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
+    /// of the old type-check for now. See #57280 for details.
+    pub variance: ty::Variance,
+    pub user_ty_span: Span,
+}
+
+#[derive(Clone, Debug, PartialEq, HashStable)]
+pub enum PatKind<'tcx> {
+    Wild,
+
+    AscribeUserType {
+        ascription: Ascription<'tcx>,
+        subpattern: Pat<'tcx>,
+    },
+
+    /// `x`, `ref x`, `x @ P`, etc.
+    Binding {
+        mutability: Mutability,
+        name: Symbol,
+        mode: BindingMode,
+        var: hir::HirId,
+        ty: Ty<'tcx>,
+        subpattern: Option<Pat<'tcx>>,
+        /// Is this the leftmost occurrence of the binding, i.e., is `var` the
+        /// `HirId` of this pattern?
+        is_primary: bool,
+    },
+
+    /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
+    /// multiple variants.
+    Variant {
+        adt_def: &'tcx AdtDef,
+        substs: SubstsRef<'tcx>,
+        variant_index: VariantIdx,
+        subpatterns: Vec<FieldPat<'tcx>>,
+    },
+
+    /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
+    /// a single variant.
+    Leaf {
+        subpatterns: Vec<FieldPat<'tcx>>,
+    },
+
+    /// `box P`, `&P`, `&mut P`, etc.
+    Deref {
+        subpattern: Pat<'tcx>,
+    },
+
+    /// One of the following:
+    /// * `&str`, which will be handled as a string pattern and thus exhaustiveness
+    ///   checking will detect if you use the same string twice in different patterns.
+    /// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly
+    ///   its own value, similar to `&str`, but these values are much simpler.
+    /// * Opaque constants, that must not be matched structurally. So anything that does not derive
+    ///   `PartialEq` and `Eq`.
+    Constant {
+        value: &'tcx ty::Const<'tcx>,
+    },
+
+    Range(PatRange<'tcx>),
+
+    /// Matches against a slice, checking the length and extracting elements.
+    /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
+    /// e.g., `&[ref xs @ ..]`.
+    Slice {
+        prefix: Vec<Pat<'tcx>>,
+        slice: Option<Pat<'tcx>>,
+        suffix: Vec<Pat<'tcx>>,
+    },
+
+    /// Fixed match against an array; irrefutable.
+    Array {
+        prefix: Vec<Pat<'tcx>>,
+        slice: Option<Pat<'tcx>>,
+        suffix: Vec<Pat<'tcx>>,
+    },
+
+    /// An or-pattern, e.g. `p | q`.
+    /// Invariant: `pats.len() >= 2`.
+    Or {
+        pats: Vec<Pat<'tcx>>,
+    },
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+pub struct PatRange<'tcx> {
+    pub lo: &'tcx ty::Const<'tcx>,
+    pub hi: &'tcx ty::Const<'tcx>,
+    pub end: RangeEnd,
+}
+
+impl<'tcx> fmt::Display for Pat<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Printing lists is a chore.
+        let mut first = true;
+        let mut start_or_continue = |s| {
+            if first {
+                first = false;
+                ""
+            } else {
+                s
+            }
+        };
+        let mut start_or_comma = || start_or_continue(", ");
+
+        match *self.kind {
+            PatKind::Wild => write!(f, "_"),
+            PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
+            PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
+                let is_mut = match mode {
+                    BindingMode::ByValue => mutability == Mutability::Mut,
+                    BindingMode::ByRef(bk) => {
+                        write!(f, "ref ")?;
+                        matches!(bk, BorrowKind::Mut { .. })
+                    }
+                };
+                if is_mut {
+                    write!(f, "mut ")?;
+                }
+                write!(f, "{}", name)?;
+                if let Some(ref subpattern) = *subpattern {
+                    write!(f, " @ {}", subpattern)?;
+                }
+                Ok(())
+            }
+            PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
+                let variant = match *self.kind {
+                    PatKind::Variant { adt_def, variant_index, .. } => {
+                        Some(&adt_def.variants[variant_index])
+                    }
+                    _ => {
+                        if let ty::Adt(adt, _) = self.ty.kind() {
+                            if !adt.is_enum() {
+                                Some(&adt.variants[VariantIdx::new(0)])
+                            } else {
+                                None
+                            }
+                        } else {
+                            None
+                        }
+                    }
+                };
+
+                if let Some(variant) = variant {
+                    write!(f, "{}", variant.ident)?;
+
+                    // Only for Adt we can have `S {...}`,
+                    // which we handle separately here.
+                    if variant.ctor_kind == CtorKind::Fictive {
+                        write!(f, " {{ ")?;
+
+                        let mut printed = 0;
+                        for p in subpatterns {
+                            if let PatKind::Wild = *p.pattern.kind {
+                                continue;
+                            }
+                            let name = variant.fields[p.field.index()].ident;
+                            write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
+                            printed += 1;
+                        }
+
+                        if printed < variant.fields.len() {
+                            write!(f, "{}..", start_or_comma())?;
+                        }
+
+                        return write!(f, " }}");
+                    }
+                }
+
+                let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
+                if num_fields != 0 || variant.is_none() {
+                    write!(f, "(")?;
+                    for i in 0..num_fields {
+                        write!(f, "{}", start_or_comma())?;
+
+                        // Common case: the field is where we expect it.
+                        if let Some(p) = subpatterns.get(i) {
+                            if p.field.index() == i {
+                                write!(f, "{}", p.pattern)?;
+                                continue;
+                            }
+                        }
+
+                        // Otherwise, we have to go looking for it.
+                        if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
+                            write!(f, "{}", p.pattern)?;
+                        } else {
+                            write!(f, "_")?;
+                        }
+                    }
+                    write!(f, ")")?;
+                }
+
+                Ok(())
+            }
+            PatKind::Deref { ref subpattern } => {
+                match self.ty.kind() {
+                    ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
+                    ty::Ref(_, _, mutbl) => {
+                        write!(f, "&{}", mutbl.prefix_str())?;
+                    }
+                    _ => bug!("{} is a bad Deref pattern type", self.ty),
+                }
+                write!(f, "{}", subpattern)
+            }
+            PatKind::Constant { value } => write!(f, "{}", value),
+            PatKind::Range(PatRange { lo, hi, end }) => {
+                write!(f, "{}", lo)?;
+                write!(f, "{}", end)?;
+                write!(f, "{}", hi)
+            }
+            PatKind::Slice { ref prefix, ref slice, ref suffix }
+            | PatKind::Array { ref prefix, ref slice, ref suffix } => {
+                write!(f, "[")?;
+                for p in prefix {
+                    write!(f, "{}{}", start_or_comma(), p)?;
+                }
+                if let Some(ref slice) = *slice {
+                    write!(f, "{}", start_or_comma())?;
+                    match *slice.kind {
+                        PatKind::Wild => {}
+                        _ => write!(f, "{}", slice)?,
+                    }
+                    write!(f, "..")?;
+                }
+                for p in suffix {
+                    write!(f, "{}{}", start_or_comma(), p)?;
+                }
+                write!(f, "]")
+            }
+            PatKind::Or { ref pats } => {
+                for pat in pats {
+                    write!(f, "{}{}", start_or_continue(" | "), pat)?;
+                }
+                Ok(())
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index a50dda69a0f..8f648b21131 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -47,7 +47,7 @@ pub enum PointerCast {
 /// 1. The simplest cases are where a pointer is not adjusted fat vs thin.
 ///    Here the pointer will be dereferenced N times (where a dereference can
 ///    happen to raw or borrowed pointers or any smart pointer which implements
-///    Deref, including Box<_>). The types of dereferences is given by
+///    `Deref`, including `Box<_>`). The types of dereferences is given by
 ///    `autoderefs`. It can then be auto-referenced zero or one times, indicated
 ///    by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
 ///    `false`.
@@ -56,7 +56,7 @@ pub enum PointerCast {
 ///    with a thin pointer, deref a number of times, unsize the underlying data,
 ///    then autoref. The 'unsize' phase may change a fixed length array to a
 ///    dynamically sized one, a concrete object to a trait object, or statically
-///    sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is
+///    sized struct to a dynamically sized one. E.g., `&[i32; 4]` -> `&[i32]` is
 ///    represented by:
 ///
 ///    ```
@@ -66,7 +66,7 @@ pub enum PointerCast {
 ///    ```
 ///
 ///    Note that for a struct, the 'deep' unsizing of the struct is not recorded.
-///    E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]>
+///    E.g., `struct Foo<T> { x: T }` we can coerce `&Foo<[i32; 4]>` to `&Foo<[i32]>`
 ///    The autoderef and -ref are the same as in the above example, but the type
 ///    stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about
 ///    the underlying conversions from `[i32; 4]` to `[i32]`.
@@ -75,8 +75,8 @@ pub enum PointerCast {
 ///    that case, we have the pointer we need coming in, so there are no
 ///    autoderefs, and no autoref. Instead we just do the `Unsize` transformation.
 ///    At some point, of course, `Box` should move out of the compiler, in which
-///    case this is analogous to transforming a struct. E.g., Box<[i32; 4]> ->
-///    Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`.
+///    case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` ->
+///    `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`.
 #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)]
 pub struct Adjustment<'tcx> {
     pub kind: Adjust<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index 7790369af7f..0706a057dd0 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -1,7 +1,7 @@
 use crate::hir::place::{
     Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind,
 };
-use crate::ty;
+use crate::{mir, ty};
 
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_hir as hir;
@@ -12,6 +12,10 @@ use super::{Ty, TyCtxt};
 
 use self::BorrowKind::*;
 
+// Captures are represented using fields inside a structure.
+// This represents accessing self in the closure structure
+pub const CAPTURE_STRUCT_LOCAL: mir::Local = mir::Local::from_u32(1);
+
 #[derive(
     Clone,
     Copy,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index dde5cbadbd9..970e669c16f 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -13,6 +13,7 @@ use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetime
 use crate::middle::stability;
 use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
 use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted};
+use crate::thir::Thir;
 use crate::traits;
 use crate::ty::query::{self, OnDiskCache, TyCtxtAt};
 use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
@@ -30,7 +31,7 @@ use rustc_attr as attr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableVec};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal};
 use rustc_errors::ErrorReported;
@@ -965,10 +966,6 @@ pub struct GlobalCtxt<'tcx> {
     /// Resolutions of `extern crate` items produced by resolver.
     extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
 
-    /// Map indicating what traits are in scope for places where this
-    /// is relevant; generated by resolve.
-    trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, StableVec<TraitCandidate>>>,
-
     /// Export map produced by name resolution.
     export_map: ExportMap<LocalDefId>,
 
@@ -1008,7 +1005,7 @@ pub struct GlobalCtxt<'tcx> {
 
     /// The definite name of the current crate after taking into account
     /// attributes, commandline parameters, etc.
-    pub crate_name: Symbol,
+    crate_name: Symbol,
 
     /// Data layout specification for the current target.
     pub data_layout: TargetDataLayout,
@@ -1041,6 +1038,10 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
+    pub fn alloc_steal_thir(self, thir: Thir<'tcx>) -> &'tcx Steal<Thir<'tcx>> {
+        self.arena.alloc(Steal::new(thir))
+    }
+
     pub fn alloc_steal_mir(self, mir: Body<'tcx>) -> &'tcx Steal<Body<'tcx>> {
         self.arena.alloc(Steal::new(mir))
     }
@@ -1072,7 +1073,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Allocates a read-only byte or string literal for `mir::interpret`.
     pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
         // Create an allocation that just contains these bytes.
-        let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);
+        let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes);
         let alloc = self.intern_const_alloc(alloc);
         self.create_memory_alloc(alloc)
     }
@@ -1134,7 +1135,7 @@ impl<'tcx> TyCtxt<'tcx> {
         on_disk_cache: Option<query::OnDiskCache<'tcx>>,
         queries: &'tcx dyn query::QueryEngine<'tcx>,
         crate_name: &str,
-        output_filenames: &OutputFilenames,
+        output_filenames: OutputFilenames,
     ) -> GlobalCtxt<'tcx> {
         let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| {
             s.fatal(&err);
@@ -1145,12 +1146,6 @@ impl<'tcx> TyCtxt<'tcx> {
         let common_consts = CommonConsts::new(&interners, &common_types);
         let cstore = resolutions.cstore;
 
-        let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default();
-        for (hir_id, v) in krate.trait_map.iter() {
-            let map = trait_map.entry(hir_id.owner).or_default();
-            map.insert(hir_id.local_id, StableVec::new(v.to_vec()));
-        }
-
         GlobalCtxt {
             sess: s,
             lint_store,
@@ -1164,7 +1159,6 @@ impl<'tcx> TyCtxt<'tcx> {
             consts: common_consts,
             visibilities: resolutions.visibilities,
             extern_crate_map: resolutions.extern_crate_map,
-            trait_map,
             export_map: resolutions.export_map,
             maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports,
             maybe_unused_extern_crates: resolutions.maybe_unused_extern_crates,
@@ -1185,7 +1179,7 @@ impl<'tcx> TyCtxt<'tcx> {
             stability_interner: Default::default(),
             const_stability_interner: Default::default(),
             alloc_map: Lock::new(interpret::AllocMap::new()),
-            output_filenames: Arc::new(output_filenames.clone()),
+            output_filenames: Arc::new(output_filenames),
             main_def: resolutions.main_def,
         }
     }
@@ -1270,12 +1264,6 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    /// Returns whether or not the crate with CrateNum 'cnum'
-    /// is marked as a private dependency
-    pub fn is_private_dep(self, cnum: CrateNum) -> bool {
-        if cnum == LOCAL_CRATE { false } else { self.cstore.crate_is_private_dep_untracked(cnum) }
-    }
-
     #[inline]
     pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash {
         if let Some(def_id) = def_id.as_local() {
@@ -1287,24 +1275,24 @@ impl<'tcx> TyCtxt<'tcx> {
 
     pub fn def_path_debug_str(self, def_id: DefId) -> String {
         // We are explicitly not going through queries here in order to get
-        // crate name and disambiguator since this code is called from debug!()
+        // crate name and stable crate id since this code is called from debug!()
         // statements within the query system and we'd run into endless
         // recursion otherwise.
-        let (crate_name, crate_disambiguator) = if def_id.is_local() {
-            (self.crate_name, self.sess.local_crate_disambiguator())
+        let (crate_name, stable_crate_id) = if def_id.is_local() {
+            (self.crate_name, self.sess.local_stable_crate_id())
         } else {
             (
                 self.cstore.crate_name_untracked(def_id.krate),
-                self.cstore.crate_disambiguator_untracked(def_id.krate),
+                self.def_path_hash(def_id.krate.as_def_id()).stable_crate_id(),
             )
         };
 
         format!(
             "{}[{}]{}",
             crate_name,
-            // Don't print the whole crate disambiguator. That's just
+            // Don't print the whole stable crate id. That's just
             // annoying in debug output.
-            &(crate_disambiguator.to_fingerprint().to_hex())[..4],
+            &(format!("{:08x}", stable_crate_id.to_u64()))[..4],
             self.def_path(def_id).to_string_no_crate_verbose()
         )
     }
@@ -2657,8 +2645,10 @@ impl<'tcx> TyCtxt<'tcx> {
         struct_lint_level(self.sess, lint, level, src, None, decorate);
     }
 
-    pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx StableVec<TraitCandidate>> {
-        self.in_scope_traits_map(id.owner).and_then(|map| map.get(&id.local_id))
+    pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> {
+        let map = self.in_scope_traits_map(id.owner)?;
+        let candidates = map.get(&id.local_id)?;
+        Some(&*candidates)
     }
 
     pub fn named_region(self, id: HirId) -> Option<resolve_lifetime::Region> {
@@ -2788,7 +2778,7 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
 }
 
 pub fn provide(providers: &mut ty::query::Providers) {
-    providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id);
+    providers.in_scope_traits_map = |tcx, id| tcx.hir_crate(()).trait_map.get(&id);
     providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).map(|v| &v[..]);
     providers.crate_name = |tcx, id| {
         assert_eq!(id, LOCAL_CRATE);
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index c8fdbc30d15..4e3f475a915 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -93,6 +93,7 @@ pub struct Generics {
 }
 
 impl<'tcx> Generics {
+    #[inline]
     pub fn count(&self) -> usize {
         self.parent_count + self.params.len()
     }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index c2e9dba6c8e..03a026500d7 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -2579,7 +2579,7 @@ where
     fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
 }
 
-fn fn_can_unwind(
+pub fn fn_can_unwind(
     panic_strategy: PanicStrategy,
     codegen_fn_attr_flags: CodegenFnAttrFlags,
     call_conv: Conv,
@@ -2641,6 +2641,43 @@ fn fn_can_unwind(
     }
 }
 
+pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
+    use rustc_target::spec::abi::Abi::*;
+    match tcx.sess.target.adjust_abi(abi) {
+        RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
+
+        // It's the ABI's job to select this, not ours.
+        System { .. } => bug!("system abi should be selected elsewhere"),
+        EfiApi => bug!("eficall abi should be selected elsewhere"),
+
+        Stdcall { .. } => Conv::X86Stdcall,
+        Fastcall => Conv::X86Fastcall,
+        Vectorcall => Conv::X86VectorCall,
+        Thiscall { .. } => Conv::X86ThisCall,
+        C { .. } => Conv::C,
+        Unadjusted => Conv::C,
+        Win64 => Conv::X86_64Win64,
+        SysV64 => Conv::X86_64SysV,
+        Aapcs => Conv::ArmAapcs,
+        CCmseNonSecureCall => Conv::CCmseNonSecureCall,
+        PtxKernel => Conv::PtxKernel,
+        Msp430Interrupt => Conv::Msp430Intr,
+        X86Interrupt => Conv::X86Intr,
+        AmdGpuKernel => Conv::AmdGpuKernel,
+        AvrInterrupt => Conv::AvrInterrupt,
+        AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
+        Wasm => Conv::C,
+
+        // These API constants ought to be more specific...
+        Cdecl => Conv::C,
+    }
+}
+
+pub fn fn_ptr_codegen_fn_attr_flags() -> CodegenFnAttrFlags {
+    // Assume that fn pointers may always unwind
+    CodegenFnAttrFlags::UNWIND
+}
+
 impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
 where
     C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
@@ -2650,10 +2687,7 @@ where
         + HasParamEnv<'tcx>,
 {
     fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
-        // Assume that fn pointers may always unwind
-        let codegen_fn_attr_flags = CodegenFnAttrFlags::UNWIND;
-
-        call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, false)
+        call::FnAbi::new_internal(cx, sig, extra_args, None, fn_ptr_codegen_fn_attr_flags(), false)
     }
 
     fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
@@ -2689,35 +2723,7 @@ where
 
         let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
 
-        use rustc_target::spec::abi::Abi::*;
-        let conv = match cx.tcx().sess.target.adjust_abi(sig.abi) {
-            RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
-
-            // It's the ABI's job to select this, not ours.
-            System { .. } => bug!("system abi should be selected elsewhere"),
-            EfiApi => bug!("eficall abi should be selected elsewhere"),
-
-            Stdcall { .. } => Conv::X86Stdcall,
-            Fastcall => Conv::X86Fastcall,
-            Vectorcall => Conv::X86VectorCall,
-            Thiscall { .. } => Conv::X86ThisCall,
-            C { .. } => Conv::C,
-            Unadjusted => Conv::C,
-            Win64 => Conv::X86_64Win64,
-            SysV64 => Conv::X86_64SysV,
-            Aapcs => Conv::ArmAapcs,
-            CCmseNonSecureCall => Conv::CCmseNonSecureCall,
-            PtxKernel => Conv::PtxKernel,
-            Msp430Interrupt => Conv::Msp430Intr,
-            X86Interrupt => Conv::X86Intr,
-            AmdGpuKernel => Conv::AmdGpuKernel,
-            AvrInterrupt => Conv::AvrInterrupt,
-            AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt,
-            Wasm => Conv::C,
-
-            // These API constants ought to be more specific...
-            Cdecl => Conv::C,
-        };
+        let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
 
         let mut inputs = sig.inputs();
         let extra_args = if sig.abi == RustCall {
@@ -2753,6 +2759,7 @@ where
             target.os == "linux" && target.arch == "sparc64" && target_env_gnu_like;
         let linux_powerpc_gnu_like =
             target.os == "linux" && target.arch == "powerpc" && target_env_gnu_like;
+        use SpecAbi::*;
         let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
 
         // Handle safe Rust thin and fat pointers.
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index e657088a5e4..44dfcbf1866 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -37,9 +37,11 @@ pub struct List<T> {
 
 unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> {
     const BITS: usize = std::mem::align_of::<usize>().trailing_zeros() as usize;
+    #[inline]
     fn into_usize(self) -> usize {
         self as *const List<T> as usize
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         &*(ptr as *const List<T>)
     }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 94e325e9e87..af2be37f387 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -269,7 +269,7 @@ pub struct CrateVariancesMap<'tcx> {
 // the types of AST nodes.
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct CReaderCacheKey {
-    pub cnum: CrateNum,
+    pub cnum: Option<CrateNum>,
     pub pos: usize,
 }
 
@@ -1097,12 +1097,14 @@ pub struct ParamEnv<'tcx> {
 
 unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal {
     const BITS: usize = 1;
+    #[inline]
     fn into_usize(self) -> usize {
         match self {
             traits::Reveal::UserFacing => 0,
             traits::Reveal::All => 1,
         }
     }
+    #[inline]
     unsafe fn from_usize(ptr: usize) -> Self {
         match ptr {
             0 => traits::Reveal::UserFacing,
@@ -1200,6 +1202,7 @@ impl<'tcx> ParamEnv<'tcx> {
     }
 
     /// Returns this same environment but with no caller bounds.
+    #[inline]
     pub fn without_caller_bounds(self) -> Self {
         Self::new(List::empty(), self.reveal())
     }
@@ -1618,7 +1621,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
     fn item_name_from_def_id(self, def_id: DefId) -> Option<Symbol> {
         if def_id.index == CRATE_DEF_INDEX {
-            Some(self.original_crate_name(def_id.krate))
+            Some(self.crate_name(def_id.krate))
         } else {
             let def_key = self.def_key(def_id);
             match def_key.disambiguated_data.data {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 76c48597092..25557bdd100 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,5 +1,5 @@
 use crate::middle::cstore::{ExternCrate, ExternCrateSource};
-use crate::mir::interpret::{AllocId, ConstValue, GlobalAlloc, Pointer, Scalar};
+use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Scalar};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
 use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
 use rustc_apfloat::ieee::{Double, Single};
@@ -452,7 +452,7 @@ pub trait PrettyPrinter<'tcx>:
             }
             // Re-exported `extern crate` (#43189).
             DefPathData::CrateRoot => {
-                data = DefPathData::TypeNs(self.tcx().original_crate_name(def_id.krate));
+                data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate));
             }
             _ => {}
         }
@@ -1004,9 +1004,9 @@ pub trait PrettyPrinter<'tcx>:
                 _,
             ) => match self.tcx().get_global_alloc(ptr.alloc_id) {
                 Some(GlobalAlloc::Memory(alloc)) => {
-                    let bytes = int.assert_bits(self.tcx().data_layout.pointer_size);
-                    let size = Size::from_bytes(bytes);
-                    if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), ptr, size) {
+                    let len = int.assert_bits(self.tcx().data_layout.pointer_size);
+                    let range = AllocRange { start: ptr.offset, size: Size::from_bytes(len) };
+                    if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), range) {
                         p!(pretty_print_byte_str(byte_str))
                     } else {
                         p!("<too short allocation>")
@@ -1181,10 +1181,9 @@ pub trait PrettyPrinter<'tcx>:
             (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
                 let n = n.val.try_to_bits(self.tcx().data_layout.pointer_size).unwrap();
                 // cast is ok because we already checked for pointer size (32 or 64 bit) above
-                let n = Size::from_bytes(n);
-                let ptr = Pointer::new(AllocId(0), offset);
+                let range = AllocRange { start: offset, size: Size::from_bytes(n) };
 
-                let byte_str = alloc.get_bytes(&self.tcx(), ptr, n).unwrap();
+                let byte_str = alloc.get_bytes(&self.tcx(), range).unwrap();
                 p!("*");
                 p!(pretty_print_byte_str(byte_str));
                 Ok(self)
diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs
index 3c772a14647..a5b540dcb70 100644
--- a/compiler/rustc_middle/src/ty/query/mod.rs
+++ b/compiler/rustc_middle/src/ty/query/mod.rs
@@ -18,6 +18,7 @@ use crate::mir::interpret::GlobalId;
 use crate::mir::interpret::{ConstAlloc, LitToConstError, LitToConstInput};
 use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult};
 use crate::mir::mono::CodegenUnit;
+use crate::thir;
 use crate::traits::query::{
     CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
     CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
@@ -33,7 +34,6 @@ use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
 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;
@@ -47,7 +47,6 @@ 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;
 use rustc_target::spec::PanicStrategy;
 
 use rustc_ast as ast;
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 a688b816e9a..e473559812f 100644
--- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs
@@ -18,7 +18,7 @@ use rustc_serialize::{
     opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize},
     Decodable, Decoder, Encodable, Encoder,
 };
-use rustc_session::{CrateDisambiguator, Session};
+use rustc_session::{Session, StableCrateId};
 use rustc_span::hygiene::{
     ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext,
     SyntaxContext, SyntaxContextData,
@@ -52,7 +52,7 @@ pub struct OnDiskCache<'sess> {
     // session.
     current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>,
 
-    prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
+    prev_cnums: Vec<(u32, StableCrateId)>,
     cnum_map: OnceCell<IndexVec<CrateNum, Option<CrateNum>>>,
 
     source_map: &'sess SourceMap,
@@ -120,7 +120,7 @@ pub struct OnDiskCache<'sess> {
 #[derive(Encodable, Decodable)]
 struct Footer {
     file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>,
-    prev_cnums: Vec<(u32, String, CrateDisambiguator)>,
+    prev_cnums: Vec<(u32, StableCrateId)>,
     query_result_index: EncodedQueryResultIndex,
     diagnostics_index: EncodedQueryResultIndex,
     // The location of all allocations.
@@ -349,9 +349,8 @@ impl<'sess> OnDiskCache<'sess> {
             let prev_cnums: Vec<_> = sorted_cnums
                 .iter()
                 .map(|&cnum| {
-                    let crate_name = tcx.original_crate_name(cnum).to_string();
-                    let crate_disambiguator = tcx.crate_disambiguator(cnum);
-                    (cnum.as_u32(), crate_name, crate_disambiguator)
+                    let stable_crate_id = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
+                    (cnum.as_u32(), stable_crate_id)
                 })
                 .collect();
 
@@ -575,25 +574,23 @@ impl<'sess> OnDiskCache<'sess> {
     // maps to None.
     fn compute_cnum_map(
         tcx: TyCtxt<'_>,
-        prev_cnums: &[(u32, String, CrateDisambiguator)],
+        prev_cnums: &[(u32, StableCrateId)],
     ) -> IndexVec<CrateNum, Option<CrateNum>> {
         tcx.dep_graph.with_ignore(|| {
             let current_cnums = tcx
                 .all_crate_nums(())
                 .iter()
                 .map(|&cnum| {
-                    let crate_name = tcx.original_crate_name(cnum).to_string();
-                    let crate_disambiguator = tcx.crate_disambiguator(cnum);
-                    ((crate_name, crate_disambiguator), cnum)
+                    let stable_crate_id = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
+                    (stable_crate_id, cnum)
                 })
                 .collect::<FxHashMap<_, _>>();
 
             let map_size = prev_cnums.iter().map(|&(cnum, ..)| cnum).max().unwrap_or(0) + 1;
             let mut map = IndexVec::from_elem_n(None, map_size as usize);
 
-            for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums {
-                let key = (crate_name.clone(), crate_disambiguator);
-                map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&key).cloned();
+            for &(prev_cnum, stable_crate_id) in prev_cnums {
+                map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&stable_crate_id).cloned();
             }
 
             map[LOCAL_CRATE] = Some(LOCAL_CRATE);
@@ -758,8 +755,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
     {
         let tcx = self.tcx();
 
-        let cache_key =
-            ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand };
+        let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
 
         if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
             return Ok(ty);
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 691bfcc98d1..012d9bd82c8 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -669,7 +669,7 @@ impl<'tcx> GeneratorSubsts<'tcx> {
     }
 }
 
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, HashStable)]
 pub enum UpvarSubsts<'tcx> {
     Closure(SubstsRef<'tcx>),
     Generator(SubstsRef<'tcx>),
@@ -1837,10 +1837,12 @@ impl<'tcx> TyS<'tcx> {
 
     #[inline]
     pub fn is_enum(&self) -> bool {
-        match self.kind() {
-            Adt(adt_def, _) => adt_def.is_enum(),
-            _ => false,
-        }
+        matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum())
+    }
+
+    #[inline]
+    pub fn is_union(&self) -> bool {
+        matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union())
     }
 
     #[inline]
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index c84ca61122f..9b8d22d8eaf 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -197,7 +197,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
     }
 
     /// Interpret these substitutions as the substitutions of a generator type.
-    /// Closure substitutions have a particular structure controlled by the
+    /// Generator substitutions have a particular structure controlled by the
     /// compiler that encodes information like the signature and generator kind;
     /// see `ty::GeneratorSubsts` struct for more comments.
     pub fn as_generator(&'tcx self) -> GeneratorSubsts<'tcx> {
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
index 30e0b293ffb..8b0761889b8 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -4,10 +4,9 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
-use rustc_index::vec::Idx;
 use rustc_middle::mir::{
     self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
-    FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
+    FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
     ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
 };
 use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable};
@@ -1274,7 +1273,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         bug!("temporary or return pointer with a name")
                     }
                     LocalKind::Var => "local variable ",
-                    LocalKind::Arg if !self.upvars.is_empty() && local == Local::new(1) => {
+                    LocalKind::Arg
+                        if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL =>
+                    {
                         "variable captured by `move` "
                     }
                     LocalKind::Arg => "function parameter ",
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 1e2714a2c1b..d2b15661047 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,5 @@
 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};
@@ -115,12 +114,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 }
             }
             PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
-                if the_place_err.local == Local::new(1)
+                if the_place_err.local == ty::CAPTURE_STRUCT_LOCAL
                     && proj_base.is_empty()
                     && !self.upvars.is_empty()
                 {
                     item_msg = format!("`{}`", access_place_desc.unwrap());
-                    debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr());
+                    debug_assert!(
+                        self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr()
+                    );
                     debug_assert!(is_closure_or_generator(
                         Place::ty_from(
                             the_place_err.local,
@@ -478,11 +479,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 }
             }
 
-            PlaceRef {
-                local,
-                projection: [ProjectionElem::Deref],
-                // FIXME document what is this 1 magic number about
-            } if local == Local::new(1) && !self.upvars.is_empty() => {
+            PlaceRef { local, projection: [ProjectionElem::Deref] }
+                if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() =>
+            {
                 self.expected_fn_found_fn_mut_call(&mut err, span, act);
             }
 
diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs
index 4c35be39a3d..36eb8a4baa8 100644
--- a/compiler/rustc_mir/src/borrow_check/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/mod.rs
@@ -1965,13 +1965,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // no move out from an earlier location) then this is an attempt at initialization
                 // of the union - we should error in that case.
                 let tcx = this.infcx.tcx;
-                if let ty::Adt(def, _) = base.ty(this.body(), tcx).ty.kind() {
-                    if def.is_union() {
-                        if this.move_data.path_map[mpi].iter().any(|moi| {
-                            this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
-                        }) {
-                            return;
-                        }
+                if base.ty(this.body(), tcx).ty.is_union() {
+                    if this.move_data.path_map[mpi].iter().any(|moi| {
+                        this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
+                    }) {
+                        return;
                     }
                 }
 
diff --git a/compiler/rustc_mir/src/borrow_check/places_conflict.rs b/compiler/rustc_mir/src/borrow_check/places_conflict.rs
index 3654b51949e..d21550a8e1a 100644
--- a/compiler/rustc_mir/src/borrow_check/places_conflict.rs
+++ b/compiler/rustc_mir/src/borrow_check/places_conflict.rs
@@ -331,17 +331,14 @@ fn place_projection_conflict<'tcx>(
                 Overlap::EqualOrDisjoint
             } else {
                 let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty;
-                match ty.kind() {
-                    ty::Adt(def, _) if def.is_union() => {
-                        // Different fields of a union, we are basically stuck.
-                        debug!("place_element_conflict: STUCK-UNION");
-                        Overlap::Arbitrary
-                    }
-                    _ => {
-                        // Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
-                        debug!("place_element_conflict: DISJOINT-FIELD");
-                        Overlap::Disjoint
-                    }
+                if ty.is_union() {
+                    // Different fields of a union, we are basically stuck.
+                    debug!("place_element_conflict: STUCK-UNION");
+                    Overlap::Arbitrary
+                } else {
+                    // Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
+                    debug!("place_element_conflict: DISJOINT-FIELD");
+                    Overlap::Disjoint
                 }
             }
         }
diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
index bbd512fd360..f4d78ac04cb 100644
--- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
+++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs
@@ -1241,7 +1241,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// it. However, it works pretty well in practice. In particular,
     /// this is needed to deal with projection outlives bounds like
     ///
-    /// ```ignore (internal compiler representation so lifetime syntax is invalid)
+    /// ```text
     /// <T as Foo<'0>>::Item: '1
     /// ```
     ///
diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs
index 754ed0bea84..fc21047ab72 100644
--- a/compiler/rustc_mir/src/const_eval/error.rs
+++ b/compiler/rustc_mir/src/const_eval/error.rs
@@ -9,7 +9,7 @@ use rustc_span::{Span, Symbol};
 
 use super::InterpCx;
 use crate::interpret::{
-    struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine,
+    struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType,
 };
 
 /// The CTFE machine has some custom error kinds.
@@ -24,12 +24,21 @@ pub enum ConstEvalErrKind {
     Abort(String),
 }
 
+impl MachineStopType for ConstEvalErrKind {
+    fn is_hard_err(&self) -> bool {
+        match self {
+            Self::Panic { .. } => true,
+            _ => false,
+        }
+    }
+}
+
 // The errors become `MachineStop` with plain strings when being raised.
 // `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to
 // handle these.
 impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
     fn into(self) -> InterpErrorInfo<'tcx> {
-        err_machine_stop!(self.to_string()).into()
+        err_machine_stop!(self).into()
     }
 }
 
@@ -148,31 +157,10 @@ impl<'tcx> ConstEvalErr<'tcx> {
         tcx: TyCtxtAt<'tcx>,
         message: &str,
         emit: impl FnOnce(DiagnosticBuilder<'_>),
-        lint_root: Option<hir::HirId>,
+        mut lint_root: Option<hir::HirId>,
     ) -> ErrorHandled {
-        let must_error = match self.error {
-            err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
-                return ErrorHandled::TooGeneric;
-            }
-            err_inval!(AlreadyReported(error_reported)) => {
-                return ErrorHandled::Reported(error_reported);
-            }
-            // We must *always* hard error on these, even if the caller wants just a lint.
-            err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
-            _ => false,
-        };
-        trace!("reporting const eval failure at {:?}", self.span);
-
-        let err_msg = match &self.error {
-            InterpError::MachineStop(msg) => {
-                // A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
-                // Should be turned into a string by now.
-                msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
-            }
-            err => err.to_string(),
-        };
-
         let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
+            trace!("reporting const eval failure at {:?}", self.span);
             if let Some(span_msg) = span_msg {
                 err.span_label(self.span, span_msg);
             }
@@ -186,34 +174,50 @@ impl<'tcx> ConstEvalErr<'tcx> {
             emit(err)
         };
 
-        if must_error {
-            // The `message` makes little sense here, this is a more serious error than the
-            // caller thinks anyway.
-            // See <https://github.com/rust-lang/rust/pull/63152>.
-            finish(struct_error(tcx, &err_msg), None);
-            ErrorHandled::Reported(ErrorReported)
-        } else {
-            // Regular case.
-            if let Some(lint_root) = lint_root {
-                // Report as lint.
-                let hir_id = self
-                    .stacktrace
-                    .iter()
-                    .rev()
-                    .find_map(|frame| frame.lint_root)
-                    .unwrap_or(lint_root);
-                tcx.struct_span_lint_hir(
-                    rustc_session::lint::builtin::CONST_ERR,
-                    hir_id,
-                    tcx.span,
-                    |lint| finish(lint.build(message), Some(err_msg)),
-                );
-                ErrorHandled::Linted
-            } else {
-                // Report as hard error.
-                finish(struct_error(tcx, message), Some(err_msg));
-                ErrorHandled::Reported(ErrorReported)
+        // Special handling for certain errors
+        match &self.error {
+            // Don't emit a new diagnostic for these errors
+            err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
+                return ErrorHandled::TooGeneric;
+            }
+            err_inval!(AlreadyReported(error_reported)) => {
+                return ErrorHandled::Reported(*error_reported);
+            }
+            err_inval!(Layout(LayoutError::SizeOverflow(_))) => {
+                // We must *always* hard error on these, even if the caller wants just a lint.
+                // The `message` makes little sense here, this is a more serious error than the
+                // caller thinks anyway.
+                // See <https://github.com/rust-lang/rust/pull/63152>.
+                finish(struct_error(tcx, &self.error.to_string()), None);
+                return ErrorHandled::Reported(ErrorReported);
             }
+            _ => {}
+        };
+
+        // If we have a 'hard error', then set `lint_root` to `None` so that we don't
+        // emit a lint.
+        if matches!(&self.error, InterpError::MachineStop(err) if err.is_hard_err()) {
+            lint_root = None;
+        }
+
+        let err_msg = self.error.to_string();
+
+        // Regular case - emit a lint.
+        if let Some(lint_root) = lint_root {
+            // Report as lint.
+            let hir_id =
+                self.stacktrace.iter().rev().find_map(|frame| frame.lint_root).unwrap_or(lint_root);
+            tcx.struct_span_lint_hir(
+                rustc_session::lint::builtin::CONST_ERR,
+                hir_id,
+                tcx.span,
+                |lint| finish(lint.build(message), Some(err_msg)),
+            );
+            ErrorHandled::Linted
+        } else {
+            // Report as hard error.
+            finish(struct_error(tcx, message), Some(err_msg));
+            ErrorHandled::Reported(ErrorReported)
         }
     }
 }
diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs
index d51adc8864d..460fea37461 100644
--- a/compiler/rustc_mir/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs
@@ -16,6 +16,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, subst::Subst, TyCtxt};
 use rustc_span::source_map::Span;
 use rustc_target::abi::{Abi, LayoutOf};
+use std::borrow::Cow;
 use std::convert::TryInto;
 
 pub fn note_on_undefined_behavior_error() -> &'static str {
@@ -169,8 +170,9 @@ pub(super) fn op_to_const<'tcx>(
                         (ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(), ptr.offset.bytes())
                     }
                     Scalar::Int { .. } => (
-                        ecx.tcx
-                            .intern_const_alloc(Allocation::from_byte_aligned_bytes(b"" as &[u8])),
+                        ecx.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable(
+                            b"" as &[u8],
+                        )),
                         0,
                     ),
                 };
@@ -327,11 +329,22 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
                 ))
             } else {
                 let msg = if is_static {
-                    "could not evaluate static initializer"
+                    Cow::from("could not evaluate static initializer")
                 } else {
-                    "evaluation of constant value failed"
+                    // If the current item has generics, we'd like to enrich the message with the
+                    // instance and its substs: to show the actual compile-time values, in addition to
+                    // the expression, leading to the const eval error.
+                    let instance = &key.value.instance;
+                    if !instance.substs.is_empty() {
+                        let instance = with_no_trimmed_paths(|| instance.to_string());
+                        let msg = format!("evaluation of `{}` failed", instance);
+                        Cow::from(msg)
+                    } else {
+                        Cow::from("evaluation of constant value failed")
+                    }
                 };
-                Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), msg))
+
+                Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), &msg))
             }
         }
         Ok(mplace) => {
diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs
index 8e9148f5b66..773df7d7b60 100644
--- a/compiler/rustc_mir/src/const_eval/machine.rs
+++ b/compiler/rustc_mir/src/const_eval/machine.rs
@@ -17,7 +17,7 @@ use rustc_target::spec::abi::Abi;
 
 use crate::interpret::{
     self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, Memory,
-    OpTy, PlaceTy, Pointer, Scalar,
+    OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind,
 };
 
 use super::error::*;
@@ -223,7 +223,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         _abi: Abi,
         args: &[OpTy<'tcx>],
         _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
-        _unwind: Option<mir::BasicBlock>, // unwinding is not supported in consts
+        _unwind: StackPopUnwind, // unwinding is not supported in consts
     ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
         debug!("find_mir_or_eval_fn: {:?}", instance);
 
@@ -263,7 +263,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx>],
         ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
-        _unwind: Option<mir::BasicBlock>,
+        _unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
         // Shared intrinsics.
         if ecx.emulate_intrinsic(instance, args, ret)? {
diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs
index 3f14efc920f..6a514e9f62f 100644
--- a/compiler/rustc_mir/src/const_eval/mod.rs
+++ b/compiler/rustc_mir/src/const_eval/mod.rs
@@ -181,7 +181,7 @@ pub(crate) fn deref_const<'tcx>(
     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,
+            tcx.get_global_alloc(ptr.alloc_id).unwrap().unwrap_memory().mutability,
             Mutability::Not,
             "deref_const cannot be used with mutable allocations as \
             that could allow pattern matching to observe mutable statics",
diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
index 1bfbb843114..cea465ea1ed 100644
--- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
+++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs
@@ -519,10 +519,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
         // Check if we are assigning into a field of a union, if so, lookup the place
         // of the union so it is marked as initialized again.
         if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() {
-            if let ty::Adt(def, _) = place_base.ty(self.builder.body, self.builder.tcx).ty.kind() {
-                if def.is_union() {
-                    place = place_base;
-                }
+            if place_base.ty(self.builder.body, self.builder.tcx).ty.is_union() {
+                place = place_base;
             }
         }
 
diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs
index e9dd7a3fe68..6f7519e6156 100644
--- a/compiler/rustc_mir/src/interpret/eval_context.rs
+++ b/compiler/rustc_mir/src/interpret/eval_context.rs
@@ -134,14 +134,25 @@ pub struct FrameInfo<'tcx> {
     pub lint_root: Option<hir::HirId>,
 }
 
-#[derive(Clone, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
+/// Unwind information.
+#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)]
+pub enum StackPopUnwind {
+    /// The cleanup block.
+    Cleanup(mir::BasicBlock),
+    /// No cleanup needs to be done.
+    Skip,
+    /// Unwinding is not allowed (UB).
+    NotAllowed,
+}
+
+#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these
 pub enum StackPopCleanup {
     /// Jump to the next block in the caller, or cause UB if None (that's a function
     /// that may never return). Also store layout of return place so
     /// we can validate it at that layout.
     /// `ret` stores the block we jump to on a normal return, while `unwind`
     /// stores the block used for cleanup during unwinding.
-    Goto { ret: Option<mir::BasicBlock>, unwind: Option<mir::BasicBlock> },
+    Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind },
     /// Just do nothing: Used by Main and for the `box_alloc` hook in miri.
     /// `cleanup` says whether locals are deallocated. Static computation
     /// wants them leaked to intern what they need (and just throw away
@@ -746,13 +757,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// *Unwind* to the given `target` basic block.
     /// Do *not* use for returning! Use `return_to_block` instead.
     ///
-    /// If `target` is `None`, that indicates the function does not need cleanup during
-    /// unwinding, and we will just keep propagating that upwards.
-    pub fn unwind_to_block(&mut self, target: Option<mir::BasicBlock>) {
+    /// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup
+    /// during unwinding, and we will just keep propagating that upwards.
+    ///
+    /// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow
+    /// unwinding, and doing so is UB.
+    pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> {
         self.frame_mut().loc = match target {
-            Some(block) => Ok(mir::Location { block, statement_index: 0 }),
-            None => Err(self.frame_mut().body.span),
+            StackPopUnwind::Cleanup(block) => Ok(mir::Location { block, statement_index: 0 }),
+            StackPopUnwind::Skip => Err(self.frame_mut().body.span),
+            StackPopUnwind::NotAllowed => {
+                throw_ub_format!("unwinding past a stack frame that does not allow unwinding")
+            }
         };
+        Ok(())
     }
 
     /// Pops the current frame from the stack, deallocating the
@@ -801,21 +819,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
         }
 
+        let return_to_block = frame.return_to_block;
+
         // Now where do we jump next?
 
         // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
         // In that case, we return early. We also avoid validation in that case,
         // because this is CTFE and the final value will be thoroughly validated anyway.
-        let (cleanup, next_block) = match frame.return_to_block {
-            StackPopCleanup::Goto { ret, unwind } => {
-                (true, Some(if unwinding { unwind } else { ret }))
-            }
-            StackPopCleanup::None { cleanup, .. } => (cleanup, None),
+        let cleanup = match return_to_block {
+            StackPopCleanup::Goto { .. } => true,
+            StackPopCleanup::None { cleanup, .. } => cleanup,
         };
 
         if !cleanup {
             assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked");
-            assert!(next_block.is_none(), "tried to skip cleanup when we have a next block!");
             assert!(!unwinding, "tried to skip cleanup during unwinding");
             // Leak the locals, skip validation, skip machine hook.
             return Ok(());
@@ -834,16 +851,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // Normal return, figure out where to jump.
         if unwinding {
             // Follow the unwind edge.
-            let unwind = next_block.expect("Encountered StackPopCleanup::None when unwinding!");
-            self.unwind_to_block(unwind);
+            let unwind = match return_to_block {
+                StackPopCleanup::Goto { unwind, .. } => unwind,
+                StackPopCleanup::None { .. } => {
+                    panic!("Encountered StackPopCleanup::None when unwinding!")
+                }
+            };
+            self.unwind_to_block(unwind)
         } else {
             // Follow the normal return edge.
-            if let Some(ret) = next_block {
-                self.return_to_block(ret)?;
+            match return_to_block {
+                StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
+                StackPopCleanup::None { .. } => Ok(()),
             }
         }
-
-        Ok(())
     }
 
     /// Mark a storage as live, killing the previous content.
diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs
index 69ab50fa86e..99622fb310a 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics.rs
@@ -14,7 +14,7 @@ use rustc_middle::ty;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
-use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size};
+use rustc_target::abi::{Abi, Align, LayoutOf as _, Primitive, Size};
 
 use super::{
     util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy,
@@ -525,7 +525,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         self.memory.check_ptr_access_align(
             min_ptr,
             Size::from_bytes(size),
-            None,
+            Align::ONE,
             CheckInAllocMsg::PointerArithmeticTest,
         )?;
         Ok(offset_ptr)
@@ -549,17 +549,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             )
         })?;
 
-        // Make sure we check both pointers for an access of the total size and aligment,
-        // *even if* the total size is 0.
-        let src =
-            self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?;
+        let src = self.read_scalar(&src)?.check_init()?;
+        let dst = self.read_scalar(&dst)?.check_init()?;
 
-        let dst =
-            self.memory.check_ptr_access(self.read_scalar(&dst)?.check_init()?, size, align)?;
-
-        if let (Some(src), Some(dst)) = (src, dst) {
-            self.memory.copy(src, dst, size, nonoverlapping)?;
-        }
-        Ok(())
+        self.memory.copy(src, align, dst, align, size, nonoverlapping)
     }
 }
diff --git a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
index 2b996cf62a3..792a4749108 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs
@@ -1,5 +1,6 @@
 use std::convert::TryFrom;
 
+use rustc_ast::Mutability;
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir::TerminatorKind;
 use rustc_middle::ty::subst::Subst;
@@ -79,7 +80,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         line: u32,
         col: u32,
     ) -> MPlaceTy<'tcx, M::PointerTag> {
-        let file = self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation);
+        let file =
+            self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not);
         let line = Scalar::from_u32(line);
         let col = Scalar::from_u32(col);
 
diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
index ae5e78ee33f..a7012cd63f3 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs
@@ -1,5 +1,5 @@
 use rustc_hir::def_id::CrateNum;
-use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
+use rustc_hir::definitions::DisambiguatedDefPathData;
 use rustc_middle::mir::interpret::Allocation;
 use rustc_middle::ty::{
     self,
@@ -88,7 +88,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
     }
 
     fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
-        self.path.push_str(&self.tcx.original_crate_name(cnum).as_str());
+        self.path.push_str(&self.tcx.crate_name(cnum).as_str());
         Ok(self)
     }
 
@@ -127,11 +127,6 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
     ) -> Result<Self::Path, Self::Error> {
         self = print_prefix(self)?;
 
-        // Skip `::{{constructor}}` on tuple/unit structs.
-        if disambiguated_data.data == DefPathData::Ctor {
-            return Ok(self);
-        }
-
         write!(self.path, "::{}", disambiguated_data.data).unwrap();
 
         Ok(self)
@@ -197,6 +192,6 @@ impl Write for AbsolutePathPrinter<'_> {
 /// Directly returns an `Allocation` containing an absolute path representation of the given type.
 crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation {
     let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path;
-    let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes());
+    let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
     tcx.intern_const_alloc(alloc)
 }
diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs
index 52baf1a6330..0d01dc3c219 100644
--- a/compiler/rustc_mir/src/interpret/machine.rs
+++ b/compiler/rustc_mir/src/interpret/machine.rs
@@ -13,8 +13,8 @@ use rustc_target::abi::Size;
 use rustc_target::spec::abi::Abi;
 
 use super::{
-    AllocId, Allocation, AllocationExtra, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult,
-    LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar,
+    AllocId, Allocation, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult, LocalValue,
+    MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar, StackPopUnwind,
 };
 
 /// Data returned by Machine::stack_pop,
@@ -105,7 +105,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
     type MemoryExtra;
 
     /// Extra data stored in every allocation.
-    type AllocExtra: AllocationExtra<Self::PointerTag> + 'static;
+    type AllocExtra: Debug + Clone + 'static;
 
     /// Memory's allocation map
     type MemoryMap: AllocMap<
@@ -132,6 +132,11 @@ pub trait Machine<'mir, 'tcx>: Sized {
     /// Whether to enforce the validity invariant
     fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool;
 
+    /// Whether function calls should be [ABI](Abi)-checked.
+    fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+        true
+    }
+
     /// Entry point for obtaining the MIR of anything that should get evaluated.
     /// So not just functions and shims, but also const/static initializers, anonymous
     /// constants, ...
@@ -158,7 +163,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         abi: Abi,
         args: &[OpTy<'tcx, Self::PointerTag>],
         ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
-        unwind: Option<mir::BasicBlock>,
+        unwind: StackPopUnwind,
     ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;
 
     /// Execute `fn_val`.  It is the hook's responsibility to advance the instruction
@@ -169,7 +174,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         abi: Abi,
         args: &[OpTy<'tcx, Self::PointerTag>],
         ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
-        unwind: Option<mir::BasicBlock>,
+        unwind: StackPopUnwind,
     ) -> InterpResult<'tcx>;
 
     /// Directly process an intrinsic without pushing a stack frame. It is the hook's
@@ -179,7 +184,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         instance: ty::Instance<'tcx>,
         args: &[OpTy<'tcx, Self::PointerTag>],
         ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>,
-        unwind: Option<mir::BasicBlock>,
+        unwind: StackPopUnwind,
     ) -> InterpResult<'tcx>;
 
     /// Called to evaluate `Assert` MIR terminators that trigger a panic.
@@ -305,10 +310,39 @@ pub trait Machine<'mir, 'tcx>: Sized {
         kind: Option<MemoryKind<Self::MemoryKind>>,
     ) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag);
 
-    /// Called to notify the machine before a deallocation occurs.
-    fn before_deallocation(
+    /// Hook for performing extra checks on a memory read access.
+    ///
+    /// Takes read-only access to the allocation so we can keep all the memory read
+    /// operations take `&self`. Use a `RefCell` in `AllocExtra` if you
+    /// need to mutate.
+    #[inline(always)]
+    fn memory_read(
+        _memory_extra: &Self::MemoryExtra,
+        _alloc_extra: &Self::AllocExtra,
+        _ptr: Pointer<Self::PointerTag>,
+        _size: Size,
+    ) -> InterpResult<'tcx> {
+        Ok(())
+    }
+
+    /// Hook for performing extra checks on a memory write access.
+    #[inline(always)]
+    fn memory_written(
         _memory_extra: &mut Self::MemoryExtra,
-        _id: AllocId,
+        _alloc_extra: &mut Self::AllocExtra,
+        _ptr: Pointer<Self::PointerTag>,
+        _size: Size,
+    ) -> InterpResult<'tcx> {
+        Ok(())
+    }
+
+    /// Hook for performing extra operations on a memory deallocation.
+    #[inline(always)]
+    fn memory_deallocated(
+        _memory_extra: &mut Self::MemoryExtra,
+        _alloc_extra: &mut Self::AllocExtra,
+        _ptr: Pointer<Self::PointerTag>,
+        _size: Size,
     ) -> InterpResult<'tcx> {
         Ok(())
     }
@@ -322,7 +356,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
         Ok(())
     }
 
-    /// Executes a retagging operation
+    /// Executes a retagging operation.
     #[inline]
     fn retag(
         _ecx: &mut InterpCx<'mir, 'tcx, Self>,
@@ -422,7 +456,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
         _abi: Abi,
         _args: &[OpTy<$tcx>],
         _ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>,
-        _unwind: Option<mir::BasicBlock>,
+        _unwind: StackPopUnwind,
     ) -> InterpResult<$tcx> {
         match fn_val {}
     }
diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs
index 5200e4aa90d..77de19ac674 100644
--- a/compiler/rustc_mir/src/interpret/memory.rs
+++ b/compiler/rustc_mir/src/interpret/memory.rs
@@ -18,8 +18,8 @@ use rustc_middle::ty::{Instance, ParamEnv, TyCtxt};
 use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout};
 
 use super::{
-    AllocId, AllocMap, Allocation, AllocationExtra, CheckInAllocMsg, GlobalAlloc, InterpResult,
-    Machine, MayLeak, Pointer, PointerArithmetic, Scalar,
+    alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc,
+    InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Scalar, ScalarMaybeUninit,
 };
 use crate::util::pretty;
 
@@ -125,6 +125,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M>
     }
 }
 
+/// A reference to some allocation that was already bounds-checked for the given region
+/// and had the on-access machine hooks run.
+#[derive(Copy, Clone)]
+pub struct AllocRef<'a, 'tcx, Tag, Extra> {
+    alloc: &'a Allocation<Tag, Extra>,
+    range: AllocRange,
+    tcx: TyCtxt<'tcx>,
+    alloc_id: AllocId,
+}
+/// A reference to some allocation that was already bounds-checked for the given region
+/// and had the on-access machine hooks run.
+pub struct AllocRefMut<'a, 'tcx, Tag, Extra> {
+    alloc: &'a mut Allocation<Tag, Extra>,
+    range: AllocRange,
+    tcx: TyCtxt<'tcx>,
+    alloc_id: AllocId,
+}
+
 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
     pub fn new(tcx: TyCtxt<'tcx>, extra: M::MemoryExtra) -> Self {
         Memory {
@@ -201,9 +219,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
     pub fn allocate_bytes(
         &mut self,
         bytes: &[u8],
+        align: Align,
         kind: MemoryKind<M::MemoryKind>,
+        mutability: Mutability,
     ) -> Pointer<M::PointerTag> {
-        let alloc = Allocation::from_byte_aligned_bytes(bytes);
+        let alloc = Allocation::from_bytes(bytes, align, mutability);
         self.allocate_with(alloc, kind)
     }
 
@@ -246,7 +266,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
             Some((size, _align)) => size,
             None => self.get_raw(ptr.alloc_id)?.size(),
         };
-        self.copy(ptr, new_ptr, old_size.min(new_size), /*nonoverlapping*/ true)?;
+        // This will also call the access hooks.
+        self.copy(
+            ptr.into(),
+            Align::ONE,
+            new_ptr.into(),
+            Align::ONE,
+            old_size.min(new_size),
+            /*nonoverlapping*/ true,
+        )?;
         self.deallocate(ptr, old_size_and_align, kind)?;
 
         Ok(new_ptr)
@@ -278,8 +306,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
             );
         }
 
-        M::before_deallocation(&mut self.extra, ptr.alloc_id)?;
-
         let (alloc_kind, mut alloc) = match self.alloc_map.remove(&ptr.alloc_id) {
             Some(alloc) => alloc,
             None => {
@@ -297,6 +323,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
             }
         };
 
+        if alloc.mutability == Mutability::Not {
+            throw_ub_format!("deallocating immutable allocation {}", ptr.alloc_id);
+        }
         if alloc_kind != kind {
             throw_ub_format!(
                 "deallocating {}, which is {} memory, using {} deallocation operation",
@@ -320,10 +349,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
 
         // Let the machine take some extra action
         let size = alloc.size();
-        AllocationExtra::memory_deallocated(&mut alloc, ptr, size)?;
+        M::memory_deallocated(&mut self.extra, &mut alloc.extra, ptr, size)?;
 
         // Don't forget to remember size and align of this now-dead allocation
-        let old = self.dead_alloc_map.insert(ptr.alloc_id, (alloc.size(), alloc.align));
+        let old = self.dead_alloc_map.insert(ptr.alloc_id, (size, alloc.align));
         if old.is_some() {
             bug!("Nothing can be deallocated twice");
         }
@@ -331,40 +360,53 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         Ok(())
     }
 
-    /// Check if the given scalar is allowed to do a memory access of given `size`
-    /// and `align`. On success, returns `None` for zero-sized accesses (where
-    /// nothing else is left to do) and a `Pointer` to use for the actual access otherwise.
-    /// Crucially, if the input is a `Pointer`, we will test it for liveness
-    /// *even if* the size is 0.
-    ///
-    /// Everyone accessing memory based on a `Scalar` should use this method to get the
-    /// `Pointer` they need. And even if you already have a `Pointer`, call this method
-    /// to make sure it is sufficiently aligned and not dangling.  Not doing that may
-    /// cause ICEs.
-    ///
-    /// Most of the time you should use `check_mplace_access`, but when you just have a pointer,
-    /// this method is still appropriate.
+    /// Internal helper function for APIs that offer memory access based on `Scalar` pointers.
     #[inline(always)]
-    pub fn check_ptr_access(
+    pub(super) fn check_ptr_access(
         &self,
         sptr: Scalar<M::PointerTag>,
         size: Size,
         align: Align,
     ) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
         let align = M::enforce_alignment(&self.extra).then_some(align);
-        self.check_ptr_access_align(sptr, size, align, CheckInAllocMsg::MemoryAccessTest)
+        self.check_and_deref_ptr(sptr, size, align, CheckInAllocMsg::MemoryAccessTest, |ptr| {
+            let (size, align) =
+                self.get_size_and_align(ptr.alloc_id, AllocCheck::Dereferenceable)?;
+            Ok((size, align, ptr))
+        })
     }
 
-    /// Like `check_ptr_access`, but *definitely* checks alignment when `align`
-    /// is `Some` (overriding `M::enforce_alignment`). Also lets the caller control
-    /// the error message for the out-of-bounds case.
+    /// Check if the given scalar is allowed to do a memory access of given `size` and `align`
+    /// (ignoring `M::enforce_alignment`). The caller can control the error message for the
+    /// out-of-bounds case.
+    #[inline(always)]
     pub fn check_ptr_access_align(
         &self,
         sptr: Scalar<M::PointerTag>,
         size: Size,
+        align: Align,
+        msg: CheckInAllocMsg,
+    ) -> InterpResult<'tcx> {
+        self.check_and_deref_ptr(sptr, size, Some(align), msg, |ptr| {
+            let (size, align) =
+                self.get_size_and_align(ptr.alloc_id, AllocCheck::Dereferenceable)?;
+            Ok((size, align, ()))
+        })?;
+        Ok(())
+    }
+
+    /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference
+    /// to the allocation it points to. Supports both shared and mutable references, to the actual
+    /// checking is offloaded to a helper closure. `align` defines whether and which alignment check
+    /// is done. Returns `None` for size 0, and otherwise `Some` of what `alloc_size` returned.
+    fn check_and_deref_ptr<T>(
+        &self,
+        sptr: Scalar<M::PointerTag>,
+        size: Size,
         align: Option<Align>,
         msg: CheckInAllocMsg,
-    ) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
+        alloc_size: impl FnOnce(Pointer<M::PointerTag>) -> InterpResult<'tcx, (Size, Align, T)>,
+    ) -> InterpResult<'tcx, Option<T>> {
         fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> {
             if offset % align.bytes() == 0 {
                 Ok(())
@@ -402,8 +444,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
                 None
             }
             Err(ptr) => {
-                let (allocation_size, alloc_align) =
-                    self.get_size_and_align(ptr.alloc_id, AllocCheck::Dereferenceable)?;
+                let (allocation_size, alloc_align, ret_val) = alloc_size(ptr)?;
                 // Test bounds. This also ensures non-null.
                 // It is sufficient to check this for the end pointer. The addition
                 // checks for overflow.
@@ -431,7 +472,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
 
                 // We can still be zero-sized in this branch, in which case we have to
                 // return `None`.
-                if size.bytes() == 0 { None } else { Some(ptr) }
+                if size.bytes() == 0 { None } else { Some(ret_val) }
             }
         })
     }
@@ -502,8 +543,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
     }
 
     /// Gives raw access to the `Allocation`, without bounds or alignment checks.
-    /// Use the higher-level, `PlaceTy`- and `OpTy`-based APIs in `InterpCx` instead!
-    pub fn get_raw(
+    /// The caller is responsible for calling the access hooks!
+    fn get_raw(
         &self,
         id: AllocId,
     ) -> InterpResult<'tcx, &Allocation<M::PointerTag, M::AllocExtra>> {
@@ -537,21 +578,58 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
         }
     }
 
+    /// "Safe" (bounds and align-checked) allocation access.
+    pub fn get<'a>(
+        &'a self,
+        sptr: Scalar<M::PointerTag>,
+        size: Size,
+        align: Align,
+    ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::PointerTag, M::AllocExtra>>> {
+        let align = M::enforce_alignment(&self.extra).then_some(align);
+        let ptr_and_alloc = self.check_and_deref_ptr(
+            sptr,
+            size,
+            align,
+            CheckInAllocMsg::MemoryAccessTest,
+            |ptr| {
+                let alloc = self.get_raw(ptr.alloc_id)?;
+                Ok((alloc.size(), alloc.align, (ptr, alloc)))
+            },
+        )?;
+        if let Some((ptr, alloc)) = ptr_and_alloc {
+            M::memory_read(&self.extra, &alloc.extra, ptr, size)?;
+            let range = alloc_range(ptr.offset, size);
+            Ok(Some(AllocRef { alloc, range, tcx: self.tcx, alloc_id: ptr.alloc_id }))
+        } else {
+            // Even in this branch we have to be sure that we actually access the allocation, in
+            // order to ensure that `static FOO: Type = FOO;` causes a cycle error instead of
+            // magically pulling *any* ZST value from the ether. However, the `get_raw` above is
+            // always called when `sptr` is truly a `Pointer`, so we are good.
+            Ok(None)
+        }
+    }
+
+    /// Return the `extra` field of the given allocation.
+    pub fn get_alloc_extra<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, &'a M::AllocExtra> {
+        Ok(&self.get_raw(id)?.extra)
+    }
+
     /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks.
-    /// Use the higher-level, `PlaceTy`- and `OpTy`-based APIs in `InterpCx` instead!
-    pub fn get_raw_mut(
+    /// The caller is responsible for calling the access hooks!
+    ///
+    /// Also returns a ptr to `self.extra` so that the caller can use it in parallel with the
+    /// allocation.
+    fn get_raw_mut(
         &mut self,
         id: AllocId,
-    ) -> InterpResult<'tcx, &mut Allocation<M::PointerTag, M::AllocExtra>> {
+    ) -> InterpResult<'tcx, (&mut Allocation<M::PointerTag, M::AllocExtra>, &mut M::MemoryExtra)>
+    {
         let tcx = self.tcx;
-        let memory_extra = &self.extra;
+        let memory_extra = &mut self.extra;
         let a = self.alloc_map.get_mut_or(id, || {
             // Need to make a copy, even if `get_global_alloc` is able
             // to give us a cheap reference.
             let alloc = Self::get_global_alloc(memory_extra, tcx, id, /*is_write*/ true)?;
-            if alloc.mutability == Mutability::Not {
-                throw_ub!(WriteToReadOnly(id))
-            }
             let kind = M::GLOBAL_KIND.expect(
                 "I got a global allocation that I have to copy but the machine does \
                     not expect that to happen",
@@ -567,11 +645,41 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
                 if a.mutability == Mutability::Not {
                     throw_ub!(WriteToReadOnly(id))
                 }
-                Ok(a)
+                Ok((a, memory_extra))
             }
         }
     }
 
+    /// "Safe" (bounds and align-checked) allocation access.
+    pub fn get_mut<'a>(
+        &'a mut self,
+        sptr: Scalar<M::PointerTag>,
+        size: Size,
+        align: Align,
+    ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::PointerTag, M::AllocExtra>>> {
+        let ptr = self.check_ptr_access(sptr, size, align)?;
+        if let Some(ptr) = ptr {
+            let tcx = self.tcx;
+            // FIXME: can we somehow avoid looking up the allocation twice here?
+            // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
+            let (alloc, extra) = self.get_raw_mut(ptr.alloc_id)?;
+            M::memory_written(extra, &mut alloc.extra, ptr, size)?;
+            let range = alloc_range(ptr.offset, size);
+            Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id: ptr.alloc_id }))
+        } else {
+            Ok(None)
+        }
+    }
+
+    /// Return the `extra` field of the given allocation.
+    pub fn get_alloc_extra_mut<'a>(
+        &'a mut self,
+        id: AllocId,
+    ) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M::MemoryExtra)> {
+        let (alloc, memory_extra) = self.get_raw_mut(id)?;
+        Ok((&mut alloc.extra, memory_extra))
+    }
+
     /// Obtain the size and alignment of an allocation, even if that allocation has
     /// been deallocated.
     ///
@@ -596,7 +704,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
                 // The caller requested no function pointers.
                 throw_ub!(DerefFunctionPointer(id))
             } else {
-                Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
+                Ok((Size::ZERO, Align::ONE))
             };
         }
 
@@ -658,7 +766,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
     }
 
     pub fn mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {
-        self.get_raw_mut(id)?.mutability = Mutability::Not;
+        self.get_raw_mut(id)?.0.mutability = Mutability::Not;
         Ok(())
     }
 
@@ -792,16 +900,62 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
 }
 
 /// Reading and writing.
+impl<'tcx, 'a, Tag: Copy, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> {
+    pub fn write_scalar(
+        &mut self,
+        range: AllocRange,
+        val: ScalarMaybeUninit<Tag>,
+    ) -> InterpResult<'tcx> {
+        Ok(self
+            .alloc
+            .write_scalar(&self.tcx, self.range.subrange(range), val)
+            .map_err(|e| e.to_interp_error(self.alloc_id))?)
+    }
+
+    pub fn write_ptr_sized(
+        &mut self,
+        offset: Size,
+        val: ScalarMaybeUninit<Tag>,
+    ) -> InterpResult<'tcx> {
+        self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val)
+    }
+}
+
+impl<'tcx, 'a, Tag: Copy, Extra> AllocRef<'a, 'tcx, Tag, Extra> {
+    pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+        Ok(self
+            .alloc
+            .read_scalar(&self.tcx, self.range.subrange(range))
+            .map_err(|e| e.to_interp_error(self.alloc_id))?)
+    }
+
+    pub fn read_ptr_sized(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> {
+        self.read_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size))
+    }
+
+    pub fn check_bytes(&self, range: AllocRange, allow_uninit_and_ptr: bool) -> InterpResult<'tcx> {
+        Ok(self
+            .alloc
+            .check_bytes(&self.tcx, self.range.subrange(range), allow_uninit_and_ptr)
+            .map_err(|e| e.to_interp_error(self.alloc_id))?)
+    }
+}
+
 impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
     /// Reads the given number of bytes from memory. Returns them as a slice.
     ///
     /// Performs appropriate bounds checks.
-    pub fn read_bytes(&self, ptr: Scalar<M::PointerTag>, size: Size) -> InterpResult<'tcx, &[u8]> {
-        let ptr = match self.check_ptr_access(ptr, size, Align::from_bytes(1).unwrap())? {
-            Some(ptr) => ptr,
+    pub fn read_bytes(&self, sptr: Scalar<M::PointerTag>, size: Size) -> InterpResult<'tcx, &[u8]> {
+        let alloc_ref = match self.get(sptr, size, Align::ONE)? {
+            Some(a) => a,
             None => return Ok(&[]), // zero-sized access
         };
-        self.get_raw(ptr.alloc_id)?.get_bytes(self, ptr, size)
+        // Side-step AllocRef and directly access the underlying bytes more efficiently.
+        // (We are staying inside the bounds here so all is good.)
+        Ok(alloc_ref
+            .alloc
+            .get_bytes(&alloc_ref.tcx, alloc_ref.range)
+            .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?)
     }
 
     /// Writes the given stream of bytes into memory.
@@ -809,14 +963,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
     /// Performs appropriate bounds checks.
     pub fn write_bytes(
         &mut self,
-        ptr: Scalar<M::PointerTag>,
+        sptr: Scalar<M::PointerTag>,
         src: impl IntoIterator<Item = u8>,
     ) -> InterpResult<'tcx> {
         let mut src = src.into_iter();
-        let size = Size::from_bytes(src.size_hint().0);
-        // `write_bytes` checks that this lower bound `size` matches the upper bound and reality.
-        let ptr = match self.check_ptr_access(ptr, size, Align::from_bytes(1).unwrap())? {
-            Some(ptr) => ptr,
+        let (lower, upper) = src.size_hint();
+        let len = upper.expect("can only write bounded iterators");
+        assert_eq!(lower, len, "can only write iterators with a precise length");
+
+        let size = Size::from_bytes(len);
+        let alloc_ref = match self.get_mut(sptr, size, Align::ONE)? {
+            Some(alloc_ref) => alloc_ref,
             None => {
                 // zero-sized access
                 assert_matches!(
@@ -827,56 +984,88 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
                 return Ok(());
             }
         };
-        let tcx = self.tcx;
-        self.get_raw_mut(ptr.alloc_id)?.write_bytes(&tcx, ptr, src)
+
+        // Side-step AllocRef and directly access the underlying bytes more efficiently.
+        // (We are staying inside the bounds here so all is good.)
+        let bytes = alloc_ref.alloc.get_bytes_mut(&alloc_ref.tcx, alloc_ref.range);
+        // `zip` would stop when the first iterator ends; we want to definitely
+        // cover all of `bytes`.
+        for dest in bytes {
+            *dest = src.next().expect("iterator was shorter than it said it would be");
+        }
+        assert_matches!(src.next(), None, "iterator was longer than it said it would be");
+        Ok(())
     }
 
-    /// Expects the caller to have checked bounds and alignment.
     pub fn copy(
         &mut self,
-        src: Pointer<M::PointerTag>,
-        dest: Pointer<M::PointerTag>,
+        src: Scalar<M::PointerTag>,
+        src_align: Align,
+        dest: Scalar<M::PointerTag>,
+        dest_align: Align,
         size: Size,
         nonoverlapping: bool,
     ) -> InterpResult<'tcx> {
-        self.copy_repeatedly(src, dest, size, 1, nonoverlapping)
+        self.copy_repeatedly(src, src_align, dest, dest_align, size, 1, nonoverlapping)
     }
 
-    /// Expects the caller to have checked bounds and alignment.
     pub fn copy_repeatedly(
         &mut self,
-        src: Pointer<M::PointerTag>,
-        dest: Pointer<M::PointerTag>,
+        src: Scalar<M::PointerTag>,
+        src_align: Align,
+        dest: Scalar<M::PointerTag>,
+        dest_align: Align,
         size: Size,
-        length: u64,
+        num_copies: u64,
         nonoverlapping: bool,
     ) -> InterpResult<'tcx> {
+        let tcx = self.tcx;
+        // We need to do our own bounds-checks.
+        let src = self.check_ptr_access(src, size, src_align)?;
+        let dest = self.check_ptr_access(dest, size * num_copies, dest_align)?; // `Size` multiplication
+
+        // FIXME: we look up both allocations twice here, once ebfore for the `check_ptr_access`
+        // and once below to get the underlying `&[mut] Allocation`.
+
+        // Source alloc preparations and access hooks.
+        let src = match src {
+            None => return Ok(()), // Zero-sized *source*, that means dst is also zero-sized and we have nothing to do.
+            Some(src_ptr) => src_ptr,
+        };
+        let src_alloc = self.get_raw(src.alloc_id)?;
+        M::memory_read(&self.extra, &src_alloc.extra, src, size)?;
+        // We need the `dest` ptr for the next operation, so we get it now.
+        // We already did the source checks and called the hooks so we are good to return early.
+        let dest = match dest {
+            None => return Ok(()), // Zero-sized *destiantion*.
+            Some(dest_ptr) => dest_ptr,
+        };
+
         // first copy the relocations to a temporary buffer, because
         // `get_bytes_mut` will clear the relocations, which is correct,
         // since we don't want to keep any relocations at the target.
         // (`get_bytes_with_uninit_and_ptr` below checks that there are no
         // relocations overlapping the edges; those would not be handled correctly).
-        let relocations =
-            self.get_raw(src.alloc_id)?.prepare_relocation_copy(self, src, size, dest, length);
-
-        let tcx = self.tcx;
-
-        // This checks relocation edges on the src.
-        let src_bytes =
-            self.get_raw(src.alloc_id)?.get_bytes_with_uninit_and_ptr(&tcx, src, size)?.as_ptr();
-        let dest_bytes =
-            self.get_raw_mut(dest.alloc_id)?.get_bytes_mut(&tcx, dest, size * length)?; // `Size` multiplication
-
-        // If `dest_bytes` is empty we just optimize to not run anything for zsts.
-        // See #67539
-        if dest_bytes.is_empty() {
-            return Ok(());
-        }
-
-        let dest_bytes = dest_bytes.as_mut_ptr();
-
+        let relocations = src_alloc.prepare_relocation_copy(
+            self,
+            alloc_range(src.offset, size),
+            dest.offset,
+            num_copies,
+        );
         // Prepare a copy of the initialization mask.
-        let compressed = self.get_raw(src.alloc_id)?.compress_uninit_range(src, size);
+        let compressed = src_alloc.compress_uninit_range(src, size);
+        // This checks relocation edges on the src.
+        let src_bytes = src_alloc
+            .get_bytes_with_uninit_and_ptr(&tcx, alloc_range(src.offset, size))
+            .map_err(|e| e.to_interp_error(src.alloc_id))?
+            .as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation
+
+        // Destination alloc preparations and access hooks.
+        let (dest_alloc, extra) = self.get_raw_mut(dest.alloc_id)?;
+        M::memory_written(extra, &mut dest_alloc.extra, dest, size * num_copies)?;
+        let dest_bytes = dest_alloc
+            .get_bytes_mut_ptr(&tcx, alloc_range(dest.offset, size * num_copies))
+            .as_mut_ptr();
 
         if compressed.no_bytes_init() {
             // Fast path: If all bytes are `uninit` then there is nothing to copy. The target range
@@ -885,8 +1074,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
             // This also avoids writing to the target bytes so that the backing allocation is never
             // touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary
             // operating system this can avoid physically allocating the page.
-            let dest_alloc = self.get_raw_mut(dest.alloc_id)?;
-            dest_alloc.mark_init(dest, size * length, false); // `Size` multiplication
+            dest_alloc.mark_init(alloc_range(dest.offset, size * num_copies), false); // `Size` multiplication
             dest_alloc.mark_relocation_range(relocations);
             return Ok(());
         }
@@ -907,7 +1095,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
                     }
                 }
 
-                for i in 0..length {
+                for i in 0..num_copies {
                     ptr::copy(
                         src_bytes,
                         dest_bytes.add((size * i).bytes_usize()), // `Size` multiplication
@@ -915,7 +1103,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
                     );
                 }
             } else {
-                for i in 0..length {
+                for i in 0..num_copies {
                     ptr::copy_nonoverlapping(
                         src_bytes,
                         dest_bytes.add((size * i).bytes_usize()), // `Size` multiplication
@@ -925,16 +1113,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
             }
         }
 
-        // now fill in all the data
-        self.get_raw_mut(dest.alloc_id)?.mark_compressed_init_range(
-            &compressed,
-            dest,
-            size,
-            length,
-        );
-
+        // now fill in all the "init" data
+        dest_alloc.mark_compressed_init_range(&compressed, dest, size, num_copies);
         // copy the relocations to the destination
-        self.get_raw_mut(dest.alloc_id)?.mark_relocation_range(relocations);
+        dest_alloc.mark_relocation_range(relocations);
 
         Ok(())
     }
diff --git a/compiler/rustc_mir/src/interpret/mod.rs b/compiler/rustc_mir/src/interpret/mod.rs
index a29ef117ace..2b9fe565997 100644
--- a/compiler/rustc_mir/src/interpret/mod.rs
+++ b/compiler/rustc_mir/src/interpret/mod.rs
@@ -18,10 +18,12 @@ mod visitor;
 
 pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here
 
-pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup};
+pub use self::eval_context::{
+    Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind,
+};
 pub use self::intern::{intern_const_alloc_recursive, InternKind};
 pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
-pub use self::memory::{AllocCheck, FnVal, Memory, MemoryKind};
+pub use self::memory::{AllocCheck, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
 pub use self::operand::{ImmTy, Immediate, OpTy, Operand};
 pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
 pub use self::validity::{CtfeValidationMode, RefTracking};
diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs
index e5bc9320260..06432a8b902 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_mir/src/interpret/operand.rs
@@ -15,8 +15,8 @@ use rustc_target::abi::{Abi, HasDataLayout, LayoutOf, Size, TagEncoding};
 use rustc_target::abi::{VariantIdx, Variants};
 
 use super::{
-    from_known_layout, mir_assign_valid_types, ConstValue, GlobalId, InterpCx, InterpResult,
-    MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Scalar, ScalarMaybeUninit,
+    alloc_range, from_known_layout, mir_assign_valid_types, ConstValue, GlobalId, InterpCx,
+    InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Scalar, ScalarMaybeUninit,
 };
 
 /// An `Immediate` represents a single immediate self-contained Rust value.
@@ -249,19 +249,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             return Ok(None);
         }
 
-        let ptr = match self
-            .check_mplace_access(mplace, None)
-            .expect("places should be checked on creation")
-        {
+        let alloc = match self.get_alloc(mplace)? {
             Some(ptr) => ptr,
             None => {
-                if let Scalar::Ptr(ptr) = mplace.ptr {
-                    // We may be reading from a static.
-                    // In order to ensure that `static FOO: Type = FOO;` causes a cycle error
-                    // instead of magically pulling *any* ZST value from the ether, we need to
-                    // actually access the referenced allocation.
-                    self.memory.get_raw(ptr.alloc_id)?;
-                }
                 return Ok(Some(ImmTy {
                     // zero-sized type
                     imm: Scalar::ZST.into(),
@@ -270,11 +260,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
         };
 
-        let alloc = self.memory.get_raw(ptr.alloc_id)?;
-
         match mplace.layout.abi {
             Abi::Scalar(..) => {
-                let scalar = alloc.read_scalar(self, ptr, mplace.layout.size)?;
+                let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?;
                 Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout }))
             }
             Abi::ScalarPair(ref a, ref b) => {
@@ -283,12 +271,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
                 let (a, b) = (&a.value, &b.value);
                 let (a_size, b_size) = (a.size(self), b.size(self));
-                let a_ptr = ptr;
                 let b_offset = a_size.align_to(b.align(self).abi);
                 assert!(b_offset.bytes() > 0); // we later use the offset to tell apart the fields
-                let b_ptr = ptr.offset(b_offset, self)?;
-                let a_val = alloc.read_scalar(self, a_ptr, a_size)?;
-                let b_val = alloc.read_scalar(self, b_ptr, b_size)?;
+                let a_val = alloc.read_scalar(alloc_range(Size::ZERO, a_size))?;
+                let b_val = alloc.read_scalar(alloc_range(b_offset, b_size))?;
                 Ok(Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout }))
             }
             _ => Ok(None),
diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs
index d7c11aee21f..4c53510ed00 100644
--- a/compiler/rustc_mir/src/interpret/place.rs
+++ b/compiler/rustc_mir/src/interpret/place.rs
@@ -6,6 +6,7 @@ use std::convert::TryFrom;
 use std::fmt::Debug;
 use std::hash::Hash;
 
+use rustc_ast::Mutability;
 use rustc_macros::HashStable;
 use rustc_middle::mir;
 use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout};
@@ -14,8 +15,8 @@ use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding};
 use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants};
 
 use super::{
-    mir_assign_valid_types, AllocId, AllocMap, Allocation, AllocationExtra, ConstAlloc, ImmTy,
-    Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer,
+    alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, ConstAlloc, ImmTy, Immediate,
+    InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer,
     PointerArithmetic, Scalar, ScalarMaybeUninit,
 };
 
@@ -291,9 +292,6 @@ where
     // FIXME: Working around https://github.com/rust-lang/rust/issues/54385
     Tag: Debug + Copy + Eq + Hash + 'static,
     M: Machine<'mir, 'tcx, PointerTag = Tag>,
-    // FIXME: Working around https://github.com/rust-lang/rust/issues/24159
-    M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKind>, Allocation<Tag, M::AllocExtra>)>,
-    M::AllocExtra: AllocationExtra<Tag>,
 {
     /// Take a value, which represents a (thin or wide) reference, and make it a place.
     /// Alignment is just based on the type.  This is the inverse of `MemPlace::to_ref()`.
@@ -339,24 +337,26 @@ where
         self.mplace_access_checked(place, None)
     }
 
-    /// Check if the given place is good for memory access with the given
-    /// size, falling back to the layout's size if `None` (in the latter case,
-    /// this must be a statically sized type).
-    ///
-    /// On success, returns `None` for zero-sized accesses (where nothing else is
-    /// left to do) and a `Pointer` to use for the actual access otherwise.
     #[inline]
-    pub(super) fn check_mplace_access(
+    pub(super) fn get_alloc(
         &self,
         place: &MPlaceTy<'tcx, M::PointerTag>,
-        size: Option<Size>,
-    ) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> {
-        let size = size.unwrap_or_else(|| {
-            assert!(!place.layout.is_unsized());
-            assert!(!place.meta.has_meta());
-            place.layout.size
-        });
-        self.memory.check_ptr_access(place.ptr, size, place.align)
+    ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::PointerTag, M::AllocExtra>>> {
+        assert!(!place.layout.is_unsized());
+        assert!(!place.meta.has_meta());
+        let size = place.layout.size;
+        self.memory.get(place.ptr, size, place.align)
+    }
+
+    #[inline]
+    pub(super) fn get_alloc_mut(
+        &mut self,
+        place: &MPlaceTy<'tcx, M::PointerTag>,
+    ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::PointerTag, M::AllocExtra>>> {
+        assert!(!place.layout.is_unsized());
+        assert!(!place.meta.has_meta());
+        let size = place.layout.size;
+        self.memory.get_mut(place.ptr, size, place.align)
     }
 
     /// Return the "access-checked" version of this `MPlace`, where for non-ZST
@@ -373,10 +373,11 @@ where
             .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);
+        let align = force_align.unwrap_or(align);
+        // Record new (stricter, unless forced) alignment requirement in place.
+        place.mplace.align = 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.memory.check_ptr_access(place.ptr, size, align)? {
             place.mplace.ptr = ptr.into();
         }
         Ok(place)
@@ -786,12 +787,12 @@ where
         // wrong type.
 
         // Invalid places are a thing: the return place of a diverging function
-        let ptr = match self.check_mplace_access(dest, None)? {
-            Some(ptr) => ptr,
+        let tcx = *self.tcx;
+        let mut alloc = match self.get_alloc_mut(dest)? {
+            Some(a) => a,
             None => return Ok(()), // zero-sized access
         };
 
-        let tcx = *self.tcx;
         // FIXME: We should check that there are dest.layout.size many bytes available in
         // memory.  The code below is not sufficient, with enough padding it might not
         // cover all the bytes!
@@ -805,12 +806,7 @@ where
                         dest.layout
                     ),
                 }
-                self.memory.get_raw_mut(ptr.alloc_id)?.write_scalar(
-                    &tcx,
-                    ptr,
-                    scalar,
-                    dest.layout.size,
-                )
+                alloc.write_scalar(alloc_range(Size::ZERO, dest.layout.size), scalar)
             }
             Immediate::ScalarPair(a_val, b_val) => {
                 // We checked `ptr_align` above, so all fields will have the alignment they need.
@@ -824,16 +820,15 @@ where
                         dest.layout
                     ),
                 };
-                let (a_size, b_size) = (a.size(self), b.size(self));
-                let b_offset = a_size.align_to(b.align(self).abi);
-                let b_ptr = ptr.offset(b_offset, self)?;
+                let (a_size, b_size) = (a.size(&tcx), b.size(&tcx));
+                let b_offset = a_size.align_to(b.align(&tcx).abi);
 
                 // It is tempting to verify `b_offset` against `layout.fields.offset(1)`,
                 // but that does not work: We could be a newtype around a pair, then the
                 // fields do not match the `ScalarPair` components.
 
-                self.memory.get_raw_mut(ptr.alloc_id)?.write_scalar(&tcx, ptr, a_val, a_size)?;
-                self.memory.get_raw_mut(b_ptr.alloc_id)?.write_scalar(&tcx, b_ptr, b_val, b_size)
+                alloc.write_scalar(alloc_range(Size::ZERO, a_size), a_val)?;
+                alloc.write_scalar(alloc_range(b_offset, b_size), b_val)
             }
         }
     }
@@ -902,19 +897,8 @@ where
         });
         assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances");
 
-        let src = self
-            .check_mplace_access(&src, Some(size))
-            .expect("places should be checked on creation");
-        let dest = self
-            .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),
-            (None, None) => return Ok(()), // zero-sized copy
-            _ => bug!("The pointers should both be Some or both None"),
-        };
-
-        self.memory.copy(src_ptr, dest_ptr, size, /*nonoverlapping*/ true)
+        self.memory
+            .copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ true)
     }
 
     /// Copies the data from an operand to a place. The layouts may disagree, but they must
@@ -1039,21 +1023,23 @@ where
         MPlaceTy::from_aligned_ptr(ptr, layout)
     }
 
-    /// Returns a wide MPlace.
+    /// Returns a wide MPlace of type `&'static [mut] str` to a new 1-aligned allocation.
     pub fn allocate_str(
         &mut self,
         str: &str,
         kind: MemoryKind<M::MemoryKind>,
+        mutbl: Mutability,
     ) -> MPlaceTy<'tcx, M::PointerTag> {
-        let ptr = self.memory.allocate_bytes(str.as_bytes(), kind);
+        let ptr = self.memory.allocate_bytes(str.as_bytes(), Align::ONE, kind, mutbl);
         let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self);
-        let mplace = MemPlace {
-            ptr: ptr.into(),
-            align: Align::from_bytes(1).unwrap(),
-            meta: MemPlaceMeta::Meta(meta),
-        };
+        let mplace =
+            MemPlace { ptr: ptr.into(), align: Align::ONE, meta: MemPlaceMeta::Meta(meta) };
 
-        let layout = self.layout_of(self.tcx.mk_static_str()).unwrap();
+        let ty = self.tcx.mk_ref(
+            self.tcx.lifetimes.re_static,
+            ty::TypeAndMut { ty: self.tcx.types.str_, mutbl },
+        );
+        let layout = self.layout_of(ty).unwrap();
         MPlaceTy { mplace, layout }
     }
 
diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs
index 5a10ffe6d61..129dd8f8e01 100644
--- a/compiler/rustc_mir/src/interpret/step.rs
+++ b/compiler/rustc_mir/src/interpret/step.rs
@@ -222,28 +222,34 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
 
             Repeat(ref operand, _) => {
-                let op = self.eval_operand(operand, None)?;
+                let src = self.eval_operand(operand, None)?;
+                assert!(!src.layout.is_unsized());
                 let dest = self.force_allocation(&dest)?;
                 let length = dest.len(self)?;
 
-                if let Some(first_ptr) = self.check_mplace_access(&dest, None)? {
-                    // Write the first.
+                if length == 0 {
+                    // Nothing to copy... but let's still make sure that `dest` as a place is valid.
+                    self.get_alloc_mut(&dest)?;
+                } else {
+                    // Write the src to the first element.
                     let first = self.mplace_field(&dest, 0)?;
-                    self.copy_op(&op, &first.into())?;
-
-                    if length > 1 {
-                        let elem_size = first.layout.size;
-                        // Copy the rest. This is performance-sensitive code
-                        // for big static/const arrays!
-                        let rest_ptr = first_ptr.offset(elem_size, self)?;
-                        self.memory.copy_repeatedly(
-                            first_ptr,
-                            rest_ptr,
-                            elem_size,
-                            length - 1,
-                            /*nonoverlapping:*/ true,
-                        )?;
-                    }
+                    self.copy_op(&src, &first.into())?;
+
+                    // This is performance-sensitive code for big static/const arrays! So we
+                    // avoid writing each operand individually and instead just make many copies
+                    // of the first element.
+                    let elem_size = first.layout.size;
+                    let first_ptr = first.ptr;
+                    let rest_ptr = first_ptr.ptr_offset(elem_size, self)?;
+                    self.memory.copy_repeatedly(
+                        first_ptr,
+                        first.align,
+                        rest_ptr,
+                        first.align,
+                        elem_size,
+                        length - 1,
+                        /*nonoverlapping:*/ true,
+                    )?;
                 }
             }
 
diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs
index a7fcb41f74a..a5bdeb55e78 100644
--- a/compiler/rustc_mir/src/interpret/terminator.rs
+++ b/compiler/rustc_mir/src/interpret/terminator.rs
@@ -1,7 +1,8 @@
 use std::borrow::Cow;
 use std::convert::TryFrom;
 
-use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::ty::layout::{self, TyAndLayout};
 use rustc_middle::ty::Instance;
 use rustc_middle::{
     mir,
@@ -12,9 +13,19 @@ use rustc_target::spec::abi::Abi;
 
 use super::{
     FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, StackPopCleanup,
+    StackPopUnwind,
 };
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
+    fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool {
+        layout::fn_can_unwind(
+            self.tcx.sess.panic_strategy(),
+            attrs,
+            layout::conv_from_spec_abi(*self.tcx, abi),
+            abi,
+        )
+    }
+
     pub(super) fn eval_terminator(
         &mut self,
         terminator: &mir::Terminator<'tcx>,
@@ -58,12 +69,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 let old_stack = self.frame_idx();
                 let old_loc = self.frame().loc;
                 let func = self.eval_operand(func, None)?;
-                let (fn_val, abi) = match *func.layout.ty.kind() {
+                let (fn_val, abi, caller_can_unwind) = match *func.layout.ty.kind() {
                     ty::FnPtr(sig) => {
                         let caller_abi = sig.abi();
                         let fn_ptr = self.read_scalar(&func)?.check_init()?;
                         let fn_val = self.memory.get_fn(fn_ptr)?;
-                        (fn_val, caller_abi)
+                        (
+                            fn_val,
+                            caller_abi,
+                            self.fn_can_unwind(layout::fn_ptr_codegen_fn_attr_flags(), caller_abi),
+                        )
                     }
                     ty::FnDef(def_id, substs) => {
                         let sig = func.layout.ty.fn_sig(*self.tcx);
@@ -72,6 +87,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                                 self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?,
                             ),
                             sig.abi(),
+                            self.fn_can_unwind(self.tcx.codegen_fn_attrs(def_id).flags, sig.abi()),
                         )
                     }
                     _ => span_bug!(
@@ -89,7 +105,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     }
                     None => None,
                 };
-                self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?;
+                self.eval_fn_call(
+                    fn_val,
+                    abi,
+                    &args[..],
+                    ret,
+                    match (cleanup, caller_can_unwind) {
+                        (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup),
+                        (None, true) => StackPopUnwind::Skip,
+                        (_, false) => StackPopUnwind::NotAllowed,
+                    },
+                )?;
                 // Sanity-check that `eval_fn_call` either pushed a new frame or
                 // did a jump to another block.
                 if self.frame_idx() == old_stack && self.frame().loc == old_loc {
@@ -219,7 +245,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         caller_abi: Abi,
         args: &[OpTy<'tcx, M::PointerTag>],
         ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>,
-        unwind: Option<mir::BasicBlock>,
+        mut unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
         trace!("eval_fn_call: {:#?}", fn_val);
 
@@ -230,14 +256,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             }
         };
 
+        let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() {
+            ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
+            ty::Closure(..) => Abi::RustCall,
+            ty::Generator(..) => Abi::Rust,
+            _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
+        };
+
         // ABI check
-        let check_abi = |this: &Self, instance_ty: Ty<'tcx>| -> InterpResult<'tcx> {
-            let callee_abi = match instance_ty.kind() {
-                ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(),
-                ty::Closure(..) => Abi::RustCall,
-                ty::Generator(..) => Abi::Rust,
-                _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty),
-            };
+        let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> {
             let normalize_abi = |abi| match abi {
                 Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic =>
                 // These are all the same ABI, really.
@@ -258,7 +285,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
         match instance.def {
             ty::InstanceDef::Intrinsic(..) => {
-                check_abi(self, instance.ty(*self.tcx, self.param_env))?;
+                if M::enforce_abi(self) {
+                    check_abi(get_abi(self, instance.ty(*self.tcx, self.param_env)))?;
+                }
                 assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic);
                 M::call_intrinsic(self, instance, args, ret, unwind)
             }
@@ -279,7 +308,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 // Check against the ABI of the MIR body we are calling (not the ABI of `instance`;
                 // these can differ when `find_mir_or_eval_fn` does something clever like resolve
                 // exported symbol names).
-                check_abi(self, self.tcx.type_of(body.source.def_id()))?;
+                let callee_def_id = body.source.def_id();
+                let callee_abi = get_abi(self, self.tcx.type_of(callee_def_id));
+
+                if M::enforce_abi(self) {
+                    check_abi(callee_abi)?;
+                }
+
+                if !matches!(unwind, StackPopUnwind::NotAllowed)
+                    && !self
+                        .fn_can_unwind(self.tcx.codegen_fn_attrs(callee_def_id).flags, callee_abi)
+                {
+                    // The callee cannot unwind.
+                    unwind = StackPopUnwind::NotAllowed;
+                }
 
                 self.push_stack_frame(
                     instance,
@@ -469,7 +511,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             Abi::Rust,
             &[arg.into()],
             Some((&dest.into(), target)),
-            unwind,
+            match unwind {
+                Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
+                None => StackPopUnwind::Skip,
+            },
         )
     }
 }
diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs
index 50603bdd45b..11f8d388820 100644
--- a/compiler/rustc_mir/src/interpret/traits.rs
+++ b/compiler/rustc_mir/src/interpret/traits.rs
@@ -62,32 +62,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let drop = Instance::resolve_drop_in_place(tcx, ty);
         let drop = self.memory.create_fn_alloc(FnVal::Instance(drop));
 
+        // Prepare the fn ptrs we will write into the vtable later.
+        let fn_ptrs = methods
+            .iter()
+            .enumerate() // remember the original position
+            .filter_map(|(i, method)| {
+                if let Some((def_id, substs)) = method { Some((i, def_id, substs)) } else { None }
+            })
+            .map(|(i, def_id, substs)| {
+                let instance =
+                    ty::Instance::resolve_for_vtable(tcx, self.param_env, *def_id, substs)
+                        .ok_or_else(|| err_inval!(TooGeneric))?;
+                Ok((i, self.memory.create_fn_alloc(FnVal::Instance(instance))))
+            })
+            .collect::<InterpResult<'tcx, Vec<(usize, Pointer<M::PointerTag>)>>>()?;
+
         // No need to do any alignment checks on the memory accesses below, because we know the
         // allocation is correctly aligned as we created it above. Also we're only offsetting by
         // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
-        let vtable_alloc = self.memory.get_raw_mut(vtable.alloc_id)?;
-        vtable_alloc.write_ptr_sized(&tcx, vtable, drop.into())?;
-
-        let size_ptr = vtable.offset(ptr_size, &tcx)?;
-        vtable_alloc.write_ptr_sized(&tcx, size_ptr, Scalar::from_uint(size, ptr_size).into())?;
-        let align_ptr = vtable.offset(ptr_size * 2, &tcx)?;
-        vtable_alloc.write_ptr_sized(&tcx, align_ptr, Scalar::from_uint(align, ptr_size).into())?;
-
-        for (i, method) in methods.iter().enumerate() {
-            if let Some((def_id, substs)) = *method {
-                // resolve for vtable: insert shims where needed
-                let instance =
-                    ty::Instance::resolve_for_vtable(tcx, self.param_env, def_id, substs)
-                        .ok_or_else(|| err_inval!(TooGeneric))?;
-                let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
-                // We cannot use `vtable_allic` as we are creating fn ptrs in this loop.
-                let method_ptr = vtable.offset(ptr_size * (3 + i as u64), &tcx)?;
-                self.memory.get_raw_mut(vtable.alloc_id)?.write_ptr_sized(
-                    &tcx,
-                    method_ptr,
-                    fn_ptr.into(),
-                )?;
-            }
+        let mut vtable_alloc =
+            self.memory.get_mut(vtable.into(), vtable_size, ptr_align)?.expect("not a ZST");
+        vtable_alloc.write_ptr_sized(ptr_size * 0, drop.into())?;
+        vtable_alloc.write_ptr_sized(ptr_size * 1, Scalar::from_uint(size, ptr_size).into())?;
+        vtable_alloc.write_ptr_sized(ptr_size * 2, Scalar::from_uint(align, ptr_size).into())?;
+
+        for (i, fn_ptr) in fn_ptrs.into_iter() {
+            vtable_alloc.write_ptr_sized(ptr_size * (3 + i as u64), fn_ptr.into())?;
         }
 
         M::after_static_mem_initialized(self, vtable, vtable_size)?;
@@ -111,13 +111,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         let vtable_slot = vtable.ptr_offset(ptr_size * idx.checked_add(3).unwrap(), self)?;
         let vtable_slot = self
             .memory
-            .check_ptr_access(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)?
+            .get(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)?
             .expect("cannot be a ZST");
-        let fn_ptr = self
-            .memory
-            .get_raw(vtable_slot.alloc_id)?
-            .read_ptr_sized(self, vtable_slot)?
-            .check_init()?;
+        let fn_ptr = vtable_slot.read_ptr_sized(Size::ZERO)?.check_init()?;
         self.memory.get_fn(fn_ptr)
     }
 
@@ -129,14 +125,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // We don't care about the pointee type; we just want a pointer.
         let vtable = self
             .memory
-            .check_ptr_access(
-                vtable,
-                self.tcx.data_layout.pointer_size,
-                self.tcx.data_layout.pointer_align.abi,
-            )?
+            .get(vtable, self.tcx.data_layout.pointer_size, self.tcx.data_layout.pointer_align.abi)?
             .expect("cannot be a ZST");
-        let drop_fn =
-            self.memory.get_raw(vtable.alloc_id)?.read_ptr_sized(self, vtable)?.check_init()?;
+        let drop_fn = vtable.read_ptr_sized(Size::ZERO)?.check_init()?;
         // We *need* an instance here, no other kind of function value, to be able
         // to determine the type.
         let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?;
@@ -161,13 +152,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         // the size, and the align (which we read below).
         let vtable = self
             .memory
-            .check_ptr_access(vtable, 3 * pointer_size, self.tcx.data_layout.pointer_align.abi)?
+            .get(vtable, 3 * pointer_size, self.tcx.data_layout.pointer_align.abi)?
             .expect("cannot be a ZST");
-        let alloc = self.memory.get_raw(vtable.alloc_id)?;
-        let size = alloc.read_ptr_sized(self, vtable.offset(pointer_size, self)?)?.check_init()?;
+        let size = vtable.read_ptr_sized(pointer_size)?.check_init()?;
         let size = u64::try_from(self.force_bits(size, pointer_size)?).unwrap();
-        let align =
-            alloc.read_ptr_sized(self, vtable.offset(pointer_size * 2, self)?)?.check_init()?;
+        let align = vtable.read_ptr_sized(pointer_size * 2)?.check_init()?;
         let align = u64::try_from(self.force_bits(align, pointer_size)?).unwrap();
 
         if size >= self.tcx.data_layout.obj_size_bound() {
diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs
index 83b0d0528f7..fb165a991bc 100644
--- a/compiler/rustc_mir/src/interpret/validity.rs
+++ b/compiler/rustc_mir/src/interpret/validity.rs
@@ -15,13 +15,13 @@ use rustc_middle::mir::interpret::InterpError;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_span::symbol::{sym, Symbol};
-use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx, Variants};
+use rustc_target::abi::{Abi, LayoutOf, Scalar as ScalarAbi, Size, VariantIdx, Variants};
 
 use std::hash::Hash;
 
 use super::{
-    CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
-    ScalarMaybeUninit, ValueVisitor,
+    alloc_range, CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine,
+    MemPlaceMeta, OpTy, Scalar, ScalarMaybeUninit, ValueVisitor,
 };
 
 macro_rules! throw_validation_failure {
@@ -329,7 +329,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                     self.ecx.memory.check_ptr_access_align(
                         vtable,
                         3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align
-                        Some(self.ecx.tcx.data_layout.pointer_align.abi),
+                        self.ecx.tcx.data_layout.pointer_align.abi,
                         CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
                     ),
                     self.path,
@@ -411,11 +411,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
             // alignment should take attributes into account).
             .unwrap_or_else(|| (place.layout.size, place.layout.align.abi));
         // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines.
-        let ptr: Option<_> = try_validation!(
+        try_validation!(
             self.ecx.memory.check_ptr_access_align(
                 place.ptr,
                 size,
-                Some(align),
+                align,
                 CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
             ),
             self.path,
@@ -441,9 +441,18 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
         );
         // Recursive checking
         if let Some(ref mut ref_tracking) = self.ref_tracking {
-            if let Some(ptr) = ptr {
+            // Proceed recursively even for ZST, no reason to skip them!
+            // `!` is a ZST and we want to validate it.
+            // Normalize before handing `place` to tracking because that will
+            // check for duplicates.
+            let place = if size.bytes() > 0 {
+                self.ecx.force_mplace_ptr(place).expect("we already bounds-checked")
+            } else {
+                place
+            };
+            // Skip validation entirely for some external statics
+            if let Scalar::Ptr(ptr) = place.ptr {
                 // not a ZST
-                // Skip validation entirely for some external statics
                 let alloc_kind = self.ecx.tcx.get_global_alloc(ptr.alloc_id);
                 if let Some(GlobalAlloc::Static(did)) = alloc_kind {
                     assert!(!self.ecx.tcx.is_thread_local_static(did));
@@ -473,15 +482,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                     return Ok(());
                 }
             }
-            // Proceed recursively even for ZST, no reason to skip them!
-            // `!` is a ZST and we want to validate it.
-            // Normalize before handing `place` to tracking because that will
-            // check for duplicates.
-            let place = if size.bytes() > 0 {
-                self.ecx.force_mplace_ptr(place).expect("we already bounds-checked")
-            } else {
-                place
-            };
             let path = &self.path;
             ref_tracking.track(place, || {
                 // We need to clone the path anyway, make sure it gets created
@@ -638,7 +638,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
     fn visit_scalar(
         &mut self,
         op: &OpTy<'tcx, M::PointerTag>,
-        scalar_layout: &Scalar,
+        scalar_layout: &ScalarAbi,
     ) -> InterpResult<'tcx> {
         let value = self.read_scalar(op)?;
         let valid_range = &scalar_layout.valid_range;
@@ -851,16 +851,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                 let mplace = op.assert_mem_place(self.ecx);
                 // This is the length of the array/slice.
                 let len = mplace.len(self.ecx)?;
-                // Zero length slices have nothing to be checked.
-                if len == 0 {
-                    return Ok(());
-                }
                 // This is the element type size.
                 let layout = self.ecx.layout_of(tys)?;
                 // This is the size in bytes of the whole array. (This checks for overflow.)
                 let size = layout.size * len;
-                // Size is not 0, get a pointer.
-                let ptr = self.ecx.force_ptr(mplace.ptr)?;
 
                 // Optimization: we just check the entire range at once.
                 // NOTE: Keep this in sync with the handling of integer and float
@@ -872,10 +866,16 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                 // to reject those pointers, we just do not have the machinery to
                 // talk about parts of a pointer.
                 // We also accept uninit, for consistency with the slow path.
-                match self.ecx.memory.get_raw(ptr.alloc_id)?.check_bytes(
-                    self.ecx,
-                    ptr,
-                    size,
+                let alloc = match self.ecx.memory.get(mplace.ptr, size, mplace.align)? {
+                    Some(a) => a,
+                    None => {
+                        // Size 0, nothing more to check.
+                        return Ok(());
+                    }
+                };
+
+                match alloc.check_bytes(
+                    alloc_range(Size::ZERO, size),
                     /*allow_uninit_and_ptr*/ self.ctfe_mode.is_none(),
                 ) {
                     // In the happy case, we needn't check anything else.
@@ -885,12 +885,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
                         // For some errors we might be able to provide extra information.
                         // (This custom logic does not fit the `try_validation!` macro.)
                         match err.kind() {
-                            err_ub!(InvalidUninitBytes(Some(access))) => {
+                            err_ub!(InvalidUninitBytes(Some((_alloc_id, access)))) => {
                                 // Some byte was uninitialized, determine which
                                 // element that byte belongs to so we can
                                 // provide an index.
                                 let i = usize::try_from(
-                                    access.uninit_ptr.offset.bytes() / layout.size.bytes(),
+                                    access.uninit_offset.bytes() / layout.size.bytes(),
                                 )
                                 .unwrap();
                                 self.path.push(PathElem::ArrayElem(i));
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs
index 783aa9465c3..12a36976f1d 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_mir/src/lib.rs
@@ -12,22 +12,20 @@ Rust MIR: a lowered representation of Rust.
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![feature(exact_size_is_empty)]
-#![feature(exhaustive_patterns)]
 #![feature(iter_zip)]
 #![feature(never_type)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
+#![feature(slice_ptr_get)]
 #![feature(trusted_len)]
 #![feature(try_blocks)]
 #![feature(associated_type_defaults)]
 #![feature(stmt_expr_attributes)]
 #![feature(trait_alias)]
 #![feature(option_get_or_insert_default)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(once_cell)]
 #![feature(control_flow_enum)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs
index ef79f36b3b5..31cb5484bce 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -184,7 +184,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator};
 use rustc_errors::{ErrorReported, FatalError};
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
+use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::GrowableBitSet;
@@ -194,6 +194,7 @@ use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
 use rustc_middle::mir::visit::Visitor as MirVisitor;
 use rustc_middle::mir::{self, Local, Location};
 use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
 use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext};
@@ -342,7 +343,8 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<
         .collect()
 }
 
-// Collect all monomorphized items reachable from `starting_point`
+/// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a
+/// post-monorphization error is encountered during a collection step.
 fn collect_items_rec<'tcx>(
     tcx: TyCtxt<'tcx>,
     starting_point: Spanned<MonoItem<'tcx>>,
@@ -359,6 +361,31 @@ fn collect_items_rec<'tcx>(
     let mut neighbors = Vec::new();
     let recursion_depth_reset;
 
+    //
+    // Post-monomorphization errors MVP
+    //
+    // We can encounter errors while monomorphizing an item, but we don't have a good way of
+    // showing a complete stack of spans ultimately leading to collecting the erroneous one yet.
+    // (It's also currently unclear exactly which diagnostics and information would be interesting
+    // to report in such cases)
+    //
+    // This leads to suboptimal error reporting: a post-monomorphization error (PME) will be
+    // shown with just a spanned piece of code causing the error, without information on where
+    // it was called from. This is especially obscure if the erroneous mono item is in a
+    // dependency. See for example issue #85155, where, before minimization, a PME happened two
+    // crates downstream from libcore's stdarch, without a way to know which dependency was the
+    // cause.
+    //
+    // If such an error occurs in the current crate, its span will be enough to locate the
+    // source. If the cause is in another crate, the goal here is to quickly locate which mono
+    // item in the current crate is ultimately responsible for causing the error.
+    //
+    // To give at least _some_ context to the user: while collecting mono items, we check the
+    // error count. If it has changed, a PME occurred, and we trigger some diagnostics about the
+    // current step of mono items collection.
+    //
+    let error_count = tcx.sess.diagnostic().err_count();
+
     match starting_point.node {
         MonoItem::Static(def_id) => {
             let instance = Instance::mono(tcx, def_id);
@@ -411,6 +438,20 @@ fn collect_items_rec<'tcx>(
         }
     }
 
+    // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the
+    // mono item graph where the PME diagnostics are currently the most problematic (e.g. ones
+    // involving a dependency, and the lack of context is confusing) in this MVP, we focus on
+    // diagnostics on edges crossing a crate boundary: the collected mono items which are not
+    // defined in the local crate.
+    if tcx.sess.diagnostic().err_count() > error_count && starting_point.node.krate() != LOCAL_CRATE
+    {
+        let formatted_item = with_no_trimmed_paths(|| starting_point.node.to_string());
+        tcx.sess.span_note_without_error(
+            starting_point.span,
+            &format!("the above error was encountered while instantiating `{}`", formatted_item),
+        );
+    }
+
     record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map);
 
     for neighbour in neighbors {
diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs
index 16f5f14f563..dcbc9c523dc 100644
--- a/compiler/rustc_mir/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs
@@ -541,30 +541,6 @@ impl NonConstOp for UnionAccess {
     }
 }
 
-/// See [#64992].
-///
-/// [#64992]: https://github.com/rust-lang/rust/issues/64992
-#[derive(Debug)]
-pub struct UnsizingCast;
-impl NonConstOp for UnsizingCast {
-    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
-        if ccx.const_kind() != hir::ConstContext::ConstFn {
-            Status::Allowed
-        } else {
-            Status::Unstable(sym::const_fn_unsize)
-        }
-    }
-
-    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        feature_err(
-            &ccx.tcx.sess.parse_sess,
-            sym::const_fn_unsize,
-            span,
-            "unsizing casts to types besides slices are not allowed in const fn",
-        )
-    }
-}
-
 // Types that cannot appear in the signature or locals of a `const fn`.
 pub mod ty {
     use super::*;
diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs
index 63fc66f2b9f..ac3420ad339 100644
--- a/compiler/rustc_mir/src/transform/check_consts/validation.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs
@@ -10,9 +10,7 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC
 use rustc_middle::mir::*;
 use rustc_middle::ty::cast::CastTy;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{
-    self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut,
-};
+use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
 use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
 use rustc_span::{sym, Span, Symbol};
 use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
@@ -358,10 +356,9 @@ impl Validator<'mir, 'tcx> {
     }
 
     fn check_static(&mut self, def_id: DefId, span: Span) {
-        assert!(
-            !self.tcx.is_thread_local_static(def_id),
-            "tls access is checked in `Rvalue::ThreadLocalRef"
-        );
+        if self.tcx.is_thread_local_static(def_id) {
+            self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef");
+        }
         self.check_op_spanned(ops::StaticAccess, span)
     }
 
@@ -636,17 +633,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
                 _,
             ) => self.check_op(ops::FnPtrCast),
 
-            Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, cast_ty) => {
-                if let Some(TypeAndMut { ty, .. }) = cast_ty.builtin_deref(true) {
-                    let unsized_ty = self.tcx.struct_tail_erasing_lifetimes(ty, self.param_env);
-
-                    // Casting/coercing things to slices is fine.
-                    if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
-                        return;
-                    }
-                }
-
-                self.check_op(ops::UnsizingCast);
+            Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
+                // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur
+                // in the type of any local, which also excludes casts).
             }
 
             Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
@@ -763,12 +752,8 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
             | ProjectionElem::Field(..)
             | ProjectionElem::Index(_) => {
                 let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
-                match base_ty.ty_adt_def() {
-                    Some(def) if def.is_union() => {
-                        self.check_op(ops::UnionAccess);
-                    }
-
-                    _ => {}
+                if base_ty.is_union() {
+                    self.check_op(ops::UnionAccess);
                 }
             }
         }
diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs
index 955be8cc81e..103ddda1a1d 100644
--- a/compiler/rustc_mir/src/transform/check_unsafety.rs
+++ b/compiler/rustc_mir/src/transform/check_unsafety.rs
@@ -221,7 +221,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
             }
 
             let base_ty = base.ty(self.body, self.tcx).ty;
-            if base_ty.ty_adt_def().map_or(false, |adt| adt.is_union()) {
+            if base_ty.is_union() {
                 // If we did not hit a `Deref` yet and the overall place use is an assignment, the
                 // rules are different.
                 let assign_to_field = !saw_deref
@@ -376,6 +376,12 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
     /// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether
     /// the called function has target features the calling function hasn't.
     fn check_target_features(&mut self, func_did: DefId) {
+        // Unsafety isn't required on wasm targets. For more information see
+        // the corresponding check in typeck/src/collect.rs
+        if self.tcx.sess.target.options.is_like_wasm {
+            return;
+        }
+
         let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
         let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features;
 
diff --git a/compiler/rustc_mir/src/transform/const_goto.rs b/compiler/rustc_mir/src/transform/const_goto.rs
index b5c8b4bebc3..ba10b54c5ae 100644
--- a/compiler/rustc_mir/src/transform/const_goto.rs
+++ b/compiler/rustc_mir/src/transform/const_goto.rs
@@ -47,7 +47,7 @@ impl<'tcx> MirPass<'tcx> for ConstGoto {
         // if we applied optimizations, we potentially have some cfg to cleanup to
         // make it easier for further passes
         if should_simplify {
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
             simplify_locals(body, tcx);
         }
     }
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
index 5968bbbfca7..681d63c6fc9 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir/src/transform/const_prop.rs
@@ -33,6 +33,7 @@ use crate::interpret::{
     self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy,
     Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy,
     Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup,
+    StackPopUnwind,
 };
 use crate::transform::MirPass;
 
@@ -198,7 +199,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         _abi: Abi,
         _args: &[OpTy<'tcx>],
         _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
-        _unwind: Option<BasicBlock>,
+        _unwind: StackPopUnwind,
     ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> {
         Ok(None)
     }
@@ -208,7 +209,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
         _instance: ty::Instance<'tcx>,
         _args: &[OpTy<'tcx>],
         _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
-        _unwind: Option<BasicBlock>,
+        _unwind: StackPopUnwind,
     ) -> InterpResult<'tcx> {
         throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
     }
diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs
index 2397d627880..f6672335cb1 100644
--- a/compiler/rustc_mir/src/transform/coverage/debug.rs
+++ b/compiler/rustc_mir/src/transform/coverage/debug.rs
@@ -116,7 +116,6 @@ use crate::util::pretty;
 use crate::util::spanview::{self, SpanViewable};
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_index::vec::Idx;
 use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::{self, BasicBlock, TerminatorKind};
 use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs
index c41e71e09a4..912505c6598 100644
--- a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs
+++ b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs
@@ -26,7 +26,7 @@ impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
         if has_opts_to_apply {
             let mut opt_applier = OptApplier { tcx, duplicates };
             opt_applier.visit_body(body);
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
         }
     }
 }
diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs
index 29df86ca6cd..4f5a467a6ee 100644
--- a/compiler/rustc_mir/src/transform/dest_prop.rs
+++ b/compiler/rustc_mir/src/transform/dest_prop.rs
@@ -114,7 +114,7 @@ use rustc_middle::mir::{
     traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem,
     Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
 };
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::TyCtxt;
 
 // Empirical measurements have resulted in some observations:
 // - Running on a body with a single block and 500 locals takes barely any time
@@ -910,17 +910,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> {
 
             // Handle the "subtle case" described above by rejecting any `dest` that is or
             // projects through a union.
-            let is_union = |ty: Ty<'_>| {
-                if let ty::Adt(def, _) = ty.kind() {
-                    if def.is_union() {
-                        return true;
-                    }
-                }
-
-                false
-            };
             let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty);
-            if is_union(place_ty.ty) {
+            if place_ty.ty.is_union() {
                 return;
             }
             for elem in dest.projection {
@@ -930,7 +921,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> {
                 }
 
                 place_ty = place_ty.projection_ty(self.tcx, elem);
-                if is_union(place_ty.ty) {
+                if place_ty.ty.is_union() {
                     return;
                 }
             }
diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
index 7934d4ba849..07127042fa4 100644
--- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
+++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
@@ -164,7 +164,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
         // Since this optimization adds new basic blocks and invalidates others,
         // clean up the cfg to make it nicer for other passes
         if should_cleanup {
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
         }
     }
 }
diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs
index 003003a8abb..3560b4b1e86 100644
--- a/compiler/rustc_mir/src/transform/generator.rs
+++ b/compiler/rustc_mir/src/transform/generator.rs
@@ -964,7 +964,7 @@ fn create_generator_drop_shim<'tcx>(
 
     // Make sure we remove dead blocks to remove
     // unrelated code from the resume part of the function
-    simplify::remove_dead_blocks(&mut body);
+    simplify::remove_dead_blocks(tcx, &mut body);
 
     dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(()));
 
@@ -1137,7 +1137,7 @@ fn create_generator_resume_function<'tcx>(
 
     // Make sure we remove dead blocks to remove
     // unrelated code from the drop part of the function
-    simplify::remove_dead_blocks(body);
+    simplify::remove_dead_blocks(tcx, body);
 
     dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(()));
 }
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index b6f80763bc8..f1c95a84ade 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -57,7 +57,7 @@ impl<'tcx> MirPass<'tcx> for Inline {
         if inline(tcx, body) {
             debug!("running simplify cfg on {:?}", body.source);
             CfgSimplifier::new(body).simplify();
-            remove_dead_blocks(body);
+            remove_dead_blocks(tcx, body);
         }
     }
 }
diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs
index f7a9835353e..21b208a08c2 100644
--- a/compiler/rustc_mir/src/transform/match_branches.rs
+++ b/compiler/rustc_mir/src/transform/match_branches.rs
@@ -167,7 +167,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
         }
 
         if should_cleanup {
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
         }
     }
 }
diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs
index 4aaa0baa9f4..cd2db180552 100644
--- a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs
+++ b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs
@@ -38,6 +38,6 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
             }
         }
 
-        simplify::remove_dead_blocks(body)
+        simplify::remove_dead_blocks(tcx, body)
     }
 }
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index f6b1323e107..78e84419c62 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -415,11 +415,9 @@ impl<'tcx> Validator<'_, 'tcx> {
 
                     ProjectionElem::Field(..) => {
                         let base_ty = place_base.ty(self.body, self.tcx).ty;
-                        if let Some(def) = base_ty.ty_adt_def() {
+                        if base_ty.is_union() {
                             // No promotion of union field accesses.
-                            if def.is_union() {
-                                return Err(Unpromotable);
-                            }
+                            return Err(Unpromotable);
                         }
                     }
                 }
diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
index 5144d48750d..02e45021a0a 100644
--- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
@@ -36,7 +36,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
         // if we applied optimizations, we potentially have some cfg to cleanup to
         // make it easier for further passes
         if should_simplify {
-            simplify_cfg(body);
+            simplify_cfg(tcx, body);
         }
     }
 }
diff --git a/compiler/rustc_mir/src/transform/remove_zsts.rs b/compiler/rustc_mir/src/transform/remove_zsts.rs
index 70f7538dd57..a0f225e6de6 100644
--- a/compiler/rustc_mir/src/transform/remove_zsts.rs
+++ b/compiler/rustc_mir/src/transform/remove_zsts.rs
@@ -69,21 +69,14 @@ fn involves_a_union<'tcx>(
     tcx: TyCtxt<'tcx>,
 ) -> bool {
     let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty);
-    if is_union(place_ty.ty) {
+    if place_ty.ty.is_union() {
         return true;
     }
     for elem in place.projection {
         place_ty = place_ty.projection_ty(tcx, elem);
-        if is_union(place_ty.ty) {
+        if place_ty.ty.is_union() {
             return true;
         }
     }
     return false;
 }
-
-fn is_union(ty: Ty<'_>) -> bool {
-    match ty.kind() {
-        ty::Adt(def, _) if def.is_union() => true,
-        _ => false,
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs
index 65e2d096b20..7aebca77e6f 100644
--- a/compiler/rustc_mir/src/transform/simplify.rs
+++ b/compiler/rustc_mir/src/transform/simplify.rs
@@ -29,6 +29,7 @@
 
 use crate::transform::MirPass;
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::mir::coverage::*;
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
@@ -46,9 +47,9 @@ impl SimplifyCfg {
     }
 }
 
-pub fn simplify_cfg(body: &mut Body<'_>) {
+pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
     CfgSimplifier::new(body).simplify();
-    remove_dead_blocks(body);
+    remove_dead_blocks(tcx, body);
 
     // FIXME: Should probably be moved into some kind of pass manager
     body.basic_blocks_mut().raw.shrink_to_fit();
@@ -59,9 +60,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg {
         Cow::Borrowed(&self.label)
     }
 
-    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source);
-        simplify_cfg(body);
+        simplify_cfg(tcx, body);
     }
 }
 
@@ -286,7 +287,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
     }
 }
 
-pub fn remove_dead_blocks(body: &mut Body<'_>) {
+pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
     let reachable = traversal::reachable_as_bitset(body);
     let num_blocks = body.basic_blocks().len();
     if num_blocks == reachable.count() {
@@ -306,6 +307,11 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
         }
         used_blocks += 1;
     }
+
+    if tcx.sess.instrument_coverage() {
+        save_unreachable_coverage(basic_blocks, used_blocks);
+    }
+
     basic_blocks.raw.truncate(used_blocks);
 
     for block in basic_blocks {
@@ -315,6 +321,75 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
     }
 }
 
+/// Some MIR transforms can determine at compile time that a sequences of
+/// statements will never be executed, so they can be dropped from the MIR.
+/// For example, an `if` or `else` block that is guaranteed to never be executed
+/// because its condition can be evaluated at compile time, such as by const
+/// evaluation: `if false { ... }`.
+///
+/// Those statements are bypassed by redirecting paths in the CFG around the
+/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually
+/// include `Coverage` statements representing the Rust source code regions to
+/// be counted at runtime. Without these `Coverage` statements, the regions are
+/// lost, and the Rust source code will show no coverage information.
+///
+/// What we want to show in a coverage report is the dead code with coverage
+/// counts of `0`. To do this, we need to save the code regions, by injecting
+/// `Unreachable` coverage statements. These are non-executable statements whose
+/// code regions are still recorded in the coverage map, representing regions
+/// with `0` executions.
+fn save_unreachable_coverage(
+    basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
+    first_dead_block: usize,
+) {
+    let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| {
+        live_block.statements.iter().any(|statement| {
+            if let StatementKind::Coverage(coverage) = &statement.kind {
+                matches!(coverage.kind, CoverageKind::Counter { .. })
+            } else {
+                false
+            }
+        })
+    });
+    if !has_live_counters {
+        // If there are no live `Counter` `Coverage` statements anymore, don't
+        // move dead coverage to the `START_BLOCK`. Just allow the dead
+        // `Coverage` statements to be dropped with the dead blocks.
+        //
+        // The `generator::StateTransform` MIR pass can create atypical
+        // conditions, where all live `Counter`s are dropped from the MIR.
+        //
+        // At least one Counter per function is required by LLVM (and necessary,
+        // to add the `function_hash` to the counter's call to the LLVM
+        // intrinsic `instrprof.increment()`).
+        return;
+    }
+
+    // Retain coverage info for dead blocks, so coverage reports will still
+    // report `0` executions for the uncovered code regions.
+    let mut dropped_coverage = Vec::new();
+    for dead_block in basic_blocks.raw[first_dead_block..].iter() {
+        for statement in dead_block.statements.iter() {
+            if let StatementKind::Coverage(coverage) = &statement.kind {
+                if let Some(code_region) = &coverage.code_region {
+                    dropped_coverage.push((statement.source_info, code_region.clone()));
+                }
+            }
+        }
+    }
+
+    let start_block = &mut basic_blocks[START_BLOCK];
+    for (source_info, code_region) in dropped_coverage {
+        start_block.statements.push(Statement {
+            source_info,
+            kind: StatementKind::Coverage(box Coverage {
+                kind: CoverageKind::Unreachable,
+                code_region: Some(code_region),
+            }),
+        })
+    }
+}
+
 pub struct SimplifyLocals;
 
 impl<'tcx> MirPass<'tcx> for SimplifyLocals {
diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs
index 89fddc95c98..dd2ec39c066 100644
--- a/compiler/rustc_mir/src/transform/simplify_try.rs
+++ b/compiler/rustc_mir/src/transform/simplify_try.rs
@@ -558,7 +558,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
 
         if did_remove_blocks {
             // We have dead blocks now, so remove those.
-            simplify::remove_dead_blocks(body);
+            simplify::remove_dead_blocks(tcx, body);
         }
     }
 }
diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs
index 658c6b6e9db..e7fb6b4f6b4 100644
--- a/compiler/rustc_mir/src/transform/unreachable_prop.rs
+++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs
@@ -60,7 +60,7 @@ impl MirPass<'_> for UnreachablePropagation {
         }
 
         if replaced {
-            simplify::remove_dead_blocks(body);
+            simplify::remove_dead_blocks(tcx, body);
         }
     }
 }
diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs
index d009b0b1b23..835789069bb 100644
--- a/compiler/rustc_mir/src/transform/validate.rs
+++ b/compiler/rustc_mir/src/transform/validate.rs
@@ -11,8 +11,9 @@ use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
-    AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceRef,
-    Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind,
+    AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem,
+    PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+    TerminatorKind,
 };
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable};
@@ -217,6 +218,23 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
         self.super_operand(operand, location);
     }
 
+    fn visit_projection_elem(
+        &mut self,
+        local: Local,
+        proj_base: &[PlaceElem<'tcx>],
+        elem: PlaceElem<'tcx>,
+        context: PlaceContext,
+        location: Location,
+    ) {
+        if let ProjectionElem::Index(index) = elem {
+            let index_ty = self.body.local_decls[index].ty;
+            if index_ty != self.tcx.types.usize {
+                self.fail(location, format!("bad index ({:?} != usize)", index_ty))
+            }
+        }
+        self.super_projection_elem(local, proj_base, elem, context, location);
+    }
+
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         match &statement.kind {
             StatementKind::Assign(box (dest, rvalue)) => {
diff --git a/compiler/rustc_mir/src/util/generic_graph.rs b/compiler/rustc_mir/src/util/generic_graph.rs
index 6ce305a4821..770b52a4d4b 100644
--- a/compiler/rustc_mir/src/util/generic_graph.rs
+++ b/compiler/rustc_mir/src/util/generic_graph.rs
@@ -1,6 +1,5 @@
 use gsgdt::{Edge, Graph, Node, NodeStyle};
 use rustc_hir::def_id::DefId;
-use rustc_index::vec::Idx;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 808c6e3ff64..8426b24270d 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -1,8 +1,8 @@
 use crate::build::matches::ArmHasGuard;
 use crate::build::ForGuard::OutsideGuard;
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
-use crate::thir::*;
 use rustc_middle::mir::*;
+use rustc_middle::thir::*;
 use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
 use rustc_session::lint::Level;
 use rustc_span::Span;
@@ -12,18 +12,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         destination: Place<'tcx>,
         block: BasicBlock,
-        ast_block: &Block<'_, 'tcx>,
+        ast_block: &Block,
         source_info: SourceInfo,
     ) -> BlockAnd<()> {
         let Block {
             region_scope,
             opt_destruction_scope,
             span,
-            stmts,
+            ref stmts,
             expr,
             targeted_by_break,
             safety_mode,
         } = *ast_block;
+        let expr = expr.map(|expr| &self.thir[expr]);
         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 {
@@ -32,13 +33,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             destination,
                             block,
                             span,
-                            stmts,
+                            &stmts,
                             expr,
                             safety_mode,
                         ))
                     })
                 } else {
-                    this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode)
+                    this.ast_block_stmts(destination, block, span, &stmts, expr, safety_mode)
                 }
             })
         })
@@ -49,8 +50,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         destination: Place<'tcx>,
         mut block: BasicBlock,
         span: Span,
-        stmts: &[Stmt<'_, 'tcx>],
-        expr: Option<&Expr<'_, 'tcx>>,
+        stmts: &[StmtId],
+        expr: Option<&Expr<'tcx>>,
         safety_mode: BlockSafety,
     ) -> BlockAnd<()> {
         let this = self;
@@ -78,23 +79,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         this.update_source_scope_for_safety_mode(span, safety_mode);
 
         let source_info = this.source_info(span);
-        for Stmt { kind, opt_destruction_scope } in stmts {
+        for stmt in stmts {
+            let Stmt { ref kind, opt_destruction_scope } = this.thir[*stmt];
             match kind {
-                &StmtKind::Expr { scope, expr } => {
+                StmtKind::Expr { scope, expr } => {
                     this.block_context.push(BlockFrame::Statement { ignores_expr_result: true });
                     unpack!(
                         block = this.in_opt_scope(
                             opt_destruction_scope.map(|de| (de, source_info)),
                             |this| {
-                                let si = (scope, source_info);
+                                let si = (*scope, source_info);
                                 this.in_scope(si, LintLevel::Inherited, |this| {
-                                    this.stmt_expr(block, expr, Some(scope))
+                                    this.stmt_expr(block, &this.thir[*expr], Some(*scope))
                                 })
                             }
                         )
                     );
                 }
-                StmtKind::Let { remainder_scope, init_scope, pattern, initializer, lint_level } => {
+                StmtKind::Let {
+                    remainder_scope,
+                    init_scope,
+                    ref pattern,
+                    initializer,
+                    lint_level,
+                } => {
                     let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild);
                     this.block_context.push(BlockFrame::Statement { ignores_expr_result });
 
@@ -110,6 +118,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                     // Evaluate the initializer, if present.
                     if let Some(init) = initializer {
+                        let init = &this.thir[*init];
                         let initializer_span = init.span;
 
                         unpack!(
@@ -145,7 +154,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                         debug!("ast_block_stmts: pattern={:?}", pattern);
                         this.visit_primary_bindings(
-                            &pattern,
+                            pattern,
                             UserTypeProjections::none(),
                             &mut |this, _, _, _, node, span, _, _| {
                                 this.storage_live_binding(block, node, span, OutsideGuard, true);
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 57f56e2d092..5e305ebba2f 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -1,18 +1,20 @@
 //! See docs in build/expr/mod.rs
 
 use crate::build::Builder;
-use crate::thir::*;
 use rustc_middle::mir::*;
+use rustc_middle::thir::*;
 use rustc_middle::ty::CanonicalUserTypeAnnotation;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr`, yielding a compile-time constant. Assumes that
     /// `expr` is a valid compile-time constant!
-    crate fn as_constant(&mut self, expr: &Expr<'_, 'tcx>) -> Constant<'tcx> {
+    crate fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
         let this = self;
         let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
         match *kind {
-            ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value),
+            ExprKind::Scope { region_scope: _, lint_level: _, value } => {
+                this.as_constant(&this.thir[value])
+            }
             ExprKind::Literal { literal, user_ty, const_id: _ } => {
                 let user_ty = user_ty.map(|user_ty| {
                     this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index c393878e0b9..b2a1dbf4c52 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -2,9 +2,9 @@
 
 use crate::build::expr::category::Category;
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::thir::*;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
+use rustc_middle::thir::*;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Returns an operand suitable for use until the end of the current
@@ -17,7 +17,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn as_local_operand(
         &mut self,
         block: BasicBlock,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         let local_scope = self.local_scope();
         self.as_operand(block, Some(local_scope), expr)
@@ -74,7 +74,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn as_local_call_operand(
         &mut self,
         block: BasicBlock,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         let local_scope = self.local_scope();
         self.as_call_operand(block, Some(local_scope), expr)
@@ -93,7 +93,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         mut block: BasicBlock,
         scope: Option<region::Scope>,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         debug!("as_operand(block={:?}, expr={:?})", block, expr);
         let this = self;
@@ -101,8 +101,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
             let source_info = this.source_info(expr.span);
             let region_scope = (region_scope, source_info);
-            return this
-                .in_scope(region_scope, lint_level, |this| this.as_operand(block, scope, value));
+            return this.in_scope(region_scope, lint_level, |this| {
+                this.as_operand(block, scope, &this.thir[value])
+            });
         }
 
         let category = Category::of(&expr.kind).unwrap();
@@ -123,7 +124,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         mut block: BasicBlock,
         scope: Option<region::Scope>,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         debug!("as_call_operand(block={:?}, expr={:?})", block, expr);
         let this = self;
@@ -132,7 +133,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             let source_info = this.source_info(expr.span);
             let region_scope = (region_scope, source_info);
             return this.in_scope(region_scope, lint_level, |this| {
-                this.as_call_operand(block, scope, value)
+                this.as_call_operand(block, scope, &this.thir[value])
             });
         }
 
@@ -151,7 +152,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // type, and that value is coming from the deref of a box.
                 if let ExprKind::Deref { arg } = expr.kind {
                     // Generate let tmp0 = arg0
-                    let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut));
+                    let operand = unpack!(
+                        block = this.as_temp(block, scope, &this.thir[arg], Mutability::Mut)
+                    );
 
                     // Return the operand *tmp0 to be used as the call argument
                     let place = Place {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 1053890e618..5511cd4c73b 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -3,13 +3,13 @@
 use crate::build::expr::category::Category;
 use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::thir::*;
 use rustc_hir::def_id::DefId;
 use rustc_hir::HirId;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::middle::region;
 use rustc_middle::mir::AssertKind::BoundsCheck;
 use rustc_middle::mir::*;
+use rustc_middle::thir::*;
 use rustc_middle::ty::AdtDef;
 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance};
 use rustc_span::Span;
@@ -209,9 +209,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
     match from_builder.base {
         PlaceBase::Local(_) => Ok(from_builder),
         PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => {
-            // Captures are represented using fields inside a structure.
-            // This represents accessing self in the closure structure
-            let mut upvar_resolved_place_builder = PlaceBuilder::from(Local::new(1));
+            let mut upvar_resolved_place_builder = PlaceBuilder::from(ty::CAPTURE_STRUCT_LOCAL);
             match closure_kind {
                 ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
                     upvar_resolved_place_builder = upvar_resolved_place_builder.deref();
@@ -381,7 +379,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn as_place(
         &mut self,
         mut block: BasicBlock,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
     ) -> BlockAnd<Place<'tcx>> {
         let place_builder = unpack!(block = self.as_place_builder(block, expr));
         block.and(place_builder.into_place(self.tcx, self.typeck_results))
@@ -392,7 +390,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn as_place_builder(
         &mut self,
         block: BasicBlock,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
         self.expr_as_place(block, expr, Mutability::Mut, None)
     }
@@ -405,7 +403,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn as_read_only_place(
         &mut self,
         mut block: BasicBlock,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
     ) -> BlockAnd<Place<'tcx>> {
         let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
         block.and(place_builder.into_place(self.tcx, self.typeck_results))
@@ -420,7 +418,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn as_read_only_place_builder(
         &mut self,
         block: BasicBlock,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
         self.expr_as_place(block, expr, Mutability::Not, None)
     }
@@ -428,7 +426,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn expr_as_place(
         &mut self,
         mut block: BasicBlock,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
         mutability: Mutability,
         fake_borrow_temps: Option<&mut Vec<Local>>,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
@@ -440,23 +438,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         match expr.kind {
             ExprKind::Scope { region_scope, lint_level, value } => {
                 this.in_scope((region_scope, source_info), lint_level, |this| {
-                    this.expr_as_place(block, value, mutability, fake_borrow_temps)
+                    this.expr_as_place(block, &this.thir[value], mutability, fake_borrow_temps)
                 })
             }
             ExprKind::Field { lhs, name } => {
-                let place_builder =
-                    unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,));
+                let place_builder = unpack!(
+                    block =
+                        this.expr_as_place(block, &this.thir[lhs], mutability, fake_borrow_temps,)
+                );
                 block.and(place_builder.field(name, expr.ty))
             }
             ExprKind::Deref { arg } => {
-                let place_builder =
-                    unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,));
+                let place_builder = unpack!(
+                    block =
+                        this.expr_as_place(block, &this.thir[arg], mutability, fake_borrow_temps,)
+                );
                 block.and(place_builder.deref())
             }
             ExprKind::Index { lhs, index } => this.lower_index_expression(
                 block,
-                lhs,
-                index,
+                &this.thir[lhs],
+                &this.thir[index],
                 mutability,
                 fake_borrow_temps,
                 expr.temp_lifetime,
@@ -481,7 +483,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             ExprKind::PlaceTypeAscription { source, user_ty } => {
                 let place_builder = unpack!(
-                    block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
+                    block = this.expr_as_place(
+                        block,
+                        &this.thir[source],
+                        mutability,
+                        fake_borrow_temps,
+                    )
                 );
                 if let Some(user_ty) = user_ty {
                     let annotation_index =
@@ -509,6 +516,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.and(place_builder)
             }
             ExprKind::ValueTypeAscription { source, user_ty } => {
+                let source = &this.thir[source];
                 let temp =
                     unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability));
                 if let Some(user_ty) = user_ty {
@@ -613,8 +621,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn lower_index_expression(
         &mut self,
         mut block: BasicBlock,
-        base: &Expr<'_, 'tcx>,
-        index: &Expr<'_, 'tcx>,
+        base: &Expr<'tcx>,
+        index: &Expr<'tcx>,
         mutability: Mutability,
         fake_borrow_temps: Option<&mut Vec<Local>>,
         temp_lifetime: Option<region::Scope>,
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 822fbd91c94..69786c14ee8 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -5,11 +5,11 @@ use rustc_index::vec::Idx;
 use crate::build::expr::as_place::PlaceBase;
 use crate::build::expr::category::{Category, RvalueFunc};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::thir::*;
 use rustc_middle::middle::region;
 use rustc_middle::mir::AssertKind;
 use rustc_middle::mir::Place;
 use rustc_middle::mir::*;
+use rustc_middle::thir::*;
 use rustc_middle::ty::{self, Ty, UpvarSubsts};
 use rustc_span::Span;
 
@@ -23,7 +23,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn as_local_rvalue(
         &mut self,
         block: BasicBlock,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
     ) -> BlockAnd<Rvalue<'tcx>> {
         let local_scope = self.local_scope();
         self.as_rvalue(block, Some(local_scope), expr)
@@ -34,7 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         mut block: BasicBlock,
         scope: Option<region::Scope>,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
     ) -> BlockAnd<Rvalue<'tcx>> {
         debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr);
 
@@ -46,19 +46,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             ExprKind::ThreadLocalRef(did) => block.and(Rvalue::ThreadLocalRef(did)),
             ExprKind::Scope { region_scope, lint_level, value } => {
                 let region_scope = (region_scope, source_info);
-                this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value))
+                this.in_scope(region_scope, lint_level, |this| {
+                    this.as_rvalue(block, scope, &this.thir[value])
+                })
             }
             ExprKind::Repeat { value, count } => {
-                let value_operand = unpack!(block = this.as_operand(block, scope, value));
+                let value_operand =
+                    unpack!(block = this.as_operand(block, scope, &this.thir[value]));
                 block.and(Rvalue::Repeat(value_operand, count))
             }
             ExprKind::Binary { op, lhs, rhs } => {
-                let lhs = unpack!(block = this.as_operand(block, scope, lhs));
-                let rhs = unpack!(block = this.as_operand(block, scope, rhs));
+                let lhs = unpack!(block = this.as_operand(block, scope, &this.thir[lhs]));
+                let rhs = unpack!(block = this.as_operand(block, scope, &this.thir[rhs]));
                 this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs)
             }
             ExprKind::Unary { op, arg } => {
-                let arg = unpack!(block = this.as_operand(block, scope, arg));
+                let arg = unpack!(block = this.as_operand(block, scope, &this.thir[arg]));
                 // Check for -MIN on signed integers
                 if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() {
                     let bool_ty = this.tcx.types.bool;
@@ -84,6 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.and(Rvalue::UnaryOp(op, arg))
             }
             ExprKind::Box { value } => {
+                let value = &this.thir[value];
                 // The `Box<T>` temporary created here is not a part of the HIR,
                 // and therefore is not considered during generator auto-trait
                 // determination. See the comment about `box` at `yield_in_scope`.
@@ -112,14 +116,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.and(Rvalue::Use(Operand::Move(Place::from(result))))
             }
             ExprKind::Cast { source } => {
-                let source = unpack!(block = this.as_operand(block, scope, source));
+                let source = unpack!(block = this.as_operand(block, scope, &this.thir[source]));
                 block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty))
             }
             ExprKind::Pointer { cast, source } => {
-                let source = unpack!(block = this.as_operand(block, scope, source));
+                let source = unpack!(block = this.as_operand(block, scope, &this.thir[source]));
                 block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty))
             }
-            ExprKind::Array { fields } => {
+            ExprKind::Array { ref fields } => {
                 // (*) We would (maybe) be closer to codegen if we
                 // handled this and other aggregate cases via
                 // `into()`, not `as_rvalue` -- in that case, instead
@@ -150,22 +154,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let el_ty = expr.ty.sequence_element_type(this.tcx);
                 let fields: Vec<_> = fields
                     .into_iter()
-                    .map(|f| unpack!(block = this.as_operand(block, scope, f)))
+                    .copied()
+                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f])))
                     .collect();
 
                 block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
             }
-            ExprKind::Tuple { fields } => {
+            ExprKind::Tuple { ref fields } => {
                 // see (*) above
                 // first process the set of fields
                 let fields: Vec<_> = fields
                     .into_iter()
-                    .map(|f| unpack!(block = this.as_operand(block, scope, f)))
+                    .copied()
+                    .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f])))
                     .collect();
 
                 block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
             }
-            ExprKind::Closure { closure_id, substs, upvars, movability, ref fake_reads } => {
+            ExprKind::Closure { closure_id, substs, ref upvars, movability, ref fake_reads } => {
                 // Convert the closure fake reads, if any, from `ExprRef` to mir `Place`
                 // and push the fake reads.
                 // This must come before creating the operands. This is required in case
@@ -179,8 +185,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 //     match x { _ => () } // fake read of `x`
                 // };
                 // ```
+                //
                 for (thir_place, cause, hir_id) in fake_reads.into_iter() {
-                    let place_builder = unpack!(block = this.as_place_builder(block, thir_place));
+                    let place_builder =
+                        unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
 
                     if let Ok(place_builder_resolved) =
                         place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
@@ -199,7 +207,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // see (*) above
                 let operands: Vec<_> = upvars
                     .into_iter()
+                    .copied()
                     .map(|upvar| {
+                        let upvar = &this.thir[upvar];
                         match Category::of(&upvar.kind) {
                             // Use as_place to avoid creating a temporary when
                             // moving a variable into a closure, so that
@@ -225,7 +235,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                         arg,
                                     } => unpack!(
                                         block = this.limit_capture_mutability(
-                                            upvar.span, upvar.ty, scope, block, arg,
+                                            upvar.span,
+                                            upvar.ty,
+                                            scope,
+                                            block,
+                                            &this.thir[arg],
                                         )
                                     ),
                                     _ => unpack!(block = this.as_operand(block, scope, upvar)),
@@ -398,7 +412,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         upvar_ty: Ty<'tcx>,
         temp_lifetime: Option<region::Scope>,
         mut block: BasicBlock,
-        arg: &Expr<'_, 'tcx>,
+        arg: &Expr<'tcx>,
     ) -> BlockAnd<Operand<'tcx>> {
         let this = self;
 
@@ -433,7 +447,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     } => {
                         // Not in a closure
                         debug_assert!(
-                            local == Local::new(1),
+                            local == ty::CAPTURE_STRUCT_LOCAL,
                             "Expected local to be Local(1), found {:?}",
                             local
                         );
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 98b910ab21c..45e0243c88a 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs
@@ -2,10 +2,10 @@
 
 use crate::build::scope::DropKind;
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
-use crate::thir::*;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
+use rustc_middle::thir::*;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Compile `expr` into a fresh temporary. This is used when building
@@ -14,7 +14,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         block: BasicBlock,
         temp_lifetime: Option<region::Scope>,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
         mutability: Mutability,
     ) -> BlockAnd<Local> {
         // this is the only place in mir building that we need to truly need to worry about
@@ -27,7 +27,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         mut block: BasicBlock,
         temp_lifetime: Option<region::Scope>,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
         mutability: Mutability,
     ) -> BlockAnd<Local> {
         debug!(
@@ -40,7 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         let source_info = this.source_info(expr_span);
         if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind {
             return this.in_scope((region_scope, source_info), lint_level, |this| {
-                this.as_temp(block, temp_lifetime, value, mutability)
+                this.as_temp(block, temp_lifetime, &this.thir[value], mutability)
             });
         }
 
diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs
index 0cadfa2f0a1..c834ce6ce68 100644
--- a/compiler/rustc_mir_build/src/build/expr/category.rs
+++ b/compiler/rustc_mir_build/src/build/expr/category.rs
@@ -1,4 +1,4 @@
-use crate::thir::*;
+use rustc_middle::thir::*;
 
 #[derive(Debug, PartialEq)]
 crate enum Category {
@@ -31,7 +31,7 @@ crate enum RvalueFunc {
 /// Determines the category for a given expression. Note that scope
 /// and paren expressions have no category.
 impl Category {
-    crate fn of(ek: &ExprKind<'_, '_>) -> Option<Category> {
+    crate fn of(ek: &ExprKind<'_>) -> Option<Category> {
         match *ek {
             ExprKind::Scope { .. } => None,
 
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 1e7ed3d95d2..f2b00f0f6ed 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -2,13 +2,13 @@
 
 use crate::build::expr::category::{Category, RvalueFunc};
 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_index::vec::Idx;
 use rustc_middle::mir::*;
+use rustc_middle::thir::*;
 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
 use std::iter;
 
@@ -19,7 +19,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         destination: Place<'tcx>,
         mut block: BasicBlock,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
     ) -> BlockAnd<()> {
         debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
 
@@ -42,19 +42,24 @@ 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.expr_into_dest(destination, block, value)
+                        this.expr_into_dest(destination, block, &this.thir[value])
                     })
                 })
             }
             ExprKind::Block { body: ref ast_block } => {
                 this.ast_block(destination, block, ast_block, source_info)
             }
-            ExprKind::Match { scrutinee, arms } => {
-                this.match_expr(destination, expr_span, block, scrutinee, arms)
+            ExprKind::Match { scrutinee, ref arms } => {
+                this.match_expr(destination, expr_span, block, &this.thir[scrutinee], arms)
             }
             ExprKind::If { cond, then, else_opt } => {
                 let place = unpack!(
-                    block = this.as_temp(block, Some(this.local_scope()), cond, Mutability::Mut)
+                    block = this.as_temp(
+                        block,
+                        Some(this.local_scope()),
+                        &this.thir[cond],
+                        Mutability::Mut
+                    )
                 );
                 let operand = Operand::Move(Place::from(place));
 
@@ -63,9 +68,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let term = TerminatorKind::if_(this.tcx, operand, then_block, else_block);
                 this.cfg.terminate(block, source_info, term);
 
-                unpack!(then_block = this.expr_into_dest(destination, then_block, then));
+                unpack!(
+                    then_block = this.expr_into_dest(destination, then_block, &this.thir[then])
+                );
                 else_block = if let Some(else_opt) = else_opt {
-                    unpack!(this.expr_into_dest(destination, else_block, else_opt))
+                    unpack!(this.expr_into_dest(destination, else_block, &this.thir[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.
@@ -89,6 +96,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 join_block.unit()
             }
             ExprKind::NeverToAny { source } => {
+                let source = &this.thir[source];
                 let is_call =
                     matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. });
 
@@ -127,7 +135,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     this.cfg.start_new_block(),
                 );
 
-                let lhs = unpack!(block = this.as_local_operand(block, lhs));
+                let lhs = unpack!(block = this.as_local_operand(block, &this.thir[lhs]));
                 let blocks = match op {
                     LogicalOp::And => (else_block, shortcircuit_block),
                     LogicalOp::Or => (shortcircuit_block, else_block),
@@ -150,7 +158,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 );
                 this.cfg.goto(shortcircuit_block, source_info, join_block);
 
-                let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs));
+                let rhs = unpack!(else_block = this.as_local_operand(else_block, &this.thir[rhs]));
                 this.cfg.push_assign(else_block, source_info, destination, Rvalue::Use(rhs));
                 this.cfg.goto(else_block, source_info, join_block);
 
@@ -186,18 +194,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     // 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.expr_into_dest(tmp, body_block, body));
+                    let body_block_end =
+                        unpack!(this.expr_into_dest(tmp, body_block, &this.thir[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));
+            ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => {
+                let fun = unpack!(block = this.as_local_operand(block, &this.thir[fun]));
                 let args: Vec<_> = args
                     .into_iter()
-                    .map(|arg| unpack!(block = this.as_local_call_operand(block, arg)))
+                    .copied()
+                    .map(|arg| unpack!(block = this.as_local_call_operand(block, &this.thir[arg])))
                     .collect();
 
                 let success = this.cfg.start_new_block();
@@ -228,8 +238,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 this.diverge_from(block);
                 success.unit()
             }
-            ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
+            ExprKind::Use { source } => this.expr_into_dest(destination, block, &this.thir[source]),
             ExprKind::Borrow { arg, borrow_kind } => {
+                let arg = &this.thir[arg];
                 // We don't do this in `as_rvalue` because we use `as_place`
                 // for borrow expressions, so we cannot create an `RValue` that
                 // remains valid across user code. `as_rvalue` is usually called
@@ -244,6 +255,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.unit()
             }
             ExprKind::AddressOf { mutability, arg } => {
+                let arg = &this.thir[arg];
                 let place = match mutability {
                     hir::Mutability::Not => this.as_read_only_place(block, arg),
                     hir::Mutability::Mut => this.as_place(block, arg),
@@ -252,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 this.cfg.push_assign(block, source_info, destination, address_of);
                 block.unit()
             }
-            ExprKind::Adt { adt_def, variant_index, substs, user_ty, fields, ref base } => {
+            ExprKind::Adt { adt_def, variant_index, substs, user_ty, ref fields, ref base } => {
                 // See the notes for `ExprKind::Array` in `as_rvalue` and for
                 // `ExprKind::Borrow` above.
                 let is_union = adt_def.is_union();
@@ -264,19 +276,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // (evaluating them in order given by user)
                 let fields_map: FxHashMap<_, _> = fields
                     .into_iter()
-                    .map(|f| (f.name, unpack!(block = this.as_operand(block, Some(scope), f.expr))))
+                    .map(|f| {
+                        (
+                            f.name,
+                            unpack!(
+                                block = this.as_operand(block, Some(scope), &this.thir[f.expr])
+                            ),
+                        )
+                    })
                     .collect();
 
                 let field_names: Vec<_> =
                     (0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect();
 
                 let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
-                    let place_builder = unpack!(block = this.as_place_builder(block, base));
+                    let place_builder =
+                        unpack!(block = this.as_place_builder(block, &this.thir[*base]));
 
                     // MIR does not natively support FRU, so for each
                     // base-supplied field, generate an operand that
                     // reads it from the base.
-                    iter::zip(field_names, *field_types)
+                    iter::zip(field_names, &**field_types)
                         .map(|(n, ty)| match fields_map.get(&n) {
                             Some(v) => v.clone(),
                             None => {
@@ -316,27 +336,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 );
                 block.unit()
             }
-            ExprKind::InlineAsm { template, operands, options, line_spans } => {
-                use crate::thir;
-                use rustc_middle::mir;
+            ExprKind::InlineAsm { template, ref operands, options, line_spans } => {
+                use rustc_middle::{mir, thir};
                 let operands = operands
                     .into_iter()
                     .map(|op| match *op {
                         thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In {
                             reg,
-                            value: unpack!(block = this.as_local_operand(block, expr)),
+                            value: unpack!(block = this.as_local_operand(block, &this.thir[expr])),
                         },
                         thir::InlineAsmOperand::Out { reg, late, expr } => {
                             mir::InlineAsmOperand::Out {
                                 reg,
                                 late,
-                                place: expr
-                                    .as_ref()
-                                    .map(|expr| unpack!(block = this.as_place(block, expr))),
+                                place: expr.map(|expr| {
+                                    unpack!(block = this.as_place(block, &this.thir[expr]))
+                                }),
                             }
                         }
                         thir::InlineAsmOperand::InOut { reg, late, expr } => {
-                            let place = unpack!(block = this.as_place(block, expr));
+                            let place = unpack!(block = this.as_place(block, &this.thir[expr]));
                             mir::InlineAsmOperand::InOut {
                                 reg,
                                 late,
@@ -349,9 +368,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             mir::InlineAsmOperand::InOut {
                                 reg,
                                 late,
-                                in_value: unpack!(block = this.as_local_operand(block, in_expr)),
-                                out_place: out_expr.as_ref().map(|out_expr| {
-                                    unpack!(block = this.as_place(block, out_expr))
+                                in_value: unpack!(
+                                    block = this.as_local_operand(block, &this.thir[in_expr])
+                                ),
+                                out_place: out_expr.map(|out_expr| {
+                                    unpack!(block = this.as_place(block, &this.thir[out_expr]))
                                 }),
                             }
                         }
@@ -360,9 +381,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 value: box Constant { span, user_ty: None, literal: value.into() },
                             }
                         }
-                        thir::InlineAsmOperand::SymFn { expr } => {
-                            mir::InlineAsmOperand::SymFn { value: box this.as_constant(expr) }
-                        }
+                        thir::InlineAsmOperand::SymFn { expr } => mir::InlineAsmOperand::SymFn {
+                            value: box this.as_constant(&this.thir[expr]),
+                        },
                         thir::InlineAsmOperand::SymStatic { def_id } => {
                             mir::InlineAsmOperand::SymStatic { def_id }
                         }
@@ -434,7 +455,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             ExprKind::Yield { value } => {
                 let scope = this.local_scope();
-                let value = unpack!(block = this.as_operand(block, Some(scope), value));
+                let value = unpack!(block = this.as_operand(block, Some(scope), &this.thir[value]));
                 let resume = this.cfg.start_new_block();
                 this.cfg.terminate(
                     block,
diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs
index f01315fc5db..b03a6bb1a2b 100644
--- a/compiler/rustc_mir_build/src/build/expr/stmt.rs
+++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs
@@ -1,8 +1,8 @@
 use crate::build::scope::BreakableTarget;
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
-use crate::thir::*;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
+use rustc_middle::thir::*;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Builds a block of MIR statements to evaluate the THIR `expr`.
@@ -13,7 +13,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn stmt_expr(
         &mut self,
         mut block: BasicBlock,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
         statement_scope: Option<region::Scope>,
     ) -> BlockAnd<()> {
         let this = self;
@@ -24,10 +24,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         match expr.kind {
             ExprKind::Scope { region_scope, lint_level, value } => {
                 this.in_scope((region_scope, source_info), lint_level, |this| {
-                    this.stmt_expr(block, value, statement_scope)
+                    this.stmt_expr(block, &this.thir[value], statement_scope)
                 })
             }
             ExprKind::Assign { lhs, rhs } => {
+                let lhs = &this.thir[lhs];
+                let rhs = &this.thir[rhs];
                 let lhs_span = lhs.span;
 
                 // Note: we evaluate assignments right-to-left. This
@@ -61,6 +63,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // only affects weird things like `x += {x += 1; x}`
                 // -- is that equal to `x + (x + 1)` or `2*(x+1)`?
 
+                let lhs = &this.thir[lhs];
+                let rhs = &this.thir[rhs];
                 let lhs_ty = lhs.ty;
 
                 debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr);
@@ -87,24 +91,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             ExprKind::Break { label, value } => this.break_scope(
                 block,
-                value.as_deref(),
+                value.map(|value| &this.thir[value]),
                 BreakableTarget::Break(label),
                 source_info,
             ),
-            ExprKind::Return { value } => {
-                this.break_scope(block, value.as_deref(), BreakableTarget::Return, source_info)
-            }
-            ExprKind::LlvmInlineAsm { asm, outputs, inputs } => {
+            ExprKind::Return { value } => this.break_scope(
+                block,
+                value.map(|value| &this.thir[value]),
+                BreakableTarget::Return,
+                source_info,
+            ),
+            ExprKind::LlvmInlineAsm { asm, ref outputs, ref inputs } => {
                 debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr);
                 this.block_context.push(BlockFrame::SubExpr);
                 let outputs = outputs
                     .into_iter()
-                    .map(|output| unpack!(block = this.as_place(block, &output)))
+                    .copied()
+                    .map(|output| unpack!(block = this.as_place(block, &this.thir[output])))
                     .collect::<Vec<_>>()
                     .into_boxed_slice();
                 let inputs = inputs
                     .into_iter()
+                    .copied()
                     .map(|input| {
+                        let input = &this.thir[input];
                         (input.span, unpack!(block = this.as_local_operand(block, &input)))
                     })
                     .collect::<Vec<_>>()
@@ -139,14 +149,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 // than the entirety of block(s) surrounding it.
                 let adjusted_span = (|| {
                     if let ExprKind::Block { body } = &expr.kind {
-                        if let Some(tail_expr) = &body.expr {
-                            let mut expr = &*tail_expr;
+                        if let Some(tail_expr) = body.expr {
+                            let mut expr = &this.thir[tail_expr];
                             while let ExprKind::Block {
                                 body: Block { expr: Some(nested_expr), .. },
                             }
-                            | ExprKind::Scope { value: nested_expr, .. } = &expr.kind
+                            | ExprKind::Scope { value: nested_expr, .. } = expr.kind
                             {
-                                expr = nested_expr;
+                                expr = &this.thir[nested_expr];
                             }
                             this.block_context.push(BlockFrame::TailExpr {
                                 tail_result_is_ignored: true,
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 0e422dc3c63..8164529dd1f 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -10,7 +10,6 @@ use crate::build::scope::DropKind;
 use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
 use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
-use crate::thir::{self, *};
 use rustc_data_structures::{
     fx::{FxHashSet, FxIndexMap},
     stack::ensure_sufficient_stack,
@@ -19,6 +18,7 @@ use rustc_hir::HirId;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
+use rustc_middle::thir::{self, *};
 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
@@ -90,8 +90,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         destination: Place<'tcx>,
         span: Span,
         mut block: BasicBlock,
-        scrutinee: &Expr<'_, 'tcx>,
-        arms: &[Arm<'_, 'tcx>],
+        scrutinee: &Expr<'tcx>,
+        arms: &[ArmId],
     ) -> BlockAnd<()> {
         let scrutinee_span = scrutinee.span;
         let scrutinee_place =
@@ -99,7 +99,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms);
 
-        let match_has_guard = arms.iter().any(|arm| arm.guard.is_some());
+        let match_has_guard = arms.iter().copied().any(|arm| self.thir[arm].guard.is_some());
         let mut candidates =
             arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
 
@@ -120,7 +120,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn lower_scrutinee(
         &mut self,
         mut block: BasicBlock,
-        scrutinee: &Expr<'_, 'tcx>,
+        scrutinee: &Expr<'tcx>,
         scrutinee_span: Span,
     ) -> BlockAnd<PlaceBuilder<'tcx>> {
         let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee));
@@ -156,12 +156,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn create_match_candidates<'pat>(
         &mut self,
         scrutinee: PlaceBuilder<'tcx>,
-        arms: &'pat [Arm<'pat, 'tcx>],
-    ) -> Vec<(&'pat Arm<'pat, 'tcx>, Candidate<'pat, 'tcx>)> {
+        arms: &'pat [ArmId],
+    ) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)>
+    where
+        'a: 'pat,
+    {
         // Assemble a list of candidates: there is one candidate per pattern,
         // which means there may be more than one candidate *per arm*.
         arms.iter()
+            .copied()
             .map(|arm| {
+                let arm = &self.thir[arm];
                 let arm_has_guard = arm.guard.is_some();
                 let arm_candidate = Candidate::new(scrutinee.clone(), &arm.pattern, arm_has_guard);
                 (arm, arm_candidate)
@@ -231,7 +236,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         destination: Place<'tcx>,
         scrutinee_place_builder: PlaceBuilder<'tcx>,
         scrutinee_span: Span,
-        arm_candidates: Vec<(&'_ Arm<'_, 'tcx>, Candidate<'_, 'tcx>)>,
+        arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>,
         outer_source_info: SourceInfo,
         fake_borrow_temps: Vec<(Place<'tcx>, Local)>,
     ) -> BlockAnd<()> {
@@ -286,7 +291,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         this.source_scope = source_scope;
                     }
 
-                    this.expr_into_dest(destination, arm_block, &arm.body)
+                    this.expr_into_dest(destination, arm_block, &&this.thir[arm.body])
                 })
             })
             .collect();
@@ -313,7 +318,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         outer_source_info: SourceInfo,
         candidate: Candidate<'_, 'tcx>,
-        guard: Option<&Guard<'_, 'tcx>>,
+        guard: Option<&Guard<'tcx>>,
         fake_borrow_temps: &Vec<(Place<'tcx>, Local)>,
         scrutinee_span: Span,
         arm_span: Option<Span>,
@@ -389,7 +394,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         mut block: BasicBlock,
         irrefutable_pat: Pat<'tcx>,
-        initializer: &Expr<'_, 'tcx>,
+        initializer: &Expr<'tcx>,
     ) -> BlockAnd<()> {
         match *irrefutable_pat.kind {
             // Optimize the case of `let x = ...` to write directly into `x`
@@ -427,7 +432,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         ..
                     },
                 ascription:
-                    thir::pattern::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
+                    thir::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span },
             } => {
                 let place =
                     self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
@@ -682,7 +687,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
             PatKind::AscribeUserType {
                 ref subpattern,
-                ascription: thir::pattern::Ascription { ref user_ty, user_ty_span, variance: _ },
+                ascription: thir::Ascription { ref user_ty, user_ty_span, variance: _ },
             } => {
                 // This corresponds to something like
                 //
@@ -1665,7 +1670,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         candidate: Candidate<'pat, 'tcx>,
         parent_bindings: &[(Vec<Binding<'tcx>>, Vec<Ascription<'tcx>>)],
-        guard: Option<&Guard<'_, 'tcx>>,
+        guard: Option<&Guard<'tcx>>,
         fake_borrows: &Vec<(Place<'tcx>, Local)>,
         scrutinee_span: Span,
         arm_span: Option<Span>,
@@ -1799,12 +1804,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow);
             }
 
-            let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match guard {
+            let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match *guard {
                 Guard::If(e) => {
+                    let e = &self.thir[e];
                     let source_info = self.source_info(e.span);
                     (e.span, self.test_bool(block, e, source_info))
                 }
-                Guard::IfLet(pat, scrutinee) => {
+                Guard::IfLet(ref pat, scrutinee) => {
+                    let scrutinee = &self.thir[scrutinee];
                     let scrutinee_span = scrutinee.span;
                     let scrutinee_place_builder =
                         unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span));
@@ -1840,7 +1847,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         guard_candidate,
                         None,
                         &fake_borrow_temps,
-                        scrutinee.span,
+                        scrutinee_span,
                         None,
                         None,
                     );
diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs
index 3ad143a57ff..13cfc3695cc 100644
--- a/compiler/rustc_mir_build/src/build/matches/simplify.rs
+++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs
@@ -15,8 +15,8 @@
 use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::matches::{Ascription, Binding, Candidate, MatchPair};
 use crate::build::Builder;
-use crate::thir::{self, *};
 use rustc_hir::RangeEnd;
+use rustc_middle::thir::{self, *};
 use rustc_middle::ty;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_target::abi::{Integer, Size};
@@ -152,7 +152,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         match *match_pair.pattern.kind {
             PatKind::AscribeUserType {
                 ref subpattern,
-                ascription: thir::pattern::Ascription { variance, user_ty, user_ty_span },
+                ascription: thir::Ascription { variance, user_ty, user_ty_span },
             } => {
                 // Apply the type ascription to the value at `match_pair.place`, which is the
                 candidate.ascriptions.push(Ascription {
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index b082169cd63..c87f42738c6 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -9,11 +9,11 @@ use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::matches::{Candidate, MatchPair, Test, TestKind};
 use crate::build::Builder;
 use crate::thir::pattern::compare_const_vals;
-use crate::thir::*;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir::{LangItem, RangeEnd};
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::*;
+use rustc_middle::thir::*;
 use rustc_middle::ty::subst::{GenericArg, Subst};
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt};
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index d49a00a5660..3cf8ae6efd9 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -1,8 +1,8 @@
 use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::matches::MatchPair;
 use crate::build::Builder;
-use crate::thir::*;
 use rustc_middle::mir::*;
+use rustc_middle::thir::*;
 use rustc_middle::ty;
 use smallvec::SmallVec;
 use std::convert::TryInto;
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index f944e5f8f04..10d6521e7de 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -1,7 +1,7 @@
 use crate::build;
 use crate::build::expr::as_place::PlaceBuilder;
 use crate::build::scope::DropKind;
-use crate::thir::{build_thir, Arena, BindingMode, Expr, LintLevel, Pat, PatKind};
+use crate::thir::pattern::pat_from_hir;
 use rustc_attr::{self as attr, UnwindAttr};
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
@@ -13,6 +13,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
+use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, PatKind, Thir};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
 use rustc_span::symbol::{kw, sym};
@@ -45,6 +46,16 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
     let body_owner_kind = tcx.hir().body_owner_kind(id);
     let typeck_results = tcx.typeck_opt_const_arg(def);
 
+    // Ensure unsafeck is ran before we steal the THIR.
+    match def {
+        ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => {
+            tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did))
+        }
+        ty::WithOptConstParam { did, const_param_did: None } => {
+            tcx.ensure().thir_check_unsafety(did)
+        }
+    }
+
     // Figure out what primary body this item has.
     let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) {
         Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) => {
@@ -88,7 +99,6 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
     // If we don't have a specialized span for the body, just use the
     // normal def span.
     let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id));
-    let arena = Arena::default();
 
     tcx.infer_ctxt().enter(|infcx| {
         let body = if let Some(ErrorReported) = typeck_results.tainted_by_errors {
@@ -105,7 +115,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
             };
 
             let body = tcx.hir().body(body_id);
-            let thir = build_thir(tcx, def, &arena, &body.value);
+            let (thir, expr) = tcx.thir_body(def);
+            // We ran all queries that depended on THIR at the beginning
+            // of `mir_build`, so now we can steal it
+            let thir = thir.steal();
             let ty = tcx.type_of(fn_def_id);
             let mut abi = fn_sig.abi;
             let implicit_argument = match ty.kind() {
@@ -181,6 +194,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
             };
 
             let mut mir = build::construct_fn(
+                &thir,
                 &infcx,
                 def,
                 id,
@@ -190,7 +204,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
                 return_ty,
                 return_ty_span,
                 body,
-                thir,
+                expr,
                 span_with_body,
             );
             if yield_ty.is_some() {
@@ -212,10 +226,12 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
 
             let return_ty = typeck_results.node_type(id);
 
-            let ast_expr = &tcx.hir().body(body_id).value;
-            let thir = build_thir(tcx, def, &arena, ast_expr);
+            let (thir, expr) = tcx.thir_body(def);
+            // We ran all queries that depended on THIR at the beginning
+            // of `mir_build`, so now we can steal it
+            let thir = thir.steal();
 
-            build::construct_const(&infcx, thir, def, id, return_ty, return_ty_span)
+            build::construct_const(&thir, &infcx, expr, def, id, return_ty, return_ty_span)
         };
 
         lints::check(tcx, &body);
@@ -323,6 +339,7 @@ struct Builder<'a, 'tcx> {
     region_scope_tree: &'tcx region::ScopeTree,
     param_env: ty::ParamEnv<'tcx>,
 
+    thir: &'a Thir<'tcx>,
     cfg: CFG<'tcx>,
 
     def_id: DefId,
@@ -633,6 +650,7 @@ struct ArgInfo<'tcx>(
 );
 
 fn construct_fn<'tcx, A>(
+    thir: &Thir<'tcx>,
     infcx: &InferCtxt<'_, 'tcx>,
     fn_def: ty::WithOptConstParam<LocalDefId>,
     fn_id: hir::HirId,
@@ -642,7 +660,7 @@ fn construct_fn<'tcx, A>(
     return_ty: Ty<'tcx>,
     return_ty_span: Span,
     body: &'tcx hir::Body<'tcx>,
-    expr: &Expr<'_, 'tcx>,
+    expr: ExprId,
     span_with_body: Span,
 ) -> Body<'tcx>
 where
@@ -654,6 +672,7 @@ where
     let span = tcx.hir().span(fn_id);
 
     let mut builder = Builder::new(
+        thir,
         infcx,
         fn_def,
         fn_id,
@@ -683,7 +702,7 @@ where
                         fn_def.did.to_def_id(),
                         &arguments,
                         arg_scope,
-                        expr,
+                        &thir[expr],
                     )
                 }))
             }));
@@ -708,8 +727,9 @@ where
 }
 
 fn construct_const<'a, 'tcx>(
+    thir: &'a Thir<'tcx>,
     infcx: &'a InferCtxt<'a, 'tcx>,
-    expr: &Expr<'_, 'tcx>,
+    expr: ExprId,
     def: ty::WithOptConstParam<LocalDefId>,
     hir_id: hir::HirId,
     const_ty: Ty<'tcx>,
@@ -717,11 +737,21 @@ fn construct_const<'a, 'tcx>(
 ) -> Body<'tcx> {
     let tcx = infcx.tcx;
     let span = tcx.hir().span(hir_id);
-    let mut builder =
-        Builder::new(infcx, def, hir_id, span, 0, Safety::Safe, const_ty, const_ty_span, None);
+    let mut builder = Builder::new(
+        thir,
+        infcx,
+        def,
+        hir_id,
+        span,
+        0,
+        Safety::Safe,
+        const_ty,
+        const_ty_span,
+        None,
+    );
 
     let mut block = START_BLOCK;
-    unpack!(block = builder.expr_into_dest(Place::return_place(), block, &expr));
+    unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr]));
 
     let source_info = builder.source_info(span);
     builder.cfg.terminate(block, source_info, TerminatorKind::Return);
@@ -761,22 +791,48 @@ fn construct_error<'a, 'tcx>(
         hir::BodyOwnerKind::Const => 0,
         hir::BodyOwnerKind::Static(_) => 0,
     };
-    let mut builder =
-        Builder::new(infcx, def, hir_id, span, num_params, Safety::Safe, ty, span, generator_kind);
-    let source_info = builder.source_info(span);
+    let mut cfg = CFG { basic_blocks: IndexVec::new() };
+    let mut source_scopes = IndexVec::new();
+    let mut local_decls = IndexVec::from_elem_n(LocalDecl::new(ty, span), 1);
+
+    cfg.start_new_block();
+    source_scopes.push(SourceScopeData {
+        span,
+        parent_scope: None,
+        inlined: None,
+        inlined_parent_scope: None,
+        local_data: ClearCrossCrate::Set(SourceScopeLocalData {
+            lint_root: hir_id,
+            safety: Safety::Safe,
+        }),
+    });
+    let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE };
+
     // Some MIR passes will expect the number of parameters to match the
     // function declaration.
     for _ in 0..num_params {
-        builder.local_decls.push(LocalDecl::with_source_info(ty, source_info));
+        local_decls.push(LocalDecl::with_source_info(ty, source_info));
     }
-    builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
-    let mut body = builder.finish();
+    cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
+
+    let mut body = Body::new(
+        MirSource::item(def.did.to_def_id()),
+        cfg.basic_blocks,
+        source_scopes,
+        local_decls,
+        IndexVec::new(),
+        num_params,
+        vec![],
+        span,
+        generator_kind,
+    );
     body.generator.as_mut().map(|gen| gen.yield_ty = Some(ty));
     body
 }
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
     fn new(
+        thir: &'a Thir<'tcx>,
         infcx: &'a InferCtxt<'a, 'tcx>,
         def: ty::WithOptConstParam<LocalDefId>,
         hir_id: hir::HirId,
@@ -803,6 +859,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let lint_level = LintLevel::Explicit(hir_id);
         let mut builder = Builder {
+            thir,
             tcx,
             infcx,
             typeck_results: tcx.typeck_opt_const_arg(def),
@@ -866,7 +923,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         fn_def_id: DefId,
         arguments: &[ArgInfo<'tcx>],
         argument_scope: region::Scope,
-        expr: &Expr<'_, 'tcx>,
+        expr: &Expr<'tcx>,
     ) -> BlockAnd<()> {
         // Allocate locals for the function arguments
         for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
@@ -896,9 +953,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         // the given closure and use the necessary information to create upvar
         // debuginfo and to fill `self.upvar_mutbls`.
         if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() {
-            let closure_env_arg = Local::new(1);
             let mut closure_env_projs = vec![];
-            let mut closure_ty = self.local_decls[closure_env_arg].ty;
+            let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
             if let ty::Ref(_, ty, _) = closure_ty.kind() {
                 closure_env_projs.push(ProjectionElem::Deref);
                 closure_ty = ty;
@@ -944,7 +1000,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         name,
                         source_info: SourceInfo::outermost(tcx_hir.span(var_id)),
                         value: VarDebugInfoContents::Place(Place {
-                            local: closure_env_arg,
+                            local: ty::CAPTURE_STRUCT_LOCAL,
                             projection: tcx.intern_place_elems(&projs),
                         }),
                     });
@@ -975,7 +1031,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     Node::Pat(pat) | Node::Binding(pat) => pat,
                     node => bug!("pattern became {:?}", node),
                 };
-                let pattern = Pat::from_hir(tcx, self.param_env, self.typeck_results, pat);
+                let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat);
                 let original_source_scope = self.source_scope;
                 let span = pattern.span;
                 self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 41fc925c049..3de894bd370 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -82,11 +82,12 @@ that contains only loops and breakable blocks. It tracks where a `break`,
 */
 
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
-use crate::thir::{Expr, LintLevel};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_index::vec::IndexVec;
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
+use rustc_middle::thir::{Expr, LintLevel};
+
 use rustc_span::{Span, DUMMY_SP};
 
 #[derive(Debug)]
@@ -574,7 +575,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn break_scope(
         &mut self,
         mut block: BasicBlock,
-        value: Option<&Expr<'_, 'tcx>>,
+        value: Option<&Expr<'tcx>>,
         target: BreakableTarget,
         source_info: SourceInfo,
     ) -> BlockAnd<()> {
@@ -933,7 +934,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     crate fn test_bool(
         &mut self,
         mut block: BasicBlock,
-        condition: &Expr<'_, 'tcx>,
+        condition: &Expr<'tcx>,
         source_info: SourceInfo,
     ) -> (BasicBlock, BasicBlock) {
         let cond = unpack!(block = self.as_local_operand(block, condition));
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 83288fa541e..2d52577829c 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -1,16 +1,20 @@
 use crate::thir::visit::{self, Visitor};
-use crate::thir::*;
 
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
+use rustc_middle::thir::*;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
 use rustc_session::lint::Level;
 use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
-struct UnsafetyVisitor<'tcx> {
+use std::ops::Bound;
+
+struct UnsafetyVisitor<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
+    thir: &'a Thir<'tcx>,
     /// The `HirId` of the current scope, which would be the `HirId`
     /// of the current HIR node, modulo adjustments. Used for lint levels.
     hir_context: hir::HirId,
@@ -18,9 +22,13 @@ struct UnsafetyVisitor<'tcx> {
     /// `unsafe` block, and whether it has been used.
     safety_context: SafetyContext,
     body_unsafety: BodyUnsafety,
+    /// The `#[target_feature]` attributes of the body. Used for checking
+    /// calls to functions with `#[target_feature]` (RFC 2396).
+    body_target_features: &'tcx Vec<Symbol>,
+    is_const: bool,
 }
 
-impl<'tcx> UnsafetyVisitor<'tcx> {
+impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
     fn in_safety_context<R>(
         &mut self,
         safety_context: SafetyContext,
@@ -34,7 +42,7 @@ impl<'tcx> UnsafetyVisitor<'tcx> {
             self.warn_unused_unsafe(
                 hir_id,
                 block_span,
-                Some(self.tcx.sess.source_map().guess_head_span(enclosing_span)),
+                Some((self.tcx.sess.source_map().guess_head_span(enclosing_span), "block")),
             );
             f(self);
         } else {
@@ -44,7 +52,15 @@ impl<'tcx> UnsafetyVisitor<'tcx> {
             f(self);
 
             if let SafetyContext::UnsafeBlock { used: false, span, hir_id } = self.safety_context {
-                self.warn_unused_unsafe(hir_id, span, self.body_unsafety.unsafe_fn_sig_span());
+                self.warn_unused_unsafe(
+                    hir_id,
+                    span,
+                    if self.unsafe_op_in_unsafe_fn_allowed() {
+                        self.body_unsafety.unsafe_fn_sig_span().map(|span| (span, "fn"))
+                    } else {
+                        None
+                    },
+                );
             }
             self.safety_context = prev_context;
             return;
@@ -64,38 +80,34 @@ impl<'tcx> UnsafetyVisitor<'tcx> {
             SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
             SafetyContext::UnsafeFn => {
                 // unsafe_op_in_unsafe_fn is disallowed
-                if kind == BorrowOfPackedField {
-                    // FIXME handle borrows of packed fields
-                } else {
-                    struct_span_err!(
-                        self.tcx.sess,
-                        span,
-                        E0133,
-                        "{} is unsafe and requires unsafe block",
-                        description,
-                    )
-                    .span_label(span, description)
-                    .note(note)
-                    .emit();
-                }
+                self.tcx.struct_span_lint_hir(
+                    UNSAFE_OP_IN_UNSAFE_FN,
+                    self.hir_context,
+                    span,
+                    |lint| {
+                        lint.build(&format!(
+                            "{} is unsafe and requires unsafe block (error E0133)",
+                            description,
+                        ))
+                        .span_label(span, description)
+                        .note(note)
+                        .emit();
+                    },
+                )
             }
             SafetyContext::Safe => {
-                if kind == BorrowOfPackedField {
-                    // FIXME handle borrows of packed fields
-                } else {
-                    let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" };
-                    struct_span_err!(
-                        self.tcx.sess,
-                        span,
-                        E0133,
-                        "{} is unsafe and requires unsafe{} block",
-                        description,
-                        fn_sugg,
-                    )
-                    .span_label(span, description)
-                    .note(note)
-                    .emit();
-                }
+                let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" };
+                struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0133,
+                    "{} is unsafe and requires unsafe{} block",
+                    description,
+                    fn_sugg,
+                )
+                .span_label(span, description)
+                .note(note)
+                .emit();
             }
         }
     }
@@ -104,18 +116,15 @@ impl<'tcx> UnsafetyVisitor<'tcx> {
         &self,
         hir_id: hir::HirId,
         block_span: Span,
-        enclosing_span: Option<Span>,
+        enclosing_unsafe: Option<(Span, &'static str)>,
     ) {
         let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
         self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, |lint| {
             let msg = "unnecessary `unsafe` block";
             let mut db = lint.build(msg);
             db.span_label(block_span, msg);
-            if let Some(enclosing_span) = enclosing_span {
-                db.span_label(
-                    enclosing_span,
-                    format!("because it's nested under this `unsafe` block"),
-                );
+            if let Some((span, kind)) = enclosing_unsafe {
+                db.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
             }
             db.emit();
         });
@@ -127,8 +136,12 @@ impl<'tcx> UnsafetyVisitor<'tcx> {
     }
 }
 
-impl<'thir, 'tcx> Visitor<'thir, 'tcx> for UnsafetyVisitor<'tcx> {
-    fn visit_block(&mut self, block: &Block<'thir, 'tcx>) {
+impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
+    fn thir(&self) -> &'a Thir<'tcx> {
+        &self.thir
+    }
+
+    fn visit_block(&mut self, block: &Block) {
         if let BlockSafety::ExplicitUnsafe(hir_id) = block.safety_mode {
             self.in_safety_context(
                 SafetyContext::UnsafeBlock { span: block.span, hir_id, used: false },
@@ -139,23 +152,94 @@ impl<'thir, 'tcx> Visitor<'thir, 'tcx> for UnsafetyVisitor<'tcx> {
         }
     }
 
-    fn visit_expr(&mut self, expr: &'thir Expr<'thir, 'tcx>) {
+    fn visit_expr(&mut self, expr: &Expr<'tcx>) {
         match expr.kind {
             ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), region_scope: _ } => {
                 let prev_id = self.hir_context;
                 self.hir_context = hir_id;
-                self.visit_expr(value);
+                self.visit_expr(&self.thir[value]);
                 self.hir_context = prev_id;
                 return;
             }
             ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
-                if fun.ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
+                if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
                     self.requires_unsafe(expr.span, CallToUnsafeFunction);
+                } else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
+                    // If the called function has target features the calling function hasn't,
+                    // the call requires `unsafe`. Don't check this on wasm
+                    // targets, though. For more information on wasm see the
+                    // is_like_wasm check in typeck/src/collect.rs
+                    if !self.tcx.sess.target.options.is_like_wasm
+                        && !self
+                            .tcx
+                            .codegen_fn_attrs(func_did)
+                            .target_features
+                            .iter()
+                            .all(|feature| self.body_target_features.contains(feature))
+                    {
+                        self.requires_unsafe(expr.span, CallToFunctionWith);
+                    }
+                }
+            }
+            ExprKind::Deref { arg } => {
+                if let ExprKind::StaticRef { def_id, .. } = self.thir[arg].kind {
+                    if self.tcx.is_mutable_static(def_id) {
+                        self.requires_unsafe(expr.span, UseOfMutableStatic);
+                    } else if self.tcx.is_foreign_item(def_id) {
+                        self.requires_unsafe(expr.span, UseOfExternStatic);
+                    }
+                } else if self.thir[arg].ty.is_unsafe_ptr() {
+                    self.requires_unsafe(expr.span, DerefOfRawPointer);
                 }
             }
             ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => {
                 self.requires_unsafe(expr.span, UseOfInlineAssembly);
             }
+            ExprKind::Adt {
+                adt_def,
+                variant_index: _,
+                substs: _,
+                user_ty: _,
+                fields: _,
+                base: _,
+            } => match self.tcx.layout_scalar_valid_range(adt_def.did) {
+                (Bound::Unbounded, Bound::Unbounded) => {}
+                _ => self.requires_unsafe(expr.span, InitializingTypeWith),
+            },
+            ExprKind::Cast { source } => {
+                let source = &self.thir[source];
+                if self.tcx.features().const_raw_ptr_to_usize_cast
+                    && self.is_const
+                    && (source.ty.is_unsafe_ptr() || source.ty.is_fn_ptr())
+                    && expr.ty.is_integral()
+                {
+                    self.requires_unsafe(expr.span, CastOfPointerToInt);
+                }
+            }
+            ExprKind::Closure {
+                closure_id,
+                substs: _,
+                upvars: _,
+                movability: _,
+                fake_reads: _,
+            } => {
+                let closure_id = closure_id.expect_local();
+                let closure_def = if let Some((did, const_param_id)) =
+                    ty::WithOptConstParam::try_lookup(closure_id, self.tcx)
+                {
+                    ty::WithOptConstParam { did, const_param_did: Some(const_param_id) }
+                } else {
+                    ty::WithOptConstParam::unknown(closure_id)
+                };
+                let (closure_thir, expr) = self.tcx.thir_body(closure_def);
+                let closure_thir = &closure_thir.borrow();
+                let hir_context = self.tcx.hir().local_def_id_to_hir_id(closure_id);
+                let mut closure_visitor =
+                    UnsafetyVisitor { thir: closure_thir, hir_context, ..*self };
+                closure_visitor.visit_expr(&closure_thir[expr]);
+                // Unsafe blocks can be used in closures, make sure to take it into account
+                self.safety_context = closure_visitor.safety_context;
+            }
             _ => {}
         }
 
@@ -198,17 +282,10 @@ impl BodyUnsafety {
 enum UnsafeOpKind {
     CallToUnsafeFunction,
     UseOfInlineAssembly,
-    #[allow(dead_code)] // FIXME
     InitializingTypeWith,
-    #[allow(dead_code)] // FIXME
     CastOfPointerToInt,
-    #[allow(dead_code)] // FIXME
-    BorrowOfPackedField,
-    #[allow(dead_code)] // FIXME
     UseOfMutableStatic,
-    #[allow(dead_code)] // FIXME
     UseOfExternStatic,
-    #[allow(dead_code)] // FIXME
     DerefOfRawPointer,
     #[allow(dead_code)] // FIXME
     AssignToDroppingUnionField,
@@ -218,7 +295,6 @@ enum UnsafeOpKind {
     MutationOfLayoutConstrainedField,
     #[allow(dead_code)] // FIXME
     BorrowOfLayoutConstrainedField,
-    #[allow(dead_code)] // FIXME
     CallToFunctionWith,
 }
 
@@ -244,11 +320,6 @@ impl UnsafeOpKind {
             CastOfPointerToInt => {
                 ("cast of pointer to int", "casting pointers to integers in constants")
             }
-            BorrowOfPackedField => (
-                "borrow of packed field",
-                "fields of packed structs might be misaligned: dereferencing a misaligned pointer \
-                 or even just creating a misaligned reference is undefined behavior",
-            ),
             UseOfMutableStatic => (
                 "use of mutable static",
                 "mutable statics can be mutated by multiple threads: aliasing violations or data \
@@ -261,7 +332,7 @@ impl UnsafeOpKind {
             ),
             DerefOfRawPointer => (
                 "dereference of raw pointer",
-                "raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules \
+                "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
                  and cause data races: all of these are undefined behavior",
             ),
             AssignToDroppingUnionField => (
@@ -291,9 +362,26 @@ impl UnsafeOpKind {
     }
 }
 
-// FIXME: checking unsafety for closures should be handled by their parent body,
-// as they inherit their "safety context" from their declaration site.
-pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, thir: &Expr<'_, 'tcx>, hir_id: hir::HirId) {
+pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) {
+    // THIR unsafeck is gated under `-Z thir-unsafeck`
+    if !tcx.sess.opts.debugging_opts.thir_unsafeck {
+        return;
+    }
+
+    // Closures are handled by their parent function
+    if tcx.is_closure(def.did.to_def_id()) {
+        tcx.ensure().thir_check_unsafety(tcx.hir().local_def_id_to_hir_id(def.did).owner);
+        return;
+    }
+
+    let (thir, expr) = tcx.thir_body(def);
+    let thir = &thir.borrow();
+    // If `thir` is empty, a type error occured, skip this body.
+    if thir.exprs.is_empty() {
+        return;
+    }
+
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
     let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| {
         if fn_sig.header.unsafety == hir::Unsafety::Unsafe {
             BodyUnsafety::Unsafe(fn_sig.span)
@@ -301,30 +389,31 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, thir: &Expr<'_, 'tcx>, hir_id: hi
             BodyUnsafety::Safe
         }
     });
+    let body_target_features = &tcx.codegen_fn_attrs(def.did).target_features;
     let safety_context =
         if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
-    let mut visitor = UnsafetyVisitor { tcx, safety_context, hir_context: hir_id, body_unsafety };
-    visitor.visit_expr(thir);
-}
-
-crate fn thir_check_unsafety_inner<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def: ty::WithOptConstParam<LocalDefId>,
-) {
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
-    let body_id = tcx.hir().body_owned_by(hir_id);
-    let body = tcx.hir().body(body_id);
-
-    let arena = Arena::default();
-    let thir = cx::build_thir(tcx, def, &arena, &body.value);
-    check_unsafety(tcx, thir, hir_id);
+    let is_const = match tcx.hir().body_owner_kind(hir_id) {
+        hir::BodyOwnerKind::Closure => false,
+        hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def.did.to_def_id()),
+        hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => true,
+    };
+    let mut visitor = UnsafetyVisitor {
+        tcx,
+        thir,
+        safety_context,
+        hir_context: hir_id,
+        body_unsafety,
+        body_target_features,
+        is_const,
+    };
+    visitor.visit_expr(&thir[expr]);
 }
 
 crate fn thir_check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
     if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
         tcx.thir_check_unsafety_for_const_arg(def)
     } else {
-        thir_check_unsafety_inner(tcx, ty::WithOptConstParam::unknown(def_id))
+        check_unsafety(tcx, ty::WithOptConstParam::unknown(def_id))
     }
 }
 
@@ -332,5 +421,5 @@ crate fn thir_check_unsafety_for_const_arg<'tcx>(
     tcx: TyCtxt<'tcx>,
     (did, param_did): (LocalDefId, DefId),
 ) {
-    thir_check_unsafety_inner(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
+    check_unsafety(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
 }
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index d4e9a0a3169..d2992f0bf18 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -1,16 +1,14 @@
 //! Construction of MIR from HIR.
 //!
 //! This crate also contains the match exhaustiveness and usefulness checking.
-#![feature(array_windows)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
-#![feature(const_panic)]
 #![feature(control_flow_enum)]
 #![feature(crate_visibility_modifier)]
 #![feature(bool_to_option)]
 #![feature(iter_zip)]
 #![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
+#![feature(min_specialization)]
 #![recursion_limit = "256"]
 
 #[macro_use]
@@ -31,4 +29,5 @@ pub fn provide(providers: &mut Providers) {
     providers.mir_built = build::mir_built;
     providers.thir_check_unsafety = check_unsafety::thir_check_unsafety;
     providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg;
+    providers.thir_body = thir::cx::thir_body;
 }
diff --git a/compiler/rustc_mir_build/src/thir/arena.rs b/compiler/rustc_mir_build/src/thir/arena.rs
deleted file mode 100644
index aacc7b12a42..00000000000
--- a/compiler/rustc_mir_build/src/thir/arena.rs
+++ /dev/null
@@ -1,98 +0,0 @@
-use crate::thir::*;
-
-macro_rules! declare_arena {
-    ([], [$($a:tt $name:ident: $ty:ty,)*]) => {
-        #[derive(Default)]
-        pub struct Arena<'thir, 'tcx> {
-            pub dropless: rustc_arena::DroplessArena,
-            drop: rustc_arena::DropArena,
-            $($name: rustc_arena::arena_for_type!($a[$ty]),)*
-        }
-
-        pub trait ArenaAllocatable<'thir, 'tcx, T = Self>: Sized {
-            fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self;
-            fn allocate_from_iter(
-                arena: &'thir Arena<'thir, 'tcx>,
-                iter: impl ::std::iter::IntoIterator<Item = Self>,
-            ) -> &'thir mut [Self];
-        }
-
-        impl<'thir, 'tcx, T: Copy> ArenaAllocatable<'thir, 'tcx, ()> for T {
-            #[inline]
-            fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self {
-                arena.dropless.alloc(self)
-            }
-            #[inline]
-            fn allocate_from_iter(
-                arena: &'thir Arena<'thir, 'tcx>,
-                iter: impl ::std::iter::IntoIterator<Item = Self>,
-            ) -> &'thir mut [Self] {
-                arena.dropless.alloc_from_iter(iter)
-            }
-
-        }
-        $(
-            impl<'thir, 'tcx> ArenaAllocatable<'thir, 'tcx, $ty> for $ty {
-                #[inline]
-                fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self {
-                    if !::std::mem::needs_drop::<Self>() {
-                        return arena.dropless.alloc(self);
-                    }
-                    match rustc_arena::which_arena_for_type!($a[&arena.$name]) {
-                        ::std::option::Option::<&rustc_arena::TypedArena<Self>>::Some(ty_arena) => {
-                            ty_arena.alloc(self)
-                        }
-                        ::std::option::Option::None => unsafe { arena.drop.alloc(self) },
-                    }
-                }
-
-                #[inline]
-                fn allocate_from_iter(
-                    arena: &'thir Arena<'thir, 'tcx>,
-                    iter: impl ::std::iter::IntoIterator<Item = Self>,
-                ) -> &'thir mut [Self] {
-                    if !::std::mem::needs_drop::<Self>() {
-                        return arena.dropless.alloc_from_iter(iter);
-                    }
-                    match rustc_arena::which_arena_for_type!($a[&arena.$name]) {
-                        ::std::option::Option::<&rustc_arena::TypedArena<Self>>::Some(ty_arena) => {
-                            ty_arena.alloc_from_iter(iter)
-                        }
-                        ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) },
-                    }
-                }
-            }
-        )*
-
-        impl<'thir, 'tcx> Arena<'thir, 'tcx> {
-            #[inline]
-            pub fn alloc<T: ArenaAllocatable<'thir, 'tcx, U>, U>(&'thir self, value: T) -> &'thir mut T {
-                value.allocate_on(self)
-            }
-
-            #[allow(dead_code)] // function is never used
-            #[inline]
-            pub fn alloc_slice<T: ::std::marker::Copy>(&'thir self, value: &[T]) -> &'thir mut [T] {
-                if value.is_empty() {
-                    return &mut [];
-                }
-                self.dropless.alloc_slice(value)
-            }
-
-            pub fn alloc_from_iter<T: ArenaAllocatable<'thir, 'tcx, U>, U>(
-                &'thir self,
-                iter: impl ::std::iter::IntoIterator<Item = T>,
-            ) -> &'thir mut [T] {
-                T::allocate_from_iter(self, iter)
-            }
-        }
-    }
-}
-
-declare_arena!([], [
-    [] arm: Arm<'thir, 'tcx>,
-    [] expr: Expr<'thir, 'tcx>,
-    [] field_expr: FieldExpr<'thir, 'tcx>,
-    [few] inline_asm_operand: InlineAsmOperand<'thir, 'tcx>,
-    [] stmt: Stmt<'thir, 'tcx>,
-]);
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index ac93d042970..d62fd161e2f 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -25,14 +25,14 @@ crate fn lit_to_const<'tcx>(
     let lit = match (lit, &ty.kind()) {
         (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
             let s = s.as_str();
-            let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes());
+            let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
             let allocation = tcx.intern_const_alloc(allocation);
             ConstValue::Slice { data: allocation, start: 0, end: s.len() }
         }
         (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
             if matches!(inner_ty.kind(), ty::Slice(_)) =>
         {
-            let allocation = Allocation::from_byte_aligned_bytes(data as &[u8]);
+            let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
             let allocation = tcx.intern_const_alloc(allocation);
             ConstValue::Slice { data: allocation, start: 0, end: data.len() }
         }
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index d450f8a265d..77235fe9ab3 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -1,14 +1,14 @@
 use crate::thir::cx::Cx;
-use crate::thir::{self, *};
 
 use rustc_hir as hir;
 use rustc_middle::middle::region;
+use rustc_middle::thir::*;
 use rustc_middle::ty;
 
 use rustc_index::vec::Idx;
 
-impl<'thir, 'tcx> Cx<'thir, 'tcx> {
-    crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block<'thir, 'tcx> {
+impl<'tcx> Cx<'tcx> {
+    crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block {
         // We have to eagerly lower the "spine" of the statements
         // in order to get the lexical scoping correctly.
         let stmts = self.mirror_stmts(block.hir_id.local_id, block.stmts);
@@ -37,65 +37,78 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         &mut self,
         block_id: hir::ItemLocalId,
         stmts: &'tcx [hir::Stmt<'tcx>],
-    ) -> &'thir [Stmt<'thir, 'tcx>] {
-        self.arena.alloc_from_iter(stmts.iter().enumerate().filter_map(|(index, stmt)| {
-            let hir_id = stmt.hir_id;
-            let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id);
-            match stmt.kind {
-                hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => Some(Stmt {
-                    kind: StmtKind::Expr {
-                        scope: region::Scope { id: hir_id.local_id, data: region::ScopeData::Node },
-                        expr: self.mirror_expr(expr),
-                    },
-                    opt_destruction_scope: opt_dxn_ext,
-                }),
-                hir::StmtKind::Item(..) => {
-                    // ignore for purposes of the MIR
-                    None
-                }
-                hir::StmtKind::Local(ref local) => {
-                    let remainder_scope = region::Scope {
-                        id: block_id,
-                        data: region::ScopeData::Remainder(region::FirstStatementIndex::new(index)),
-                    };
+    ) -> Box<[StmtId]> {
+        stmts
+            .iter()
+            .enumerate()
+            .filter_map(|(index, stmt)| {
+                let hir_id = stmt.hir_id;
+                let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id);
+                match stmt.kind {
+                    hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
+                        let stmt = Stmt {
+                            kind: StmtKind::Expr {
+                                scope: region::Scope {
+                                    id: hir_id.local_id,
+                                    data: region::ScopeData::Node,
+                                },
+                                expr: self.mirror_expr(expr),
+                            },
+                            opt_destruction_scope: opt_dxn_ext,
+                        };
+                        Some(self.thir.stmts.push(stmt))
+                    }
+                    hir::StmtKind::Item(..) => {
+                        // ignore for purposes of the MIR
+                        None
+                    }
+                    hir::StmtKind::Local(ref local) => {
+                        let remainder_scope = region::Scope {
+                            id: block_id,
+                            data: region::ScopeData::Remainder(region::FirstStatementIndex::new(
+                                index,
+                            )),
+                        };
 
-                    let mut pattern = self.pattern_from_hir(local.pat);
+                        let mut pattern = self.pattern_from_hir(local.pat);
 
-                    if let Some(ty) = &local.ty {
-                        if let Some(&user_ty) =
-                            self.typeck_results.user_provided_types().get(ty.hir_id)
-                        {
-                            debug!("mirror_stmts: user_ty={:?}", user_ty);
-                            pattern = Pat {
-                                ty: pattern.ty,
-                                span: pattern.span,
-                                kind: Box::new(PatKind::AscribeUserType {
-                                    ascription: thir::pattern::Ascription {
-                                        user_ty: PatTyProj::from_user_type(user_ty),
-                                        user_ty_span: ty.span,
-                                        variance: ty::Variance::Covariant,
-                                    },
-                                    subpattern: pattern,
-                                }),
-                            };
+                        if let Some(ty) = &local.ty {
+                            if let Some(&user_ty) =
+                                self.typeck_results.user_provided_types().get(ty.hir_id)
+                            {
+                                debug!("mirror_stmts: user_ty={:?}", user_ty);
+                                pattern = Pat {
+                                    ty: pattern.ty,
+                                    span: pattern.span,
+                                    kind: Box::new(PatKind::AscribeUserType {
+                                        ascription: Ascription {
+                                            user_ty: PatTyProj::from_user_type(user_ty),
+                                            user_ty_span: ty.span,
+                                            variance: ty::Variance::Covariant,
+                                        },
+                                        subpattern: pattern,
+                                    }),
+                                };
+                            }
                         }
-                    }
 
-                    Some(Stmt {
-                        kind: StmtKind::Let {
-                            remainder_scope,
-                            init_scope: region::Scope {
-                                id: hir_id.local_id,
-                                data: region::ScopeData::Node,
+                        let stmt = Stmt {
+                            kind: StmtKind::Let {
+                                remainder_scope,
+                                init_scope: region::Scope {
+                                    id: hir_id.local_id,
+                                    data: region::ScopeData::Node,
+                                },
+                                pattern,
+                                initializer: local.init.map(|init| self.mirror_expr(init)),
+                                lint_level: LintLevel::Explicit(local.hir_id),
                             },
-                            pattern,
-                            initializer: local.init.map(|init| self.mirror_expr(init)),
-                            lint_level: LintLevel::Explicit(local.hir_id),
-                        },
-                        opt_destruction_scope: opt_dxn_ext,
-                    })
+                            opt_destruction_scope: opt_dxn_ext,
+                        };
+                        Some(self.thir.stmts.push(stmt))
+                    }
                 }
-            }
-        }))
+            })
+            .collect()
     }
 }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 924278e1a7f..aa4acfab5c8 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -1,6 +1,5 @@
 use crate::thir::cx::Cx;
 use crate::thir::util::UserAnnotatedTyHelpers;
-use crate::thir::*;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -8,43 +7,30 @@ use rustc_index::vec::Idx;
 use rustc_middle::hir::place::Place as HirPlace;
 use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
+use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::mir::BorrowKind;
+use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
+use rustc_middle::thir::*;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast,
 };
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
-use rustc_middle::ty::{self, AdtKind, Ty};
+use rustc_middle::ty::{self, AdtKind, Ty, UpvarSubsts, UserType};
+use rustc_span::def_id::DefId;
 use rustc_span::Span;
+use rustc_target::abi::VariantIdx;
 
-use std::iter;
-
-impl<'thir, 'tcx> Cx<'thir, 'tcx> {
-    /// Mirrors and allocates a single [`hir::Expr`]. If you need to mirror a whole slice
-    /// of expressions, prefer using [`mirror_exprs`].
-    ///
-    /// [`mirror_exprs`]: Self::mirror_exprs
-    crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> &'thir Expr<'thir, 'tcx> {
+impl<'tcx> Cx<'tcx> {
+    crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId {
         // `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow.
-        ensure_sufficient_stack(|| self.arena.alloc(self.mirror_expr_inner(expr)))
+        ensure_sufficient_stack(|| self.mirror_expr_inner(expr))
     }
 
-    /// Mirrors and allocates a slice of [`hir::Expr`]s. They will be allocated as a
-    /// contiguous sequence in memory.
-    crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> &'thir [Expr<'thir, 'tcx>] {
-        self.arena.alloc_from_iter(exprs.iter().map(|expr| self.mirror_expr_inner(expr)))
+    crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> {
+        exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect()
     }
 
-    /// Mirrors a [`hir::Expr`] without allocating it into the arena.
-    /// This is a separate, private function so that [`mirror_expr`] and [`mirror_exprs`] can
-    /// decide how to allocate this expression (alone or within a slice).
-    ///
-    /// [`mirror_expr`]: Self::mirror_expr
-    /// [`mirror_exprs`]: Self::mirror_exprs
-    pub(super) fn mirror_expr_inner(
-        &mut self,
-        hir_expr: &'tcx hir::Expr<'tcx>,
-    ) -> Expr<'thir, 'tcx> {
+    pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId {
         let temp_lifetime = self.region_scope_tree.temporary_scope(hir_expr.hir_id.local_id);
         let expr_scope =
             region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node };
@@ -66,7 +52,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
             span: hir_expr.span,
             kind: ExprKind::Scope {
                 region_scope: expr_scope,
-                value: self.arena.alloc(expr),
+                value: self.thir.exprs.push(expr),
                 lint_level: LintLevel::Explicit(hir_expr.hir_id),
             },
         };
@@ -81,22 +67,22 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                 span: hir_expr.span,
                 kind: ExprKind::Scope {
                     region_scope,
-                    value: self.arena.alloc(expr),
+                    value: self.thir.exprs.push(expr),
                     lint_level: LintLevel::Inherited,
                 },
             };
         }
 
         // OK, all done!
-        expr
+        self.thir.exprs.push(expr)
     }
 
     fn apply_adjustment(
         &mut self,
         hir_expr: &'tcx hir::Expr<'tcx>,
-        mut expr: Expr<'thir, 'tcx>,
+        mut expr: Expr<'tcx>,
         adjustment: &Adjustment<'tcx>,
-    ) -> Expr<'thir, 'tcx> {
+    ) -> Expr<'tcx> {
         let Expr { temp_lifetime, mut span, .. } = expr;
 
         // Adjust the span from the block, to the last expression of the
@@ -109,10 +95,10 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         //      x
         //   // ^ error message points at this expression.
         // }
-        let mut adjust_span = |expr: &mut Expr<'thir, 'tcx>| {
+        let mut adjust_span = |expr: &mut Expr<'tcx>| {
             if let ExprKind::Block { body } = &expr.kind {
-                if let Some(ref last_expr) = body.expr {
-                    span = last_expr.span;
+                if let Some(last_expr) = body.expr {
+                    span = self.thir[last_expr].span;
                     expr.span = span;
                 }
             }
@@ -121,13 +107,13 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         let kind = match adjustment.kind {
             Adjust::Pointer(PointerCast::Unsize) => {
                 adjust_span(&mut expr);
-                ExprKind::Pointer { cast: PointerCast::Unsize, source: self.arena.alloc(expr) }
+                ExprKind::Pointer { cast: PointerCast::Unsize, source: self.thir.exprs.push(expr) }
             }
-            Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.arena.alloc(expr) },
-            Adjust::NeverToAny => ExprKind::NeverToAny { source: self.arena.alloc(expr) },
+            Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.thir.exprs.push(expr) },
+            Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) },
             Adjust::Deref(None) => {
                 adjust_span(&mut expr);
-                ExprKind::Deref { arg: self.arena.alloc(expr) }
+                ExprKind::Deref { arg: self.thir.exprs.push(expr) }
             }
             Adjust::Deref(Some(deref)) => {
                 // We don't need to do call adjust_span here since
@@ -142,30 +128,27 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                     span,
                     kind: ExprKind::Borrow {
                         borrow_kind: deref.mutbl.to_borrow_kind(),
-                        arg: self.arena.alloc(expr),
+                        arg: self.thir.exprs.push(expr),
                     },
                 };
 
-                self.overloaded_place(
-                    hir_expr,
-                    adjustment.target,
-                    Some(call),
-                    self.arena.alloc_from_iter(iter::once(expr)),
-                    deref.span,
-                )
-            }
-            Adjust::Borrow(AutoBorrow::Ref(_, m)) => {
-                ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: self.arena.alloc(expr) }
+                let expr = box [self.thir.exprs.push(expr)];
+
+                self.overloaded_place(hir_expr, adjustment.target, Some(call), expr, deref.span)
             }
+            Adjust::Borrow(AutoBorrow::Ref(_, m)) => ExprKind::Borrow {
+                borrow_kind: m.to_borrow_kind(),
+                arg: self.thir.exprs.push(expr),
+            },
             Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
-                ExprKind::AddressOf { mutability, arg: self.arena.alloc(expr) }
+                ExprKind::AddressOf { mutability, arg: self.thir.exprs.push(expr) }
             }
         };
 
         Expr { temp_lifetime, ty: adjustment.target, span, kind }
     }
 
-    fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'thir, 'tcx> {
+    fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> {
         let expr_ty = self.typeck_results().expr_ty(expr);
         let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
 
@@ -177,7 +160,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                 let args = self.mirror_exprs(args);
                 ExprKind::Call {
                     ty: expr.ty,
-                    fun: self.arena.alloc(expr),
+                    fun: self.thir.exprs.push(expr),
                     args,
                     from_hir_call: true,
                     fn_span,
@@ -202,13 +185,12 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                         span: expr.span,
                         kind: ExprKind::Tuple { fields: self.mirror_exprs(args) },
                     };
+                    let tupled_args = self.thir.exprs.push(tupled_args);
 
                     ExprKind::Call {
                         ty: method.ty,
-                        fun: self.arena.alloc(method),
-                        args: self
-                            .arena
-                            .alloc_from_iter(vec![self.mirror_expr_inner(fun), tupled_args]),
+                        fun: self.thir.exprs.push(method),
+                        args: box [self.mirror_expr(fun), tupled_args],
                         from_hir_call: true,
                         fn_span: expr.span,
                     }
@@ -238,10 +220,14 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                             });
                         debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty);
 
-                        let field_refs =
-                            self.arena.alloc_from_iter(args.iter().enumerate().map(|(idx, e)| {
-                                FieldExpr { name: Field::new(idx), expr: self.mirror_expr(e) }
-                            }));
+                        let field_refs = args
+                            .iter()
+                            .enumerate()
+                            .map(|(idx, e)| FieldExpr {
+                                name: Field::new(idx),
+                                expr: self.mirror_expr(e),
+                            })
+                            .collect();
                         ExprKind::Adt {
                             adt_def,
                             substs,
@@ -278,9 +264,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let lhs = self.mirror_expr_inner(lhs);
-                    let rhs = self.mirror_expr_inner(rhs);
-                    self.overloaded_operator(expr, self.arena.alloc_from_iter(vec![lhs, rhs]))
+                    let lhs = self.mirror_expr(lhs);
+                    let rhs = self.mirror_expr(rhs);
+                    self.overloaded_operator(expr, box [lhs, rhs])
                 } else {
                     ExprKind::AssignOp {
                         op: bin_op(op.node),
@@ -298,9 +284,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::Binary(op, ref lhs, ref rhs) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let lhs = self.mirror_expr_inner(lhs);
-                    let rhs = self.mirror_expr_inner(rhs);
-                    self.overloaded_operator(expr, self.arena.alloc_from_iter(vec![lhs, rhs]))
+                    let lhs = self.mirror_expr(lhs);
+                    let rhs = self.mirror_expr(rhs);
+                    self.overloaded_operator(expr, box [lhs, rhs])
                 } else {
                     // FIXME overflow
                     match op.node {
@@ -329,15 +315,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::Index(ref lhs, ref index) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let lhs = self.mirror_expr_inner(lhs);
-                    let index = self.mirror_expr_inner(index);
-                    self.overloaded_place(
-                        expr,
-                        expr_ty,
-                        None,
-                        self.arena.alloc_from_iter(vec![lhs, index]),
-                        expr.span,
-                    )
+                    let lhs = self.mirror_expr(lhs);
+                    let index = self.mirror_expr(index);
+                    self.overloaded_place(expr, expr_ty, None, box [lhs, index], expr.span)
                 } else {
                     ExprKind::Index { lhs: self.mirror_expr(lhs), index: self.mirror_expr(index) }
                 }
@@ -345,14 +325,8 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::Unary(hir::UnOp::Deref, ref arg) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let arg = self.mirror_expr_inner(arg);
-                    self.overloaded_place(
-                        expr,
-                        expr_ty,
-                        None,
-                        self.arena.alloc_from_iter(iter::once(arg)),
-                        expr.span,
-                    )
+                    let arg = self.mirror_expr(arg);
+                    self.overloaded_place(expr, expr_ty, None, box [arg], expr.span)
                 } else {
                     ExprKind::Deref { arg: self.mirror_expr(arg) }
                 }
@@ -360,8 +334,8 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::Unary(hir::UnOp::Not, ref arg) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let arg = self.mirror_expr_inner(arg);
-                    self.overloaded_operator(expr, self.arena.alloc_from_iter(iter::once(arg)))
+                    let arg = self.mirror_expr(arg);
+                    self.overloaded_operator(expr, box [arg])
                 } else {
                     ExprKind::Unary { op: UnOp::Not, arg: self.mirror_expr(arg) }
                 }
@@ -369,8 +343,8 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::Unary(hir::UnOp::Neg, ref arg) => {
                 if self.typeck_results().is_method_call(expr) {
-                    let arg = self.mirror_expr_inner(arg);
-                    self.overloaded_operator(expr, self.arena.alloc_from_iter(iter::once(arg)))
+                    let arg = self.mirror_expr(arg);
+                    self.overloaded_operator(expr, box [arg])
                 } else if let hir::ExprKind::Lit(ref lit) = arg.kind {
                     ExprKind::Literal {
                         literal: self.const_eval_literal(&lit.node, expr_ty, lit.span, true),
@@ -396,11 +370,10 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                             fields: self.field_refs(fields),
                             base: base.as_ref().map(|base| FruInfo {
                                 base: self.mirror_expr(base),
-                                field_types: self.arena.alloc_from_iter(
-                                    self.typeck_results().fru_field_types()[expr.hir_id]
-                                        .iter()
-                                        .cloned(),
-                                ),
+                                field_types: self.typeck_results().fru_field_types()[expr.hir_id]
+                                    .iter()
+                                    .copied()
+                                    .collect(),
                             }),
                         }
                     }
@@ -447,12 +420,15 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                     }
                 };
 
-                let upvars = self.arena.alloc_from_iter(
-                    self.typeck_results
-                        .closure_min_captures_flattened(def_id)
-                        .zip(substs.upvar_tys())
-                        .map(|(captured_place, ty)| self.capture_upvar(expr, captured_place, ty)),
-                );
+                let upvars = self
+                    .typeck_results
+                    .closure_min_captures_flattened(def_id)
+                    .zip(substs.upvar_tys())
+                    .map(|(captured_place, ty)| {
+                        let upvars = self.capture_upvar(expr, captured_place, ty);
+                        self.thir.exprs.push(upvars)
+                    })
+                    .collect();
 
                 // Convert the closure fake reads, if any, from hir `Place` to ExprRef
                 let fake_reads = match self.typeck_results.closure_fake_reads.get(&def_id) {
@@ -460,8 +436,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                         .iter()
                         .map(|(place, cause, hir_id)| {
                             let expr = self.convert_captured_hir_place(expr, place.clone());
-                            let expr_ref: &'thir Expr<'thir, 'tcx> = self.arena.alloc(expr);
-                            (expr_ref, *cause, *hir_id)
+                            (self.thir.exprs.push(expr), *cause, *hir_id)
                         })
                         .collect(),
                     None => Vec::new(),
@@ -477,99 +452,105 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
 
             hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm {
                 template: asm.template,
-                operands: self.arena.alloc_from_iter(asm.operands.iter().map(|(op, _op_sp)| {
-                    match *op {
-                        hir::InlineAsmOperand::In { reg, ref expr } => {
-                            InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) }
-                        }
-                        hir::InlineAsmOperand::Out { reg, late, ref expr } => {
-                            InlineAsmOperand::Out {
+                operands: asm
+                    .operands
+                    .iter()
+                    .map(|(op, _op_sp)| {
+                        match *op {
+                            hir::InlineAsmOperand::In { reg, ref expr } => {
+                                InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) }
+                            }
+                            hir::InlineAsmOperand::Out { reg, late, ref expr } => {
+                                InlineAsmOperand::Out {
+                                    reg,
+                                    late,
+                                    expr: expr.as_ref().map(|expr| self.mirror_expr(expr)),
+                                }
+                            }
+                            hir::InlineAsmOperand::InOut { reg, late, ref expr } => {
+                                InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) }
+                            }
+                            hir::InlineAsmOperand::SplitInOut {
                                 reg,
                                 late,
-                                expr: expr.as_ref().map(|expr| self.mirror_expr(expr)),
-                            }
-                        }
-                        hir::InlineAsmOperand::InOut { reg, late, ref expr } => {
-                            InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) }
-                        }
-                        hir::InlineAsmOperand::SplitInOut {
-                            reg,
-                            late,
-                            ref in_expr,
-                            ref out_expr,
-                        } => InlineAsmOperand::SplitInOut {
-                            reg,
-                            late,
-                            in_expr: self.mirror_expr(in_expr),
-                            out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)),
-                        },
-                        hir::InlineAsmOperand::Const { ref anon_const } => {
-                            let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
-                            let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
-                            let span = self.tcx.hir().span(anon_const.hir_id);
+                                ref in_expr,
+                                ref out_expr,
+                            } => InlineAsmOperand::SplitInOut {
+                                reg,
+                                late,
+                                in_expr: self.mirror_expr(in_expr),
+                                out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)),
+                            },
+                            hir::InlineAsmOperand::Const { ref anon_const } => {
+                                let anon_const_def_id =
+                                    self.tcx.hir().local_def_id(anon_const.hir_id);
+                                let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+                                let span = self.tcx.hir().span(anon_const.hir_id);
 
-                            InlineAsmOperand::Const { value, span }
-                        }
-                        hir::InlineAsmOperand::Sym { ref expr } => {
-                            let qpath = match expr.kind {
-                                hir::ExprKind::Path(ref qpath) => qpath,
-                                _ => span_bug!(
-                                    expr.span,
-                                    "asm `sym` operand should be a path, found {:?}",
-                                    expr.kind
-                                ),
-                            };
-                            let temp_lifetime =
-                                self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-                            let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
-                            let ty;
-                            match res {
-                                Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) => {
-                                    ty = self.typeck_results().node_type(expr.hir_id);
-                                    let user_ty = self.user_substs_applied_to_res(expr.hir_id, res);
-                                    InlineAsmOperand::SymFn {
-                                        expr: self.arena.alloc(Expr {
-                                            ty,
-                                            temp_lifetime,
-                                            span: expr.span,
-                                            kind: ExprKind::Literal {
-                                                literal: ty::Const::zero_sized(self.tcx, ty),
-                                                user_ty,
-                                                const_id: None,
-                                            },
-                                        }),
+                                InlineAsmOperand::Const { value, span }
+                            }
+                            hir::InlineAsmOperand::Sym { ref expr } => {
+                                let qpath = match expr.kind {
+                                    hir::ExprKind::Path(ref qpath) => qpath,
+                                    _ => span_bug!(
+                                        expr.span,
+                                        "asm `sym` operand should be a path, found {:?}",
+                                        expr.kind
+                                    ),
+                                };
+                                let temp_lifetime =
+                                    self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
+                                let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
+                                let ty;
+                                match res {
+                                    Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) => {
+                                        ty = self.typeck_results().node_type(expr.hir_id);
+                                        let user_ty =
+                                            self.user_substs_applied_to_res(expr.hir_id, res);
+                                        InlineAsmOperand::SymFn {
+                                            expr: self.thir.exprs.push(Expr {
+                                                ty,
+                                                temp_lifetime,
+                                                span: expr.span,
+                                                kind: ExprKind::Literal {
+                                                    literal: ty::Const::zero_sized(self.tcx, ty),
+                                                    user_ty,
+                                                    const_id: None,
+                                                },
+                                            }),
+                                        }
                                     }
-                                }
 
-                                Res::Def(DefKind::Static, def_id) => {
-                                    InlineAsmOperand::SymStatic { def_id }
-                                }
+                                    Res::Def(DefKind::Static, def_id) => {
+                                        InlineAsmOperand::SymStatic { def_id }
+                                    }
 
-                                _ => {
-                                    self.tcx.sess.span_err(
-                                        expr.span,
-                                        "asm `sym` operand must point to a fn or static",
-                                    );
-
-                                    // Not a real fn, but we're not reaching codegen anyways...
-                                    ty = self.tcx.ty_error();
-                                    InlineAsmOperand::SymFn {
-                                        expr: self.arena.alloc(Expr {
-                                            ty,
-                                            temp_lifetime,
-                                            span: expr.span,
-                                            kind: ExprKind::Literal {
-                                                literal: ty::Const::zero_sized(self.tcx, ty),
-                                                user_ty: None,
-                                                const_id: None,
-                                            },
-                                        }),
+                                    _ => {
+                                        self.tcx.sess.span_err(
+                                            expr.span,
+                                            "asm `sym` operand must point to a fn or static",
+                                        );
+
+                                        // Not a real fn, but we're not reaching codegen anyways...
+                                        ty = self.tcx.ty_error();
+                                        InlineAsmOperand::SymFn {
+                                            expr: self.thir.exprs.push(Expr {
+                                                ty,
+                                                temp_lifetime,
+                                                span: expr.span,
+                                                kind: ExprKind::Literal {
+                                                    literal: ty::Const::zero_sized(self.tcx, ty),
+                                                    user_ty: None,
+                                                    const_id: None,
+                                                },
+                                            }),
+                                        }
                                     }
                                 }
                             }
                         }
-                    }
-                })),
+                    })
+                    .collect(),
                 options: asm.options,
                 line_spans: asm.line_spans,
             },
@@ -616,13 +597,13 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
             },
             hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match {
                 scrutinee: self.mirror_expr(discr),
-                arms: self.arena.alloc_from_iter(arms.iter().map(|a| self.convert_arm(a))),
+                arms: arms.iter().map(|a| self.convert_arm(a)).collect(),
             },
             hir::ExprKind::Loop(ref body, ..) => {
                 let block_ty = self.typeck_results().node_type(body.hir_id);
                 let temp_lifetime = self.region_scope_tree.temporary_scope(body.hir_id.local_id);
                 let block = self.mirror_block(body);
-                let body = self.arena.alloc(Expr {
+                let body = self.thir.exprs.push(Expr {
                     ty: block_ty,
                     temp_lifetime,
                     span: block.span,
@@ -692,35 +673,34 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                     };
 
                     let source = if let Some((did, offset, var_ty)) = var {
-                        let mk_const = |literal| {
-                            self.arena.alloc(Expr {
-                                temp_lifetime,
-                                ty: var_ty,
-                                span: expr.span,
-                                kind: ExprKind::Literal { literal, user_ty: None, const_id: None },
-                            })
+                        let mk_const = |literal| Expr {
+                            temp_lifetime,
+                            ty: var_ty,
+                            span: expr.span,
+                            kind: ExprKind::Literal { literal, user_ty: None, const_id: None },
                         };
-                        let offset = mk_const(ty::Const::from_bits(
+                        let offset = self.thir.exprs.push(mk_const(ty::Const::from_bits(
                             self.tcx,
                             offset as u128,
                             self.param_env.and(var_ty),
-                        ));
+                        )));
                         match did {
                             Some(did) => {
                                 // in case we are offsetting from a computed discriminant
                                 // and not the beginning of discriminants (which is always `0`)
                                 let substs = InternalSubsts::identity_for_item(self.tcx(), did);
-                                let lhs = mk_const(self.tcx().mk_const(ty::Const {
+                                let lhs = ty::Const {
                                     val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                                         def: ty::WithOptConstParam::unknown(did),
                                         substs,
                                         promoted: None,
                                     }),
                                     ty: var_ty,
-                                }));
+                                };
+                                let lhs = self.thir.exprs.push(mk_const(self.tcx().mk_const(lhs)));
                                 let bin =
                                     ExprKind::Binary { op: BinOp::Add, lhs: lhs, rhs: offset };
-                                self.arena.alloc(Expr {
+                                self.thir.exprs.push(Expr {
                                     temp_lifetime,
                                     ty: var_ty,
                                     span: expr.span,
@@ -739,7 +719,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                 if let Some(user_ty) = user_ty {
                     // NOTE: Creating a new Expr and wrapping a Cast inside of it may be
                     //       inefficient, revisit this when performance becomes an issue.
-                    let cast_expr = self.arena.alloc(Expr {
+                    let cast_expr = self.thir.exprs.push(Expr {
                         temp_lifetime,
                         ty: expr_ty,
                         span: expr.span,
@@ -819,7 +799,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         expr: &hir::Expr<'_>,
         span: Span,
         overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
-    ) -> Expr<'thir, 'tcx> {
+    ) -> Expr<'tcx> {
         let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
         let (def_id, substs, user_ty) = match overloaded_callee {
             Some((def_id, substs)) => (def_id, substs, None),
@@ -846,8 +826,8 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         }
     }
 
-    fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> Arm<'thir, 'tcx> {
-        Arm {
+    fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId {
+        let arm = Arm {
             pattern: self.pattern_from_hir(&arm.pat),
             guard: arm.guard.as_ref().map(|g| match g {
                 hir::Guard::If(ref e) => Guard::If(self.mirror_expr(e)),
@@ -859,14 +839,11 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
             lint_level: LintLevel::Explicit(arm.hir_id),
             scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node },
             span: arm.span,
-        }
+        };
+        self.thir.arms.push(arm)
     }
 
-    fn convert_path_expr(
-        &mut self,
-        expr: &'tcx hir::Expr<'tcx>,
-        res: Res,
-    ) -> ExprKind<'thir, 'tcx> {
+    fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKind<'tcx> {
         let substs = self.typeck_results().node_substs(expr.hir_id);
         match res {
             // A regular function, constructor function or a constant.
@@ -934,7 +911,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                         variant_index: adt_def.variant_index_with_ctor_id(def_id),
                         substs,
                         user_ty: user_provided_type,
-                        fields: self.arena.alloc_from_iter(iter::empty()),
+                        fields: box [],
                         base: None,
                     },
                     _ => bug!("unexpected ty: {:?}", ty),
@@ -956,7 +933,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                     }
                 };
                 ExprKind::Deref {
-                    arg: self.arena.alloc(Expr { ty, temp_lifetime, span: expr.span, kind }),
+                    arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }),
                 }
             }
 
@@ -966,7 +943,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         }
     }
 
-    fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'thir, 'tcx> {
+    fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'tcx> {
         // We want upvars here not captures.
         // Captures will be handled in MIR.
         let is_upvar = self
@@ -989,10 +966,17 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
     fn overloaded_operator(
         &mut self,
         expr: &'tcx hir::Expr<'tcx>,
-        args: &'thir [Expr<'thir, 'tcx>],
-    ) -> ExprKind<'thir, 'tcx> {
-        let fun = self.arena.alloc(self.method_callee(expr, expr.span, None));
-        ExprKind::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: expr.span }
+        args: Box<[ExprId]>,
+    ) -> ExprKind<'tcx> {
+        let fun = self.method_callee(expr, expr.span, None);
+        let fun = self.thir.exprs.push(fun);
+        ExprKind::Call {
+            ty: self.thir[fun].ty,
+            fun,
+            args,
+            from_hir_call: false,
+            fn_span: expr.span,
+        }
     }
 
     fn overloaded_place(
@@ -1000,9 +984,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         expr: &'tcx hir::Expr<'tcx>,
         place_ty: Ty<'tcx>,
         overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
-        args: &'thir [Expr<'thir, 'tcx>],
+        args: Box<[ExprId]>,
         span: Span,
-    ) -> ExprKind<'thir, 'tcx> {
+    ) -> ExprKind<'tcx> {
         // For an overloaded *x or x[y] expression of type T, the method
         // call returns an &T and we must add the deref so that the types
         // line up (this is because `*x` and `x[y]` represent places):
@@ -1010,7 +994,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         // Reconstruct the output assuming it's a reference with the
         // same region and mutability as the receiver. This holds for
         // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
-        let (region, mutbl) = match *args[0].ty.kind() {
+        let (region, mutbl) = match *self.thir[args[0]].ty.kind() {
             ty::Ref(region, _, mutbl) => (region, mutbl),
             _ => span_bug!(span, "overloaded_place: receiver is not a reference"),
         };
@@ -1019,12 +1003,14 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         // construct the complete expression `foo()` for the overloaded call,
         // which will yield the &T type
         let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
-        let fun = self.arena.alloc(self.method_callee(expr, span, overloaded_callee));
-        let ref_expr = self.arena.alloc(Expr {
+        let fun = self.method_callee(expr, span, overloaded_callee);
+        let fun = self.thir.exprs.push(fun);
+        let fun_ty = self.thir[fun].ty;
+        let ref_expr = self.thir.exprs.push(Expr {
             temp_lifetime,
             ty: ref_ty,
             span,
-            kind: ExprKind::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: span },
+            kind: ExprKind::Call { ty: fun_ty, fun, args, from_hir_call: false, fn_span: span },
         });
 
         // construct and return a deref wrapper `*foo()`
@@ -1035,7 +1021,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         &mut self,
         closure_expr: &'tcx hir::Expr<'tcx>,
         place: HirPlace<'tcx>,
-    ) -> Expr<'thir, 'tcx> {
+    ) -> Expr<'tcx> {
         let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
         let var_ty = place.base_ty;
 
@@ -1059,13 +1045,13 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         for proj in place.projections.iter() {
             let kind = match proj.kind {
                 HirProjectionKind::Deref => {
-                    ExprKind::Deref { arg: self.arena.alloc(captured_place_expr) }
+                    ExprKind::Deref { arg: self.thir.exprs.push(captured_place_expr) }
                 }
                 HirProjectionKind::Field(field, ..) => {
                     // Variant index will always be 0, because for multi-variant
                     // enums, we capture the enum entirely.
                     ExprKind::Field {
-                        lhs: self.arena.alloc(captured_place_expr),
+                        lhs: self.thir.exprs.push(captured_place_expr),
                         name: Field::new(field as usize),
                     }
                 }
@@ -1087,7 +1073,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
         closure_expr: &'tcx hir::Expr<'tcx>,
         captured_place: &'tcx ty::CapturedPlace<'tcx>,
         upvar_ty: Ty<'tcx>,
-    ) -> Expr<'thir, 'tcx> {
+    ) -> Expr<'tcx> {
         let upvar_capture = captured_place.info.capture_kind;
         let captured_place_expr =
             self.convert_captured_hir_place(closure_expr, captured_place.place.clone());
@@ -1107,7 +1093,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
                     span: closure_expr.span,
                     kind: ExprKind::Borrow {
                         borrow_kind,
-                        arg: self.arena.alloc(captured_place_expr),
+                        arg: self.thir.exprs.push(captured_place_expr),
                     },
                 }
             }
@@ -1115,14 +1101,14 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
     }
 
     /// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExpr.
-    fn field_refs(
-        &mut self,
-        fields: &'tcx [hir::ExprField<'tcx>],
-    ) -> &'thir [FieldExpr<'thir, 'tcx>] {
-        self.arena.alloc_from_iter(fields.iter().map(|field| FieldExpr {
-            name: Field::new(self.tcx.field_index(field.hir_id, self.typeck_results)),
-            expr: self.mirror_expr(field.expr),
-        }))
+    fn field_refs(&mut self, fields: &'tcx [hir::ExprField<'tcx>]) -> Box<[FieldExpr]> {
+        fields
+            .iter()
+            .map(|field| FieldExpr {
+                name: Field::new(self.tcx.field_index(field.hir_id, self.typeck_results)),
+                expr: self.mirror_expr(field.expr),
+            })
+            .collect()
     }
 }
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index c0433604f8c..49ba71e3520 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -2,30 +2,37 @@
 //! structures into the THIR. The `builder` is generally ignorant of the tcx,
 //! etc., and instead goes through the `Cx` for most of its work.
 
-use crate::thir::arena::Arena;
+use crate::thir::pattern::pat_from_hir;
 use crate::thir::util::UserAnnotatedTyHelpers;
-use crate::thir::*;
 
 use rustc_ast as ast;
+use rustc_data_structures::steal::Steal;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::Node;
 use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
+use rustc_middle::thir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::Span;
 
-pub fn build_thir<'thir, 'tcx>(
+crate fn thir_body<'tcx>(
     tcx: TyCtxt<'tcx>,
     owner_def: ty::WithOptConstParam<LocalDefId>,
-    arena: &'thir Arena<'thir, 'tcx>,
-    expr: &'tcx hir::Expr<'tcx>,
-) -> &'thir Expr<'thir, 'tcx> {
-    Cx::new(tcx, owner_def, &arena).mirror_expr(expr)
+) -> (&'tcx Steal<Thir<'tcx>>, ExprId) {
+    let hir = tcx.hir();
+    let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(owner_def.did)));
+    let mut cx = Cx::new(tcx, owner_def);
+    if cx.typeck_results.tainted_by_errors.is_some() {
+        return (tcx.alloc_steal_thir(Thir::new()), ExprId::from_u32(0));
+    }
+    let expr = cx.mirror_expr(&body.value);
+    (tcx.alloc_steal_thir(cx.thir), expr)
 }
 
-struct Cx<'thir, 'tcx> {
+struct Cx<'tcx> {
     tcx: TyCtxt<'tcx>,
-    arena: &'thir Arena<'thir, 'tcx>,
+    thir: Thir<'tcx>,
 
     crate param_env: ty::ParamEnv<'tcx>,
 
@@ -36,16 +43,12 @@ struct Cx<'thir, 'tcx> {
     body_owner: DefId,
 }
 
-impl<'thir, 'tcx> Cx<'thir, 'tcx> {
-    fn new(
-        tcx: TyCtxt<'tcx>,
-        def: ty::WithOptConstParam<LocalDefId>,
-        arena: &'thir Arena<'thir, 'tcx>,
-    ) -> Cx<'thir, 'tcx> {
+impl<'tcx> Cx<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> {
         let typeck_results = tcx.typeck_opt_const_arg(def);
         Cx {
             tcx,
-            arena,
+            thir: Thir::new(),
             param_env: tcx.param_env(def.did),
             region_scope_tree: tcx.region_scope_tree(def.did),
             typeck_results,
@@ -83,11 +86,11 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
             Node::Pat(p) | Node::Binding(p) => p,
             node => bug!("pattern became {:?}", node),
         };
-        Pat::from_hir(self.tcx, self.param_env, self.typeck_results(), p)
+        pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p)
     }
 }
 
-impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'_, 'tcx> {
+impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs
index 9bcb000920c..e5123d8ef0c 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -4,384 +4,11 @@
 //! unit-tested and separated from the Rust source and compiler data
 //! structures.
 
-use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_middle::infer::canonical::Canonical;
-use rustc_middle::middle::region;
-use rustc_middle::mir::{BinOp, BorrowKind, FakeReadCause, Field, UnOp};
-use rustc_middle::ty::adjustment::PointerCast;
-use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{AdtDef, Const, Ty, UpvarSubsts, UserType};
-use rustc_span::Span;
-use rustc_target::abi::VariantIdx;
-use rustc_target::asm::InlineAsmRegOrRegClass;
-
 crate mod constant;
 
 crate mod cx;
-pub use cx::build_thir;
 
 crate mod pattern;
-pub use self::pattern::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
-
-mod arena;
-pub use arena::Arena;
 
 mod util;
 pub mod visit;
-
-#[derive(Copy, Clone, Debug)]
-pub enum LintLevel {
-    Inherited,
-    Explicit(hir::HirId),
-}
-
-#[derive(Debug)]
-pub struct Block<'thir, 'tcx> {
-    pub targeted_by_break: bool,
-    pub region_scope: region::Scope,
-    pub opt_destruction_scope: Option<region::Scope>,
-    pub span: Span,
-    pub stmts: &'thir [Stmt<'thir, 'tcx>],
-    pub expr: Option<&'thir Expr<'thir, 'tcx>>,
-    pub safety_mode: BlockSafety,
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum BlockSafety {
-    Safe,
-    ExplicitUnsafe(hir::HirId),
-    PushUnsafe,
-    PopUnsafe,
-}
-
-#[derive(Debug)]
-pub struct Stmt<'thir, 'tcx> {
-    pub kind: StmtKind<'thir, 'tcx>,
-    pub opt_destruction_scope: Option<region::Scope>,
-}
-
-#[derive(Debug)]
-pub enum StmtKind<'thir, 'tcx> {
-    Expr {
-        /// scope for this statement; may be used as lifetime of temporaries
-        scope: region::Scope,
-
-        /// expression being evaluated in this statement
-        expr: &'thir Expr<'thir, 'tcx>,
-    },
-
-    Let {
-        /// scope for variables bound in this let; covers this and
-        /// remaining statements in block
-        remainder_scope: region::Scope,
-
-        /// scope for the initialization itself; might be used as
-        /// lifetime of temporaries
-        init_scope: region::Scope,
-
-        /// `let <PAT> = ...`
-        ///
-        /// if a type is included, it is added as an ascription pattern
-        pattern: Pat<'tcx>,
-
-        /// let pat: ty = <INIT> ...
-        initializer: Option<&'thir Expr<'thir, 'tcx>>,
-
-        /// the lint level for this let-statement
-        lint_level: LintLevel,
-    },
-}
-
-// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Expr<'_, '_>, 144);
-
-/// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`)
-/// into instances of this `Expr` enum. This lowering can be done
-/// basically as lazily or as eagerly as desired: every recursive
-/// reference to an expression in this enum is an `&'thir Expr<'thir, 'tcx>`, which
-/// may in turn be another instance of this enum (boxed), or else an
-/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
-/// short-lived. They are created by `Thir::to_expr`, analyzed and
-/// converted into MIR, and then discarded.
-///
-/// If you compare `Expr` to the full compiler AST, you will see it is
-/// a good bit simpler. In fact, a number of the more straight-forward
-/// MIR simplifications are already done in the impl of `Thir`. For
-/// example, method calls and overloaded operators are absent: they are
-/// expected to be converted into `Expr::Call` instances.
-#[derive(Debug)]
-pub struct Expr<'thir, 'tcx> {
-    /// type of this expression
-    pub ty: Ty<'tcx>,
-
-    /// lifetime of this expression if it should be spilled into a
-    /// temporary; should be None only if in a constant context
-    pub temp_lifetime: Option<region::Scope>,
-
-    /// span of the expression in the source
-    pub span: Span,
-
-    /// kind of expression
-    pub kind: ExprKind<'thir, 'tcx>,
-}
-
-#[derive(Debug)]
-pub enum ExprKind<'thir, 'tcx> {
-    Scope {
-        region_scope: region::Scope,
-        lint_level: LintLevel,
-        value: &'thir Expr<'thir, 'tcx>,
-    },
-    Box {
-        value: &'thir Expr<'thir, 'tcx>,
-    },
-    If {
-        cond: &'thir Expr<'thir, 'tcx>,
-        then: &'thir Expr<'thir, 'tcx>,
-        else_opt: Option<&'thir Expr<'thir, 'tcx>>,
-    },
-    Call {
-        ty: Ty<'tcx>,
-        fun: &'thir Expr<'thir, 'tcx>,
-        args: &'thir [Expr<'thir, 'tcx>],
-        /// Whether this is from a call in HIR, rather than from an overloaded
-        /// operator. `true` for overloaded function call.
-        from_hir_call: bool,
-        /// This `Span` is the span of the function, without the dot and receiver
-        /// (e.g. `foo(a, b)` in `x.foo(a, b)`
-        fn_span: Span,
-    },
-    Deref {
-        arg: &'thir Expr<'thir, 'tcx>,
-    }, // NOT overloaded!
-    Binary {
-        op: BinOp,
-        lhs: &'thir Expr<'thir, 'tcx>,
-        rhs: &'thir Expr<'thir, 'tcx>,
-    }, // NOT overloaded!
-    LogicalOp {
-        op: LogicalOp,
-        lhs: &'thir Expr<'thir, 'tcx>,
-        rhs: &'thir Expr<'thir, 'tcx>,
-    }, // NOT overloaded!
-    // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
-    Unary {
-        op: UnOp,
-        arg: &'thir Expr<'thir, 'tcx>,
-    }, // NOT overloaded!
-    Cast {
-        source: &'thir Expr<'thir, 'tcx>,
-    },
-    Use {
-        source: &'thir Expr<'thir, 'tcx>,
-    }, // Use a lexpr to get a vexpr.
-    NeverToAny {
-        source: &'thir Expr<'thir, 'tcx>,
-    },
-    Pointer {
-        cast: PointerCast,
-        source: &'thir Expr<'thir, 'tcx>,
-    },
-    Loop {
-        body: &'thir Expr<'thir, 'tcx>,
-    },
-    Match {
-        scrutinee: &'thir Expr<'thir, 'tcx>,
-        arms: &'thir [Arm<'thir, 'tcx>],
-    },
-    Block {
-        body: Block<'thir, 'tcx>,
-    },
-    Assign {
-        lhs: &'thir Expr<'thir, 'tcx>,
-        rhs: &'thir Expr<'thir, 'tcx>,
-    },
-    AssignOp {
-        op: BinOp,
-        lhs: &'thir Expr<'thir, 'tcx>,
-        rhs: &'thir Expr<'thir, 'tcx>,
-    },
-    Field {
-        lhs: &'thir Expr<'thir, 'tcx>,
-        name: Field,
-    },
-    Index {
-        lhs: &'thir Expr<'thir, 'tcx>,
-        index: &'thir Expr<'thir, 'tcx>,
-    },
-    VarRef {
-        id: hir::HirId,
-    },
-    /// Used to represent upvars mentioned in a closure/generator
-    UpvarRef {
-        /// DefId of the closure/generator
-        closure_def_id: DefId,
-
-        /// HirId of the root variable
-        var_hir_id: hir::HirId,
-    },
-    Borrow {
-        borrow_kind: BorrowKind,
-        arg: &'thir Expr<'thir, 'tcx>,
-    },
-    /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
-    AddressOf {
-        mutability: hir::Mutability,
-        arg: &'thir Expr<'thir, 'tcx>,
-    },
-    Break {
-        label: region::Scope,
-        value: Option<&'thir Expr<'thir, 'tcx>>,
-    },
-    Continue {
-        label: region::Scope,
-    },
-    Return {
-        value: Option<&'thir Expr<'thir, 'tcx>>,
-    },
-    ConstBlock {
-        value: &'tcx Const<'tcx>,
-    },
-    Repeat {
-        value: &'thir Expr<'thir, 'tcx>,
-        count: &'tcx Const<'tcx>,
-    },
-    Array {
-        fields: &'thir [Expr<'thir, 'tcx>],
-    },
-    Tuple {
-        fields: &'thir [Expr<'thir, 'tcx>],
-    },
-    Adt {
-        adt_def: &'tcx AdtDef,
-        variant_index: VariantIdx,
-        substs: SubstsRef<'tcx>,
-
-        /// Optional user-given substs: for something like `let x =
-        /// Bar::<T> { ... }`.
-        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
-
-        fields: &'thir [FieldExpr<'thir, 'tcx>],
-        base: Option<FruInfo<'thir, 'tcx>>,
-    },
-    PlaceTypeAscription {
-        source: &'thir Expr<'thir, 'tcx>,
-        /// Type that the user gave to this expression
-        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
-    },
-    ValueTypeAscription {
-        source: &'thir Expr<'thir, 'tcx>,
-        /// Type that the user gave to this expression
-        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
-    },
-    Closure {
-        closure_id: DefId,
-        substs: UpvarSubsts<'tcx>,
-        upvars: &'thir [Expr<'thir, 'tcx>],
-        movability: Option<hir::Movability>,
-        fake_reads: Vec<(&'thir Expr<'thir, 'tcx>, FakeReadCause, hir::HirId)>,
-    },
-    Literal {
-        literal: &'tcx Const<'tcx>,
-        user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
-        /// The `DefId` of the `const` item this literal
-        /// was produced from, if this is not a user-written
-        /// literal value.
-        const_id: Option<DefId>,
-    },
-    /// A literal containing the address of a `static`.
-    ///
-    /// This is only distinguished from `Literal` so that we can register some
-    /// info for diagnostics.
-    StaticRef {
-        literal: &'tcx Const<'tcx>,
-        def_id: DefId,
-    },
-    InlineAsm {
-        template: &'tcx [InlineAsmTemplatePiece],
-        operands: &'thir [InlineAsmOperand<'thir, 'tcx>],
-        options: InlineAsmOptions,
-        line_spans: &'tcx [Span],
-    },
-    /// An expression taking a reference to a thread local.
-    ThreadLocalRef(DefId),
-    LlvmInlineAsm {
-        asm: &'tcx hir::LlvmInlineAsmInner,
-        outputs: &'thir [Expr<'thir, 'tcx>],
-        inputs: &'thir [Expr<'thir, 'tcx>],
-    },
-    Yield {
-        value: &'thir Expr<'thir, 'tcx>,
-    },
-}
-
-#[derive(Debug)]
-pub struct FieldExpr<'thir, 'tcx> {
-    pub name: Field,
-    pub expr: &'thir Expr<'thir, 'tcx>,
-}
-
-#[derive(Debug)]
-pub struct FruInfo<'thir, 'tcx> {
-    pub base: &'thir Expr<'thir, 'tcx>,
-    pub field_types: &'thir [Ty<'tcx>],
-}
-
-#[derive(Debug)]
-pub struct Arm<'thir, 'tcx> {
-    pub pattern: Pat<'tcx>,
-    pub guard: Option<Guard<'thir, 'tcx>>,
-    pub body: &'thir Expr<'thir, 'tcx>,
-    pub lint_level: LintLevel,
-    pub scope: region::Scope,
-    pub span: Span,
-}
-
-#[derive(Debug)]
-pub enum Guard<'thir, 'tcx> {
-    If(&'thir Expr<'thir, 'tcx>),
-    IfLet(Pat<'tcx>, &'thir Expr<'thir, 'tcx>),
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum LogicalOp {
-    And,
-    Or,
-}
-
-#[derive(Debug)]
-pub enum InlineAsmOperand<'thir, 'tcx> {
-    In {
-        reg: InlineAsmRegOrRegClass,
-        expr: &'thir Expr<'thir, 'tcx>,
-    },
-    Out {
-        reg: InlineAsmRegOrRegClass,
-        late: bool,
-        expr: Option<&'thir Expr<'thir, 'tcx>>,
-    },
-    InOut {
-        reg: InlineAsmRegOrRegClass,
-        late: bool,
-        expr: &'thir Expr<'thir, 'tcx>,
-    },
-    SplitInOut {
-        reg: InlineAsmRegOrRegClass,
-        late: bool,
-        in_expr: &'thir Expr<'thir, 'tcx>,
-        out_expr: Option<&'thir Expr<'thir, 'tcx>>,
-    },
-    Const {
-        value: &'tcx Const<'tcx>,
-        span: Span,
-    },
-    SymFn {
-        expr: &'thir Expr<'thir, 'tcx>,
-    },
-    SymStatic {
-        def_id: DefId,
-    },
-}
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 e4419070cbd..389a7595315 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1,8 +1,8 @@
 use super::usefulness::{
-    compute_match_usefulness, expand_pattern, MatchArm, MatchCheckCtxt, Reachability,
+    compute_match_usefulness, expand_pattern, is_wildcard, MatchArm, MatchCheckCtxt, Reachability,
     UsefulnessReport,
 };
-use super::{PatCtxt, PatKind, PatternError};
+use super::{PatCtxt, PatternError};
 
 use rustc_arena::TypedArena;
 use rustc_ast::Mutability;
@@ -12,6 +12,7 @@ use rustc_hir::def::*;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{HirId, Pat};
+use rustc_middle::thir::PatKind;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME;
 use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS};
@@ -344,7 +345,7 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa
 
 /// Checks for common cases of "catchall" patterns that may not be intended as such.
 fn pat_is_catchall(pat: &super::Pat<'_>) -> bool {
-    use super::PatKind::*;
+    use PatKind::*;
     match &*pat.kind {
         Binding { subpattern: None, .. } => true,
         Binding { subpattern: Some(s), .. } | Deref { subpattern: s } => pat_is_catchall(s),
@@ -514,7 +515,7 @@ fn non_exhaustive_match<'p, 'tcx>(
     if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize)
         && !is_empty_match
         && witnesses.len() == 1
-        && witnesses[0].is_wildcard()
+        && is_wildcard(&witnesses[0])
     {
         err.note(&format!(
             "`{}` does not have a fixed maximum value, \
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 c0624c805a6..369fff00456 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
@@ -2,6 +2,7 @@ use rustc_hir as hir;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::mir::Field;
+use rustc_middle::thir::{FieldPat, Pat, PatKind};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_session::lint;
@@ -12,7 +13,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
 
 use std::cell::Cell;
 
-use super::{FieldPat, Pat, PatCtxt, PatKind};
+use super::PatCtxt;
 
 impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     /// Converts an evaluated constant to a pattern (if possible).
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 db0f487645f..4b5b648c504 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -46,8 +46,7 @@ use self::Constructor::*;
 use self::SliceKind::*;
 
 use super::compare_const_vals;
-use super::usefulness::{MatchCheckCtxt, PatCtxt};
-use super::{FieldPat, Pat, PatKind, PatRange};
+use super::usefulness::{is_wildcard, MatchCheckCtxt, PatCtxt};
 
 use rustc_data_structures::captures::Captures;
 use rustc_index::vec::Idx;
@@ -55,6 +54,7 @@ use rustc_index::vec::Idx;
 use rustc_hir::{HirId, RangeEnd};
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::mir::Field;
+use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{self, Const, Ty, TyCtxt};
 use rustc_session::lint;
@@ -1245,13 +1245,13 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
                         // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`.
                         // This is incorrect if the size is not known, since `[_, ..]` captures
                         // arrays of lengths `>= 1` whereas `[..]` captures any length.
-                        while !prefix.is_empty() && prefix.last().unwrap().is_wildcard() {
+                        while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) {
                             prefix.pop();
                         }
                     }
                     let suffix: Vec<_> = if slice.array_len.is_some() {
                         // Same as above.
-                        subpatterns.skip_while(Pat::is_wildcard).collect()
+                        subpatterns.skip_while(is_wildcard).collect()
                     } else {
                         subpatterns.collect()
                     };
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 9ac79a37ac6..3225d302cb3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -11,7 +11,7 @@ use crate::thir::util::UserAnnotatedTyHelpers;
 
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
-use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
+use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::RangeEnd;
 use rustc_index::vec::Idx;
@@ -19,16 +19,12 @@ use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue};
 use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput};
 use rustc_middle::mir::UserTypeProjection;
 use rustc_middle::mir::{BorrowKind, Field, Mutability};
+use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj};
 use rustc_middle::ty::subst::{GenericArg, SubstsRef};
 use rustc_middle::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType};
-use rustc_middle::ty::{
-    CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
-};
-use rustc_span::{Span, Symbol, DUMMY_SP};
-use rustc_target::abi::VariantIdx;
+use rustc_span::{Span, Symbol};
 
 use std::cmp::Ordering;
-use std::fmt;
 
 #[derive(Clone, Debug)]
 crate enum PatternError {
@@ -39,317 +35,6 @@ crate enum PatternError {
     NonConstPath(Span),
 }
 
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum BindingMode {
-    ByValue,
-    ByRef(BorrowKind),
-}
-
-#[derive(Clone, Debug, PartialEq)]
-pub struct FieldPat<'tcx> {
-    pub field: Field,
-    pub pattern: Pat<'tcx>,
-}
-
-#[derive(Clone, Debug, PartialEq)]
-pub struct Pat<'tcx> {
-    pub ty: Ty<'tcx>,
-    pub span: Span,
-    pub kind: Box<PatKind<'tcx>>,
-}
-
-impl<'tcx> Pat<'tcx> {
-    pub(crate) fn wildcard_from_ty(ty: Ty<'tcx>) -> Self {
-        Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) }
-    }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct PatTyProj<'tcx> {
-    pub user_ty: CanonicalUserType<'tcx>,
-}
-
-impl<'tcx> PatTyProj<'tcx> {
-    pub(crate) fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self {
-        Self { user_ty: user_annotation }
-    }
-
-    pub(crate) fn user_ty(
-        self,
-        annotations: &mut CanonicalUserTypeAnnotations<'tcx>,
-        inferred_ty: Ty<'tcx>,
-        span: Span,
-    ) -> UserTypeProjection {
-        UserTypeProjection {
-            base: annotations.push(CanonicalUserTypeAnnotation {
-                span,
-                user_ty: self.user_ty,
-                inferred_ty,
-            }),
-            projs: Vec::new(),
-        }
-    }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct Ascription<'tcx> {
-    pub user_ty: PatTyProj<'tcx>,
-    /// Variance to use when relating the type `user_ty` to the **type of the value being
-    /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must
-    /// have a type that is some subtype of the ascribed type.
-    ///
-    /// Note that this variance does not apply for any bindings within subpatterns. The type
-    /// assigned to those bindings must be exactly equal to the `user_ty` given here.
-    ///
-    /// The only place where this field is not `Covariant` is when matching constants, where
-    /// we currently use `Contravariant` -- this is because the constant type just needs to
-    /// be "comparable" to the type of the input value. So, for example:
-    ///
-    /// ```text
-    /// match x { "foo" => .. }
-    /// ```
-    ///
-    /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should
-    /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior
-    /// of the old type-check for now. See #57280 for details.
-    pub variance: ty::Variance,
-    pub user_ty_span: Span,
-}
-
-#[derive(Clone, Debug, PartialEq)]
-pub enum PatKind<'tcx> {
-    Wild,
-
-    AscribeUserType {
-        ascription: Ascription<'tcx>,
-        subpattern: Pat<'tcx>,
-    },
-
-    /// `x`, `ref x`, `x @ P`, etc.
-    Binding {
-        mutability: Mutability,
-        name: Symbol,
-        mode: BindingMode,
-        var: hir::HirId,
-        ty: Ty<'tcx>,
-        subpattern: Option<Pat<'tcx>>,
-        /// Is this the leftmost occurrence of the binding, i.e., is `var` the
-        /// `HirId` of this pattern?
-        is_primary: bool,
-    },
-
-    /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with
-    /// multiple variants.
-    Variant {
-        adt_def: &'tcx AdtDef,
-        substs: SubstsRef<'tcx>,
-        variant_index: VariantIdx,
-        subpatterns: Vec<FieldPat<'tcx>>,
-    },
-
-    /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with
-    /// a single variant.
-    Leaf {
-        subpatterns: Vec<FieldPat<'tcx>>,
-    },
-
-    /// `box P`, `&P`, `&mut P`, etc.
-    Deref {
-        subpattern: Pat<'tcx>,
-    },
-
-    /// One of the following:
-    /// * `&str`, which will be handled as a string pattern and thus exhaustiveness
-    ///   checking will detect if you use the same string twice in different patterns.
-    /// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly
-    ///   its own value, similar to `&str`, but these values are much simpler.
-    /// * Opaque constants, that must not be matched structurally. So anything that does not derive
-    ///   `PartialEq` and `Eq`.
-    Constant {
-        value: &'tcx ty::Const<'tcx>,
-    },
-
-    Range(PatRange<'tcx>),
-
-    /// Matches against a slice, checking the length and extracting elements.
-    /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
-    /// e.g., `&[ref xs @ ..]`.
-    Slice {
-        prefix: Vec<Pat<'tcx>>,
-        slice: Option<Pat<'tcx>>,
-        suffix: Vec<Pat<'tcx>>,
-    },
-
-    /// Fixed match against an array; irrefutable.
-    Array {
-        prefix: Vec<Pat<'tcx>>,
-        slice: Option<Pat<'tcx>>,
-        suffix: Vec<Pat<'tcx>>,
-    },
-
-    /// An or-pattern, e.g. `p | q`.
-    /// Invariant: `pats.len() >= 2`.
-    Or {
-        pats: Vec<Pat<'tcx>>,
-    },
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub struct PatRange<'tcx> {
-    pub lo: &'tcx ty::Const<'tcx>,
-    pub hi: &'tcx ty::Const<'tcx>,
-    pub end: RangeEnd,
-}
-
-impl<'tcx> fmt::Display for Pat<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // Printing lists is a chore.
-        let mut first = true;
-        let mut start_or_continue = |s| {
-            if first {
-                first = false;
-                ""
-            } else {
-                s
-            }
-        };
-        let mut start_or_comma = || start_or_continue(", ");
-
-        match *self.kind {
-            PatKind::Wild => write!(f, "_"),
-            PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern),
-            PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
-                let is_mut = match mode {
-                    BindingMode::ByValue => mutability == Mutability::Mut,
-                    BindingMode::ByRef(bk) => {
-                        write!(f, "ref ")?;
-                        matches!(bk, BorrowKind::Mut { .. })
-                    }
-                };
-                if is_mut {
-                    write!(f, "mut ")?;
-                }
-                write!(f, "{}", name)?;
-                if let Some(ref subpattern) = *subpattern {
-                    write!(f, " @ {}", subpattern)?;
-                }
-                Ok(())
-            }
-            PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => {
-                let variant = match *self.kind {
-                    PatKind::Variant { adt_def, variant_index, .. } => {
-                        Some(&adt_def.variants[variant_index])
-                    }
-                    _ => {
-                        if let ty::Adt(adt, _) = self.ty.kind() {
-                            if !adt.is_enum() {
-                                Some(&adt.variants[VariantIdx::new(0)])
-                            } else {
-                                None
-                            }
-                        } else {
-                            None
-                        }
-                    }
-                };
-
-                if let Some(variant) = variant {
-                    write!(f, "{}", variant.ident)?;
-
-                    // Only for Adt we can have `S {...}`,
-                    // which we handle separately here.
-                    if variant.ctor_kind == CtorKind::Fictive {
-                        write!(f, " {{ ")?;
-
-                        let mut printed = 0;
-                        for p in subpatterns {
-                            if let PatKind::Wild = *p.pattern.kind {
-                                continue;
-                            }
-                            let name = variant.fields[p.field.index()].ident;
-                            write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
-                            printed += 1;
-                        }
-
-                        if printed < variant.fields.len() {
-                            write!(f, "{}..", start_or_comma())?;
-                        }
-
-                        return write!(f, " }}");
-                    }
-                }
-
-                let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len());
-                if num_fields != 0 || variant.is_none() {
-                    write!(f, "(")?;
-                    for i in 0..num_fields {
-                        write!(f, "{}", start_or_comma())?;
-
-                        // Common case: the field is where we expect it.
-                        if let Some(p) = subpatterns.get(i) {
-                            if p.field.index() == i {
-                                write!(f, "{}", p.pattern)?;
-                                continue;
-                            }
-                        }
-
-                        // Otherwise, we have to go looking for it.
-                        if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) {
-                            write!(f, "{}", p.pattern)?;
-                        } else {
-                            write!(f, "_")?;
-                        }
-                    }
-                    write!(f, ")")?;
-                }
-
-                Ok(())
-            }
-            PatKind::Deref { ref subpattern } => {
-                match self.ty.kind() {
-                    ty::Adt(def, _) if def.is_box() => write!(f, "box ")?,
-                    ty::Ref(_, _, mutbl) => {
-                        write!(f, "&{}", mutbl.prefix_str())?;
-                    }
-                    _ => bug!("{} is a bad Deref pattern type", self.ty),
-                }
-                write!(f, "{}", subpattern)
-            }
-            PatKind::Constant { value } => write!(f, "{}", value),
-            PatKind::Range(PatRange { lo, hi, end }) => {
-                write!(f, "{}", lo)?;
-                write!(f, "{}", end)?;
-                write!(f, "{}", hi)
-            }
-            PatKind::Slice { ref prefix, ref slice, ref suffix }
-            | PatKind::Array { ref prefix, ref slice, ref suffix } => {
-                write!(f, "[")?;
-                for p in prefix {
-                    write!(f, "{}{}", start_or_comma(), p)?;
-                }
-                if let Some(ref slice) = *slice {
-                    write!(f, "{}", start_or_comma())?;
-                    match *slice.kind {
-                        PatKind::Wild => {}
-                        _ => write!(f, "{}", slice)?,
-                    }
-                    write!(f, "..")?;
-                }
-                for p in suffix {
-                    write!(f, "{}{}", start_or_comma(), p)?;
-                }
-                write!(f, "]")
-            }
-            PatKind::Or { ref pats } => {
-                for pat in pats {
-                    write!(f, "{}{}", start_or_continue(" | "), pat)?;
-                }
-                Ok(())
-            }
-        }
-    }
-}
-
 crate struct PatCtxt<'a, 'tcx> {
     crate tcx: TyCtxt<'tcx>,
     crate param_env: ty::ParamEnv<'tcx>,
@@ -358,22 +43,20 @@ crate struct PatCtxt<'a, 'tcx> {
     include_lint_checks: bool,
 }
 
-impl<'a, 'tcx> Pat<'tcx> {
-    crate fn from_hir(
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        typeck_results: &'a ty::TypeckResults<'tcx>,
-        pat: &'tcx hir::Pat<'tcx>,
-    ) -> Self {
-        let mut pcx = PatCtxt::new(tcx, param_env, typeck_results);
-        let result = pcx.lower_pattern(pat);
-        if !pcx.errors.is_empty() {
-            let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
-            tcx.sess.delay_span_bug(pat.span, &msg);
-        }
-        debug!("Pat::from_hir({:?}) = {:?}", pat, result);
-        result
-    }
+crate fn pat_from_hir<'a, 'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    typeck_results: &'a ty::TypeckResults<'tcx>,
+    pat: &'tcx hir::Pat<'tcx>,
+) -> Pat<'tcx> {
+    let mut pcx = PatCtxt::new(tcx, param_env, typeck_results);
+    let result = pcx.lower_pattern(pat);
+    if !pcx.errors.is_empty() {
+        let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors);
+        tcx.sess.delay_span_bug(pat.span, &msg);
+    }
+    debug!("pat_from_hir({:?}) = {:?}", pat, result);
+    result
 }
 
 impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index dce0df8473b..5d4eb75155a 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -284,7 +284,6 @@ use self::Usefulness::*;
 use self::WitnessPreference::*;
 
 use super::deconstruct_pat::{Constructor, Fields, SplitWildcard};
-use super::{Pat, PatKind};
 use super::{PatternFoldable, PatternFolder};
 
 use rustc_data_structures::captures::Captures;
@@ -293,6 +292,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_arena::TypedArena;
 use rustc_hir::def_id::DefId;
 use rustc_hir::HirId;
+use rustc_middle::thir::{Pat, PatKind};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
 
@@ -382,31 +382,29 @@ impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
     }
 }
 
-impl<'tcx> Pat<'tcx> {
-    pub(super) fn is_wildcard(&self) -> bool {
-        matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
-    }
+pub(super) fn is_wildcard(pat: &Pat<'_>) -> bool {
+    matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild)
+}
 
-    fn is_or_pat(&self) -> bool {
-        matches!(*self.kind, PatKind::Or { .. })
-    }
+fn is_or_pat(pat: &Pat<'_>) -> bool {
+    matches!(*pat.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)
+/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
+fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
+    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
     }
+
+    let mut pats = Vec::new();
+    expand(pat, &mut pats);
+    pats
 }
 
 /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]`
@@ -451,7 +449,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> {
     // 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| {
+        expand_or_pat(self.head()).into_iter().map(move |pat| {
             let mut new_patstack = PatStack::from_pattern(pat);
             new_patstack.pats.extend_from_slice(&self.pats[1..]);
             new_patstack
@@ -525,7 +523,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> {
     /// 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 !row.is_empty() && row.head().is_or_pat() {
+        if !row.is_empty() && is_or_pat(row.head()) {
             for row in row.expand_or_pat() {
                 self.patterns.push(row);
             }
@@ -760,7 +758,7 @@ impl<'p, 'tcx> SubPatSet<'p, 'tcx> {
                     }
                 }
                 SubPatSet::Alt { subpats, pat, alt_count, .. } => {
-                    let expanded = pat.expand_or_pat();
+                    let expanded = expand_or_pat(pat);
                     for i in 0..*alt_count {
                         let sub_set = subpats.get(&i).unwrap_or(&SubPatSet::Empty);
                         if sub_set.is_empty() {
@@ -1118,7 +1116,7 @@ fn is_useful<'p, 'tcx>(
     let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level };
 
     // If the first pattern is an or-pattern, expand it.
-    let ret = if v.head().is_or_pat() {
+    let ret = if is_or_pat(v.head()) {
         debug!("expanding or-pattern");
         let v_head = v.head();
         let vs: Vec<_> = v.expand_or_pat().collect();
@@ -1174,7 +1172,7 @@ fn is_useful<'p, 'tcx>(
 #[derive(Clone, Copy)]
 crate struct MatchArm<'p, 'tcx> {
     /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
-    crate pat: &'p super::Pat<'tcx>,
+    crate pat: &'p Pat<'tcx>,
     crate hir_id: HirId,
     crate has_guard: bool,
 }
@@ -1196,7 +1194,7 @@ crate struct UsefulnessReport<'p, '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>>,
+    crate non_exhaustiveness_witnesses: Vec<Pat<'tcx>>,
 }
 
 /// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which
@@ -1232,7 +1230,7 @@ crate fn compute_match_usefulness<'p, 'tcx>(
         })
         .collect();
 
-    let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(scrut_ty));
+    let wild_pattern = cx.pattern_arena.alloc(Pat::wildcard_from_ty(scrut_ty));
     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 {
diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_mir_build/src/thir/visit.rs
index 9c5b07e2b2a..1a60b1de7fd 100644
--- a/compiler/rustc_mir_build/src/thir/visit.rs
+++ b/compiler/rustc_mir_build/src/thir/visit.rs
@@ -1,123 +1,125 @@
-use crate::thir::*;
+use rustc_middle::thir::*;
+use rustc_middle::ty::Const;
 
-pub trait Visitor<'thir, 'tcx>: Sized {
-    fn visit_expr(&mut self, expr: &'thir Expr<'thir, 'tcx>) {
+pub trait Visitor<'a, 'tcx: 'a>: Sized {
+    fn thir(&self) -> &'a Thir<'tcx>;
+
+    fn visit_expr(&mut self, expr: &Expr<'tcx>) {
         walk_expr(self, expr);
     }
 
-    fn visit_stmt(&mut self, stmt: &'thir Stmt<'thir, 'tcx>) {
+    fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) {
         walk_stmt(self, stmt);
     }
 
-    fn visit_block(&mut self, block: &Block<'thir, 'tcx>) {
+    fn visit_block(&mut self, block: &Block) {
         walk_block(self, block);
     }
 
-    fn visit_arm(&mut self, arm: &'thir Arm<'thir, 'tcx>) {
+    fn visit_arm(&mut self, arm: &Arm<'tcx>) {
         walk_arm(self, arm);
     }
 
     fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {}
 }
 
-pub fn walk_expr<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
-    visitor: &mut V,
-    expr: &'thir Expr<'thir, 'tcx>,
-) {
+pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
     use ExprKind::*;
     match expr.kind {
-        Scope { value, region_scope: _, lint_level: _ } => visitor.visit_expr(value),
-        Box { value } => visitor.visit_expr(value),
+        Scope { value, region_scope: _, lint_level: _ } => {
+            visitor.visit_expr(&visitor.thir()[value])
+        }
+        Box { value } => visitor.visit_expr(&visitor.thir()[value]),
         If { cond, then, else_opt } => {
-            visitor.visit_expr(cond);
-            visitor.visit_expr(then);
+            visitor.visit_expr(&visitor.thir()[cond]);
+            visitor.visit_expr(&visitor.thir()[then]);
             if let Some(else_expr) = else_opt {
-                visitor.visit_expr(else_expr);
+                visitor.visit_expr(&visitor.thir()[else_expr]);
             }
         }
-        Call { fun, args, ty: _, from_hir_call: _, fn_span: _ } => {
-            visitor.visit_expr(fun);
-            for arg in args {
-                visitor.visit_expr(arg);
+        Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => {
+            visitor.visit_expr(&visitor.thir()[fun]);
+            for &arg in &**args {
+                visitor.visit_expr(&visitor.thir()[arg]);
             }
         }
-        Deref { arg } => visitor.visit_expr(arg),
+        Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
         Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
-            visitor.visit_expr(lhs);
-            visitor.visit_expr(rhs);
-        }
-        Unary { arg, op: _ } => visitor.visit_expr(arg),
-        Cast { source } => visitor.visit_expr(source),
-        Use { source } => visitor.visit_expr(source),
-        NeverToAny { source } => visitor.visit_expr(source),
-        Pointer { source, cast: _ } => visitor.visit_expr(source),
-        Loop { body } => visitor.visit_expr(body),
-        Match { scrutinee, arms } => {
-            visitor.visit_expr(scrutinee);
-            for arm in arms {
-                visitor.visit_arm(arm);
+            visitor.visit_expr(&visitor.thir()[lhs]);
+            visitor.visit_expr(&visitor.thir()[rhs]);
+        }
+        Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]),
+        Cast { source } => visitor.visit_expr(&visitor.thir()[source]),
+        Use { source } => visitor.visit_expr(&visitor.thir()[source]),
+        NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
+        Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
+        Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
+        Match { scrutinee, ref arms } => {
+            visitor.visit_expr(&visitor.thir()[scrutinee]);
+            for &arm in &**arms {
+                visitor.visit_arm(&visitor.thir()[arm]);
             }
         }
         Block { ref body } => visitor.visit_block(body),
         Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
-            visitor.visit_expr(lhs);
-            visitor.visit_expr(rhs);
+            visitor.visit_expr(&visitor.thir()[lhs]);
+            visitor.visit_expr(&visitor.thir()[rhs]);
         }
-        Field { lhs, name: _ } => visitor.visit_expr(lhs),
+        Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]),
         Index { lhs, index } => {
-            visitor.visit_expr(lhs);
-            visitor.visit_expr(index);
+            visitor.visit_expr(&visitor.thir()[lhs]);
+            visitor.visit_expr(&visitor.thir()[index]);
         }
         VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {}
-        Borrow { arg, borrow_kind: _ } => visitor.visit_expr(arg),
-        AddressOf { arg, mutability: _ } => visitor.visit_expr(arg),
+        Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]),
+        AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]),
         Break { value, label: _ } => {
             if let Some(value) = value {
-                visitor.visit_expr(value)
+                visitor.visit_expr(&visitor.thir()[value])
             }
         }
         Continue { label: _ } => {}
         Return { value } => {
             if let Some(value) = value {
-                visitor.visit_expr(value)
+                visitor.visit_expr(&visitor.thir()[value])
             }
         }
         ConstBlock { value } => visitor.visit_const(value),
         Repeat { value, count } => {
-            visitor.visit_expr(value);
+            visitor.visit_expr(&visitor.thir()[value]);
             visitor.visit_const(count);
         }
-        Array { fields } | Tuple { fields } => {
-            for field in fields {
-                visitor.visit_expr(field);
+        Array { ref fields } | Tuple { ref fields } => {
+            for &field in &**fields {
+                visitor.visit_expr(&visitor.thir()[field]);
             }
         }
-        Adt { fields, ref base, adt_def: _, variant_index: _, substs: _, user_ty: _ } => {
-            for field in fields {
-                visitor.visit_expr(field.expr);
+        Adt { ref fields, ref base, adt_def: _, variant_index: _, substs: _, user_ty: _ } => {
+            for field in &**fields {
+                visitor.visit_expr(&visitor.thir()[field.expr]);
             }
             if let Some(base) = base {
-                visitor.visit_expr(base.base);
+                visitor.visit_expr(&visitor.thir()[base.base]);
             }
         }
         PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => {
-            visitor.visit_expr(source)
+            visitor.visit_expr(&visitor.thir()[source])
         }
         Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
         Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
         StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
-        InlineAsm { operands, template: _, options: _, line_spans: _ } => {
-            for op in operands {
+        InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
+            for op in &**operands {
                 use InlineAsmOperand::*;
                 match op {
                     In { expr, reg: _ }
                     | Out { expr: Some(expr), reg: _, late: _ }
                     | InOut { expr, reg: _, late: _ }
-                    | SymFn { expr } => visitor.visit_expr(expr),
+                    | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]),
                     SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
-                        visitor.visit_expr(in_expr);
+                        visitor.visit_expr(&visitor.thir()[*in_expr]);
                         if let Some(out_expr) = out_expr {
-                            visitor.visit_expr(out_expr);
+                            visitor.visit_expr(&visitor.thir()[*out_expr]);
                         }
                     }
                     Out { expr: None, reg: _, late: _ }
@@ -127,24 +129,21 @@ pub fn walk_expr<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
             }
         }
         ThreadLocalRef(_) => {}
-        LlvmInlineAsm { outputs, inputs, asm: _ } => {
-            for out_expr in outputs {
-                visitor.visit_expr(out_expr);
+        LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
+            for &out_expr in &**outputs {
+                visitor.visit_expr(&visitor.thir()[out_expr]);
             }
-            for in_expr in inputs {
-                visitor.visit_expr(in_expr);
+            for &in_expr in &**inputs {
+                visitor.visit_expr(&visitor.thir()[in_expr]);
             }
         }
-        Yield { value } => visitor.visit_expr(value),
+        Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
     }
 }
 
-pub fn walk_stmt<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
-    visitor: &mut V,
-    stmt: &'thir Stmt<'thir, 'tcx>,
-) {
+pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) {
     match stmt.kind {
-        StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(expr),
+        StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[expr]),
         StmtKind::Let {
             initializer,
             remainder_scope: _,
@@ -153,34 +152,28 @@ pub fn walk_stmt<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
             lint_level: _,
         } => {
             if let Some(init) = initializer {
-                visitor.visit_expr(init);
+                visitor.visit_expr(&visitor.thir()[init]);
             }
         }
     }
 }
 
-pub fn walk_block<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
-    visitor: &mut V,
-    block: &Block<'thir, 'tcx>,
-) {
-    for stmt in block.stmts {
-        visitor.visit_stmt(stmt);
+pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) {
+    for &stmt in &*block.stmts {
+        visitor.visit_stmt(&visitor.thir()[stmt]);
     }
     if let Some(expr) = block.expr {
-        visitor.visit_expr(expr);
+        visitor.visit_expr(&visitor.thir()[expr]);
     }
 }
 
-pub fn walk_arm<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
-    visitor: &mut V,
-    arm: &'thir Arm<'thir, 'tcx>,
-) {
+pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) {
     match arm.guard {
-        Some(Guard::If(expr)) => visitor.visit_expr(expr),
+        Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]),
         Some(Guard::IfLet(ref _pat, expr)) => {
-            visitor.visit_expr(expr);
+            visitor.visit_expr(&visitor.thir()[expr]);
         }
         None => {}
     }
-    visitor.visit_expr(arm.body);
+    visitor.visit_expr(&visitor.thir()[arm.body]);
 }
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 077b19fa959..51df06bd989 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -3,8 +3,6 @@
 #![feature(array_windows)]
 #![feature(crate_visibility_modifier)]
 #![feature(bindings_after_at)]
-#![feature(iter_order_by)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(box_syntax)]
 #![feature(box_patterns)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index c64fab0507c..54e6ff6272c 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1474,7 +1474,10 @@ impl<'a> Parser<'a> {
                 self.sess.gated_spans.gate(sym::unnamed_fields, lo);
             } else {
                 let err = if self.check_fn_front_matter(false) {
-                    let _ = self.parse_fn(&mut Vec::new(), |_| true, lo);
+                    // We use `parse_fn` to get a span for the function
+                    if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) {
+                        db.delay_as_bug();
+                    }
                     let mut err = self.struct_span_err(
                         lo.to(self.prev_token.span),
                         &format!("functions are not allowed in {} definitions", adt_ty),
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 35cfaae13a4..4c2bc6ebf31 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1065,24 +1065,11 @@ impl<'a> Parser<'a> {
             } else if !delimited_only {
                 if self.eat(&token::Eq) {
                     let eq_span = self.prev_token.span;
-                    let mut is_interpolated_expr = false;
-                    if let token::Interpolated(nt) = &self.token.kind {
-                        if let token::NtExpr(..) = **nt {
-                            is_interpolated_expr = true;
-                        }
-                    }
 
                     // Collect tokens because they are used during lowering to HIR.
                     let expr = self.parse_expr_force_collect()?;
                     let span = expr.span;
 
-                    match &expr.kind {
-                        // Not gated to support things like `doc = $expr` that work on stable.
-                        _ if is_interpolated_expr => {}
-                        ExprKind::Lit(lit) if lit.kind.is_unsuffixed() => {}
-                        _ => self.sess.gated_spans.gate(sym::extended_key_value_attributes, span),
-                    }
-
                     let token_kind = token::Interpolated(Lrc::new(token::NtExpr(expr)));
                     MacArgs::Eq(eq_span, Token::new(token_kind, span))
                 } else {
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 50db69f4209..9d653de910f 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -10,7 +10,6 @@
     test(attr(deny(warnings)))
 )]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(bool_to_option)]
 
 pub use Alignment::*;
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index cfc18062d53..118fcca4508 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -13,12 +13,13 @@ use crate::weak_lang_items;
 use rustc_middle::middle::cstore::ExternCrate;
 use rustc_middle::ty::TyCtxt;
 
-use rustc_errors::struct_span_err;
+use rustc_errors::{pluralize, struct_span_err};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::lang_items::{extract, ITEM_REFS};
 use rustc_hir::{HirId, LangItem, LanguageItems, Target};
+use rustc_span::Span;
 
 use rustc_middle::ty::query::Providers;
 
@@ -61,8 +62,7 @@ impl LanguageItemCollector<'tcx> {
             match ITEM_REFS.get(&value).cloned() {
                 // Known lang item with attribute on correct target.
                 Some((item_index, expected_target)) if actual_target == expected_target => {
-                    let def_id = self.tcx.hir().local_def_id(hir_id);
-                    self.collect_item(item_index, def_id.to_def_id());
+                    self.collect_item_extended(item_index, hir_id, span);
                 }
                 // Known lang item with attribute on incorrect target.
                 Some((_, expected_target)) => {
@@ -180,6 +180,127 @@ impl LanguageItemCollector<'tcx> {
             self.items.groups[group as usize].push(item_def_id);
         }
     }
+
+    // Like collect_item() above, but also checks whether the lang item is declared
+    // with the right number of generic arguments if it is a trait.
+    fn collect_item_extended(&mut self, item_index: usize, hir_id: HirId, span: Span) {
+        let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
+        let lang_item = LangItem::from_u32(item_index as u32).unwrap();
+        let name = lang_item.name();
+
+        self.collect_item(item_index, item_def_id);
+
+        // Now check whether the lang_item has the expected number of generic
+        // arguments if it is a trait. Generally speaking, binary and indexing
+        // operations have one (for the RHS/index), unary operations have none,
+        // and the rest also have none except for the closure traits (one for
+        // the argument list), generators (one for the resume argument),
+        // ordering/equality relations (one for the RHS), and various conversion
+        // traits.
+
+        let expected_num = match lang_item {
+            // Binary operations
+            LangItem::Add
+            | LangItem::Sub
+            | LangItem::Mul
+            | LangItem::Div
+            | LangItem::Rem
+            | LangItem::BitXor
+            | LangItem::BitAnd
+            | LangItem::BitOr
+            | LangItem::Shl
+            | LangItem::Shr
+            | LangItem::AddAssign
+            | LangItem::SubAssign
+            | LangItem::MulAssign
+            | LangItem::DivAssign
+            | LangItem::RemAssign
+            | LangItem::BitXorAssign
+            | LangItem::BitAndAssign
+            | LangItem::BitOrAssign
+            | LangItem::ShlAssign
+            | LangItem::ShrAssign
+            | LangItem::Index
+            | LangItem::IndexMut
+
+            // Miscellaneous
+            | LangItem::Unsize
+            | LangItem::CoerceUnsized
+            | LangItem::DispatchFromDyn
+            | LangItem::Fn
+            | LangItem::FnMut
+            | LangItem::FnOnce
+            | LangItem::Generator
+            | LangItem::PartialEq
+            | LangItem::PartialOrd
+                => Some(1),
+
+            // Unary operations
+            LangItem::Neg
+            | LangItem::Not
+
+            // Miscellaneous
+            | LangItem::Deref
+            | LangItem::DerefMut
+            | LangItem::Sized
+            | LangItem::StructuralPeq
+            | LangItem::StructuralTeq
+            | LangItem::Copy
+            | LangItem::Clone
+            | LangItem::Sync
+            | LangItem::DiscriminantKind
+            | LangItem::PointeeTrait
+            | LangItem::Freeze
+            | LangItem::Drop
+            | LangItem::Receiver
+            | LangItem::Future
+            | LangItem::Unpin
+            | LangItem::Termination
+            | LangItem::Try
+            | LangItem::Send
+            | LangItem::UnwindSafe
+            | LangItem::RefUnwindSafe
+                => Some(0),
+
+            // Not a trait
+            _ => None,
+        };
+
+        if let Some(expected_num) = expected_num {
+            let (actual_num, generics_span) = match self.tcx.hir().get(hir_id) {
+                hir::Node::Item(hir::Item {
+                    kind: hir::ItemKind::Trait(_, _, generics, ..),
+                    ..
+                }) => (generics.params.len(), generics.span),
+                _ => bug!("op/index/deref lang item target is not a trait: {:?}", lang_item),
+            };
+
+            if expected_num != actual_num {
+                // We are issuing E0718 "incorrect target" here, because while the
+                // item kind of the target is correct, the target is still wrong
+                // because of the wrong number of generic arguments.
+                struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0718,
+                    "`{}` language item must be applied to a trait with {} generic argument{}",
+                    name,
+                    expected_num,
+                    pluralize!(expected_num)
+                )
+                .span_label(
+                    generics_span,
+                    format!(
+                        "this trait has {} generic argument{}, not {}",
+                        actual_num,
+                        pluralize!(actual_num),
+                        expected_num
+                    ),
+                )
+                .emit();
+            }
+        }
+    }
 }
 
 /// Traverses and collects all the lang items in all crates.
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 0be7ef7e12a..28633faa205 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -5,12 +5,11 @@
 //! This API is completely unstable and subject to change.
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![feature(const_panic)]
 #![feature(crate_visibility_modifier)]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
+#![feature(min_specialization)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index f41e0e03706..29a0a3c48e5 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -828,7 +828,11 @@ impl Visitor<'tcx> for Checker<'tcx> {
 
     fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, id: hir::HirId) {
         if let Some(def_id) = path.res.opt_def_id() {
-            self.tcx.check_stability(def_id, Some(id), path.span, None)
+            let method_span = match path.segments {
+                [.., _, last] => Some(last.ident.span),
+                _ => None,
+            };
+            self.tcx.check_stability(def_id, Some(id), path.span, method_span)
         }
         intravisit::walk_path(self, path)
     }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 1342762bb07..e64f12ef48f 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,7 +1,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(control_flow_enum)]
 #![feature(try_blocks)]
 #![feature(associated_type_defaults)]
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 00d886000fa..4175fb6925a 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -2,13 +2,9 @@
 
 #![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]
@@ -26,7 +22,7 @@ use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_val
 use rustc_middle::ty::query::{Providers, QueryEngine};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_serialize::opaque;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 
 #[macro_use]
 mod plumbing;
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index c789aa2fa59..b4191c135b4 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -3,7 +3,7 @@
 //! manage the caches, and so forth.
 
 use super::queries;
-use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeExt, DepNodeIndex, SerializedDepNodeIndex};
+use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex};
 use rustc_middle::ty::query::on_disk_cache;
 use rustc_middle::ty::tls::{self, ImplicitCtxt};
 use rustc_middle::ty::{self, TyCtxt};
@@ -14,7 +14,7 @@ use rustc_data_structures::sync::Lock;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::Diagnostic;
 use rustc_serialize::opaque;
-use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::def_id::LocalDefId;
 
 #[derive(Copy, Clone)]
 pub struct QueryCtxt<'tcx> {
@@ -25,6 +25,7 @@ pub struct QueryCtxt<'tcx> {
 impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
     type Target = TyCtxt<'tcx>;
 
+    #[inline]
     fn deref(&self) -> &Self::Target {
         &self.tcx
     }
@@ -42,10 +43,6 @@ impl HasDepContext for QueryCtxt<'tcx> {
 }
 
 impl QueryContext for QueryCtxt<'tcx> {
-    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)
     }
@@ -60,39 +57,6 @@ impl QueryContext for QueryCtxt<'tcx> {
     }
 
     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
@@ -457,20 +421,7 @@ macro_rules! define_queries {
                 }
 
                 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
+                    force_query::<queries::$name<'_>, _>(tcx, dep_node)
                 }
 
                 fn try_load_from_on_disk_cache(tcx: QueryCtxt<'_>, dep_node: &DepNode) {
diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index 2517793ecea..95edc1e93a5 100644
--- a/compiler/rustc_query_impl/src/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -61,7 +61,7 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> {
 
         match def_key.disambiguated_data.data {
             DefPathData::CrateRoot => {
-                crate_name = self.tcx.original_crate_name(def_id.krate).as_str();
+                crate_name = self.tcx.crate_name(def_id.krate).as_str();
                 name = &*crate_name;
                 dis = "";
                 end_index = 3;
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 7a0fc320663..71e67dfee53 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -19,9 +19,8 @@ use std::marker::PhantomData;
 use std::mem;
 use std::sync::atomic::Ordering::Relaxed;
 
-use super::prev::PreviousDepGraph;
 use super::query::DepGraphQuery;
-use super::serialized::{GraphEncoder, SerializedDepNodeIndex};
+use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
 use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
 use crate::query::QueryContext;
 
@@ -45,6 +44,7 @@ rustc_index::newtype_index! {
 
 impl DepNodeIndex {
     pub const INVALID: DepNodeIndex = DepNodeIndex::MAX;
+    pub const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::from_u32(0);
 }
 
 impl std::convert::From<DepNodeIndex> for QueryInvocationId {
@@ -78,7 +78,7 @@ struct DepGraphData<K: DepKind> {
 
     /// The dep-graph from the previous compilation session. It contains all
     /// nodes and edges as well as all fingerprints of nodes that have them.
-    previous: PreviousDepGraph<K>,
+    previous: SerializedDepGraph<K>,
 
     colors: DepNodeColorMap,
 
@@ -109,7 +109,8 @@ where
 
 impl<K: DepKind> DepGraph<K> {
     pub fn new(
-        prev_graph: PreviousDepGraph<K>,
+        profiler: &SelfProfilerRef,
+        prev_graph: SerializedDepGraph<K>,
         prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
         encoder: FileEncoder,
         record_graph: bool,
@@ -117,16 +118,23 @@ impl<K: DepKind> DepGraph<K> {
     ) -> DepGraph<K> {
         let prev_graph_node_count = prev_graph.node_count();
 
+        let current =
+            CurrentDepGraph::new(prev_graph_node_count, encoder, record_graph, record_stats);
+
+        // Instantiate a dependy-less node only once for anonymous queries.
+        let _green_node_index = current.intern_new_node(
+            profiler,
+            DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() },
+            smallvec![],
+            Fingerprint::ZERO,
+        );
+        debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE);
+
         DepGraph {
             data: Some(Lrc::new(DepGraphData {
                 previous_work_products: prev_work_products,
                 dep_node_debug: Default::default(),
-                current: CurrentDepGraph::new(
-                    prev_graph_node_count,
-                    encoder,
-                    record_graph,
-                    record_stats,
-                ),
+                current,
                 emitting_diagnostics: Default::default(),
                 emitting_diagnostics_cond_var: Condvar::new(),
                 previous: prev_graph,
@@ -288,30 +296,47 @@ impl<K: DepKind> DepGraph<K> {
             let task_deps = Lock::new(TaskDeps::default());
             let result = K::with_deps(Some(&task_deps), op);
             let task_deps = task_deps.into_inner();
+            let task_deps = task_deps.reads;
+
+            let dep_node_index = match task_deps.len() {
+                0 => {
+                    // Because the dep-node id of anon nodes is computed from the sets of its
+                    // dependencies we already know what the ID of this dependency-less node is
+                    // going to be (i.e. equal to the precomputed
+                    // `SINGLETON_DEPENDENCYLESS_ANON_NODE`). As a consequence we can skip creating
+                    // a `StableHasher` and sending the node through interning.
+                    DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE
+                }
+                1 => {
+                    // When there is only one dependency, don't bother creating a node.
+                    task_deps[0]
+                }
+                _ => {
+                    // The dep node indices are hashed here instead of hashing the dep nodes of the
+                    // dependencies. These indices may refer to different nodes per session, but this isn't
+                    // a problem here because we that ensure the final dep node hash is per session only by
+                    // combining it with the per session random number `anon_id_seed`. This hash only need
+                    // to map the dependencies to a single value on a per session basis.
+                    let mut hasher = StableHasher::new();
+                    task_deps.hash(&mut hasher);
+
+                    let target_dep_node = DepNode {
+                        kind: dep_kind,
+                        // Fingerprint::combine() is faster than sending Fingerprint
+                        // through the StableHasher (at least as long as StableHasher
+                        // is so slow).
+                        hash: data.current.anon_id_seed.combine(hasher.finish()).into(),
+                    };
 
-            // The dep node indices are hashed here instead of hashing the dep nodes of the
-            // dependencies. These indices may refer to different nodes per session, but this isn't
-            // a problem here because we that ensure the final dep node hash is per session only by
-            // combining it with the per session random number `anon_id_seed`. This hash only need
-            // to map the dependencies to a single value on a per session basis.
-            let mut hasher = StableHasher::new();
-            task_deps.reads.hash(&mut hasher);
-
-            let target_dep_node = DepNode {
-                kind: dep_kind,
-                // Fingerprint::combine() is faster than sending Fingerprint
-                // through the StableHasher (at least as long as StableHasher
-                // is so slow).
-                hash: data.current.anon_id_seed.combine(hasher.finish()).into(),
+                    data.current.intern_new_node(
+                        cx.profiler(),
+                        target_dep_node,
+                        task_deps,
+                        Fingerprint::ZERO,
+                    )
+                }
             };
 
-            let dep_node_index = data.current.intern_new_node(
-                cx.profiler(),
-                target_dep_node,
-                task_deps.reads,
-                Fingerprint::ZERO,
-            );
-
             (result, dep_node_index)
         } else {
             (op(), self.next_virtual_depnode_index())
@@ -488,6 +513,117 @@ impl<K: DepKind> DepGraph<K> {
         }
     }
 
+    fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
+        &self,
+        tcx: Ctxt,
+        data: &DepGraphData<K>,
+        parent_dep_node_index: SerializedDepNodeIndex,
+        dep_node: &DepNode<K>,
+    ) -> Option<()> {
+        let dep_dep_node_color = data.colors.get(parent_dep_node_index);
+        let dep_dep_node = &data.previous.index_to_node(parent_dep_node_index);
+
+        match dep_dep_node_color {
+            Some(DepNodeColor::Green(_)) => {
+                // This dependency has been marked as green before, we are
+                // still fine and can continue with checking the other
+                // dependencies.
+                debug!(
+                    "try_mark_previous_green({:?}) --- found dependency {:?} to \
+                            be immediately green",
+                    dep_node, dep_dep_node,
+                );
+                return Some(());
+            }
+            Some(DepNodeColor::Red) => {
+                // We found a dependency the value of which has changed
+                // compared to the previous compilation session. We cannot
+                // mark the DepNode as green and also don't need to bother
+                // with checking any of the other dependencies.
+                debug!(
+                    "try_mark_previous_green({:?}) - END - dependency {:?} was immediately red",
+                    dep_node, dep_dep_node,
+                );
+                return None;
+            }
+            None => {}
+        }
+
+        // We don't know the state of this dependency. If it isn't
+        // an eval_always node, let's try to mark it green recursively.
+        if !dep_dep_node.kind.is_eval_always() {
+            debug!(
+                "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
+                                 is unknown, trying to mark it green",
+                dep_node, dep_dep_node, dep_dep_node.hash,
+            );
+
+            let node_index =
+                self.try_mark_previous_green(tcx, data, parent_dep_node_index, dep_dep_node);
+            if node_index.is_some() {
+                debug!(
+                    "try_mark_previous_green({:?}) --- managed to MARK dependency {:?} as green",
+                    dep_node, dep_dep_node
+                );
+                return Some(());
+            }
+        }
+
+        // We failed to mark it green, so we try to force the query.
+        debug!(
+            "try_mark_previous_green({:?}) --- trying to force dependency {:?}",
+            dep_node, dep_dep_node
+        );
+        if !tcx.try_force_from_dep_node(dep_dep_node) {
+            // The DepNode could not be forced.
+            debug!(
+                "try_mark_previous_green({:?}) - END - dependency {:?} could not be forced",
+                dep_node, dep_dep_node
+            );
+            return None;
+        }
+
+        let dep_dep_node_color = data.colors.get(parent_dep_node_index);
+
+        match dep_dep_node_color {
+            Some(DepNodeColor::Green(_)) => {
+                debug!(
+                    "try_mark_previous_green({:?}) --- managed to FORCE dependency {:?} to green",
+                    dep_node, dep_dep_node
+                );
+                return Some(());
+            }
+            Some(DepNodeColor::Red) => {
+                debug!(
+                    "try_mark_previous_green({:?}) - END - dependency {:?} was red after forcing",
+                    dep_node, dep_dep_node
+                );
+                return None;
+            }
+            None => {}
+        }
+
+        if !tcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
+            panic!("try_mark_previous_green() - Forcing the DepNode should have set its color")
+        }
+
+        // If the query we just forced has resulted in
+        // some kind of compilation error, we cannot rely on
+        // the dep-node color having been properly updated.
+        // This means that the query system has reached an
+        // invalid state. We let the compiler continue (by
+        // returning `None`) so it can emit error messages
+        // and wind down, but rely on the fact that this
+        // invalid state will not be persisted to the
+        // incremental compilation cache because of
+        // compilation errors being present.
+        debug!(
+            "try_mark_previous_green({:?}) - END - dependency {:?} resulted in compilation error",
+            dep_node, dep_dep_node
+        );
+        return None;
+    }
+
     /// Try to mark a dep-node which existed in the previous compilation session as green.
     fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
         &self,
@@ -512,123 +648,7 @@ impl<K: DepKind> DepGraph<K> {
         let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);
 
         for &dep_dep_node_index in prev_deps {
-            let dep_dep_node_color = data.colors.get(dep_dep_node_index);
-
-            match dep_dep_node_color {
-                Some(DepNodeColor::Green(_)) => {
-                    // This dependency has been marked as green before, we are
-                    // still fine and can continue with checking the other
-                    // dependencies.
-                    debug!(
-                        "try_mark_previous_green({:?}) --- found dependency {:?} to \
-                            be immediately green",
-                        dep_node,
-                        data.previous.index_to_node(dep_dep_node_index)
-                    );
-                }
-                Some(DepNodeColor::Red) => {
-                    // We found a dependency the value of which has changed
-                    // compared to the previous compilation session. We cannot
-                    // mark the DepNode as green and also don't need to bother
-                    // with checking any of the other dependencies.
-                    debug!(
-                        "try_mark_previous_green({:?}) - END - dependency {:?} was \
-                            immediately red",
-                        dep_node,
-                        data.previous.index_to_node(dep_dep_node_index)
-                    );
-                    return None;
-                }
-                None => {
-                    let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index);
-
-                    // We don't know the state of this dependency. If it isn't
-                    // an eval_always node, let's try to mark it green recursively.
-                    if !dep_dep_node.kind.is_eval_always() {
-                        debug!(
-                            "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
-                                 is unknown, trying to mark it green",
-                            dep_node, dep_dep_node, dep_dep_node.hash,
-                        );
-
-                        let node_index = self.try_mark_previous_green(
-                            tcx,
-                            data,
-                            dep_dep_node_index,
-                            dep_dep_node,
-                        );
-                        if node_index.is_some() {
-                            debug!(
-                                "try_mark_previous_green({:?}) --- managed to MARK \
-                                    dependency {:?} as green",
-                                dep_node, dep_dep_node
-                            );
-                            continue;
-                        }
-                    }
-
-                    // We failed to mark it green, so we try to force the query.
-                    debug!(
-                        "try_mark_previous_green({:?}) --- trying to force \
-                            dependency {:?}",
-                        dep_node, dep_dep_node
-                    );
-                    if tcx.try_force_from_dep_node(dep_dep_node) {
-                        let dep_dep_node_color = data.colors.get(dep_dep_node_index);
-
-                        match dep_dep_node_color {
-                            Some(DepNodeColor::Green(_)) => {
-                                debug!(
-                                    "try_mark_previous_green({:?}) --- managed to \
-                                        FORCE dependency {:?} to green",
-                                    dep_node, dep_dep_node
-                                );
-                            }
-                            Some(DepNodeColor::Red) => {
-                                debug!(
-                                    "try_mark_previous_green({:?}) - END - \
-                                        dependency {:?} was red after forcing",
-                                    dep_node, dep_dep_node
-                                );
-                                return None;
-                            }
-                            None => {
-                                if !tcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
-                                    panic!(
-                                        "try_mark_previous_green() - Forcing the DepNode \
-                                          should have set its color"
-                                    )
-                                } else {
-                                    // If the query we just forced has resulted in
-                                    // some kind of compilation error, we cannot rely on
-                                    // the dep-node color having been properly updated.
-                                    // This means that the query system has reached an
-                                    // invalid state. We let the compiler continue (by
-                                    // returning `None`) so it can emit error messages
-                                    // and wind down, but rely on the fact that this
-                                    // invalid state will not be persisted to the
-                                    // incremental compilation cache because of
-                                    // compilation errors being present.
-                                    debug!(
-                                        "try_mark_previous_green({:?}) - END - \
-                                            dependency {:?} resulted in compilation error",
-                                        dep_node, dep_dep_node
-                                    );
-                                    return None;
-                                }
-                            }
-                        }
-                    } else {
-                        // The DepNode could not be forced.
-                        debug!(
-                            "try_mark_previous_green({:?}) - END - dependency {:?} \
-                                could not be forced",
-                            dep_node, dep_dep_node
-                        );
-                        return None;
-                    }
-                }
-            }
+            self.try_mark_parent_green(tcx, data, dep_dep_node_index, dep_node)?
         }
 
         // If we got here without hitting a `return` that means that all
@@ -797,7 +817,7 @@ impl<K: DepKind> DepGraph<K> {
         }
     }
 
-    fn next_virtual_depnode_index(&self) -> DepNodeIndex {
+    pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex {
         let index = self.virtual_dep_node_index.fetch_add(1, Relaxed);
         DepNodeIndex::from_u32(index)
     }
@@ -857,7 +877,7 @@ rustc_index::newtype_index! {
 /// For this reason, we avoid storing `DepNode`s more than once as map
 /// keys. The `new_node_to_index` map only contains nodes not in the previous
 /// graph, and we map nodes in the previous graph to indices via a two-step
-/// mapping. `PreviousDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
+/// mapping. `SerializedDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`,
 /// and the `prev_index_to_index` vector (which is more compact and faster than
 /// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`.
 ///
@@ -982,7 +1002,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
     fn intern_node(
         &self,
         profiler: &SelfProfilerRef,
-        prev_graph: &PreviousDepGraph<K>,
+        prev_graph: &SerializedDepGraph<K>,
         key: DepNode<K>,
         edges: EdgesVec,
         fingerprint: Option<Fingerprint>,
@@ -1080,7 +1100,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
     fn promote_node_and_deps_to_current(
         &self,
         profiler: &SelfProfilerRef,
-        prev_graph: &PreviousDepGraph<K>,
+        prev_graph: &SerializedDepGraph<K>,
         prev_index: SerializedDepNodeIndex,
     ) -> DepNodeIndex {
         self.debug_assert_not_in_new_nodes(prev_graph, prev_index);
@@ -1112,7 +1132,7 @@ impl<K: DepKind> CurrentDepGraph<K> {
     #[inline]
     fn debug_assert_not_in_new_nodes(
         &self,
-        prev_graph: &PreviousDepGraph<K>,
+        prev_graph: &SerializedDepGraph<K>,
         prev_index: SerializedDepNodeIndex,
     ) {
         let node = &prev_graph.index_to_node(prev_index);
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index 1b6ecf3e637..15e2633c4f1 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -1,13 +1,11 @@
 pub mod debug;
 mod dep_node;
 mod graph;
-mod prev;
 mod query;
 mod serialized;
 
 pub use dep_node::{DepNode, DepNodeParams, WorkProductId};
 pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct};
-pub use prev::PreviousDepGraph;
 pub use query::DepGraphQuery;
 pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex};
 
diff --git a/compiler/rustc_query_system/src/dep_graph/prev.rs b/compiler/rustc_query_system/src/dep_graph/prev.rs
deleted file mode 100644
index 6303bbf53b9..00000000000
--- a/compiler/rustc_query_system/src/dep_graph/prev.rs
+++ /dev/null
@@ -1,56 +0,0 @@
-use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex};
-use super::{DepKind, DepNode};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
-
-#[derive(Debug)]
-pub struct PreviousDepGraph<K: DepKind> {
-    data: SerializedDepGraph<K>,
-    index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
-}
-
-impl<K: DepKind> Default for PreviousDepGraph<K> {
-    fn default() -> Self {
-        PreviousDepGraph { data: Default::default(), index: Default::default() }
-    }
-}
-
-impl<K: DepKind> PreviousDepGraph<K> {
-    pub fn new(data: SerializedDepGraph<K>) -> PreviousDepGraph<K> {
-        let index: FxHashMap<_, _> =
-            data.nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
-        PreviousDepGraph { data, index }
-    }
-
-    #[inline]
-    pub fn edge_targets_from(
-        &self,
-        dep_node_index: SerializedDepNodeIndex,
-    ) -> &[SerializedDepNodeIndex] {
-        self.data.edge_targets_from(dep_node_index)
-    }
-
-    #[inline]
-    pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
-        self.data.nodes[dep_node_index]
-    }
-
-    #[inline]
-    pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> {
-        self.index.get(dep_node).cloned()
-    }
-
-    #[inline]
-    pub fn fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
-        self.index.get(dep_node).map(|&node_index| self.data.fingerprints[node_index])
-    }
-
-    #[inline]
-    pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint {
-        self.data.fingerprints[dep_node_index]
-    }
-
-    pub fn node_count(&self) -> usize {
-        self.index.len()
-    }
-}
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 6f3d1fb7199..6a84a28be66 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -37,17 +37,19 @@ rustc_index::newtype_index! {
 #[derive(Debug)]
 pub struct SerializedDepGraph<K: DepKind> {
     /// The set of all DepNodes in the graph
-    pub nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
+    nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>,
     /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to
     /// the DepNode at the same index in the nodes vector.
-    pub fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
+    fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>,
     /// For each DepNode, stores the list of edges originating from that
     /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data,
     /// which holds the actual DepNodeIndices of the target nodes.
-    pub edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>,
+    edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>,
     /// A flattened list of all edge targets in the graph. Edge sources are
     /// implicit in edge_list_indices.
-    pub edge_list_data: Vec<SerializedDepNodeIndex>,
+    edge_list_data: Vec<SerializedDepNodeIndex>,
+    /// Reciprocal map to `nodes`.
+    index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>,
 }
 
 impl<K: DepKind> Default for SerializedDepGraph<K> {
@@ -57,6 +59,7 @@ impl<K: DepKind> Default for SerializedDepGraph<K> {
             fingerprints: Default::default(),
             edge_list_indices: Default::default(),
             edge_list_data: Default::default(),
+            index: Default::default(),
         }
     }
 }
@@ -67,6 +70,30 @@ impl<K: DepKind> SerializedDepGraph<K> {
         let targets = self.edge_list_indices[source];
         &self.edge_list_data[targets.0 as usize..targets.1 as usize]
     }
+
+    #[inline]
+    pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> {
+        self.nodes[dep_node_index]
+    }
+
+    #[inline]
+    pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> {
+        self.index.get(dep_node).cloned()
+    }
+
+    #[inline]
+    pub fn fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> {
+        self.index.get(dep_node).map(|&node_index| self.fingerprints[node_index])
+    }
+
+    #[inline]
+    pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint {
+        self.fingerprints[dep_node_index]
+    }
+
+    pub fn node_count(&self) -> usize {
+        self.index.len()
+    }
 }
 
 impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<'a>>
@@ -121,7 +148,10 @@ impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<
             })?;
         }
 
-        Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data })
+        let index: FxHashMap<_, _> =
+            nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect();
+
+        Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index })
     }
 }
 
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index be72baefb9e..0d4fb34265c 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -1,11 +1,8 @@
 #![feature(bool_to_option)]
-#![feature(const_panic)]
 #![feature(core_intrinsics)]
-#![feature(drain_filter)]
 #![feature(hash_raw_entry)]
 #![feature(iter_zip)]
 #![feature(min_specialization)]
-#![feature(stmt_expr_attributes)]
 
 #[macro_use]
 extern crate tracing;
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index aef8a13ccef..927e8117f05 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -19,7 +19,6 @@ use crate::dep_graph::{DepNode, DepNodeIndex, HasDepContext, SerializedDepNodeIn
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_errors::Diagnostic;
-use rustc_span::def_id::DefId;
 use rustc_span::Span;
 
 /// Description of a frame in the query stack.
@@ -64,9 +63,6 @@ impl QueryStackFrame {
 }
 
 pub trait QueryContext: HasDepContext {
-    /// Get string representation from DefPath.
-    fn def_path_str(&self, def_id: DefId) -> String;
-
     /// Get the query information from the TLS context.
     fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>>;
 
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 39dfdd78cc4..c1f9fa39e98 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::{DepContext, DepKind, DepNode};
+use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeParams};
 use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
 use crate::query::caches::QueryCache;
 use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt};
@@ -19,7 +19,7 @@ use rustc_data_structures::thin_vec::ThinVec;
 #[cfg(not(parallel_compiler))]
 use rustc_errors::DiagnosticBuilder;
 use rustc_errors::{Diagnostic, FatalError};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use std::collections::hash_map::Entry;
 use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
@@ -431,7 +431,7 @@ fn try_execute_query<CTX, C>(
 ) -> C::Stored
 where
     C: QueryCache,
-    C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+    C::Key: DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
     let job = match JobOwner::<'_, CTX::DepKind, C>::try_start(
@@ -452,11 +452,15 @@ where
         }
     };
 
-    // Fast path for when incr. comp. is off. `to_dep_node` is
-    // expensive for some `DepKind`s.
-    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;
+    let dep_graph = tcx.dep_context().dep_graph();
+
+    // Fast path for when incr. comp. is off.
+    if !dep_graph.is_fully_enabled() {
+        let prof_timer = tcx.dep_context().profiler().query_provider();
+        let result = tcx.start_query(job.id, None, || query.compute(tcx, key));
+        let dep_node_index = dep_graph.next_virtual_depnode_index();
+        prof_timer.finish_with_query_invocation_id(dep_node_index.into());
+        return job.complete(result, dep_node_index);
     }
 
     if query.anon {
@@ -464,17 +468,14 @@ where
 
         let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| {
             tcx.start_query(job.id, diagnostics, || {
-                tcx.dep_context().dep_graph().with_anon_task(
-                    *tcx.dep_context(),
-                    query.dep_kind,
-                    || query.compute(tcx, key),
-                )
+                dep_graph
+                    .with_anon_task(*tcx.dep_context(), query.dep_kind, || query.compute(tcx, key))
             })
         });
 
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
-        tcx.dep_context().dep_graph().read_index(dep_node_index);
+        dep_graph.read_index(dep_node_index);
 
         if unlikely!(!diagnostics.is_empty()) {
             tcx.store_diagnostics_for_anon_node(dep_node_index, diagnostics);
@@ -490,7 +491,7 @@ where
         // promoted to the current session during
         // `try_mark_green()`, so we can ignore them here.
         let loaded = tcx.start_query(job.id, None, || {
-            let marked = tcx.dep_context().dep_graph().try_mark_green_and_read(tcx, &dep_node);
+            let marked = 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(
@@ -511,7 +512,7 @@ where
     }
 
     let (result, dep_node_index) = force_query_with_job(tcx, key, job, dep_node, query);
-    tcx.dep_context().dep_graph().read_index(dep_node_index);
+    dep_graph.read_index(dep_node_index);
     result
 }
 
@@ -693,7 +694,7 @@ fn get_query_impl<CTX, C>(
 where
     CTX: QueryContext,
     C: QueryCache,
-    C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+    C::Key: DepNodeParams<CTX::DepContext>,
 {
     try_execute_query(tcx, state, cache, span, key, lookup, query)
 }
@@ -743,15 +744,28 @@ fn force_query_impl<CTX, C>(
     tcx: CTX,
     state: &QueryState<CTX::DepKind, C::Key>,
     cache: &QueryCacheStore<C>,
-    key: C::Key,
-    span: Span,
     dep_node: DepNode<CTX::DepKind>,
     query: &QueryVtable<CTX, C::Key, C::Value>,
-) where
+) -> bool
+where
     C: QueryCache,
-    C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+    C::Key: DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
+    debug_assert!(!query.anon);
+
+    if !<C::Key as DepNodeParams<CTX::DepContext>>::can_reconstruct_query_key() {
+        return false;
+    }
+
+    let key = if let Some(key) =
+        <C::Key as DepNodeParams<CTX::DepContext>>::recover(*tcx.dep_context(), &dep_node)
+    {
+        key
+    } else {
+        return false;
+    };
+
     // 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| {
@@ -765,7 +779,7 @@ fn force_query_impl<CTX, C>(
     });
 
     let lookup = match cached {
-        Ok(()) => return,
+        Ok(()) => return true,
         Err(lookup) => lookup,
     };
 
@@ -773,17 +787,20 @@ fn force_query_impl<CTX, C>(
         tcx,
         state,
         cache,
-        span,
+        DUMMY_SP,
         key.clone(),
         lookup,
         query,
     ) {
         TryGetJob::NotYetStarted(job) => job,
-        TryGetJob::Cycle(_) => return,
+        TryGetJob::Cycle(_) => return true,
         #[cfg(parallel_compiler)]
-        TryGetJob::JobCompleted(_) => return,
+        TryGetJob::JobCompleted(_) => return true,
     };
+
     force_query_with_job(tcx, key, job, dep_node, query);
+
+    true
 }
 
 pub enum QueryMode {
@@ -800,7 +817,7 @@ pub fn get_query<Q, CTX>(
 ) -> Option<Q::Stored>
 where
     Q: QueryDescription<CTX>,
-    Q::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+    Q::Key: DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
     let query = &Q::VTABLE;
@@ -816,11 +833,15 @@ where
     Some(value)
 }
 
-pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, span: Span, dep_node: DepNode<CTX::DepKind>)
+pub fn force_query<Q, CTX>(tcx: CTX, dep_node: &DepNode<CTX::DepKind>) -> bool
 where
     Q: QueryDescription<CTX>,
-    Q::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+    Q::Key: DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
-    force_query_impl(tcx, Q::query_state(tcx), Q::query_cache(tcx), key, span, dep_node, &Q::VTABLE)
+    if Q::ANON {
+        return false;
+    }
+
+    force_query_impl(tcx, Q::query_state(tcx), Q::query_cache(tcx), *dep_node, &Q::VTABLE)
 }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 6ea46f5c528..03d94f43897 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -425,27 +425,32 @@ impl<'a> Resolver<'a> {
                 }
                 err
             }
-            ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
-                let res = binding.res();
-                let shadows_what = res.descr();
+            ResolutionError::BindingShadowsSomethingUnacceptable {
+                shadowing_binding_descr,
+                name,
+                participle,
+                article,
+                shadowed_binding_descr,
+                shadowed_binding_span,
+            } => {
                 let mut err = struct_span_err!(
                     self.session,
                     span,
                     E0530,
                     "{}s cannot shadow {}s",
-                    what_binding,
-                    shadows_what
+                    shadowing_binding_descr,
+                    shadowed_binding_descr,
                 );
                 err.span_label(
                     span,
-                    format!("cannot be named the same as {} {}", res.article(), shadows_what),
+                    format!("cannot be named the same as {} {}", article, shadowed_binding_descr),
                 );
-                let participle = if binding.is_import() { "imported" } else { "defined" };
-                let msg = format!("the {} `{}` is {} here", shadows_what, name, participle);
-                err.span_label(binding.span, msg);
+                let msg =
+                    format!("the {} `{}` is {} here", shadowed_binding_descr, name, participle);
+                err.span_label(shadowed_binding_span, msg);
                 err
             }
-            ResolutionError::ForwardDeclaredTyParam => {
+            ResolutionError::ForwardDeclaredGenericParam => {
                 let mut err = struct_span_err!(
                     self.session,
                     span,
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index ffa825b7d46..408d9b23921 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1763,13 +1763,33 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 // to something unusable as a pattern (e.g., constructor function),
                 // but we still conservatively report an error, see
                 // issues/33118#issuecomment-233962221 for one reason why.
+                let binding = binding.expect("no binding for a ctor or static");
                 self.report_error(
                     ident.span,
-                    ResolutionError::BindingShadowsSomethingUnacceptable(
-                        pat_src.descr(),
-                        ident.name,
-                        binding.expect("no binding for a ctor or static"),
-                    ),
+                    ResolutionError::BindingShadowsSomethingUnacceptable {
+                        shadowing_binding_descr: pat_src.descr(),
+                        name: ident.name,
+                        participle: if binding.is_import() { "imported" } else { "defined" },
+                        article: binding.res().article(),
+                        shadowed_binding_descr: binding.res().descr(),
+                        shadowed_binding_span: binding.span,
+                    },
+                );
+                None
+            }
+            Res::Def(DefKind::ConstParam, def_id) => {
+                // Same as for DefKind::Const above, but here, `binding` is `None`, so we
+                // have to construct the error differently
+                self.report_error(
+                    ident.span,
+                    ResolutionError::BindingShadowsSomethingUnacceptable {
+                        shadowing_binding_descr: pat_src.descr(),
+                        name: ident.name,
+                        participle: "defined",
+                        article: res.article(),
+                        shadowed_binding_descr: res.descr(),
+                        shadowed_binding_span: self.r.opt_span(def_id).expect("const parameter defined outside of local crate"),
+                    }
                 );
                 None
             }
@@ -1939,7 +1959,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 if ns == ValueNS {
                     let item_name = path.last().unwrap().ident;
                     let traits = self.traits_in_scope(item_name, ns);
-                    self.r.trait_map.insert(id, traits);
+                    self.r.trait_map.as_mut().unwrap().insert(id, traits);
                 }
 
                 if PrimTy::from_name(path[0].ident.name).is_some() {
@@ -2415,12 +2435,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                 // the field name so that we can do some nice error reporting
                 // later on in typeck.
                 let traits = self.traits_in_scope(ident, ValueNS);
-                self.r.trait_map.insert(expr.id, traits);
+                self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
             }
             ExprKind::MethodCall(ref segment, ..) => {
                 debug!("(recording candidate traits for expr) recording traits for {}", expr.id);
                 let traits = self.traits_in_scope(segment.ident, ValueNS);
-                self.r.trait_map.insert(expr.id, traits);
+                self.r.trait_map.as_mut().unwrap().insert(expr.id, traits);
             }
             _ => {
                 // Nothing to do.
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 300d2c01cb5..41935e7d6df 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -16,7 +16,6 @@
 #![feature(format_args_capture)]
 #![feature(iter_zip)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![recursion_limit = "256"]
 #![allow(rustdoc::private_intra_doc_links)]
 
@@ -234,9 +233,16 @@ enum ResolutionError<'a> {
         /* current */ &'static str,
     ),
     /// Error E0530: `X` bindings cannot shadow `Y`s.
-    BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>),
+    BindingShadowsSomethingUnacceptable {
+        shadowing_binding_descr: &'static str,
+        name: Symbol,
+        participle: &'static str,
+        article: &'static str,
+        shadowed_binding_descr: &'static str,
+        shadowed_binding_span: Span,
+    },
     /// Error E0128: generic parameters with a default cannot use forward-declared identifiers.
-    ForwardDeclaredTyParam, // FIXME(const_generics_defaults)
+    ForwardDeclaredGenericParam,
     /// ERROR E0770: the type of const parameters must not depend on other generic parameters.
     ParamInTyOfConstParam(Symbol),
     /// generic parameters must not be used inside const evaluations.
@@ -903,7 +909,7 @@ pub struct Resolver<'a> {
     /// `CrateNum` resolutions of `extern crate` items.
     extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     export_map: ExportMap<LocalDefId>,
-    trait_map: NodeMap<Vec<TraitCandidate>>,
+    trait_map: Option<NodeMap<Vec<TraitCandidate>>>,
 
     /// A map from nodes to anonymous modules.
     /// Anonymous modules are pseudo-modules that are implicitly created around items
@@ -1132,8 +1138,8 @@ impl ResolverAstLowering for Resolver<'_> {
         self.next_node_id()
     }
 
-    fn trait_map(&self) -> &NodeMap<Vec<TraitCandidate>> {
-        &self.trait_map
+    fn take_trait_map(&mut self) -> NodeMap<Vec<TraitCandidate>> {
+        std::mem::replace(&mut self.trait_map, None).unwrap()
     }
 
     fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
@@ -1216,7 +1222,7 @@ impl<'a> Resolver<'a> {
         let mut module_map = FxHashMap::default();
         module_map.insert(root_local_def_id, graph_root);
 
-        let definitions = Definitions::new(crate_name, session.local_crate_disambiguator());
+        let definitions = Definitions::new(session.local_stable_crate_id());
         let root = definitions.get_root_def();
 
         let mut visibilities = FxHashMap::default();
@@ -1280,7 +1286,7 @@ impl<'a> Resolver<'a> {
             label_res_map: Default::default(),
             extern_crate_map: Default::default(),
             export_map: FxHashMap::default(),
-            trait_map: Default::default(),
+            trait_map: Some(NodeMap::default()),
             underscore_disambiguator: 0,
             empty_module,
             module_map,
@@ -2602,7 +2608,7 @@ impl<'a> Resolver<'a> {
                 let res_error = if rib_ident.name == kw::SelfUpper {
                     ResolutionError::SelfInTyParamDefault
                 } else {
-                    ResolutionError::ForwardDeclaredTyParam
+                    ResolutionError::ForwardDeclaredGenericParam
                 };
                 self.report_error(span, res_error);
             }
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index 54b6a121585..842f7f9deee 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -142,12 +142,7 @@ impl<'tcx> DumpVisitor<'tcx> {
         let data = CratePreludeData {
             crate_id: GlobalCrateId {
                 name: name.into(),
-                disambiguator: self
-                    .tcx
-                    .sess
-                    .local_crate_disambiguator()
-                    .to_fingerprint()
-                    .as_value(),
+                disambiguator: (self.tcx.sess.local_stable_crate_id().to_u64(), 0),
             },
             crate_root: crate_root.unwrap_or_else(|| "<no source>".to_owned()),
             external_crates: self.save_ctxt.get_external_crates(),
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 6c308ad89db..bdffdd5311e 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -1,6 +1,5 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![recursion_limit = "256"]
 
 mod dump_visitor;
@@ -128,7 +127,10 @@ impl<'tcx> SaveContext<'tcx> {
                 num: n.as_u32(),
                 id: GlobalCrateId {
                     name: self.tcx.crate_name(n).to_string(),
-                    disambiguator: self.tcx.crate_disambiguator(n).to_fingerprint().as_value(),
+                    disambiguator: (
+                        self.tcx.def_path_hash(n.as_def_id()).stable_crate_id().to_u64(),
+                        0,
+                    ),
                 },
             });
         }
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index cf5a9118275..c79786a839f 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -14,10 +14,7 @@ Core encoding and decoding interfaces.
 #![feature(nll)]
 #![feature(associated_type_bounds)]
 #![feature(min_specialization)]
-#![feature(vec_spare_capacity)]
 #![feature(core_intrinsics)]
-#![feature(maybe_uninit_array_assume_init)]
-#![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_slice)]
 #![feature(new_uninit)]
 #![cfg_attr(test, feature(test))]
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index f517c483758..94d2acc0602 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -677,6 +677,7 @@ impl Default for Options {
             optimize: OptLevel::No,
             debuginfo: DebugInfo::None,
             lint_opts: Vec::new(),
+            force_warns: Vec::new(),
             lint_cap: None,
             describe_lints: false,
             output_types: OutputTypes(BTreeMap::new()),
@@ -1092,6 +1093,13 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
              level",
             "LEVEL",
         ),
+        opt::multi_s(
+            "",
+            "force-warns",
+            "Specifiy lints that should warn even if \
+             they are allowed somewhere else",
+            "LINT",
+        ),
         opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
         opt::flag_s("V", "version", "Print version info and exit"),
         opt::flag_s("v", "verbose", "Use verbose output"),
@@ -1156,7 +1164,8 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
 pub fn get_cmd_lint_options(
     matches: &getopts::Matches,
     error_format: ErrorOutputType,
-) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
+    debugging_opts: &DebuggingOptions,
+) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>, Vec<String>) {
     let mut lint_opts_with_position = vec![];
     let mut describe_lints = false;
 
@@ -1189,7 +1198,18 @@ pub fn get_cmd_lint_options(
         lint::Level::from_str(&cap)
             .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
     });
-    (lint_opts, describe_lints, lint_cap)
+
+    if !debugging_opts.unstable_options && matches.opt_present("force-warns") {
+        early_error(
+            error_format,
+            "the `-Z unstable-options` flag must also be passed to enable \
+            the flag `--force-warns=lints`",
+        );
+    }
+
+    let force_warns = matches.opt_strs("force-warns");
+
+    (lint_opts, describe_lints, lint_cap, force_warns)
 }
 
 /// Parses the `--color` flag.
@@ -1507,7 +1527,10 @@ fn collect_print_requests(
     prints
 }
 
-fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
+pub fn parse_target_triple(
+    matches: &getopts::Matches,
+    error_format: ErrorOutputType,
+) -> TargetTriple {
     match matches.opt_str("target") {
         Some(target) if target.ends_with(".json") => {
             let path = Path::new(&target);
@@ -1923,9 +1946,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
         .unwrap_or_else(|e| early_error(error_format, &e[..]));
 
-    let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
-
     let mut debugging_opts = DebuggingOptions::build(matches, error_format);
+    let (lint_opts, describe_lints, lint_cap, force_warns) =
+        get_cmd_lint_options(matches, error_format, &debugging_opts);
+
     check_debug_option_stability(&debugging_opts, error_format, json_rendered);
 
     if !debugging_opts.unstable_options && json_unused_externs {
@@ -2097,6 +2121,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         optimize: opt_level,
         debuginfo,
         lint_opts,
+        force_warns,
         lint_cap,
         describe_lints,
         output_types,
@@ -2424,22 +2449,6 @@ crate mod dep_tracking {
         )+};
     }
 
-    macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
-        ($($t:ty),+ $(,)?) => {$(
-            impl DepTrackingHash for Vec<$t> {
-                fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
-                    let mut elems: Vec<&$t> = self.iter().collect();
-                    elems.sort();
-                    Hash::hash(&elems.len(), hasher);
-                    for (index, elem) in elems.iter().enumerate() {
-                        Hash::hash(&index, hasher);
-                        DepTrackingHash::hash(*elem, hasher, error_format);
-                    }
-                }
-            }
-        )+};
-    }
-
     impl_dep_tracking_hash_via_hash!(
         bool,
         usize,
@@ -2488,16 +2497,6 @@ crate mod dep_tracking {
         TrimmedDefPaths,
     );
 
-    impl_dep_tracking_hash_for_sortable_vec_of!(
-        String,
-        PathBuf,
-        (PathBuf, PathBuf),
-        CrateType,
-        NativeLib,
-        (String, lint::Level),
-        (String, u64)
-    );
-
     impl<T1, T2> DepTrackingHash for (T1, T2)
     where
         T1: DepTrackingHash,
@@ -2527,6 +2526,16 @@ crate mod dep_tracking {
         }
     }
 
+    impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
+        fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+            Hash::hash(&self.len(), hasher);
+            for (index, elem) in self.iter().enumerate() {
+                Hash::hash(&index, hasher);
+                DepTrackingHash::hash(elem, hasher, error_format);
+            }
+        }
+    }
+
     // This is a stable hash because BTreeMap is a sorted container
     crate fn stable_hash(
         sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 7971f7ef9ef..8d00a9a959e 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -1,6 +1,5 @@
 #![feature(crate_visibility_modifier)]
 #![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index c9f95ed1224..58a53b3de6e 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -130,6 +130,7 @@ top_level_options!(
         debuginfo: DebugInfo [TRACKED],
         lint_opts: Vec<(String, lint::Level)> [TRACKED],
         lint_cap: Option<lint::Level> [TRACKED],
+        force_warns: Vec<String> [TRACKED],
         describe_lints: bool [UNTRACKED],
         output_types: OutputTypes [TRACKED],
         search_paths: Vec<SearchPath> [UNTRACKED],
@@ -368,7 +369,7 @@ mod desc {
     pub const parse_target_feature: &str = parse_string;
     pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
     pub const parse_split_debuginfo: &str =
-        "one of supported split-debuginfo modes (`off` or `dsymutil`)";
+        "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
 }
 
 mod parse {
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index 777eea3f68d..cc1e4bb198a 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -127,6 +127,11 @@ pub fn filename_for_metadata(
     crate_name: &str,
     outputs: &OutputFilenames,
 ) -> PathBuf {
+    // If the command-line specified the path, use that directly.
+    if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) {
+        return out_filename.clone();
+    }
+
     let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
 
     let out_filename = outputs
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 1348b02b878..47833dcda4f 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -22,7 +22,7 @@ use rustc_errors::json::JsonEmitter;
 use rustc_errors::registry::Registry;
 use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported};
 use rustc_lint_defs::FutureBreakage;
-pub use rustc_span::crate_disambiguator::CrateDisambiguator;
+pub use rustc_span::def_id::StableCrateId;
 use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
 use rustc_span::{edition::Edition, RealFileName};
 use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
@@ -133,12 +133,12 @@ pub struct Session {
     /// in order to avoid redundantly verbose output (Issue #24690, #44953).
     pub one_time_diagnostics: Lock<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>,
     crate_types: OnceCell<Vec<CrateType>>,
-    /// The `crate_disambiguator` is constructed out of all the `-C metadata`
-    /// arguments passed to the compiler. Its value together with the crate-name
-    /// forms a unique global identifier for the crate. It is used to allow
-    /// multiple crates with the same name to coexist. See the
+    /// The `stable_crate_id` is constructed out of the crate name and all the
+    /// `-C metadata` arguments passed to the compiler. Its value forms a unique
+    /// global identifier for the crate. It is used to allow multiple crates
+    /// with the same name to coexist. See the
     /// `rustc_codegen_llvm::back::symbol_names` module for more information.
-    pub crate_disambiguator: OnceCell<CrateDisambiguator>,
+    pub stable_crate_id: OnceCell<StableCrateId>,
 
     features: OnceCell<rustc_feature::Features>,
 
@@ -335,8 +335,8 @@ impl Session {
         self.parse_sess.span_diagnostic.emit_future_breakage_report(diags_and_breakage);
     }
 
-    pub fn local_crate_disambiguator(&self) -> CrateDisambiguator {
-        self.crate_disambiguator.get().copied().unwrap()
+    pub fn local_stable_crate_id(&self) -> StableCrateId {
+        self.stable_crate_id.get().copied().unwrap()
     }
 
     pub fn crate_types(&self) -> &[CrateType] {
@@ -452,6 +452,7 @@ impl Session {
     pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) {
         err.into_diagnostic(self).emit()
     }
+    #[inline]
     pub fn err_count(&self) -> usize {
         self.diagnostic().err_count()
     }
@@ -524,6 +525,7 @@ impl Session {
         self.diagnostic().struct_note_without_error(msg)
     }
 
+    #[inline]
     pub fn diagnostic(&self) -> &rustc_errors::Handler {
         &self.parse_sess.span_diagnostic
     }
@@ -831,12 +833,12 @@ impl Session {
 
     /// Returns the symbol name for the registrar function,
     /// given the crate `Svh` and the function `DefIndex`.
-    pub fn generate_plugin_registrar_symbol(&self, disambiguator: CrateDisambiguator) -> String {
-        format!("__rustc_plugin_registrar_{}__", disambiguator.to_fingerprint().to_hex())
+    pub fn generate_plugin_registrar_symbol(&self, stable_crate_id: StableCrateId) -> String {
+        format!("__rustc_plugin_registrar_{:08x}__", stable_crate_id.to_u64())
     }
 
-    pub fn generate_proc_macro_decls_symbol(&self, disambiguator: CrateDisambiguator) -> String {
-        format!("__rustc_proc_macro_decls_{}__", disambiguator.to_fingerprint().to_hex())
+    pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String {
+        format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.to_u64())
     }
 
     pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
@@ -1395,7 +1397,7 @@ pub fn build_session(
         working_dir,
         one_time_diagnostics: Default::default(),
         crate_types: OnceCell::new(),
-        crate_disambiguator: OnceCell::new(),
+        stable_crate_id: OnceCell::new(),
         features: OnceCell::new(),
         lint_store: OnceCell::new(),
         recursion_limit: OnceCell::new(),
@@ -1512,6 +1514,14 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
         sess.err(&format!("`-Zsanitizer={}` is incompatible with `-Zsanitizer={}`", first, second));
     }
+
+    // Cannot enable crt-static with sanitizers on Linux
+    if sess.crt_static(None) && !sess.opts.debugging_opts.sanitizer.is_empty() {
+        sess.err(
+            "Sanitizer is incompatible with statically linked libc, \
+                                disable it using `-C target-feature=-crt-static`",
+        );
+    }
 }
 
 /// Holds data on the current incremental compilation session, if there is one.
diff --git a/compiler/rustc_span/src/crate_disambiguator.rs b/compiler/rustc_span/src/crate_disambiguator.rs
deleted file mode 100644
index bd7d8516714..00000000000
--- a/compiler/rustc_span/src/crate_disambiguator.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-// This is here because `rustc_session` wants to refer to it,
-// and so does `rustc_hir`, but `rustc_hir` shouldn't refer to `rustc_session`.
-
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::{base_n, impl_stable_hash_via_hash};
-
-use std::fmt;
-
-/// Hash value constructed out of all the `-C metadata` arguments passed to the
-/// compiler. Together with the crate-name forms a unique global identifier for
-/// the crate.
-#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, Encodable, Decodable)]
-pub struct CrateDisambiguator(Fingerprint);
-
-impl CrateDisambiguator {
-    pub fn to_fingerprint(self) -> Fingerprint {
-        self.0
-    }
-}
-
-impl fmt::Display for CrateDisambiguator {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
-        let (a, b) = self.0.as_value();
-        let as_u128 = a as u128 | ((b as u128) << 64);
-        f.write_str(&base_n::encode(as_u128, base_n::CASE_INSENSITIVE))
-    }
-}
-
-impl From<Fingerprint> for CrateDisambiguator {
-    fn from(fingerprint: Fingerprint) -> CrateDisambiguator {
-        CrateDisambiguator(fingerprint)
-    }
-}
-
-impl_stable_hash_via_hash!(CrateDisambiguator);
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 95bb0ad7ba2..b04a10d22a0 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -1,4 +1,3 @@
-use crate::crate_disambiguator::CrateDisambiguator;
 use crate::HashStableContext;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -10,65 +9,23 @@ use std::borrow::Borrow;
 use std::fmt;
 
 rustc_index::newtype_index! {
-    pub struct CrateId {
+    pub struct CrateNum {
         ENCODABLE = custom
+        DEBUG_FORMAT = "crate{}"
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum CrateNum {
-    /// A special `CrateNum` that we use for the `tcx.rcache` when decoding from
-    /// the incr. comp. cache.
-    ReservedForIncrCompCache,
-    Index(CrateId),
-}
-
 /// Item definitions in the currently-compiled crate would have the `CrateNum`
 /// `LOCAL_CRATE` in their `DefId`.
-pub const LOCAL_CRATE: CrateNum = CrateNum::Index(CrateId::from_u32(0));
-
-impl Idx for CrateNum {
-    #[inline]
-    fn new(value: usize) -> Self {
-        CrateNum::Index(Idx::new(value))
-    }
-
-    #[inline]
-    fn index(self) -> usize {
-        match self {
-            CrateNum::Index(idx) => Idx::index(idx),
-            _ => panic!("Tried to get crate index of {:?}", self),
-        }
-    }
-}
+pub const LOCAL_CRATE: CrateNum = CrateNum::from_u32(0);
 
 impl CrateNum {
+    #[inline]
     pub fn new(x: usize) -> CrateNum {
         CrateNum::from_usize(x)
     }
 
-    pub fn from_usize(x: usize) -> CrateNum {
-        CrateNum::Index(CrateId::from_usize(x))
-    }
-
-    pub fn from_u32(x: u32) -> CrateNum {
-        CrateNum::Index(CrateId::from_u32(x))
-    }
-
-    pub fn as_usize(self) -> usize {
-        match self {
-            CrateNum::Index(id) => id.as_usize(),
-            _ => panic!("tried to get index of non-standard crate {:?}", self),
-        }
-    }
-
-    pub fn as_u32(self) -> u32 {
-        match self {
-            CrateNum::Index(id) => id.as_u32(),
-            _ => panic!("tried to get index of non-standard crate {:?}", self),
-        }
-    }
-
+    #[inline]
     pub fn as_def_id(&self) -> DefId {
         DefId { krate: *self, index: CRATE_DEF_INDEX }
     }
@@ -76,10 +33,7 @@ impl CrateNum {
 
 impl fmt::Display for CrateNum {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            CrateNum::Index(id) => fmt::Display::fmt(&id.private, f),
-            CrateNum::ReservedForIncrCompCache => write!(f, "crate for decoding incr comp cache"),
-        }
+        fmt::Display::fmt(&self.private, f)
     }
 }
 
@@ -97,15 +51,6 @@ impl<D: Decoder> Decodable<D> for CrateNum {
     }
 }
 
-impl ::std::fmt::Debug for CrateNum {
-    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
-        match self {
-            CrateNum::Index(id) => write!(fmt, "crate{}", id.private),
-            CrateNum::ReservedForIncrCompCache => write!(fmt, "crate for decoding incr comp cache"),
-        }
-    }
-}
-
 /// A `DefPathHash` is a fixed-size representation of a `DefPath` that is
 /// stable across crate and compilation session boundaries. It consists of two
 /// separate 64-bit hashes. The first uniquely identifies the crate this
@@ -181,26 +126,51 @@ impl Borrow<Fingerprint> for DefPathHash {
     }
 }
 
-/// A [StableCrateId] is a 64 bit hash of `(crate-name, crate-disambiguator)`. It
-/// is to [CrateNum] what [DefPathHash] is to [DefId]. It is stable across
-/// compilation sessions.
+/// A [StableCrateId] is a 64 bit hash of the crate name combined with all
+/// `-Cmetadata` arguments. It is to [CrateNum] what [DefPathHash] is to
+/// [DefId]. It is stable across compilation sessions.
 ///
 /// Since the ID is a hash value there is a (very small) chance that two crates
 /// end up with the same [StableCrateId]. The compiler will check for such
 /// collisions when loading crates and abort compilation in order to avoid
 /// further trouble.
-#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Encodable, Decodable)]
+#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(HashStable_Generic, Encodable, Decodable)]
 pub struct StableCrateId(u64);
 
 impl StableCrateId {
+    pub fn to_u64(self) -> u64 {
+        self.0
+    }
+
     /// Computes the stable ID for a crate with the given name and
-    /// disambiguator.
-    pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> StableCrateId {
+    /// `-Cmetadata` arguments.
+    pub fn new(crate_name: &str, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId {
         use std::hash::Hash;
+        use std::hash::Hasher;
 
         let mut hasher = StableHasher::new();
         crate_name.hash(&mut hasher);
-        crate_disambiguator.hash(&mut hasher);
+
+        // We don't want the stable crate id to dependent on the order
+        // -C metadata arguments, so sort them:
+        metadata.sort();
+        // Every distinct -C metadata value is only incorporated once:
+        metadata.dedup();
+
+        hasher.write(b"metadata");
+        for s in &metadata {
+            // Also incorporate the length of a metadata string, so that we generate
+            // different values for `-Cmetadata=ab -Cmetadata=c` and
+            // `-Cmetadata=a -Cmetadata=bc`
+            hasher.write_usize(s.len());
+            hasher.write(s.as_bytes());
+        }
+
+        // Also incorporate crate type, so that we don't get symbol conflicts when
+        // linking against a library of the same name, if this is an executable.
+        hasher.write(if is_exe { b"exe" } else { b"lib" });
+
         StableCrateId(hasher.finish())
     }
 }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 0301b364591..51a53918f07 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -16,7 +16,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(array_windows)]
 #![feature(crate_visibility_modifier)]
-#![feature(const_panic)]
 #![feature(negative_impls)]
 #![feature(nll)]
 #![feature(min_specialization)]
@@ -46,8 +45,6 @@ pub mod lev_distance;
 mod span_encoding;
 pub use span_encoding::{Span, DUMMY_SP};
 
-pub mod crate_disambiguator;
-
 pub mod symbol;
 pub use symbol::{sym, Symbol};
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 03a8f2be156..46ef308cbf2 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -130,10 +130,13 @@ symbols! {
         BTreeSet,
         BinaryHeap,
         Borrow,
+        Break,
         C,
+        CStr,
         CString,
         Center,
         Clone,
+        Continue,
         Copy,
         Count,
         Debug,
@@ -326,6 +329,7 @@ symbols! {
         box_patterns,
         box_syntax,
         braced_empty_structs,
+        branch,
         breakpoint,
         bridge,
         bswap,
@@ -411,6 +415,7 @@ symbols! {
         constructor,
         contents,
         context,
+        control_flow_enum,
         convert,
         copy,
         copy_closures,
@@ -511,7 +516,6 @@ symbols! {
         env,
         eq,
         ermsb_target_feature,
-        err,
         exact_div,
         except,
         exchange_malloc,
@@ -581,10 +585,10 @@ symbols! {
         frem_fast,
         from,
         from_desugaring,
-        from_error,
         from_generator,
         from_method,
-        from_ok,
+        from_output,
+        from_residual,
         from_size_align_unchecked,
         from_trait,
         from_usize,
@@ -653,7 +657,6 @@ symbols! {
         instruction_set,
         intel,
         into_iter,
-        into_result,
         into_trait,
         intra_doc_pointers,
         intrinsics,
@@ -965,6 +968,7 @@ symbols! {
         repr_packed,
         repr_simd,
         repr_transparent,
+        residual,
         result,
         result_type,
         rhs,
@@ -1232,7 +1236,7 @@ symbols! {
         try_blocks,
         try_from_trait,
         try_into_trait,
-        try_trait,
+        try_trait_v2,
         tt,
         tuple,
         tuple_from_req,
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 7d186c330ba..0c64fe6ea60 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -126,10 +126,9 @@ fn get_symbol_hash<'tcx>(
         substs.hash_stable(&mut hcx, &mut hasher);
 
         if let Some(instantiating_crate) = instantiating_crate {
-            tcx.original_crate_name(instantiating_crate)
-                .as_str()
+            tcx.def_path_hash(instantiating_crate.as_def_id())
+                .stable_crate_id()
                 .hash_stable(&mut hcx, &mut hasher);
-            tcx.crate_disambiguator(instantiating_crate).hash_stable(&mut hcx, &mut hasher);
         }
 
         // We want to avoid accidental collision between different types of instances.
@@ -255,7 +254,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> {
     }
 
     fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
-        self.write_str(&self.tcx.original_crate_name(cnum).as_str())?;
+        self.write_str(&self.tcx.crate_name(cnum).as_str())?;
         Ok(self)
     }
     fn path_qualified(
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 7fb24ad1ed8..ba59ff96f65 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -90,7 +90,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(never_type)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(in_band_lifetimes)]
 #![recursion_limit = "256"]
 
@@ -166,12 +165,12 @@ fn compute_symbol_name(
     // FIXME(eddyb) Precompute a custom symbol name based on attributes.
     let is_foreign = if let Some(def_id) = def_id.as_local() {
         if tcx.plugin_registrar_fn(()) == Some(def_id) {
-            let disambiguator = tcx.sess.local_crate_disambiguator();
-            return tcx.sess.generate_plugin_registrar_symbol(disambiguator);
+            let stable_crate_id = tcx.sess.local_stable_crate_id();
+            return tcx.sess.generate_plugin_registrar_symbol(stable_crate_id);
         }
         if tcx.proc_macro_decls_static(()) == Some(def_id) {
-            let disambiguator = tcx.sess.local_crate_disambiguator();
-            return tcx.sess.generate_proc_macro_decls_symbol(disambiguator);
+            let stable_crate_id = tcx.sess.local_stable_crate_id();
+            return tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
         }
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
         matches!(tcx.hir().get(hir_id), Node::ForeignItem(_))
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 37a834043f6..e7da56ed0f3 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -485,9 +485,39 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
         mut self,
         predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
     ) -> Result<Self::DynExistential, Self::Error> {
-        for predicate in predicates {
-            self = self.in_binder(&predicate, |mut cx, predicate| {
-                match predicate {
+        // Okay, so this is a bit tricky. Imagine we have a trait object like
+        // `dyn for<'a> Foo<'a, Bar = &'a ()>`. When we mangle this, the
+        // output looks really close to the syntax, where the `Bar = &'a ()` bit
+        // is under the same binders (`['a]`) as the `Foo<'a>` bit. However, we
+        // actually desugar these into two separate `ExistentialPredicate`s. We
+        // can't enter/exit the "binder scope" twice though, because then we
+        // would mangle the binders twice. (Also, side note, we merging these
+        // two is kind of difficult, because of potential HRTBs in the Projection
+        // predicate.)
+        //
+        // Also worth mentioning: imagine that we instead had
+        // `dyn for<'a> Foo<'a, Bar = &'a ()> + Send`. In this case, `Send` is
+        // under the same binders as `Foo`. Currently, this doesn't matter,
+        // because only *auto traits* are allowed other than the principal trait
+        // and all auto traits don't have any generics. Two things could
+        // make this not an "okay" mangling:
+        // 1) Instead of mangling only *used*
+        // bound vars, we want to mangle *all* bound vars (`for<'b> Send` is a
+        // valid trait predicate);
+        // 2) We allow multiple "principal" traits in the future, or at least
+        // allow in any form another trait predicate that can take generics.
+        //
+        // Here we assume that predicates have the following structure:
+        // [<Trait> [{<Projection>}]] [{<Auto>}]
+        // Since any predicates after the first one shouldn't change the binders,
+        // just put them all in the binders of the first.
+        self = self.in_binder(&predicates[0], |mut cx, _| {
+            for predicate in predicates.iter() {
+                // It would be nice to be able to validate bound vars here, but
+                // projections can actually include bound vars from super traits
+                // because of HRTBs (only in the `Self` type). Also, auto traits
+                // could have different bound vars *anyways*.
+                match predicate.as_ref().skip_binder() {
                     ty::ExistentialPredicate::Trait(trait_ref) => {
                         // Use a type that can't appear in defaults of type parameters.
                         let dummy_self = cx.tcx.mk_ty_infer(ty::FreshTy(0));
@@ -504,9 +534,10 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
                         cx = cx.print_def_path(*def_id, &[])?;
                     }
                 }
-                Ok(cx)
-            })?;
-        }
+            }
+            Ok(cx)
+        })?;
+
         self.push("E");
         Ok(self)
     }
@@ -561,9 +592,9 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
 
     fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
         self.push("C");
-        let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint();
-        self.push_disambiguator(fingerprint.to_smaller_hash());
-        let name = self.tcx.original_crate_name(cnum).as_str();
+        let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
+        self.push_disambiguator(stable_crate_id.to_u64());
+        let name = self.tcx.crate_name(cnum).as_str();
         self.push_ident(&name);
         Ok(self)
     }
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index e2618da749f..1679d029374 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -222,6 +222,7 @@ pub trait HasDataLayout {
 }
 
 impl HasDataLayout for TargetDataLayout {
+    #[inline]
     fn data_layout(&self) -> &TargetDataLayout {
         self
     }
@@ -441,6 +442,8 @@ pub struct Align {
 }
 
 impl Align {
+    pub const ONE: Align = Align { pow2: 0 };
+
     #[inline]
     pub fn from_bits(bits: u64) -> Result<Align, String> {
         Align::from_bytes(Size::from_bits(bits).bytes())
@@ -450,7 +453,7 @@ impl Align {
     pub fn from_bytes(align: u64) -> Result<Align, String> {
         // Treat an alignment of 0 bytes like 1-byte alignment.
         if align == 0 {
-            return Ok(Align { pow2: 0 });
+            return Ok(Align::ONE);
         }
 
         #[cold]
@@ -860,6 +863,7 @@ pub enum Abi {
 
 impl Abi {
     /// Returns `true` if the layout corresponds to an unsized type.
+    #[inline]
     pub fn is_unsized(&self) -> bool {
         match *self {
             Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false,
@@ -879,11 +883,13 @@ impl Abi {
     }
 
     /// Returns `true` if this is an uninhabited type
+    #[inline]
     pub fn is_uninhabited(&self) -> bool {
         matches!(*self, Abi::Uninhabited)
     }
 
     /// Returns `true` is this is a scalar type
+    #[inline]
     pub fn is_scalar(&self) -> bool {
         matches!(*self, Abi::Scalar(_))
     }
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index 48ace9b65b6..cb8f6b9656c 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -9,11 +9,11 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(bool_to_option)]
-#![feature(const_panic)]
 #![feature(nll)]
 #![feature(never_type)]
 #![feature(associated_type_bounds)]
 #![feature(exhaustive_patterns)]
+#![feature(min_specialization)]
 
 use std::path::{Path, PathBuf};
 
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
index 2218c6c6da7..5682039b865 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs
@@ -10,7 +10,6 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".to_string(),
-            eliminate_frame_pointer: false,
             max_atomic_width: Some(128),
             unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
index 758950bd344..8a832546d09 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
@@ -10,7 +10,6 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a12".to_string(),
-            eliminate_frame_pointer: false,
             max_atomic_width: Some(128),
             unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
index e594ceec1b7..2187015b627 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs
@@ -18,7 +18,6 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".to_string(),
-            eliminate_frame_pointer: false,
             max_atomic_width: Some(128),
             unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
index a83de77dc2a..cb6c06b3711 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs
@@ -10,7 +10,6 @@ pub fn target() -> Target {
         arch: "aarch64".to_string(),
         options: TargetOptions {
             features: "+neon,+fp-armv8,+apple-a7".to_string(),
-            eliminate_frame_pointer: false,
             max_atomic_width: Some(128),
             unsupported_abis: super::arm_base::unsupported_abis(),
             forces_embed_bitcode: true,
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
index c9f622820de..de92b167f00 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs
@@ -16,7 +16,6 @@ pub fn target() -> Target {
         executables: true,
         relocation_model: RelocModel::Static,
         disable_redzone: true,
-        linker_is_gnu: true,
         max_atomic_width: Some(128),
         panic_strategy: PanicStrategy::Abort,
         unsupported_abis: super::arm_base::unsupported_abis(),
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
index 0811871c993..2566eeae14a 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs
@@ -16,7 +16,6 @@ pub fn target() -> Target {
         executables: true,
         relocation_model: RelocModel::Static,
         disable_redzone: true,
-        linker_is_gnu: true,
         max_atomic_width: Some(128),
         panic_strategy: PanicStrategy::Abort,
         unsupported_abis: super::arm_base::unsupported_abis(),
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index bc2ec670901..8530db179d9 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -22,10 +22,12 @@ pub fn opts(os: &str) -> TargetOptions {
         // macOS has -dead_strip, which doesn't rely on function_sections
         function_sections: false,
         dynamic_linking: true,
+        linker_is_gnu: false,
         executables: true,
         families: vec!["unix".to_string()],
         is_like_osx: true,
         dwarf_version: Some(2),
+        eliminate_frame_pointer: false,
         has_rpath: true,
         dll_suffix: ".dylib".to_string(),
         archive_format: "darwin".to_string(),
diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs
index 538c4ca8697..e7f7bb343d0 100644
--- a/compiler/rustc_target/src/spec/apple_sdk_base.rs
+++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs
@@ -44,7 +44,6 @@ pub fn opts(os: &str, arch: Arch) -> TargetOptions {
         executables: true,
         link_env_remove: link_env_remove(arch),
         has_elf_tls: false,
-        eliminate_frame_pointer: false,
         ..super::apple_base::opts(os)
     }
 }
diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs
index 69ccce875ab..2cb2661a526 100644
--- a/compiler/rustc_target/src/spec/avr_gnu_base.rs
+++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs
@@ -16,7 +16,6 @@ pub fn target(target_cpu: String) -> Target {
 
             linker: Some("avr-gcc".to_owned()),
             executables: true,
-            linker_is_gnu: true,
             eh_frame_header: false,
             pre_link_args: vec![(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu)])]
                 .into_iter()
diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs
index fb94498c131..e13a640d4d2 100644
--- a/compiler/rustc_target/src/spec/dragonfly_base.rs
+++ b/compiler/rustc_target/src/spec/dragonfly_base.rs
@@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs
index 5d3c28e5f29..bef2fce7c83 100644
--- a/compiler/rustc_target/src/spec/freebsd_base.rs
+++ b/compiler/rustc_target/src/spec/freebsd_base.rs
@@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
         eliminate_frame_pointer: false, // FIXME 43575
diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs
index 13264dffeb4..23a2e65749e 100644
--- a/compiler/rustc_target/src/spec/fuchsia_base.rs
+++ b/compiler/rustc_target/src/spec/fuchsia_base.rs
@@ -27,7 +27,6 @@ pub fn opts() -> TargetOptions {
         executables: true,
         families: vec!["unix".to_string()],
         is_like_fuchsia: true,
-        linker_is_gnu: true,
         pre_link_args,
         pre_link_objects: crt_objects::new(&[
             (LinkOutputKind::DynamicNoPicExe, &["Scrt1.o"]),
diff --git a/compiler/rustc_target/src/spec/haiku_base.rs b/compiler/rustc_target/src/spec/haiku_base.rs
index fae56f6a82d..2b95523d6f7 100644
--- a/compiler/rustc_target/src/spec/haiku_base.rs
+++ b/compiler/rustc_target/src/spec/haiku_base.rs
@@ -7,7 +7,6 @@ pub fn opts() -> TargetOptions {
         executables: true,
         families: vec!["unix".to_string()],
         relro_level: RelroLevel::Full,
-        linker_is_gnu: true,
         ..Default::default()
     }
 }
diff --git a/compiler/rustc_target/src/spec/hermit_base.rs b/compiler/rustc_target/src/spec/hermit_base.rs
index ad013047e6a..75ca1f79b12 100644
--- a/compiler/rustc_target/src/spec/hermit_base.rs
+++ b/compiler/rustc_target/src/spec/hermit_base.rs
@@ -13,7 +13,6 @@ pub fn opts() -> TargetOptions {
         linker: Some("rust-lld".to_owned()),
         executables: true,
         has_elf_tls: true,
-        linker_is_gnu: true,
         pre_link_args,
         panic_strategy: PanicStrategy::Abort,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/hermit_kernel_base.rs b/compiler/rustc_target/src/spec/hermit_kernel_base.rs
index 6d18a14d6ae..c55a46e69a8 100644
--- a/compiler/rustc_target/src/spec/hermit_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/hermit_kernel_base.rs
@@ -14,7 +14,6 @@ pub fn opts() -> TargetOptions {
         linker: Some("rust-lld".to_owned()),
         executables: true,
         has_elf_tls: true,
-        linker_is_gnu: true,
         pre_link_args,
         panic_strategy: PanicStrategy::Abort,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs
index 2b8e046c46b..9d9da50be7a 100644
--- a/compiler/rustc_target/src/spec/illumos_base.rs
+++ b/compiler/rustc_target/src/spec/illumos_base.rs
@@ -33,6 +33,7 @@ pub fn opts() -> TargetOptions {
         has_rpath: true,
         families: vec!["unix".to_string()],
         is_like_solaris: true,
+        linker_is_gnu: false,
         limit_rdylib_exports: false, // Linker doesn't support this
         eliminate_frame_pointer: false,
         eh_frame_header: false,
diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs
index 65c343a5f21..f6e3102f617 100644
--- a/compiler/rustc_target/src/spec/l4re_base.rs
+++ b/compiler/rustc_target/src/spec/l4re_base.rs
@@ -20,6 +20,7 @@ pub fn opts() -> TargetOptions {
         executables: true,
         panic_strategy: PanicStrategy::Abort,
         linker: Some("ld".to_string()),
+        linker_is_gnu: false,
         families: vec!["unix".to_string()],
         ..Default::default()
     }
diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs
index 184659e22d9..af81bc714c7 100644
--- a/compiler/rustc_target/src/spec/linux_base.rs
+++ b/compiler/rustc_target/src/spec/linux_base.rs
@@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs
index 64f47b4aa9b..145aa4a5894 100644
--- a/compiler/rustc_target/src/spec/linux_kernel_base.rs
+++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs
@@ -8,7 +8,6 @@ pub fn opts() -> TargetOptions {
         // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
         stack_probes: StackProbeType::Call,
         eliminate_frame_pointer: false,
-        linker_is_gnu: true,
         position_independent_executables: true,
         needs_plt: true,
         relro_level: RelroLevel::Full,
diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
index 08c290e6ff1..dc14e4bdf94 100644
--- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
+++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs
@@ -21,7 +21,6 @@ pub fn target() -> Target {
             cpu: "mips2".to_string(),
             executables: true,
             linker: Some("rust-lld".to_owned()),
-            linker_is_gnu: true,
             relocation_model: RelocModel::Static,
 
             // PSP FPU only supports single precision floats.
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 4bffd6e8ddd..4683def94f7 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -922,6 +922,7 @@ pub trait HasTargetSpec {
 }
 
 impl HasTargetSpec for Target {
+    #[inline]
     fn target_spec(&self) -> &Target {
         self
     }
@@ -1086,7 +1087,7 @@ pub struct TargetOptions {
     /// Version of DWARF to use if not using the default.
     /// Useful because some platforms (osx, bsd) only want up to DWARF2.
     pub dwarf_version: Option<u32>,
-    /// Whether the linker support GNU-like arguments such as -O. Defaults to false.
+    /// Whether the linker support GNU-like arguments such as -O. Defaults to true.
     pub linker_is_gnu: bool,
     /// The MinGW toolchain has a known issue that prevents it from correctly
     /// handling COFF object files with more than 2<sup>15</sup> sections. Since each weak
@@ -1307,7 +1308,7 @@ impl Default for TargetOptions {
             is_like_fuchsia: false,
             is_like_wasm: false,
             dwarf_version: None,
-            linker_is_gnu: false,
+            linker_is_gnu: true,
             allows_weak_linkage: true,
             has_rpath: false,
             no_default_libraries: true,
diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs
index 4ed7685ca07..f1ed4c154d2 100644
--- a/compiler/rustc_target/src/spec/msvc_base.rs
+++ b/compiler/rustc_target/src/spec/msvc_base.rs
@@ -16,6 +16,7 @@ pub fn opts() -> TargetOptions {
         is_like_windows: true,
         is_like_msvc: true,
         lld_flavor: LldFlavor::Link,
+        linker_is_gnu: false,
         pre_link_args,
         abi_return_struct_as_int: true,
         emit_debug_gdb_scripts: false,
diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs
index 602fb6eb641..6bb6083d47c 100644
--- a/compiler/rustc_target/src/spec/netbsd_base.rs
+++ b/compiler/rustc_target/src/spec/netbsd_base.rs
@@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         no_default_libraries: false,
         has_rpath: true,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
index 15d8e4843f9..97960a75b09 100644
--- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
+++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs
@@ -14,6 +14,7 @@ pub fn target() -> Target {
             linker_flavor: LinkerFlavor::PtxLinker,
             // The linker can be installed from `crates.io`.
             linker: Some("rust-ptx-linker".to_string()),
+            linker_is_gnu: false,
 
             // With `ptx-linker` approach, it can be later overridden via link flags.
             cpu: "sm_30".to_string(),
diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs
index 8f33bacd922..29b415e7726 100644
--- a/compiler/rustc_target/src/spec/openbsd_base.rs
+++ b/compiler/rustc_target/src/spec/openbsd_base.rs
@@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         has_rpath: true,
         abi_return_struct_as_int: true,
         position_independent_executables: true,
diff --git a/compiler/rustc_target/src/spec/redox_base.rs b/compiler/rustc_target/src/spec/redox_base.rs
index 72052b9e2e2..fcf5db3746d 100644
--- a/compiler/rustc_target/src/spec/redox_base.rs
+++ b/compiler/rustc_target/src/spec/redox_base.rs
@@ -7,7 +7,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
         relro_level: RelroLevel::Full,
diff --git a/compiler/rustc_target/src/spec/solaris_base.rs b/compiler/rustc_target/src/spec/solaris_base.rs
index 4c922eb5cea..bc32b501688 100644
--- a/compiler/rustc_target/src/spec/solaris_base.rs
+++ b/compiler/rustc_target/src/spec/solaris_base.rs
@@ -8,6 +8,7 @@ pub fn opts() -> TargetOptions {
         has_rpath: true,
         families: vec!["unix".to_string()],
         is_like_solaris: true,
+        linker_is_gnu: false,
         limit_rdylib_exports: false, // Linker doesn't support this
         eh_frame_header: false,
 
diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
index ef58824f381..f996009f830 100644
--- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs
@@ -28,7 +28,6 @@ pub fn target() -> Target {
         options: TargetOptions {
             linker_flavor: LinkerFlavor::Ld,
             linker: Some("arm-none-eabi-ld".to_string()),
-            linker_is_gnu: true,
 
             // extra args passed to the external assembler (assuming `arm-none-eabi-as`):
             // * activate t32/a32 interworking
diff --git a/compiler/rustc_target/src/spec/vxworks_base.rs b/compiler/rustc_target/src/spec/vxworks_base.rs
index 0e8e87f2dff..a91e7717865 100644
--- a/compiler/rustc_target/src/spec/vxworks_base.rs
+++ b/compiler/rustc_target/src/spec/vxworks_base.rs
@@ -10,7 +10,6 @@ pub fn opts() -> TargetOptions {
         dynamic_linking: true,
         executables: true,
         families: vec!["unix".to_string()],
-        linker_is_gnu: true,
         has_rpath: true,
         has_elf_tls: true,
         crt_static_default: true,
diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
index ddf28b423f0..302139395d3 100644
--- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
+++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
@@ -34,7 +34,6 @@ pub fn target() -> Target {
         // functionality, and a .wasm file.
         exe_suffix: ".js".to_string(),
         linker: None,
-        linker_is_gnu: true,
         is_like_emscripten: true,
         panic_strategy: PanicStrategy::Unwind,
         post_link_args,
diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
index 90705c526f4..06eb33d8d82 100644
--- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
+++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs
@@ -57,7 +57,6 @@ pub fn target() -> Target {
         vendor: "fortanix".into(),
         linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         executables: true,
-        linker_is_gnu: true,
         linker: Some("rust-lld".to_owned()),
         max_atomic_width: Some(64),
         cpu: "x86-64".into(),
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs
index 3f24a33f7d5..ac2e0ebae32 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_trait_selection/src/autoderef.rs
@@ -6,6 +6,7 @@ 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::def_id::LOCAL_CRATE;
 use rustc_span::Span;
 
 #[derive(Copy, Clone, Debug)]
@@ -231,7 +232,8 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa
         .span_label(span, "deref recursion limit reached")
         .help(&format!(
             "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
-            suggested_limit, tcx.crate_name,
+            suggested_limit,
+            tcx.crate_name(LOCAL_CRATE),
         ))
         .emit();
     }
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index bf3c8643f0d..e932b1bca7c 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -19,7 +19,6 @@
 #![feature(iter_zip)]
 #![feature(never_type)]
 #![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(control_flow_enum)]
 #![recursion_limit = "512"] // For rustdoc
 
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index fb4a8ce687c..163df26e9ff 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -46,6 +46,7 @@ pub struct OpaqueTypeDecl<'tcx> {
     /// type Foo = impl Baz;
     /// fn bar() -> Foo {
     /// //          ^^^ This is the span we are looking for!
+    /// }
     /// ```
     ///
     /// In cases where the fn returns `(impl Trait, impl Trait)` or
@@ -139,15 +140,6 @@ pub trait InferCtxtExt<'tcx> {
         first_own_region_index: usize,
     );
 
-    /*private*/
-    fn member_constraint_feature_gate(
-        &self,
-        opaque_defn: &OpaqueTypeDecl<'tcx>,
-        opaque_type_def_id: DefId,
-        conflict1: ty::Region<'tcx>,
-        conflict2: ty::Region<'tcx>,
-    ) -> bool;
-
     fn infer_opaque_definition_from_instantiation(
         &self,
         def_id: DefId,
@@ -489,9 +481,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         // ['a, 'b, 'c]`, where `'a..'c` are the
                         // regions that appear in the impl trait.
 
-                        // For now, enforce a feature gate outside of async functions.
-                        self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_region);
-
                         return self.generate_member_constraint(
                             concrete_ty,
                             opaque_defn,
@@ -558,60 +547,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         });
     }
 
-    /// Member constraints are presently feature-gated except for
-    /// async-await. We expect to lift this once we've had a bit more
-    /// time.
-    fn member_constraint_feature_gate(
-        &self,
-        opaque_defn: &OpaqueTypeDecl<'tcx>,
-        opaque_type_def_id: DefId,
-        conflict1: ty::Region<'tcx>,
-        conflict2: ty::Region<'tcx>,
-    ) -> bool {
-        // If we have `#![feature(member_constraints)]`, no problems.
-        if self.tcx.features().member_constraints {
-            return false;
-        }
-
-        let span = self.tcx.def_span(opaque_type_def_id);
-
-        // Without a feature-gate, we only generate member-constraints for async-await.
-        let context_name = match opaque_defn.origin {
-            // No feature-gate required for `async fn`.
-            hir::OpaqueTyOrigin::AsyncFn => return false,
-
-            // Otherwise, generate the label we'll use in the error message.
-            hir::OpaqueTyOrigin::Binding
-            | hir::OpaqueTyOrigin::FnReturn
-            | hir::OpaqueTyOrigin::TyAlias
-            | hir::OpaqueTyOrigin::Misc => "impl Trait",
-        };
-        let msg = format!("ambiguous lifetime bound in `{}`", context_name);
-        let mut err = self.tcx.sess.struct_span_err(span, &msg);
-
-        let conflict1_name = conflict1.to_string();
-        let conflict2_name = conflict2.to_string();
-        let label_owned;
-        let label = match (&*conflict1_name, &*conflict2_name) {
-            ("'_", "'_") => "the elided lifetimes here do not outlive one another",
-            _ => {
-                label_owned = format!(
-                    "neither `{}` nor `{}` outlives the other",
-                    conflict1_name, conflict2_name,
-                );
-                &label_owned
-            }
-        };
-        err.span_label(span, label);
-
-        if self.tcx.sess.is_nightly_build() {
-            err.help("add #![feature(member_constraints)] to the crate attributes to enable");
-        }
-
-        err.emit();
-        true
-    }
-
     /// Given the fully resolved, instantiated type for an opaque
     /// type, i.e., the value of an inference variable like C1 or C2
     /// (*), computes the "definition type" for an opaque type
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 1ea34e5814e..0ca0245a203 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
@@ -186,6 +186,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 };
                 let name = param.name;
                 flags.push((name, Some(value)));
+
+                if let GenericParamDefKind::Type { .. } = param.kind {
+                    let param_ty = trait_ref.substs[param.index as usize].expect_ty();
+                    if let Some(def) = param_ty.ty_adt_def() {
+                        // We also want to be able to select the parameter's
+                        // original signature with no type arguments resolved
+                        flags.push((name, Some(self.tcx.type_of(def.did).to_string())));
+                    }
+                }
             }
 
             if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
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 6a4d41ffc1a..5c35b515f3d 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -21,6 +21,7 @@ use rustc_middle::ty::{
     Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
 };
 use rustc_middle::ty::{TypeAndMut, TypeckResults};
+use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
 use rustc_target::spec::abi;
@@ -686,17 +687,36 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             return false;
         }
 
+        // Blacklist traits for which it would be nonsensical to suggest borrowing.
+        // For instance, immutable references are always Copy, so suggesting to
+        // borrow would always succeed, but it's probably not what the user wanted.
+        let blacklist: Vec<_> =
+            [LangItem::Copy, LangItem::Clone, LangItem::Unpin, LangItem::Sized, LangItem::Send]
+                .iter()
+                .filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok())
+                .collect();
+
         let span = obligation.cause.span;
         let param_env = obligation.param_env;
         let trait_ref = trait_ref.skip_binder();
 
-        if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code {
-            // Try to apply the original trait binding obligation by borrowing.
-            let self_ty = trait_ref.self_ty();
-            let found = self_ty.to_string();
-            let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty);
-            let substs = self.tcx.mk_substs_trait(new_self_ty, &[]);
-            let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs);
+        let found_ty = trait_ref.self_ty();
+        let found_ty_str = found_ty.to_string();
+        let imm_borrowed_found_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, found_ty);
+        let imm_substs = self.tcx.mk_substs_trait(imm_borrowed_found_ty, &[]);
+        let mut_borrowed_found_ty = self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, found_ty);
+        let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]);
+
+        // Try to apply the original trait binding obligation by borrowing.
+        let mut try_borrowing = |new_trait_ref: ty::TraitRef<'tcx>,
+                                 expected_trait_ref: ty::TraitRef<'tcx>,
+                                 mtbl: bool,
+                                 blacklist: &[DefId]|
+         -> bool {
+            if blacklist.contains(&expected_trait_ref.def_id) {
+                return false;
+            }
+
             let new_obligation = Obligation::new(
                 ObligationCause::dummy(),
                 param_env,
@@ -713,8 +733,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
                     let msg = format!(
                         "the trait bound `{}: {}` is not satisfied",
-                        found,
-                        obligation.parent_trait_ref.skip_binder().print_only_trait_path(),
+                        found_ty_str,
+                        expected_trait_ref.print_only_trait_path(),
                     );
                     if has_custom_message {
                         err.note(&msg);
@@ -730,7 +750,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         span,
                         &format!(
                             "expected an implementor of trait `{}`",
-                            obligation.parent_trait_ref.skip_binder().print_only_trait_path(),
+                            expected_trait_ref.print_only_trait_path(),
                         ),
                     );
 
@@ -745,16 +765,52 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
                         err.span_suggestion(
                             span,
-                            "consider borrowing here",
-                            format!("&{}", snippet),
+                            &format!(
+                                "consider{} borrowing here",
+                                if mtbl { " mutably" } else { "" }
+                            ),
+                            format!("&{}{}", if mtbl { "mut " } else { "" }, snippet),
                             Applicability::MaybeIncorrect,
                         );
                     }
                     return true;
                 }
             }
+            return false;
+        };
+
+        if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code {
+            let expected_trait_ref = obligation.parent_trait_ref.skip_binder();
+            let new_imm_trait_ref =
+                ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs);
+            let new_mut_trait_ref =
+                ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs);
+            if try_borrowing(new_imm_trait_ref, expected_trait_ref, false, &[]) {
+                return true;
+            } else {
+                return try_borrowing(new_mut_trait_ref, expected_trait_ref, true, &[]);
+            }
+        } else if let ObligationCauseCode::BindingObligation(_, _)
+        | ObligationCauseCode::ItemObligation(_) = &obligation.cause.code
+        {
+            if try_borrowing(
+                ty::TraitRef::new(trait_ref.def_id, imm_substs),
+                trait_ref,
+                false,
+                &blacklist[..],
+            ) {
+                return true;
+            } else {
+                return try_borrowing(
+                    ty::TraitRef::new(trait_ref.def_id, mut_substs),
+                    trait_ref,
+                    true,
+                    &blacklist[..],
+                );
+            }
+        } else {
+            false
         }
-        false
     }
 
     /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
@@ -2258,7 +2314,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let suggested_limit = current_limit * 2;
         err.help(&format!(
             "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)",
-            suggested_limit, self.tcx.crate_name,
+            suggested_limit,
+            self.tcx.crate_name(LOCAL_CRATE),
         ));
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index fc9739f70d4..120680092ba 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -6,7 +6,7 @@ use rustc_errors::ErrorReported;
 use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
 use rustc_middle::mir::abstract_const::NotConstEvaluatable;
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
@@ -591,7 +591,16 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
                             )
                         }
                         (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
-                            ProcessResult::Unchanged
+                            if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+                                ProcessResult::Unchanged
+                            } else {
+                                // Two different constants using generic parameters ~> error.
+                                let expected_found = ExpectedFound::new(true, c1, c2);
+                                ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError(
+                                    expected_found,
+                                    TypeError::ConstMismatch(expected_found),
+                                ))
+                            }
                         }
                     }
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index b3e5df4da0a..388413ae06b 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -529,15 +529,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
             // evaluation this is not the case, and dropping the trait
             // evaluations can causes ICEs (e.g., #43132).
             debug!(?ty, "found normalized ty");
-
-            // Once we have inferred everything we need to know, we
-            // can ignore the `obligations` from that point on.
-            if infcx.unresolved_type_vars(&ty.value).is_none() {
-                infcx.inner.borrow_mut().projection_cache().complete_normalized(cache_key, &ty);
-            // No need to extend `obligations`.
-            } else {
-                obligations.extend(ty.obligations);
-            }
+            obligations.extend(ty.obligations);
             return Ok(Some(ty.value));
         }
         Err(ProjectionCacheEntry::Error) => {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index a292de148a6..ea5eb2b6866 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -557,6 +557,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ty::PredicateKind::ConstEquate(c1, c2) => {
                     debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts");
 
+                    if self.tcx().features().const_evaluatable_checked {
+                        // FIXME: we probably should only try to unify abstract constants
+                        // if the constants depend on generic parameters.
+                        //
+                        // Let's just see where this breaks :shrug:
+                        if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
+                            (c1.val, c2.val)
+                        {
+                            if self
+                                .tcx()
+                                .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs)))
+                            {
+                                return Ok(EvaluatedToOk);
+                            }
+                        }
+                    }
+
                     let evaluate = |c: &'tcx ty::Const<'tcx>| {
                         if let ty::ConstKind::Unevaluated(unevaluated) = c.val {
                             self.infcx
@@ -591,7 +608,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                             )
                         }
                         (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
-                            Ok(EvaluatedToAmbig)
+                            if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() {
+                                Ok(EvaluatedToAmbig)
+                            } else {
+                                // Two different constants using generic parameters ~> error.
+                                Ok(EvaluatedToErr)
+                            }
                         }
                     }
                 }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 144c7281b67..07a3132568b 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -1,13 +1,11 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
-use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::hir::map as hir_map;
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{
     self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
 };
-use rustc_session::CrateDisambiguator;
-use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
 
@@ -389,16 +387,6 @@ fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamE
     tcx.param_env(def_id).with_reveal_all_normalized(tcx)
 }
 
-fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguator {
-    assert_eq!(crate_num, LOCAL_CRATE);
-    tcx.sess.local_crate_disambiguator()
-}
-
-fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol {
-    assert_eq!(crate_num, LOCAL_CRATE);
-    tcx.crate_name
-}
-
 fn instance_def_size_estimate<'tcx>(
     tcx: TyCtxt<'tcx>,
     instance_def: ty::InstanceDef<'tcx>,
@@ -544,8 +532,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
         param_env,
         param_env_reveal_all_normalized,
         trait_of_item,
-        crate_disambiguator,
-        original_crate_name,
         instance_def_size_estimate,
         issue33140_self_ty,
         impl_defaultness,
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index 0dbcd483c45..2d102127dd9 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -1,3 +1,5 @@
+#![feature(min_specialization)]
+
 #[macro_use]
 extern crate bitflags;
 #[macro_use]
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 5285c1c8598..ef195621044 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1394,11 +1394,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| {
             ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()))
         });
+        // N.b. principal, projections, auto traits
+        // FIXME: This is actually wrong with multiple principals in regards to symbol mangling
         let mut v = regular_trait_predicates
-            .chain(auto_trait_predicates)
             .chain(
                 existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)),
             )
+            .chain(auto_trait_predicates)
             .collect::<SmallVec<[_; 8]>>();
         v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
         v.dedup();
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index b760a54f08c..3cbc3d231f8 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -35,6 +35,7 @@ use crate::type_error_struct;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
+use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::cast::{CastKind, CastTy};
 use rustc_middle::ty::error::TypeError;
@@ -347,15 +348,52 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     fcx.ty_to_string(self.cast_ty)
                 );
                 let mut sugg = None;
+                let mut sugg_mutref = false;
                 if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() {
-                    if fcx
-                        .try_coerce(
-                            self.expr,
-                            fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
-                            self.cast_ty,
-                            AllowTwoPhase::No,
-                        )
-                        .is_ok()
+                    if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() {
+                        if fcx
+                            .try_coerce(
+                                self.expr,
+                                fcx.tcx.mk_ref(
+                                    &ty::RegionKind::ReErased,
+                                    TypeAndMut { ty: expr_ty, mutbl },
+                                ),
+                                self.cast_ty,
+                                AllowTwoPhase::No,
+                            )
+                            .is_ok()
+                        {
+                            sugg = Some(format!("&{}*", mutbl.prefix_str()));
+                        }
+                    } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() {
+                        if expr_mutbl == Mutability::Not
+                            && mutbl == Mutability::Mut
+                            && fcx
+                                .try_coerce(
+                                    self.expr,
+                                    fcx.tcx.mk_ref(
+                                        expr_reg,
+                                        TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut },
+                                    ),
+                                    self.cast_ty,
+                                    AllowTwoPhase::No,
+                                )
+                                .is_ok()
+                        {
+                            sugg_mutref = true;
+                        }
+                    }
+
+                    if !sugg_mutref
+                        && sugg == None
+                        && fcx
+                            .try_coerce(
+                                self.expr,
+                                fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }),
+                                self.cast_ty,
+                                AllowTwoPhase::No,
+                            )
+                            .is_ok()
                     {
                         sugg = Some(format!("&{}", mutbl.prefix_str()));
                     }
@@ -375,11 +413,15 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         sugg = Some(format!("&{}", mutbl.prefix_str()));
                     }
                 }
-                if let Some(sugg) = sugg {
+                if sugg_mutref {
+                    err.span_label(self.span, "invalid cast");
+                    err.span_note(self.expr.span, "this reference is immutable");
+                    err.span_note(self.cast_span, "trying to cast to a mutable reference type");
+                } else if let Some(sugg) = sugg {
                     err.span_label(self.span, "invalid cast");
                     err.span_suggestion_verbose(
                         self.expr.span.shrink_to_lo(),
-                        "borrow the value for the cast to be valid",
+                        "consider borrowing the value",
                         sugg,
                         Applicability::MachineApplicable,
                     );
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index e5fcdcfa743..9cc435a0dec 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -8,6 +8,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{is_range_literal, Node};
+use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
 use rustc_span::symbol::sym;
@@ -412,14 +413,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
     ) -> Option<(Span, &'static str, String, Applicability)> {
-        let sm = self.sess().source_map();
+        let sess = self.sess();
         let sp = expr.span;
-        if sm.is_imported(sp) {
-            // Ignore if span is from within a macro #41858, #58298. We previously used the macro
-            // call span, but that breaks down when the type error comes from multiple calls down.
+
+        // If the span is from an external macro, there's no suggestion we can make.
+        if in_external_macro(sess, sp) {
             return None;
         }
 
+        let sm = sess.source_map();
+
         let replace_prefix = |s: &str, old: &str, new: &str| {
             s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
         };
@@ -427,10 +430,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let is_struct_pat_shorthand_field =
             self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp);
 
-        // If the span is from a macro, then it's hard to extract the text
-        // and make a good suggestion, so don't bother.
-        let is_macro = sp.from_expansion() && sp.desugaring_kind().is_none();
-
         // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
         let expr = expr.peel_drop_temps();
 
@@ -570,10 +569,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
                 _,
                 &ty::Ref(_, checked, _),
-            ) if {
-                self.infcx.can_sub(self.param_env, checked, &expected).is_ok() && !is_macro
-            } =>
-            {
+            ) if self.infcx.can_sub(self.param_env, checked, &expected).is_ok() => {
                 // We have `&T`, check if what was expected was `T`. If so,
                 // we may want to suggest removing a `&`.
                 if sm.is_imported(expr.span) {
@@ -589,13 +585,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                     return None;
                 }
-                if let Ok(code) = sm.span_to_snippet(expr.span) {
-                    return Some((
-                        sp,
-                        "consider removing the borrow",
-                        code,
-                        Applicability::MachineApplicable,
-                    ));
+                if sp.contains(expr.span) {
+                    if let Ok(code) = sm.span_to_snippet(expr.span) {
+                        return Some((
+                            sp,
+                            "consider removing the borrow",
+                            code,
+                            Applicability::MachineApplicable,
+                        ));
+                    }
                 }
             }
             (
@@ -643,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
             }
-            _ if sp == expr.span && !is_macro => {
+            _ if sp == expr.span => {
                 if let Some(steps) = self.deref_steps(checked_ty, expected) {
                     let expr = expr.peel_blocks();
 
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
index 4de8216884a..96569ae0e77 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
@@ -1522,7 +1522,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let ty = tcx.type_of(impl_def_id);
 
             let impl_ty = self.instantiate_type_scheme(span, &substs, ty);
-            match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
+            match self.at(&self.misc(span), self.param_env).eq(impl_ty, self_ty) {
                 Ok(ok) => self.register_infer_ok_obligations(ok),
                 Err(_) => {
                     self.tcx.sess.delay_span_bug(
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index e40aa914858..5f26e701c0a 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -89,19 +89,31 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
             if let Some((unresolved_type, unresolved_type_span)) =
                 self.fcx.unresolved_type_vars(&ty)
             {
-                let note = format!(
-                    "the type is part of the {} because of this {}",
-                    self.kind, yield_data.source
-                );
-
                 // If unresolved type isn't a ty_var then unresolved_type_span is None
                 let span = self
                     .prev_unresolved_span
                     .unwrap_or_else(|| unresolved_type_span.unwrap_or(source_span));
-                self.fcx
-                    .need_type_info_err_in_generator(self.kind, span, unresolved_type)
-                    .span_note(yield_data.span, &*note)
-                    .emit();
+
+                // If we encounter an int/float variable, then inference fallback didn't
+                // finish due to some other error. Don't emit spurious additional errors.
+                if let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) =
+                    unresolved_type.kind()
+                {
+                    self.fcx
+                        .tcx
+                        .sess
+                        .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_type));
+                } else {
+                    let note = format!(
+                        "the type is part of the {} because of this {}",
+                        self.kind, yield_data.source
+                    );
+
+                    self.fcx
+                        .need_type_info_err_in_generator(self.kind, span, unresolved_type)
+                        .span_note(yield_data.span, &*note)
+                        .emit();
+                }
             } else {
                 // Insert the type into the ordered set.
                 let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree));
diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs
index 0b1129a6312..427102afee1 100644
--- a/compiler/rustc_typeck/src/check/method/mod.rs
+++ b/compiler/rustc_typeck/src/check/method/mod.rs
@@ -303,8 +303,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         opt_input_types: Option<&[Ty<'tcx>]>,
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
         debug!(
-            "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?})",
-            self_ty, m_name, trait_def_id
+            "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})",
+            self_ty, m_name, trait_def_id, opt_input_types
         );
 
         // Construct a trait-reference `self_ty : Trait<input_tys>`
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 2320a29e6d8..16382c7e7a4 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -383,6 +383,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         return None;
                     } else {
                         span = item_name.span;
+
+                        // Don't show generic arguments when the method can't be found in any implementation (#81576).
+                        let mut ty_str_reported = ty_str.clone();
+                        if let ty::Adt(_, ref generics) = actual.kind() {
+                            if generics.len() > 0 {
+                                let mut autoderef = self.autoderef(span, actual);
+                                let candidate_found = autoderef.any(|(ty, _)| {
+                                    if let ty::Adt(ref adt_deref, _) = ty.kind() {
+                                        self.tcx
+                                            .inherent_impls(adt_deref.did)
+                                            .iter()
+                                            .filter_map(|def_id| {
+                                                self.associated_item(
+                                                    *def_id,
+                                                    item_name,
+                                                    Namespace::ValueNS,
+                                                )
+                                            })
+                                            .count()
+                                            >= 1
+                                    } else {
+                                        false
+                                    }
+                                });
+                                let has_deref = autoderef.step_count() > 0;
+                                if !candidate_found
+                                    && !has_deref
+                                    && unsatisfied_predicates.is_empty()
+                                {
+                                    if let Some((path_string, _)) = ty_str.split_once('<') {
+                                        ty_str_reported = path_string.to_string();
+                                    }
+                                }
+                            }
+                        }
+
                         let mut err = struct_span_err!(
                             tcx.sess,
                             span,
@@ -391,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             item_kind,
                             item_name,
                             actual.prefix_string(self.tcx),
-                            ty_str,
+                            ty_str_reported,
                         );
                         if let Mode::MethodCall = mode {
                             if let SelfSource::MethodCall(call) = source {
@@ -449,6 +485,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let mut label_span_not_found = || {
                     if unsatisfied_predicates.is_empty() {
                         err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
+                        if let ty::Adt(ref adt, _) = rcvr_ty.kind() {
+                            let mut inherent_impls_candidate = self
+                                .tcx
+                                .inherent_impls(adt.did)
+                                .iter()
+                                .copied()
+                                .filter(|def_id| {
+                                    if let Some(assoc) =
+                                        self.associated_item(*def_id, item_name, Namespace::ValueNS)
+                                    {
+                                        // Check for both mode is the same so we avoid suggesting
+                                        // incorrect associated item.
+                                        match (mode, assoc.fn_has_self_parameter, source) {
+                                            (Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
+                                                // We check that the suggest type is actually
+                                                // different from the received one
+                                                // So we avoid suggestion method with Box<Self>
+                                                // for instance
+                                                self.tcx.at(span).type_of(*def_id) != actual
+                                                    && self.tcx.at(span).type_of(*def_id) != rcvr_ty
+                                            }
+                                            (Mode::Path, false, _) => true,
+                                            _ => false,
+                                        }
+                                    } else {
+                                        false
+                                    }
+                                })
+                                .collect::<Vec<_>>();
+                            if inherent_impls_candidate.len() > 0 {
+                                inherent_impls_candidate.sort();
+                                inherent_impls_candidate.dedup();
+
+                                // number of type to shows at most.
+                                let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 };
+                                let type_candidates = inherent_impls_candidate
+                                    .iter()
+                                    .take(limit)
+                                    .map(|impl_item| {
+                                        format!("- `{}`", self.tcx.at(span).type_of(*impl_item))
+                                    })
+                                    .collect::<Vec<_>>()
+                                    .join("\n");
+                                let additional_types = if inherent_impls_candidate.len() > limit {
+                                    format!(
+                                        "\nand {} more types",
+                                        inherent_impls_candidate.len() - limit
+                                    )
+                                } else {
+                                    "".to_string()
+                                };
+                                err.note(&format!(
+                                    "the {item_kind} was found for\n{}{}",
+                                    type_candidates, additional_types
+                                ));
+                            }
+                        }
                     } else {
                         err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds"));
                     }
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index d6db2e1d76f..ad7853b7cd0 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -1187,3 +1187,14 @@ fn fatally_break_rust(sess: &Session) {
 fn potentially_plural_count(count: usize, word: &str) -> String {
     format!("{} {}{}", count, word, pluralize!(count))
 }
+
+fn has_expected_num_generic_args<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    trait_did: Option<DefId>,
+    expected: usize,
+) -> bool {
+    trait_did.map_or(true, |trait_did| {
+        let generics = tcx.generics_of(trait_did);
+        generics.count() == expected + if generics.has_self { 1 } else { 0 }
+    })
+}
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 567cb1a90d0..963436d05d8 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -1,7 +1,7 @@
 //! Code related to processing overloaded binary and unary operators.
 
 use super::method::MethodCallee;
-use super::FnCtxt;
+use super::{has_expected_num_generic_args, FnCtxt};
 use rustc_ast as ast;
 use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
@@ -795,6 +795,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             lhs_ty, op, opname, trait_did
         );
 
+        // Catches cases like #83893, where a lang item is declared with the
+        // wrong number of generic arguments. Should have yielded an error
+        // elsewhere by now, but we have to catch it here so that we do not
+        // index `other_tys` out of bounds (if the lang item has too many
+        // generic arguments, `other_tys` is too short).
+        if !has_expected_num_generic_args(
+            self.tcx,
+            trait_did,
+            match op {
+                // Binary ops have a generic right-hand side, unary ops don't
+                Op::Binary(..) => 1,
+                Op::Unary(..) => 0,
+            },
+        ) {
+            return Err(());
+        }
+
         let method = trait_did.and_then(|trait_did| {
             let opname = Ident::with_dummy_span(opname);
             self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys))
diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs
index 5bd385107ca..652b82f1063 100644
--- a/compiler/rustc_typeck/src/check/place_op.rs
+++ b/compiler/rustc_typeck/src/check/place_op.rs
@@ -1,5 +1,5 @@
 use crate::check::method::MethodCallee;
-use crate::check::{FnCtxt, PlaceOp};
+use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp};
 use rustc_hir as hir;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::InferOk;
@@ -153,6 +153,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref),
             PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index),
         };
+
+        // If the lang item was declared incorrectly, stop here so that we don't
+        // run into an ICE (#83893). The error is reported where the lang item is
+        // declared.
+        if !has_expected_num_generic_args(
+            self.tcx,
+            imm_tr,
+            match op {
+                PlaceOp::Deref => 0,
+                PlaceOp::Index => 1,
+            },
+        ) {
+            return None;
+        }
+
         imm_tr.and_then(|trait_did| {
             self.lookup_method_in_trait(
                 span,
@@ -177,6 +192,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             PlaceOp::Deref => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut),
             PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut),
         };
+
+        // If the lang item was declared incorrectly, stop here so that we don't
+        // run into an ICE (#83893). The error is reported where the lang item is
+        // declared.
+        if !has_expected_num_generic_args(
+            self.tcx,
+            mut_tr,
+            match op {
+                PlaceOp::Deref => 0,
+                PlaceOp::Index => 1,
+            },
+        ) {
+            return None;
+        }
+
         mut_tr.and_then(|trait_did| {
             self.lookup_method_in_trait(
                 span,
@@ -218,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Clear previous flag; after a pointer indirection it does not apply any more.
                 inside_union = false;
             }
-            if source.ty_adt_def().map_or(false, |adt| adt.is_union()) {
+            if source.is_union() {
                 inside_union = true;
             }
             // Fix up the autoderefs. Autorefs can only occur immediately preceding
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index ff506ef8727..6baa185406e 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -323,7 +323,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ///
     /// InferBorrowKind results in a structure like this:
     ///
-    /// ```
+    /// ```text
     /// {
     ///       Place(base: hir_id_s, projections: [], ....) -> {
     ///                                                            capture_kind_expr: hir_id_L5,
@@ -348,7 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// ```
     ///
     /// After the min capture analysis, we get:
-    /// ```
+    /// ```text
     /// {
     ///       hir_id_s -> [
     ///            Place(base: hir_id_s, projections: [], ....) -> {
@@ -1588,6 +1588,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
 impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
     fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) {
         if let PlaceBase::Upvar(_) = place.base {
+            // We need to restrict Fake Read precision to avoid fake reading unsafe code,
+            // such as deref of a raw pointer.
+            let place = restrict_capture_precision(place);
+            let place =
+                restrict_repr_packed_field_ref_capture(self.fcx.tcx, self.fcx.param_env, &place);
             self.fake_reads.push((place, cause, diag_expr_id));
         }
     }
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 0528f8812f9..5d83375e5a1 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -2770,7 +2770,21 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
             }
         } else if tcx.sess.check_name(attr, sym::target_feature) {
             if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
-                if !tcx.features().target_feature_11 {
+                if tcx.sess.target.is_like_wasm {
+                    // The `#[target_feature]` attribute is allowed on
+                    // WebAssembly targets on all functions, including safe
+                    // ones. Other targets require that `#[target_feature]` is
+                    // only applied to unsafe funtions (pending the
+                    // `target_feature_11` feature) because on most targets
+                    // execution of instructions that are not supported is
+                    // considered undefined behavior. For WebAssembly which is a
+                    // 100% safe target at execution time it's not possible to
+                    // execute undefined instructions, and even if a future
+                    // feature was added in some form for this it would be a
+                    // deterministic trap. There is no undefined behavior when
+                    // executing WebAssembly so `#[target_feature]` is allowed
+                    // on safe functions (but again, only for WebAssembly)
+                } else if !tcx.features().target_feature_11 {
                     let mut err = feature_err(
                         &tcx.sess.parse_sess,
                         sym::target_feature_11,
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 47299722325..92ef8297472 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -65,7 +65,6 @@ This API is completely unstable and subject to change.
 #![feature(is_sorted)]
 #![feature(iter_zip)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(try_blocks)]
 #![feature(never_type)]
 #![feature(slice_partition_dedup)]
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
index 56f288ff051..bccc19774e0 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -509,44 +509,23 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             }
 
             AngleBrackets::Available => {
-                // angle brackets exist, so we insert missing arguments after the existing args
-
-                assert!(!self.gen_args.args.is_empty());
-
-                if self.num_provided_lifetime_args() > 0 {
-                    let last_lt_arg_span = self.gen_args.args
-                        [self.num_provided_lifetime_args() - 1]
-                        .span()
-                        .shrink_to_hi();
-                    let source_map = self.tcx.sess.source_map();
-
-                    if let Ok(last_gen_arg) = source_map.span_to_snippet(last_lt_arg_span) {
-                        let sugg = format!("{}, {}", last_gen_arg, suggested_args);
-
-                        err.span_suggestion_verbose(
-                            last_lt_arg_span,
-                            &msg,
-                            sugg,
-                            Applicability::HasPlaceholders,
-                        );
-                    }
+                let (sugg_span, is_first) = if self.num_provided_lifetime_args() == 0 {
+                    (self.gen_args.span().unwrap().shrink_to_lo(), true)
                 } else {
-                    // Non-lifetime arguments included in `gen_args` -> insert missing lifetimes before
-                    // existing arguments
-                    let first_arg_span = self.gen_args.args[0].span().shrink_to_lo();
-                    let source_map = self.tcx.sess.source_map();
-
-                    if let Ok(first_gen_arg) = source_map.span_to_snippet(first_arg_span) {
-                        let sugg = format!("{}, {}", suggested_args, first_gen_arg);
-
-                        err.span_suggestion_verbose(
-                            first_arg_span,
-                            &msg,
-                            sugg,
-                            Applicability::HasPlaceholders,
-                        );
-                    }
-                }
+                    let last_lt = &self.gen_args.args[self.num_provided_lifetime_args() - 1];
+                    (last_lt.span().shrink_to_hi(), false)
+                };
+                let has_non_lt_args = self.num_provided_type_or_const_args() != 0;
+                let has_bindings = !self.gen_args.bindings.is_empty();
+
+                let sugg_prefix = if is_first { "" } else { ", " };
+                let sugg_suffix =
+                    if is_first && (has_non_lt_args || has_bindings) { ", " } else { "" };
+
+                let sugg = format!("{}{}{}", sugg_prefix, suggested_args, sugg_suffix);
+                debug!("sugg: {:?}", sugg);
+
+                err.span_suggestion_verbose(sugg_span, &msg, sugg, Applicability::HasPlaceholders);
             }
             AngleBrackets::Implied => {
                 // We never encounter missing lifetimes in situations in which lifetimes are elided
@@ -626,30 +605,35 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         let remove_entire_generics = num_redundant_args >= self.gen_args.args.len();
 
         let remove_lifetime_args = |err: &mut DiagnosticBuilder<'_>| {
-            let idx_first_redundant_lt_args = self.num_expected_lifetime_args();
-            let span_lo_redundant_lt_args =
-                self.gen_args.args[idx_first_redundant_lt_args].span().shrink_to_lo();
-            let span_hi_redundant_lt_args = self.gen_args.args
-                [idx_first_redundant_lt_args + num_redundant_lt_args - 1]
-                .span()
-                .shrink_to_hi();
-            let eat_comma =
-                idx_first_redundant_lt_args + num_redundant_lt_args - 1 != self.gen_args.args.len();
-
-            let span_redundant_lt_args = if eat_comma {
-                let span_hi = self.gen_args.args
-                    [idx_first_redundant_lt_args + num_redundant_lt_args - 1]
-                    .span()
-                    .shrink_to_hi();
-                span_lo_redundant_lt_args.to(span_hi)
-            } else {
-                span_lo_redundant_lt_args.to(span_hi_redundant_lt_args)
-            };
+            let mut lt_arg_spans = Vec::new();
+            let mut found_redundant = false;
+            for arg in self.gen_args.args {
+                if let hir::GenericArg::Lifetime(_) = arg {
+                    lt_arg_spans.push(arg.span());
+                    if lt_arg_spans.len() > self.num_expected_lifetime_args() {
+                        found_redundant = true;
+                    }
+                } else if found_redundant {
+                    // Argument which is redundant and separated like this `'c`
+                    // is not included to avoid including `Bar` in span.
+                    // ```
+                    // type Foo<'a, T> = &'a T;
+                    // let _: Foo<'a, 'b, Bar, 'c>;
+                    // ```
+                    break;
+                }
+            }
+
+            let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()];
+            let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1];
+
+            let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args);
             debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args);
 
+            let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args();
             let msg_lifetimes = format!(
                 "remove {} {} argument{}",
-                if num_redundant_args == 1 { "this" } else { "these" },
+                if num_redundant_lt_args == 1 { "this" } else { "these" },
                 "lifetime",
                 pluralize!(num_redundant_lt_args),
             );
@@ -663,26 +647,34 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         };
 
         let remove_type_or_const_args = |err: &mut DiagnosticBuilder<'_>| {
-            let idx_first_redundant_type_or_const_args = self.get_lifetime_args_offset()
-                + num_redundant_lt_args
-                + self.num_expected_type_or_const_args();
+            let mut gen_arg_spans = Vec::new();
+            let mut found_redundant = false;
+            for arg in self.gen_args.args {
+                match arg {
+                    hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => {
+                        gen_arg_spans.push(arg.span());
+                        if gen_arg_spans.len() > self.num_expected_type_or_const_args() {
+                            found_redundant = true;
+                        }
+                    }
+                    _ if found_redundant => break,
+                    _ => {}
+                }
+            }
 
             let span_lo_redundant_type_or_const_args =
-                self.gen_args.args[idx_first_redundant_type_or_const_args].span().shrink_to_lo();
-
-            let span_hi_redundant_type_or_const_args = self.gen_args.args
-                [idx_first_redundant_type_or_const_args + num_redundant_type_or_const_args - 1]
-                .span()
-                .shrink_to_hi();
+                gen_arg_spans[self.num_expected_type_or_const_args()];
+            let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1];
 
             let span_redundant_type_or_const_args =
                 span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args);
-
             debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args);
 
+            let num_redundant_gen_args =
+                gen_arg_spans.len() - self.num_expected_type_or_const_args();
             let msg_types_or_consts = format!(
                 "remove {} {} argument{}",
-                if num_redundant_args == 1 { "this" } else { "these" },
+                if num_redundant_gen_args == 1 { "this" } else { "these" },
                 "generic",
                 pluralize!(num_redundant_type_or_const_args),
             );
diff --git a/config.toml.example b/config.toml.example
index 16952a5ced8..df2fb448b7d 100644
--- a/config.toml.example
+++ b/config.toml.example
@@ -563,6 +563,14 @@ changelog-seen = 2
 
 # Use LLVM libunwind as the implementation for Rust's unwinder.
 # Accepted values are 'in-tree' (formerly true), 'system' or 'no' (formerly false).
+# This option only applies for Linux and Fuchsia targets.
+# On Linux target, if crt-static is not enabled, 'no' means dynamic link to
+# `libgcc_s.so`, 'in-tree' means static link to the in-tree build of llvm libunwind
+# and 'system' means dynamic link to `libunwind.so`. If crt-static is enabled,
+# the behavior is depend on the libc. On musl target, 'no' and 'in-tree' both 
+# means static link to the in-tree build of llvm libunwind, and 'system' means 
+# static link to `libunwind.a` provided by system. Due to the limitation of glibc,
+# it must link to `libgcc_eh.a` to get a working output, and this option have no effect.
 #llvm-libunwind = 'no'
 
 # Enable Windows Control Flow Guard checks in the standard library.
diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs
index 48709e89823..c9bdcaa78f3 100644
--- a/library/alloc/benches/vec.rs
+++ b/library/alloc/benches/vec.rs
@@ -468,7 +468,6 @@ fn bench_in_place_recycle(b: &mut Bencher) {
                 .enumerate()
                 .map(|(idx, e)| idx.wrapping_add(e))
                 .fuse()
-                .peekable()
                 .collect::<Vec<usize>>(),
         );
     });
diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs
index a5481fd175e..1a58ad51f78 100644
--- a/library/alloc/src/collections/linked_list.rs
+++ b/library/alloc/src/collections/linked_list.rs
@@ -64,7 +64,15 @@ pub struct Iter<'a, T: 'a> {
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("Iter").field(&self.len).finish()
+        f.debug_tuple("Iter")
+            .field(&*mem::ManuallyDrop::new(LinkedList {
+                head: self.head,
+                tail: self.tail,
+                len: self.len,
+                marker: PhantomData,
+            }))
+            .field(&self.len)
+            .finish()
     }
 }
 
@@ -82,19 +90,24 @@ impl<T> Clone for Iter<'_, T> {
 /// documentation for more.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, T: 'a> {
-    // We do *not* exclusively own the entire list here, references to node's `element`
-    // have been handed out by the iterator! So be careful when using this; the methods
-    // called must be aware that there can be aliasing pointers to `element`.
-    list: &'a mut LinkedList<T>,
     head: Option<NonNull<Node<T>>>,
     tail: Option<NonNull<Node<T>>>,
     len: usize,
+    marker: PhantomData<&'a mut Node<T>>,
 }
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
 impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("IterMut").field(&self.list).field(&self.len).finish()
+        f.debug_tuple("IterMut")
+            .field(&*mem::ManuallyDrop::new(LinkedList {
+                head: self.head,
+                tail: self.tail,
+                len: self.len,
+                marker: PhantomData,
+            }))
+            .field(&self.len)
+            .finish()
     }
 }
 
@@ -442,27 +455,6 @@ impl<T> LinkedList<T> {
         }
     }
 
-    /// Moves all elements from `other` to the begin of the list.
-    #[unstable(feature = "linked_list_prepend", issue = "none")]
-    pub fn prepend(&mut self, other: &mut Self) {
-        match self.head {
-            None => mem::swap(self, other),
-            Some(mut head) => {
-                // `as_mut` is okay here because we have exclusive access to the entirety
-                // of both lists.
-                if let Some(mut other_tail) = other.tail.take() {
-                    unsafe {
-                        head.as_mut().prev = Some(other_tail);
-                        other_tail.as_mut().next = Some(head);
-                    }
-
-                    self.head = other.head.take();
-                    self.len += mem::replace(&mut other.len, 0);
-                }
-            }
-        }
-    }
-
     /// Provides a forward iterator.
     ///
     /// # Examples
@@ -514,7 +506,7 @@ impl<T> LinkedList<T> {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter_mut(&mut self) -> IterMut<'_, T> {
-        IterMut { head: self.head, tail: self.tail, len: self.len, list: self }
+        IterMut { head: self.head, tail: self.tail, len: self.len, marker: PhantomData }
     }
 
     /// Provides a cursor at the front element.
diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs
index e4cfb3acdfd..f3eb228c9e3 100644
--- a/library/alloc/src/collections/vec_deque/iter.rs
+++ b/library/alloc/src/collections/vec_deque/iter.rs
@@ -66,7 +66,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         let (mut iter, final_res);
         if self.tail <= self.head {
@@ -140,7 +140,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         let (mut iter, final_res);
         if self.tail <= self.head {
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 7d6fbf1c438..5d03be35e46 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -2416,7 +2416,6 @@ impl<T> VecDeque<T> {
     /// found; the fourth could match any position in `[1, 4]`.
     ///
     /// ```
-    /// #![feature(vecdeque_binary_search)]
     /// use std::collections::VecDeque;
     ///
     /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
@@ -2432,7 +2431,6 @@ impl<T> VecDeque<T> {
     /// sort order:
     ///
     /// ```
-    /// #![feature(vecdeque_binary_search)]
     /// use std::collections::VecDeque;
     ///
     /// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
@@ -2441,7 +2439,7 @@ impl<T> VecDeque<T> {
     /// deque.insert(idx, num);
     /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
     /// ```
-    #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+    #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
     #[inline]
     pub fn binary_search(&self, x: &T) -> Result<usize, usize>
     where
@@ -2476,7 +2474,6 @@ impl<T> VecDeque<T> {
     /// found; the fourth could match any position in `[1, 4]`.
     ///
     /// ```
-    /// #![feature(vecdeque_binary_search)]
     /// use std::collections::VecDeque;
     ///
     /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
@@ -2487,7 +2484,7 @@ impl<T> VecDeque<T> {
     /// let r = deque.binary_search_by(|x| x.cmp(&1));
     /// assert!(matches!(r, Ok(1..=4)));
     /// ```
-    #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+    #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
     pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
     where
         F: FnMut(&'a T) -> Ordering,
@@ -2530,7 +2527,6 @@ impl<T> VecDeque<T> {
     /// fourth could match any position in `[1, 4]`.
     ///
     /// ```
-    /// #![feature(vecdeque_binary_search)]
     /// use std::collections::VecDeque;
     ///
     /// let deque: VecDeque<_> = vec![(0, 0), (2, 1), (4, 1), (5, 1),
@@ -2543,7 +2539,7 @@ impl<T> VecDeque<T> {
     /// let r = deque.binary_search_by_key(&1, |&(a, b)| b);
     /// assert!(matches!(r, Ok(1..=4)));
     /// ```
-    #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+    #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
     #[inline]
     pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize>
     where
@@ -2574,7 +2570,6 @@ impl<T> VecDeque<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(vecdeque_binary_search)]
     /// use std::collections::VecDeque;
     ///
     /// let deque: VecDeque<_> = vec![1, 2, 3, 3, 5, 6, 7].into();
@@ -2584,7 +2579,7 @@ impl<T> VecDeque<T> {
     /// assert!(deque.iter().take(i).all(|&x| x < 5));
     /// assert!(deque.iter().skip(i).all(|&x| !(x < 5)));
     /// ```
-    #[unstable(feature = "vecdeque_binary_search", issue = "78021")]
+    #[stable(feature = "vecdeque_binary_search", since = "1.54.0")]
     pub fn partition_point<P>(&self, mut pred: P) -> usize
     where
         P: FnMut(&T) -> bool,
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 66b1036f2ab..7bc9aa69be9 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -88,8 +88,7 @@
 #![feature(cfg_target_has_atomic)]
 #![feature(coerce_unsized)]
 #![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))]
-#![cfg_attr(bootstrap, feature(const_fn))]
-#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))]
+#![feature(const_fn_trait_bound)]
 #![feature(cow_is_borrowed)]
 #![feature(const_cow_is_borrowed)]
 #![feature(destructuring_assignment)]
@@ -118,7 +117,6 @@
 #![feature(nonnull_slice_from_raw_parts)]
 #![feature(auto_traits)]
 #![feature(option_result_unwrap_unchecked)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(pattern)]
 #![feature(ptr_internals)]
 #![feature(rustc_attrs)]
@@ -140,11 +138,13 @@
 #![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)]
 #![feature(alloc_layout_extra)]
 #![feature(trusted_random_access)]
-#![feature(try_trait)]
+#![cfg_attr(bootstrap, feature(try_trait))]
+#![cfg_attr(not(bootstrap), feature(try_trait_v2))]
 #![feature(min_type_alias_impl_trait)]
 #![feature(associated_type_bounds)]
 #![feature(slice_group_by)]
 #![feature(decl_macro)]
+#![feature(bindings_after_at)]
 // Allow testing this library
 
 #[cfg(test)]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 800952f7a5e..f131182a896 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -1859,6 +1859,18 @@ where
     B: ToOwned + ?Sized,
     Rc<B>: From<&'a B> + From<B::Owned>,
 {
+    /// Create a reference-counted pointer from
+    /// a clone-on-write pointer by copying its content.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// # use std::rc::Rc;
+    /// # use std::borrow::Cow;
+    /// let cow: Cow<str> = Cow::Borrowed("eggplant");
+    /// let shared: Rc<str> = Rc::from(cow);
+    /// assert_eq!("eggplant", &shared[..]);
+    /// ```
     #[inline]
     fn from(cow: Cow<'a, B>) -> Rc<B> {
         match cow {
@@ -2303,7 +2315,7 @@ impl<T: ?Sized> Weak<T> {
 }
 
 #[stable(feature = "rc_weak", since = "1.4.0")]
-impl<T: ?Sized> Drop for Weak<T> {
+unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
     /// Drops the `Weak` pointer.
     ///
     /// # Examples
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index e6252452470..dbe5bc1da46 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -843,6 +843,42 @@ impl String {
         self.vec.extend_from_slice(string.as_bytes())
     }
 
+    /// Copies elements from `src` range to the end of the string.
+    ///
+    /// ## Panics
+    ///
+    /// Panics if the starting point or end point do not lie on a [`char`]
+    /// boundary, or if they're out of bounds.
+    ///
+    /// ## Examples
+    ///
+    /// ```
+    /// #![feature(string_extend_from_within)]
+    /// let mut string = String::from("abcde");
+    ///
+    /// string.extend_from_within(2..);
+    /// assert_eq!(string, "abcdecde");
+    ///
+    /// string.extend_from_within(..2);
+    /// assert_eq!(string, "abcdecdeab");
+    ///
+    /// string.extend_from_within(4..8);
+    /// assert_eq!(string, "abcdecdeabecde");
+    /// ```
+    #[cfg(not(no_global_oom_handling))]
+    #[unstable(feature = "string_extend_from_within", issue = "none")]
+    pub fn extend_from_within<R>(&mut self, src: R)
+    where
+        R: RangeBounds<usize>,
+    {
+        let src @ Range { start, end } = slice::range(src, ..self.len());
+
+        assert!(self.is_char_boundary(start));
+        assert!(self.is_char_boundary(end));
+
+        self.vec.extend_from_within(src);
+    }
+
     /// Returns this `String`'s capacity, in bytes.
     ///
     /// # Examples
@@ -2323,9 +2359,10 @@ impl<T: fmt::Display + ?Sized> ToString for T {
     // to try to remove it.
     #[inline]
     default fn to_string(&self) -> String {
-        use fmt::Write;
         let mut buf = String::new();
-        buf.write_fmt(format_args!("{}", self))
+        let mut formatter = core::fmt::Formatter::new(&mut buf);
+        // Bypass format_args!() to avoid write_str with zero-length strs
+        fmt::Display::fmt(self, &mut formatter)
             .expect("a Display implementation returned an error unexpectedly");
         buf
     }
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 17927f5f5fd..a8fa028fc90 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -2015,7 +2015,7 @@ impl<T> Default for Weak<T> {
 }
 
 #[stable(feature = "arc_weak", since = "1.4.0")]
-impl<T: ?Sized> Drop for Weak<T> {
+unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
     /// Drops the `Weak` pointer.
     ///
     /// # Examples
@@ -2413,6 +2413,18 @@ where
     B: ToOwned + ?Sized,
     Arc<B>: From<&'a B> + From<B::Owned>,
 {
+    /// Create an atomically reference-counted pointer from
+    /// a clone-on-write pointer by copying its content.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// # use std::sync::Arc;
+    /// # use std::borrow::Cow;
+    /// let cow: Cow<str> = Cow::Borrowed("eggplant");
+    /// let shared: Arc<str> = Arc::from(cow);
+    /// assert_eq!("eggplant", &shared[..]);
+    /// ```
     #[inline]
     fn from(cow: Cow<'a, B>) -> Arc<B> {
         match cow {
diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs
index 73d15d30647..64943a273c9 100644
--- a/library/alloc/src/vec/cow.rs
+++ b/library/alloc/src/vec/cow.rs
@@ -5,6 +5,12 @@ use super::Vec;
 
 #[stable(feature = "cow_from_vec", since = "1.8.0")]
 impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> {
+    /// Creates a [`Borrowed`] variant of [`Cow`]
+    /// from a slice.
+    ///
+    /// This conversion does not allocate or clone the data.
+    ///
+    /// [`Borrowed`]: crate::borrow::Cow::Borrowed
     fn from(s: &'a [T]) -> Cow<'a, [T]> {
         Cow::Borrowed(s)
     }
@@ -12,6 +18,12 @@ impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> {
 
 #[stable(feature = "cow_from_vec", since = "1.8.0")]
 impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> {
+    /// Creates an [`Owned`] variant of [`Cow`]
+    /// from an owned instance of [`Vec`].
+    ///
+    /// This conversion does not allocate or clone the data.
+    ///
+    /// [`Owned`]: crate::borrow::Cow::Owned
     fn from(v: Vec<T>) -> Cow<'a, [T]> {
         Cow::Owned(v)
     }
@@ -19,6 +31,12 @@ impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> {
 
 #[stable(feature = "cow_from_vec_ref", since = "1.28.0")]
 impl<'a, T: Clone> From<&'a Vec<T>> for Cow<'a, [T]> {
+    /// Creates a [`Borrowed`] variant of [`Cow`]
+    /// from a reference to [`Vec`].
+    ///
+    /// This conversion does not allocate or clone the data.
+    ///
+    /// [`Borrowed`]: crate::borrow::Cow::Borrowed
     fn from(v: &'a Vec<T>) -> Cow<'a, [T]> {
         Cow::Borrowed(v.as_slice())
     }
diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs
index b5739970b6e..0efc4893c3c 100644
--- a/library/alloc/src/vec/is_zero.rs
+++ b/library/alloc/src/vec/is_zero.rs
@@ -69,3 +69,36 @@ unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
         self.is_none()
     }
 }
+
+// `Option<num::NonZeroU32>` and similar have a representation guarantee that
+// they're the same size as the corresponding `u32` type, as well as a guarantee
+// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works.
+// While the documentation officially makes it UB to transmute from `None`,
+// we're the standard library so we can make extra inferences, and we know that
+// the only niche available to represent `None` is the one that's all zeros.
+
+macro_rules! impl_is_zero_option_of_nonzero {
+    ($($t:ident,)+) => {$(
+        unsafe impl IsZero for Option<core::num::$t> {
+            #[inline]
+            fn is_zero(&self) -> bool {
+                self.is_none()
+            }
+        }
+    )+};
+}
+
+impl_is_zero_option_of_nonzero!(
+    NonZeroU8,
+    NonZeroU16,
+    NonZeroU32,
+    NonZeroU64,
+    NonZeroU128,
+    NonZeroI8,
+    NonZeroI16,
+    NonZeroI32,
+    NonZeroI64,
+    NonZeroI128,
+    NonZeroUsize,
+    NonZeroIsize,
+);
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 1c33ff555d6..105c60e7bf0 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1619,6 +1619,8 @@ impl<T, A: Allocator> Vec<T, A> {
                 let prev_ptr = ptr.add(gap.write.wrapping_sub(1));
 
                 if same_bucket(&mut *read_ptr, &mut *prev_ptr) {
+                    // Increase `gap.read` now since the drop may panic.
+                    gap.read += 1;
                     /* We have found duplicate, drop it in-place */
                     ptr::drop_in_place(read_ptr);
                 } else {
@@ -1631,9 +1633,8 @@ impl<T, A: Allocator> Vec<T, A> {
 
                     /* We have filled that place, so go further */
                     gap.write += 1;
+                    gap.read += 1;
                 }
-
-                gap.read += 1;
             }
 
             /* Technically we could let `gap` clean up with its Drop, but
diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs
index bbfcc68daef..efa6868473e 100644
--- a/library/alloc/src/vec/spec_from_iter.rs
+++ b/library/alloc/src/vec/spec_from_iter.rs
@@ -1,6 +1,5 @@
 use core::mem::ManuallyDrop;
 use core::ptr::{self};
-use core::slice::{self};
 
 use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec};
 
@@ -19,9 +18,7 @@ use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec};
 /// |where I:                      |  |  |where I:             |
 /// |  Iterator (default)----------+  |  |  Iterator (default) |
 /// |  vec::IntoIter               |  |  |  TrustedLen         |
-/// |  SourceIterMarker---fallback-+  |  |                     |
-/// |  slice::Iter                    |  |                     |
-/// |  Iterator<Item = &Clone>        |  +---------------------+
+/// |  SourceIterMarker---fallback-+  |  +---------------------+
 /// +---------------------------------+
 /// ```
 pub(super) trait SpecFromIter<T, I> {
@@ -65,33 +62,3 @@ impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> {
         vec
     }
 }
-
-impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec<T>
-where
-    I: Iterator<Item = &'a T>,
-    T: Clone,
-{
-    default fn from_iter(iterator: I) -> Self {
-        SpecFromIter::from_iter(iterator.cloned())
-    }
-}
-
-// This utilizes `iterator.as_slice().to_vec()` since spec_extend
-// must take more steps to reason about the final capacity + length
-// and thus do more work. `to_vec()` directly allocates the correct amount
-// and fills it exactly.
-impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec<T> {
-    #[cfg(not(test))]
-    fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
-        iterator.as_slice().to_vec()
-    }
-
-    // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
-    // required for this method definition, is not available. Instead use the
-    // `slice::to_vec`  function which is only available with cfg(test)
-    // NB see the slice::hack module in slice.rs for more information
-    #[cfg(test)]
-    fn from_iter(iterator: slice::Iter<'a, T>) -> Self {
-        crate::slice::to_vec(iterator.as_slice(), crate::alloc::Global)
-    }
-}
diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs
index c02ba267056..ce40b5c9b0a 100644
--- a/library/alloc/tests/arc.rs
+++ b/library/alloc/tests/arc.rs
@@ -195,3 +195,18 @@ fn shared_from_iter_trustedlen_no_fuse() {
     assert_trusted_len(&iter);
     assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
 }
+
+#[test]
+fn weak_may_dangle() {
+    fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
+        val.clone()
+    }
+
+    // Without #[may_dangle] we get:
+    let mut val = Weak::new();
+    hmm(&mut val);
+    //  ~~~~~~~~ borrowed value does not live long enough
+    //
+    // `val` dropped here while still borrowed
+    // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak`
+}
diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs
index 25a83a0b014..3143afa269d 100644
--- a/library/alloc/tests/lib.rs
+++ b/library/alloc/tests/lib.rs
@@ -17,7 +17,6 @@
 #![feature(binary_heap_as_slice)]
 #![feature(inplace_iteration)]
 #![feature(iter_map_while)]
-#![feature(vecdeque_binary_search)]
 #![feature(slice_group_by)]
 #![feature(slice_partition_dedup)]
 #![feature(vec_spare_capacity)]
diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs
index 501b4f0f816..efb39a60966 100644
--- a/library/alloc/tests/rc.rs
+++ b/library/alloc/tests/rc.rs
@@ -191,3 +191,18 @@ fn shared_from_iter_trustedlen_no_fuse() {
     assert_trusted_len(&iter);
     assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
 }
+
+#[test]
+fn weak_may_dangle() {
+    fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
+        val.clone()
+    }
+
+    // Without #[may_dangle] we get:
+    let mut val = Weak::new();
+    hmm(&mut val);
+    //  ~~~~~~~~ borrowed value does not live long enough
+    //
+    // `val` dropped here while still borrowed
+    // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
+}
diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs
index 4dcc5d30deb..36c81b49709 100644
--- a/library/alloc/tests/vec.rs
+++ b/library/alloc/tests/vec.rs
@@ -1002,7 +1002,6 @@ fn test_from_iter_specialization_with_iterator_adapters() {
         .zip(std::iter::repeat(1usize))
         .map(|(a, b)| a + b)
         .map_while(Option::Some)
-        .peekable()
         .skip(1)
         .map(|e| if e != usize::MAX { Ok(std::num::NonZeroUsize::new(e)) } else { Err(()) });
     assert_in_place_trait(&iter);
@@ -1095,6 +1094,18 @@ fn test_from_iter_specialization_panic_during_drop_leaks() {
     }
 }
 
+// regression test for issue #85322. Peekable previously implemented InPlaceIterable,
+// but due to an interaction with IntoIter's current Clone implementation it failed to uphold
+// the contract.
+#[test]
+fn test_collect_after_iterator_clone() {
+    let v = vec![0; 5];
+    let mut i = v.into_iter().map(|i| i + 1).peekable();
+    i.peek();
+    let v = i.clone().collect::<Vec<_>>();
+    assert_eq!(v, [1, 1, 1, 1, 1]);
+    assert!(v.len() <= v.capacity());
+}
 #[test]
 fn test_cow_from() {
     let borrowed: &[_] = &["borrowed", "(slice)"];
@@ -2223,48 +2234,50 @@ fn test_vec_dedup() {
 #[test]
 fn test_vec_dedup_panicking() {
     #[derive(Debug)]
-    struct Panic {
-        drop_counter: &'static AtomicU32,
+    struct Panic<'a> {
+        drop_counter: &'a Cell<u32>,
         value: bool,
         index: usize,
     }
 
-    impl PartialEq for Panic {
+    impl<'a> PartialEq for Panic<'a> {
         fn eq(&self, other: &Self) -> bool {
             self.value == other.value
         }
     }
 
-    impl Drop for Panic {
+    impl<'a> Drop for Panic<'a> {
         fn drop(&mut self) {
-            let x = self.drop_counter.fetch_add(1, Ordering::SeqCst);
-            assert!(x != 4);
+            self.drop_counter.set(self.drop_counter.get() + 1);
+            if !std::thread::panicking() {
+                assert!(self.index != 4);
+            }
         }
     }
 
-    static DROP_COUNTER: AtomicU32 = AtomicU32::new(0);
+    let drop_counter = &Cell::new(0);
     let expected = [
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 0 },
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 5 },
-        Panic { drop_counter: &DROP_COUNTER, value: true, index: 6 },
-        Panic { drop_counter: &DROP_COUNTER, value: true, index: 7 },
+        Panic { drop_counter, value: false, index: 0 },
+        Panic { drop_counter, value: false, index: 5 },
+        Panic { drop_counter, value: true, index: 6 },
+        Panic { drop_counter, value: true, index: 7 },
     ];
     let mut vec = vec![
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 0 },
+        Panic { drop_counter, value: false, index: 0 },
         // these elements get deduplicated
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 1 },
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 2 },
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 3 },
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 4 },
-        // here it panics
-        Panic { drop_counter: &DROP_COUNTER, value: false, index: 5 },
-        Panic { drop_counter: &DROP_COUNTER, value: true, index: 6 },
-        Panic { drop_counter: &DROP_COUNTER, value: true, index: 7 },
+        Panic { drop_counter, value: false, index: 1 },
+        Panic { drop_counter, value: false, index: 2 },
+        Panic { drop_counter, value: false, index: 3 },
+        Panic { drop_counter, value: false, index: 4 },
+        // here it panics while dropping the item with index==4
+        Panic { drop_counter, value: false, index: 5 },
+        Panic { drop_counter, value: true, index: 6 },
+        Panic { drop_counter, value: true, index: 7 },
     ];
 
-    let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
-        vec.dedup();
-    }));
+    let _ = catch_unwind(AssertUnwindSafe(|| vec.dedup())).unwrap_err();
+
+    assert_eq!(drop_counter.get(), 4);
 
     let ok = vec.iter().zip(expected.iter()).all(|(x, y)| x.index == y.index);
 
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index c36542f6314..aedbeab6610 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -139,7 +139,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> {
         // SAFETY: Callers are only allowed to pass an index that is in bounds
         // Additionally Self: TrustedRandomAccess is only implemented for T: Copy which means even
         // multiple repeated reads of the same index would be safe and the
-        // values aree !Drop, thus won't suffer from double drops.
+        // values are !Drop, thus won't suffer from double drops.
         unsafe { self.data.get_unchecked(self.alive.start + idx).assume_init_read() }
     }
 }
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 8b56c9560aa..e25d006d213 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -1,6 +1,4 @@
-//! Implementations of things like `Eq` for fixed-length arrays
-//! up to a certain length. Eventually, we should be able to generalize
-//! to all lengths.
+//! Helper functions and types for fixed-length arrays.
 //!
 //! *[See also the array primitive type](array).*
 
@@ -158,7 +156,6 @@ impl<T: fmt::Debug, const N: usize> fmt::Debug for [T; N] {
 // Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator`
 // hides this implementation from explicit `.into_iter()` calls on editions < 2021,
 // so those calls will still resolve to the slice implementation, by reference.
-#[cfg(not(bootstrap))]
 #[stable(feature = "array_into_iter_impl", since = "1.53.0")]
 impl<T, const N: usize> IntoIterator for [T; N] {
     type Item = T;
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 4820588df25..f88a6e418c7 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1123,6 +1123,15 @@ impl<T: Clone> Clone for RefCell<T> {
     fn clone(&self) -> RefCell<T> {
         RefCell::new(self.borrow().clone())
     }
+
+    /// # Panics
+    ///
+    /// Panics if `other` is currently mutably borrowed.
+    #[inline]
+    #[track_caller]
+    fn clone_from(&mut self, other: &Self) {
+        self.get_mut().clone_from(&other.borrow())
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index f8b16b6f927..ecea898504d 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -274,7 +274,7 @@ pub trait Eq: PartialEq<Self> {
     //
     // This should never be implemented by hand.
     #[doc(hidden)]
-    #[cfg_attr(not(bootstrap), no_coverage)] // rust-lang/rust#84605
+    #[no_coverage] // rust-lang/rust#84605
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn assert_receiver_is_total_eq(&self) {}
@@ -578,7 +578,7 @@ impl Ordering {
 /// v.sort_by_key(|&num| (num > 3, Reverse(num)));
 /// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]);
 /// ```
-#[derive(PartialEq, Eq, Debug, Copy, Clone, Default, Hash)]
+#[derive(PartialEq, Eq, Debug, Copy, Default, Hash)]
 #[stable(feature = "reverse_cmp_key", since = "1.19.0")]
 #[repr(transparent)]
 pub struct Reverse<T>(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T);
@@ -616,6 +616,19 @@ impl<T: Ord> Ord for Reverse<T> {
     }
 }
 
+#[stable(feature = "reverse_cmp_key", since = "1.19.0")]
+impl<T: Clone> Clone for Reverse<T> {
+    #[inline]
+    fn clone(&self) -> Reverse<T> {
+        Reverse(self.0.clone())
+    }
+
+    #[inline]
+    fn clone_from(&mut self, other: &Self) {
+        self.0.clone_from(&other.0)
+    }
+}
+
 /// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order).
 ///
 /// An order is a total order if it is (for all `a`, `b` and `c`):
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 87042d95fbe..02ac4fb8006 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -221,6 +221,28 @@ pub struct Formatter<'a> {
     buf: &'a mut (dyn Write + 'a),
 }
 
+impl<'a> Formatter<'a> {
+    /// Creates a new formatter with default settings.
+    ///
+    /// This can be used as a micro-optimization in cases where a full `Arguments`
+    /// structure (as created by `format_args!`) is not necessary; `Arguments`
+    /// is a little more expensive to use in simple formatting scenarios.
+    ///
+    /// Currently not intended for use outside of the standard library.
+    #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")]
+    #[doc(hidden)]
+    pub fn new(buf: &'a mut (dyn Write + 'a)) -> Formatter<'a> {
+        Formatter {
+            flags: 0,
+            fill: ' ',
+            align: rt::v1::Alignment::Unknown,
+            width: None,
+            precision: None,
+            buf,
+        }
+    }
+}
+
 // NB. Argument is essentially an optimized partially applied formatting function,
 // equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`.
 
@@ -1075,22 +1097,16 @@ pub trait UpperExp {
 /// [`write!`]: crate::write!
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
-    let mut formatter = Formatter {
-        flags: 0,
-        width: None,
-        precision: None,
-        buf: output,
-        align: rt::v1::Alignment::Unknown,
-        fill: ' ',
-    };
-
+    let mut formatter = Formatter::new(output);
     let mut idx = 0;
 
     match args.fmt {
         None => {
             // We can use default formatting parameters for all arguments.
             for (arg, piece) in iter::zip(args.args, args.pieces) {
-                formatter.buf.write_str(*piece)?;
+                if !piece.is_empty() {
+                    formatter.buf.write_str(*piece)?;
+                }
                 (arg.formatter)(arg.value, &mut formatter)?;
                 idx += 1;
             }
@@ -1099,7 +1115,9 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result {
             // Every spec has a corresponding argument that is preceded by
             // a string piece.
             for (arg, piece) in iter::zip(fmt, args.pieces) {
-                formatter.buf.write_str(*piece)?;
+                if !piece.is_empty() {
+                    formatter.buf.write_str(*piece)?;
+                }
                 // SAFETY: arg and args.args come from the same Arguments,
                 // which guarantees the indexes are always within bounds.
                 unsafe { run(&mut formatter, arg, &args.args) }?;
@@ -1227,12 +1245,13 @@ impl<'a> Formatter<'a> {
     ///         // We need to remove "-" from the number output.
     ///         let tmp = self.nb.abs().to_string();
     ///
-    ///         formatter.pad_integral(self.nb > 0, "Foo ", &tmp)
+    ///         formatter.pad_integral(self.nb >= 0, "Foo ", &tmp)
     ///     }
     /// }
     ///
     /// assert_eq!(&format!("{}", Foo::new(2)), "2");
     /// assert_eq!(&format!("{}", Foo::new(-1)), "-1");
+    /// assert_eq!(&format!("{}", Foo::new(0)), "0");
     /// assert_eq!(&format!("{:#}", Foo::new(-1)), "-Foo 1");
     /// assert_eq!(&format!("{:0>#8}", Foo::new(-1)), "00-Foo 1");
     /// ```
diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs
index cc4cf54a2f7..15952c6806f 100644
--- a/library/core/src/future/future.rs
+++ b/library/core/src/future/future.rs
@@ -24,8 +24,7 @@ use crate::task::{Context, Poll};
 /// `.await` the value.
 ///
 /// [`Waker`]: crate::task::Waker
-#[cfg_attr(bootstrap, doc(spotlight))]
-#[cfg_attr(not(bootstrap), doc(notable_trait))]
+#[doc(notable_trait)]
 #[must_use = "futures do nothing unless you `.await` or poll them"]
 #[stable(feature = "futures_api", since = "1.36.0")]
 #[lang = "future_trait"]
diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs
index ce5e9936bbd..53e48500e3b 100644
--- a/library/core/src/iter/adapters/chain.rs
+++ b/library/core/src/iter/adapters/chain.rs
@@ -98,7 +98,7 @@ where
     where
         Self: Sized,
         F: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         if let Some(ref mut a) = self.a {
             acc = a.try_fold(acc, &mut f)?;
@@ -281,7 +281,7 @@ where
     where
         Self: Sized,
         F: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         if let Some(ref mut b) = self.b {
             acc = b.try_rfold(acc, &mut f)?;
diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs
index 0abdbba2ef1..7efc155175c 100644
--- a/library/core/src/iter/adapters/cloned.rs
+++ b/library/core/src/iter/adapters/cloned.rs
@@ -46,7 +46,7 @@ where
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         self.it.try_fold(init, clone_try_fold(f))
     }
@@ -82,7 +82,7 @@ where
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         self.it.try_rfold(init, clone_try_fold(f))
     }
diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs
index 0a5822452a3..def24089275 100644
--- a/library/core/src/iter/adapters/copied.rs
+++ b/library/core/src/iter/adapters/copied.rs
@@ -50,7 +50,7 @@ where
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         self.it.try_fold(init, copy_try_fold(f))
     }
@@ -98,7 +98,7 @@ where
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         self.it.try_rfold(init, copy_try_fold(f))
     }
diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs
index 6e9a011f819..815e708f9ec 100644
--- a/library/core/src/iter/adapters/cycle.rs
+++ b/library/core/src/iter/adapters/cycle.rs
@@ -53,7 +53,7 @@ where
     fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
     where
         F: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         // fully iterate the current iterator. this is necessary because
         // `self.iter` may be empty even when `self.orig` isn't
diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs
index 73cee1df30c..91722a4b62a 100644
--- a/library/core/src/iter/adapters/enumerate.rs
+++ b/library/core/src/iter/adapters/enumerate.rs
@@ -71,7 +71,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         #[inline]
         fn enumerate<'a, T, Acc, R>(
@@ -150,7 +150,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         // Can safely add and subtract the count, as `ExactSizeIterator` promises
         // that the number of elements fits into a `usize`.
diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs
index 0337892b9e8..d5f19f12747 100644
--- a/library/core/src/iter/adapters/filter.rs
+++ b/library/core/src/iter/adapters/filter.rs
@@ -37,7 +37,7 @@ fn filter_fold<T, Acc>(
     move |acc, item| if predicate(&item) { fold(acc, item) } else { acc }
 }
 
-fn filter_try_fold<'a, T, Acc, R: Try<Ok = Acc>>(
+fn filter_try_fold<'a, T, Acc, R: Try<Output = Acc>>(
     predicate: &'a mut impl FnMut(&T) -> bool,
     mut fold: impl FnMut(Acc, T) -> R + 'a,
 ) -> impl FnMut(Acc, T) -> R + 'a {
@@ -88,7 +88,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold))
     }
@@ -117,7 +117,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold))
     }
diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs
index 0dccf2c533b..01b7be9d52d 100644
--- a/library/core/src/iter/adapters/filter_map.rs
+++ b/library/core/src/iter/adapters/filter_map.rs
@@ -39,7 +39,7 @@ fn filter_map_fold<T, B, Acc>(
     }
 }
 
-fn filter_map_try_fold<'a, T, B, Acc, R: Try<Ok = Acc>>(
+fn filter_map_try_fold<'a, T, B, Acc, R: Try<Output = Acc>>(
     f: &'a mut impl FnMut(T) -> Option<B>,
     mut fold: impl FnMut(Acc, B) -> R + 'a,
 ) -> impl FnMut(Acc, T) -> R + 'a {
@@ -72,7 +72,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold))
     }
@@ -111,7 +111,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold))
     }
diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs
index 0114d7af4f4..3315d346596 100644
--- a/library/core/src/iter/adapters/flatten.rs
+++ b/library/core/src/iter/adapters/flatten.rs
@@ -61,7 +61,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         self.inner.try_fold(init, fold)
     }
@@ -91,7 +91,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         self.inner.try_rfold(init, fold)
     }
@@ -178,7 +178,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         self.inner.try_fold(init, fold)
     }
@@ -208,7 +208,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         self.inner.try_rfold(init, fold)
     }
@@ -293,10 +293,10 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         #[inline]
-        fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
+        fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>(
             frontiter: &'a mut Option<T::IntoIter>,
             fold: &'a mut impl FnMut(Acc, T::Item) -> R,
         ) -> impl FnMut(Acc, T) -> R + 'a {
@@ -382,10 +382,10 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         #[inline]
-        fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>(
+        fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>(
             backiter: &'a mut Option<T::IntoIter>,
             fold: &'a mut impl FnMut(Acc, T::Item) -> R,
         ) -> impl FnMut(Acc, T) -> R + 'a
diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs
index c01f384dec5..aff48b1b220 100644
--- a/library/core/src/iter/adapters/fuse.rs
+++ b/library/core/src/iter/adapters/fuse.rs
@@ -92,7 +92,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         FuseImpl::try_fold(self, acc, fold)
     }
@@ -148,7 +148,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         FuseImpl::try_rfold(self, acc, fold)
     }
@@ -219,7 +219,7 @@ trait FuseImpl<I> {
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>;
+        R: Try<Output = Acc>;
     fn fold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc
     where
         Fold: FnMut(Acc, Self::Item) -> Acc;
@@ -238,7 +238,7 @@ trait FuseImpl<I> {
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
         I: DoubleEndedIterator;
     fn rfold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc
     where
@@ -305,7 +305,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         if let Some(ref mut iter) = self.iter {
             acc = iter.try_fold(acc, fold)?;
@@ -354,7 +354,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
         I: DoubleEndedIterator,
     {
         if let Some(ref mut iter) = self.iter {
@@ -443,7 +443,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         unchecked!(self).try_fold(init, fold)
     }
@@ -485,7 +485,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
         I: DoubleEndedIterator,
     {
         unchecked!(self).try_rfold(init, fold)
diff --git a/library/core/src/iter/adapters/inspect.rs b/library/core/src/iter/adapters/inspect.rs
index 88f5ee61b6b..36835d12e56 100644
--- a/library/core/src/iter/adapters/inspect.rs
+++ b/library/core/src/iter/adapters/inspect.rs
@@ -87,7 +87,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold))
     }
@@ -117,7 +117,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold))
     }
diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs
index 2a4b7efd5e6..0bf9f4b0327 100644
--- a/library/core/src/iter/adapters/map.rs
+++ b/library/core/src/iter/adapters/map.rs
@@ -110,7 +110,7 @@ where
     where
         Self: Sized,
         G: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         self.iter.try_fold(init, map_try_fold(&mut self.f, g))
     }
@@ -146,7 +146,7 @@ where
     where
         Self: Sized,
         G: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         self.iter.try_rfold(init, map_try_fold(&mut self.f, g))
     }
diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs
index 26114d53284..8f89e158804 100644
--- a/library/core/src/iter/adapters/map_while.rs
+++ b/library/core/src/iter/adapters/map_while.rs
@@ -54,7 +54,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         let Self { iter, predicate } = self;
         iter.try_fold(init, |acc, x| match predicate(x) {
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 4f69b82ba4c..9fdd4fca04c 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -168,7 +168,7 @@ where
     fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
     where
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         let error = &mut *self.error;
         self.iter
diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs
index 21386e28a96..69bd2996efe 100644
--- a/library/core/src/iter/adapters/peekable.rs
+++ b/library/core/src/iter/adapters/peekable.rs
@@ -1,5 +1,5 @@
-use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen};
-use crate::ops::Try;
+use crate::iter::{adapters::SourceIter, FusedIterator, TrustedLen};
+use crate::ops::{ControlFlow, Try};
 
 /// An iterator with a `peek()` that returns an optional reference to the next
 /// element.
@@ -91,7 +91,7 @@ impl<I: Iterator> Iterator for Peekable<I> {
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         let acc = match self.peeked.take() {
             Some(None) => return try { init },
@@ -130,19 +130,42 @@ where
     }
 
     #[inline]
+    #[cfg(not(bootstrap))]
     fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         match self.peeked.take() {
             Some(None) => try { init },
+            Some(Some(v)) => match self.iter.try_rfold(init, &mut f).branch() {
+                ControlFlow::Continue(acc) => f(acc, v),
+                ControlFlow::Break(r) => {
+                    self.peeked = Some(Some(v));
+                    R::from_residual(r)
+                }
+            },
+            None => self.iter.try_rfold(init, f),
+        }
+    }
+
+    #[inline]
+    #[cfg(bootstrap)]
+    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>,
+    {
+        let _use_the_import: ControlFlow<()>;
+        match self.peeked.take() {
+            Some(None) => try { init },
             Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() {
                 Ok(acc) => f(acc, v),
                 Err(e) => {
                     self.peeked = Some(Some(v));
-                    Try::from_error(e)
+                    R::from_error(e)
                 }
             },
             None => self.iter.try_rfold(init, f),
@@ -333,6 +356,3 @@ where
         unsafe { SourceIter::as_inner(&mut self.iter) }
     }
 }
-
-#[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {}
diff --git a/library/core/src/iter/adapters/rev.rs b/library/core/src/iter/adapters/rev.rs
index 105ed40a3ed..139fb7bbdd9 100644
--- a/library/core/src/iter/adapters/rev.rs
+++ b/library/core/src/iter/adapters/rev.rs
@@ -51,7 +51,7 @@ where
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         self.iter.try_rfold(init, f)
     }
@@ -96,7 +96,7 @@ where
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         self.iter.try_fold(init, f)
     }
diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs
index 0214899295e..96705b01f66 100644
--- a/library/core/src/iter/adapters/scan.rs
+++ b/library/core/src/iter/adapters/scan.rs
@@ -56,9 +56,9 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
-        fn scan<'a, T, St, B, Acc, R: Try<Ok = Acc>>(
+        fn scan<'a, T, St, B, Acc, R: Try<Output = Acc>>(
             state: &'a mut St,
             f: &'a mut impl FnMut(&mut St, T) -> Option<B>,
             mut fold: impl FnMut(Acc, B) -> R + 'a,
diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs
index e55c7a6bf5d..c358a6d12b7 100644
--- a/library/core/src/iter/adapters/skip.rs
+++ b/library/core/src/iter/adapters/skip.rs
@@ -88,7 +88,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         let n = self.n;
         self.n = 0;
@@ -146,9 +146,9 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
-        fn check<T, Acc, R: Try<Ok = Acc>>(
+        fn check<T, Acc, R: Try<Output = Acc>>(
             mut n: usize,
             mut fold: impl FnMut(Acc, T) -> R,
         ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> {
diff --git a/library/core/src/iter/adapters/skip_while.rs b/library/core/src/iter/adapters/skip_while.rs
index efcb469fc95..93e29edc8df 100644
--- a/library/core/src/iter/adapters/skip_while.rs
+++ b/library/core/src/iter/adapters/skip_while.rs
@@ -70,7 +70,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         if !self.flag {
             match self.next() {
diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs
index 2ba56eeccba..4252c34a0e0 100644
--- a/library/core/src/iter/adapters/step_by.rs
+++ b/library/core/src/iter/adapters/step_by.rs
@@ -111,7 +111,7 @@ where
     fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
     where
         F: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         #[inline]
         fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ {
@@ -187,7 +187,7 @@ where
     fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
     where
         F: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         #[inline]
         fn nth_back<I: DoubleEndedIterator>(
diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs
index 54a47f1323e..92f82ae2325 100644
--- a/library/core/src/iter/adapters/take.rs
+++ b/library/core/src/iter/adapters/take.rs
@@ -80,9 +80,9 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
-        fn check<'a, T, Acc, R: Try<Ok = Acc>>(
+        fn check<'a, T, Acc, R: Try<Output = Acc>>(
             n: &'a mut usize,
             mut fold: impl FnMut(Acc, T) -> R + 'a,
         ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a {
@@ -178,7 +178,7 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
         if self.n == 0 {
             try { init }
diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs
index 746eb41f4c3..93457d20f7c 100644
--- a/library/core/src/iter/adapters/take_while.rs
+++ b/library/core/src/iter/adapters/take_while.rs
@@ -68,9 +68,9 @@ where
     where
         Self: Sized,
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: Try<Ok = Acc>,
+        R: Try<Output = Acc>,
     {
-        fn check<'a, T, Acc, R: Try<Ok = Acc>>(
+        fn check<'a, T, Acc, R: Try<Output = Acc>>(
             flag: &'a mut bool,
             p: &'a mut impl FnMut(&T) -> bool,
             mut fold: impl FnMut(Acc, T) -> R + 'a,
diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs
index 2f8f504d8fc..c95324c80ba 100644
--- a/library/core/src/iter/adapters/zip.rs
+++ b/library/core/src/iter/adapters/zip.rs
@@ -434,7 +434,7 @@ impl<A: Debug + TrustedRandomAccess, B: Debug + TrustedRandomAccess> ZipFmt<A, B
 ///    called on `self`:
 ///     * `std::clone::Clone::clone()`
 ///     * `std::iter::Iterator::size_hint()`
-///     * `std::iter::Iterator::next_back()`
+///     * `std::iter::DoubleEndedIterator::next_back()`
 ///     * `std::iter::Iterator::__iterator_get_unchecked()`
 ///     * `std::iter::TrustedRandomAccess::size()`
 ///
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index 2a179f0b1d7..bfb27da505e 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -384,6 +384,8 @@ pub use self::traits::FusedIterator;
 pub use self::traits::InPlaceIterable;
 #[unstable(feature = "trusted_len", issue = "37572")]
 pub use self::traits::TrustedLen;
+#[unstable(feature = "trusted_step", issue = "85731")]
+pub use self::traits::TrustedStep;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::traits::{
     DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum,
diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs
index 5e39e71252f..de5d77e96ee 100644
--- a/library/core/src/iter/range.rs
+++ b/library/core/src/iter/range.rs
@@ -3,21 +3,23 @@ use crate::convert::TryFrom;
 use crate::mem;
 use crate::ops::{self, Try};
 
-use super::{FusedIterator, TrustedLen, TrustedRandomAccess};
+use super::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedStep};
+
+// Safety: All invariants are upheld.
+macro_rules! unsafe_impl_trusted_step {
+    ($($type:ty)*) => {$(
+        #[unstable(feature = "trusted_step", issue = "85731")]
+        unsafe impl TrustedStep for $type {}
+    )*};
+}
+unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize];
 
 /// Objects that have a notion of *successor* and *predecessor* operations.
 ///
 /// The *successor* operation moves towards values that compare greater.
 /// The *predecessor* operation moves towards values that compare lesser.
-///
-/// # Safety
-///
-/// This trait is `unsafe` because its implementation must be correct for
-/// the safety of `unsafe trait TrustedLen` implementations, and the results
-/// of using this trait can otherwise be trusted by `unsafe` code to be correct
-/// and fulfill the listed obligations.
 #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-pub unsafe trait Step: Clone + PartialOrd + Sized {
+pub trait Step: Clone + PartialOrd + Sized {
     /// Returns the number of *successor* steps required to get from `start` to `end`.
     ///
     /// Returns `None` if the number of steps would overflow `usize`
@@ -55,7 +57,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
     ///
     /// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))`
     ///   * Corollary: `Step::forward_checked(&a, 0) == Some(a)`
-    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
     fn forward_checked(start: Self, count: usize) -> Option<Self>;
 
     /// Returns the value that would be obtained by taking the *successor*
@@ -81,7 +82,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
     ///   * Corollary: `Step::forward(a, 0) == a`
     /// * `Step::forward(a, n) >= a`
     /// * `Step::backward(Step::forward(a, n), n) == a`
-    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
     fn forward(start: Self, count: usize) -> Self {
         Step::forward_checked(start, count).expect("overflow in `Step::forward`")
     }
@@ -106,7 +106,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
     /// For any `a` and `n`, where no overflow occurs:
     ///
     /// * `Step::forward_unchecked(a, n)` is equivalent to `Step::forward(a, n)`
-    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
     unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
         Step::forward(start, count)
     }
@@ -127,7 +126,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
     ///
     /// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(&x, 1))`
     ///   * Corollary: `Step::backward_checked(&a, 0) == Some(a)`
-    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
     fn backward_checked(start: Self, count: usize) -> Option<Self>;
 
     /// Returns the value that would be obtained by taking the *predecessor*
@@ -153,7 +151,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
     ///   * Corollary: `Step::backward(a, 0) == a`
     /// * `Step::backward(a, n) <= a`
     /// * `Step::forward(Step::backward(a, n), n) == a`
-    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
     fn backward(start: Self, count: usize) -> Self {
         Step::backward_checked(start, count).expect("overflow in `Step::backward`")
     }
@@ -178,7 +175,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized {
     /// For any `a` and `n`, where no overflow occurs:
     ///
     /// * `Step::backward_unchecked(a, n)` is equivalent to `Step::backward(a, n)`
-    #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
     unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
         Step::backward(start, count)
     }
@@ -237,7 +233,7 @@ macro_rules! step_integer_impls {
         $(
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            unsafe impl Step for $u_narrower {
+            impl Step for $u_narrower {
                 step_identical_methods!();
 
                 #[inline]
@@ -269,7 +265,7 @@ macro_rules! step_integer_impls {
 
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            unsafe impl Step for $i_narrower {
+            impl Step for $i_narrower {
                 step_identical_methods!();
 
                 #[inline]
@@ -333,7 +329,7 @@ macro_rules! step_integer_impls {
         $(
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            unsafe impl Step for $u_wider {
+            impl Step for $u_wider {
                 step_identical_methods!();
 
                 #[inline]
@@ -358,7 +354,7 @@ macro_rules! step_integer_impls {
 
             #[allow(unreachable_patterns)]
             #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-            unsafe impl Step for $i_wider {
+            impl Step for $i_wider {
                 step_identical_methods!();
 
                 #[inline]
@@ -408,7 +404,7 @@ step_integer_impls! {
 }
 
 #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
-unsafe impl Step for char {
+impl Step for char {
     #[inline]
     fn steps_between(&start: &char, &end: &char) -> Option<usize> {
         let start = start as u32;
@@ -512,15 +508,27 @@ macro_rules! range_incl_exact_iter_impl {
     )*)
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<A: Step> Iterator for ops::Range<A> {
+/// Specialization implementations for `Range`.
+trait RangeIteratorImpl {
+    type Item;
+
+    // Iterator
+    fn spec_next(&mut self) -> Option<Self::Item>;
+    fn spec_nth(&mut self, n: usize) -> Option<Self::Item>;
+
+    // DoubleEndedIterator
+    fn spec_next_back(&mut self) -> Option<Self::Item>;
+    fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>;
+}
+
+impl<A: Step> RangeIteratorImpl for ops::Range<A> {
     type Item = A;
 
     #[inline]
-    fn next(&mut self) -> Option<A> {
+    default fn spec_next(&mut self) -> Option<A> {
         if self.start < self.end {
-            // SAFETY: just checked precondition
-            let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+            let n =
+                Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
             Some(mem::replace(&mut self.start, n))
         } else {
             None
@@ -528,17 +536,59 @@ impl<A: Step> Iterator for ops::Range<A> {
     }
 
     #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
+    default fn spec_nth(&mut self, n: usize) -> Option<A> {
+        if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
+            if plus_n < self.end {
+                self.start =
+                    Step::forward_checked(plus_n.clone(), 1).expect("`Step` invariants not upheld");
+                return Some(plus_n);
+            }
+        }
+
+        self.start = self.end.clone();
+        None
+    }
+
+    #[inline]
+    default fn spec_next_back(&mut self) -> Option<A> {
         if self.start < self.end {
-            let hint = Step::steps_between(&self.start, &self.end);
-            (hint.unwrap_or(usize::MAX), hint)
+            self.end =
+                Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
+            Some(self.end.clone())
         } else {
-            (0, Some(0))
+            None
         }
     }
 
     #[inline]
-    fn nth(&mut self, n: usize) -> Option<A> {
+    default fn spec_nth_back(&mut self, n: usize) -> Option<A> {
+        if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
+            if minus_n > self.start {
+                self.end =
+                    Step::backward_checked(minus_n, 1).expect("`Step` invariants not upheld");
+                return Some(self.end.clone());
+            }
+        }
+
+        self.end = self.start.clone();
+        None
+    }
+}
+
+impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
+    #[inline]
+    fn spec_next(&mut self) -> Option<T> {
+        if self.start < self.end {
+            // SAFETY: just checked precondition
+            let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+            Some(mem::replace(&mut self.start, n))
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn spec_nth(&mut self, n: usize) -> Option<T> {
         if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
             if plus_n < self.end {
                 // SAFETY: just checked precondition
@@ -552,6 +602,56 @@ impl<A: Step> Iterator for ops::Range<A> {
     }
 
     #[inline]
+    fn spec_next_back(&mut self) -> Option<T> {
+        if self.start < self.end {
+            // SAFETY: just checked precondition
+            self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
+            Some(self.end.clone())
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn spec_nth_back(&mut self, n: usize) -> Option<T> {
+        if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
+            if minus_n > self.start {
+                // SAFETY: just checked precondition
+                self.end = unsafe { Step::backward_unchecked(minus_n, 1) };
+                return Some(self.end.clone());
+            }
+        }
+
+        self.end = self.start.clone();
+        None
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<A: Step> Iterator for ops::Range<A> {
+    type Item = A;
+
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        self.spec_next()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        if self.start < self.end {
+            let hint = Step::steps_between(&self.start, &self.end);
+            (hint.unwrap_or(usize::MAX), hint)
+        } else {
+            (0, Some(0))
+        }
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<A> {
+        self.spec_nth(n)
+    }
+
+    #[inline]
     fn last(mut self) -> Option<A> {
         self.next_back()
     }
@@ -631,32 +731,36 @@ range_incl_exact_iter_impl! {
 impl<A: Step> DoubleEndedIterator for ops::Range<A> {
     #[inline]
     fn next_back(&mut self) -> Option<A> {
-        if self.start < self.end {
-            // SAFETY: just checked precondition
-            self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
-            Some(self.end.clone())
-        } else {
-            None
-        }
+        self.spec_next_back()
     }
 
     #[inline]
     fn nth_back(&mut self, n: usize) -> Option<A> {
-        if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
-            if minus_n > self.start {
-                // SAFETY: just checked precondition
-                self.end = unsafe { Step::backward_unchecked(minus_n, 1) };
-                return Some(self.end.clone());
-            }
-        }
-
-        self.end = self.start.clone();
-        None
+        self.spec_nth_back(n)
     }
 }
 
+// Safety:
+// The following invariants for `Step::steps_between` exist:
+//
+// > * `steps_between(&a, &b) == Some(n)` only if `a <= b`
+// >   * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
+// >     this is the case when it would require more than `usize::MAX` steps to
+// >     get to `b`
+// > * `steps_between(&a, &b) == None` if `a > b`
+//
+// The first invariant is what is generally required for `TrustedLen` to be
+// sound. The note addendum satisfies an additional `TrustedLen` invariant.
+//
+// > The upper bound must only be `None` if the actual iterator length is larger
+// > than `usize::MAX`
+//
+// The second invariant logically follows the first so long as the `PartialOrd`
+// implementation is correct; regardless it is explicitly stated. If `a < b`
+// then `(0, Some(0))` is returned by `ops::Range<A: Step>::size_hint`. As such
+// the second invariant is upheld.
 #[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Step> TrustedLen for ops::Range<A> {}
+unsafe impl<A: TrustedStep> TrustedLen for ops::Range<A> {}
 
 #[stable(feature = "fused", since = "1.26.0")]
 impl<A: Step> FusedIterator for ops::Range<A> {}
@@ -684,18 +788,130 @@ impl<A: Step> Iterator for ops::RangeFrom<A> {
     }
 }
 
+// Safety: See above implementation for `ops::Range<A>`
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<A: TrustedStep> TrustedLen for ops::RangeFrom<A> {}
+
 #[stable(feature = "fused", since = "1.26.0")]
 impl<A: Step> FusedIterator for ops::RangeFrom<A> {}
 
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Step> TrustedLen for ops::RangeFrom<A> {}
+trait RangeInclusiveIteratorImpl {
+    type Item;
 
-#[stable(feature = "inclusive_range", since = "1.26.0")]
-impl<A: Step> Iterator for ops::RangeInclusive<A> {
+    // Iterator
+    fn spec_next(&mut self) -> Option<Self::Item>;
+    fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>;
+
+    // DoubleEndedIterator
+    fn spec_next_back(&mut self) -> Option<Self::Item>;
+    fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: Try<Output = B>;
+}
+
+impl<A: Step> RangeInclusiveIteratorImpl for ops::RangeInclusive<A> {
     type Item = A;
 
     #[inline]
-    fn next(&mut self) -> Option<A> {
+    default fn spec_next(&mut self) -> Option<A> {
+        if self.is_empty() {
+            return None;
+        }
+        let is_iterating = self.start < self.end;
+        Some(if is_iterating {
+            let n =
+                Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
+            mem::replace(&mut self.start, n)
+        } else {
+            self.exhausted = true;
+            self.start.clone()
+        })
+    }
+
+    #[inline]
+    default fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, A) -> R,
+        R: Try<Output = B>,
+    {
+        if self.is_empty() {
+            return try { init };
+        }
+
+        let mut accum = init;
+
+        while self.start < self.end {
+            let n =
+                Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld");
+            let n = mem::replace(&mut self.start, n);
+            accum = f(accum, n)?;
+        }
+
+        self.exhausted = true;
+
+        if self.start == self.end {
+            accum = f(accum, self.start.clone())?;
+        }
+
+        try { accum }
+    }
+
+    #[inline]
+    default fn spec_next_back(&mut self) -> Option<A> {
+        if self.is_empty() {
+            return None;
+        }
+        let is_iterating = self.start < self.end;
+        Some(if is_iterating {
+            let n =
+                Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
+            mem::replace(&mut self.end, n)
+        } else {
+            self.exhausted = true;
+            self.end.clone()
+        })
+    }
+
+    #[inline]
+    default fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, A) -> R,
+        R: Try<Output = B>,
+    {
+        if self.is_empty() {
+            return try { init };
+        }
+
+        let mut accum = init;
+
+        while self.start < self.end {
+            let n =
+                Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld");
+            let n = mem::replace(&mut self.end, n);
+            accum = f(accum, n)?;
+        }
+
+        self.exhausted = true;
+
+        if self.start == self.end {
+            accum = f(accum, self.start.clone())?;
+        }
+
+        try { accum }
+    }
+}
+
+impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
+    #[inline]
+    fn spec_next(&mut self) -> Option<T> {
         if self.is_empty() {
             return None;
         }
@@ -711,6 +927,90 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
     }
 
     #[inline]
+    fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, T) -> R,
+        R: Try<Output = B>,
+    {
+        if self.is_empty() {
+            return try { init };
+        }
+
+        let mut accum = init;
+
+        while self.start < self.end {
+            // SAFETY: just checked precondition
+            let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
+            let n = mem::replace(&mut self.start, n);
+            accum = f(accum, n)?;
+        }
+
+        self.exhausted = true;
+
+        if self.start == self.end {
+            accum = f(accum, self.start.clone())?;
+        }
+
+        try { accum }
+    }
+
+    #[inline]
+    fn spec_next_back(&mut self) -> Option<T> {
+        if self.is_empty() {
+            return None;
+        }
+        let is_iterating = self.start < self.end;
+        Some(if is_iterating {
+            // SAFETY: just checked precondition
+            let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
+            mem::replace(&mut self.end, n)
+        } else {
+            self.exhausted = true;
+            self.end.clone()
+        })
+    }
+
+    #[inline]
+    fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, T) -> R,
+        R: Try<Output = B>,
+    {
+        if self.is_empty() {
+            return try { init };
+        }
+
+        let mut accum = init;
+
+        while self.start < self.end {
+            // SAFETY: just checked precondition
+            let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
+            let n = mem::replace(&mut self.end, n);
+            accum = f(accum, n)?;
+        }
+
+        self.exhausted = true;
+
+        if self.start == self.end {
+            accum = f(accum, self.start.clone())?;
+        }
+
+        try { accum }
+    }
+}
+
+#[stable(feature = "inclusive_range", since = "1.26.0")]
+impl<A: Step> Iterator for ops::RangeInclusive<A> {
+    type Item = A;
+
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        self.spec_next()
+    }
+
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         if self.is_empty() {
             return (0, Some(0));
@@ -751,32 +1051,13 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
     }
 
     #[inline]
-    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
-        if self.is_empty() {
-            return try { init };
-        }
-
-        let mut accum = init;
-
-        while self.start < self.end {
-            // SAFETY: just checked precondition
-            let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
-            let n = mem::replace(&mut self.start, n);
-            accum = f(accum, n)?;
-        }
-
-        self.exhausted = true;
-
-        if self.start == self.end {
-            accum = f(accum, self.start.clone())?;
-        }
-
-        try { accum }
+        self.spec_try_fold(init, f)
     }
 
     #[inline]
@@ -813,18 +1094,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
 impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
     #[inline]
     fn next_back(&mut self) -> Option<A> {
-        if self.is_empty() {
-            return None;
-        }
-        let is_iterating = self.start < self.end;
-        Some(if is_iterating {
-            // SAFETY: just checked precondition
-            let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
-            mem::replace(&mut self.end, n)
-        } else {
-            self.exhausted = true;
-            self.end.clone()
-        })
+        self.spec_next_back()
     }
 
     #[inline]
@@ -856,32 +1126,13 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
     }
 
     #[inline]
-    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
-        if self.is_empty() {
-            return try { init };
-        }
-
-        let mut accum = init;
-
-        while self.start < self.end {
-            // SAFETY: just checked precondition
-            let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
-            let n = mem::replace(&mut self.end, n);
-            accum = f(accum, n)?;
-        }
-
-        self.exhausted = true;
-
-        if self.start == self.end {
-            accum = f(accum, self.start.clone())?;
-        }
-
-        try { accum }
+        self.spec_try_rfold(init, f)
     }
 
     #[inline]
@@ -899,8 +1150,9 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
     }
 }
 
+// Safety: See above implementation for `ops::Range<A>`
 #[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<A: Step> TrustedLen for ops::RangeInclusive<A> {}
+unsafe impl<A: TrustedStep> TrustedLen for ops::RangeInclusive<A> {}
 
 #[stable(feature = "fused", since = "1.26.0")]
 impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}
diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs
index d1f2879235f..a9478041c69 100644
--- a/library/core/src/iter/sources/repeat.rs
+++ b/library/core/src/iter/sources/repeat.rs
@@ -72,10 +72,32 @@ impl<A: Clone> Iterator for Repeat<A> {
     fn next(&mut self) -> Option<A> {
         Some(self.element.clone())
     }
+
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         (usize::MAX, None)
     }
+
+    #[inline]
+    fn advance_by(&mut self, n: usize) -> Result<(), usize> {
+        // Advancing an infinite iterator of a single element is a no-op.
+        let _ = n;
+        Ok(())
+    }
+
+    #[inline]
+    fn nth(&mut self, n: usize) -> Option<A> {
+        let _ = n;
+        Some(self.element.clone())
+    }
+
+    fn last(self) -> Option<A> {
+        loop {}
+    }
+
+    fn count(self) -> usize {
+        loop {}
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -84,6 +106,19 @@ impl<A: Clone> DoubleEndedIterator for Repeat<A> {
     fn next_back(&mut self) -> Option<A> {
         Some(self.element.clone())
     }
+
+    #[inline]
+    fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
+        // Advancing an infinite iterator of a single element is a no-op.
+        let _ = n;
+        Ok(())
+    }
+
+    #[inline]
+    fn nth_back(&mut self, n: usize) -> Option<A> {
+        let _ = n;
+        Some(self.element.clone())
+    }
 }
 
 #[stable(feature = "fused", since = "1.26.0")]
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 13a2e24cadd..e2a407509b1 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -198,7 +198,7 @@ pub trait FromIterator<A>: Sized {
 /// }
 /// ```
 #[rustc_diagnostic_item = "IntoIterator"]
-#[cfg_attr(not(bootstrap), rustc_skip_array_during_method_dispatch)]
+#[rustc_skip_array_during_method_dispatch]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait IntoIterator {
     /// The type of the elements being iterated over.
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index 6f8cb6b5a65..c302502b3b7 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -218,7 +218,7 @@ pub trait DoubleEndedIterator: Iterator {
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         let mut accum = init;
         while let Some(x) = self.next_back() {
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index da9e5fde7cc..96b924f6e2a 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -26,40 +26,6 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
     on(
-        _Self = "[std::ops::Range<Idx>; 1]",
-        label = "if you meant to iterate between two values, remove the square brackets",
-        note = "`[start..end]` is an array of one `Range`; you might have meant to have a `Range` \
-                without the brackets: `start..end`"
-    ),
-    on(
-        _Self = "[std::ops::RangeFrom<Idx>; 1]",
-        label = "if you meant to iterate from a value onwards, remove the square brackets",
-        note = "`[start..]` is an array of one `RangeFrom`; you might have meant to have a \
-              `RangeFrom` without the brackets: `start..`, keeping in mind that iterating over an \
-              unbounded iterator will run forever unless you `break` or `return` from within the \
-              loop"
-    ),
-    on(
-        _Self = "[std::ops::RangeTo<Idx>; 1]",
-        label = "if you meant to iterate until a value, remove the square brackets and add a \
-                 starting value",
-        note = "`[..end]` is an array of one `RangeTo`; you might have meant to have a bounded \
-                `Range` without the brackets: `0..end`"
-    ),
-    on(
-        _Self = "[std::ops::RangeInclusive<Idx>; 1]",
-        label = "if you meant to iterate between two values, remove the square brackets",
-        note = "`[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a \
-              `RangeInclusive` without the brackets: `start..=end`"
-    ),
-    on(
-        _Self = "[std::ops::RangeToInclusive<Idx>; 1]",
-        label = "if you meant to iterate until a value (including it), remove the square brackets \
-                 and add a starting value",
-        note = "`[..=end]` is an array of one `RangeToInclusive`; you might have meant to have a \
-                bounded `RangeInclusive` without the brackets: `0..=end`"
-    ),
-    on(
         _Self = "std::ops::RangeTo<Idx>",
         label = "if you meant to iterate until a value, add a starting value",
         note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \
@@ -80,11 +46,6 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
         label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
     ),
     on(
-        _Self = "[]",
-        label = "arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)`",
-        note = "see <https://github.com/rust-lang/rust/pull/65819> for more details"
-    ),
-    on(
         _Self = "{integral}",
         note = "if you want to iterate between `start` until a value `end`, use the exclusive range \
               syntax `start..end` or the inclusive range syntax `start..=end`"
@@ -92,8 +53,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
     label = "`{Self}` is not an iterator",
     message = "`{Self}` is not an iterator"
 )]
-#[cfg_attr(bootstrap, doc(spotlight))]
-#[cfg_attr(not(bootstrap), doc(notable_trait))]
+#[doc(notable_trait)]
 #[rustc_diagnostic_item = "Iterator"]
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 pub trait Iterator {
@@ -1849,6 +1809,12 @@ pub trait Iterator {
     ///
     /// The relative order of partitioned items is not maintained.
     ///
+    /// # Current implementation
+    /// Current algorithms tries finding the first element for which the predicate evaluates
+    /// to false, and the last element for which it evaluates to true and repeatedly swaps them.
+    ///
+    /// Time Complexity: *O*(*N*)
+    ///
     /// See also [`is_partitioned()`] and [`partition()`].
     ///
     /// [`is_partitioned()`]: Iterator::is_partitioned
@@ -1999,7 +1965,7 @@ pub trait Iterator {
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> R,
-        R: Try<Ok = B>,
+        R: Try<Output = B>,
     {
         let mut accum = init;
         while let Some(x) = self.next() {
@@ -2041,7 +2007,7 @@ pub trait Iterator {
     where
         Self: Sized,
         F: FnMut(Self::Item) -> R,
-        R: Try<Ok = ()>,
+        R: Try<Output = ()>,
     {
         #[inline]
         fn call<T, R>(mut f: impl FnMut(T) -> R) -> impl FnMut((), T) -> R {
@@ -2412,17 +2378,48 @@ pub trait Iterator {
     /// ```
     #[inline]
     #[unstable(feature = "try_find", reason = "new API", issue = "63178")]
+    #[cfg(not(bootstrap))]
+    fn try_find<F, R, E>(&mut self, f: F) -> Result<Option<Self::Item>, E>
+    where
+        Self: Sized,
+        F: FnMut(&Self::Item) -> R,
+        R: Try<Output = bool>,
+        // FIXME: This bound is rather strange, but means minimal breakage on nightly.
+        // See #85115 for the issue tracking a holistic solution for this and try_map.
+        R: crate::ops::TryV2<Residual = Result<crate::convert::Infallible, E>>,
+    {
+        #[inline]
+        fn check<F, T, R, E>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, E>>
+        where
+            F: FnMut(&T) -> R,
+            R: Try<Output = bool>,
+            R: crate::ops::TryV2<Residual = Result<crate::convert::Infallible, E>>,
+        {
+            move |(), x| match f(&x).branch() {
+                ControlFlow::Continue(false) => ControlFlow::CONTINUE,
+                ControlFlow::Continue(true) => ControlFlow::Break(Ok(x)),
+                ControlFlow::Break(Err(x)) => ControlFlow::Break(Err(x)),
+            }
+        }
+
+        self.try_fold((), check(f)).break_value().transpose()
+    }
+
+    /// We're bootstrapping.
+    #[inline]
+    #[unstable(feature = "try_find", reason = "new API", issue = "63178")]
+    #[cfg(bootstrap)]
     fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error>
     where
         Self: Sized,
         F: FnMut(&Self::Item) -> R,
-        R: Try<Ok = bool>,
+        R: Try<Output = bool>,
     {
         #[inline]
         fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Error>>
         where
             F: FnMut(&T) -> R,
-            R: Try<Ok = bool>,
+            R: Try<Output = bool>,
         {
             move |(), x| match f(&x).into_result() {
                 Ok(false) => ControlFlow::CONTINUE,
@@ -2571,6 +2568,18 @@ pub trait Iterator {
     /// If several elements are equally maximum, the last element is
     /// returned. If the iterator is empty, [`None`] is returned.
     ///
+    /// Note that [`f32`]/[`f64`] doesn't implement [`Ord`] due to NaN being
+    /// incomparable. You can work around this by using [`Iterator::reduce`]:
+    /// ```
+    /// assert_eq!(
+    ///     vec![2.4, f32::NAN, 1.3]
+    ///         .into_iter()
+    ///         .reduce(f32::max)
+    ///         .unwrap(),
+    ///     2.4
+    /// );
+    /// ```
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -2594,8 +2603,20 @@ pub trait Iterator {
 
     /// Returns the minimum element of an iterator.
     ///
-    /// If several elements are equally minimum, the first element is
-    /// returned. If the iterator is empty, [`None`] is returned.
+    /// If several elements are equally minimum, the first element is returned.
+    /// If the iterator is empty, [`None`] is returned.
+    ///
+    /// Note that [`f32`]/[`f64`] doesn't implement [`Ord`] due to NaN being
+    /// incomparable. You can work around this by using [`Iterator::reduce`]:
+    /// ```
+    /// assert_eq!(
+    ///     vec![2.4, f32::NAN, 1.3]
+    ///         .into_iter()
+    ///         .reduce(f32::min)
+    ///         .unwrap(),
+    ///     1.3
+    /// );
+    /// ```
     ///
     /// # Examples
     ///
diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs
index 22b5ffdf886..ebf37f97bc6 100644
--- a/library/core/src/iter/traits/marker.rs
+++ b/library/core/src/iter/traits/marker.rs
@@ -1,3 +1,5 @@
+use crate::iter::Step;
+
 /// An iterator that always continues to yield `None` when exhausted.
 ///
 /// Calling next on a fused iterator that has returned `None` once is guaranteed
@@ -55,3 +57,18 @@ unsafe impl<I: TrustedLen + ?Sized> TrustedLen for &mut I {}
 #[unstable(issue = "none", feature = "inplace_iteration")]
 #[doc(hidden)]
 pub unsafe trait InPlaceIterable: Iterator {}
+
+/// A type that upholds all invariants of [`Step`].
+///
+/// The invariants of [`Step::steps_between()`] are a superset of the invariants
+/// of [`TrustedLen`]. As such, [`TrustedLen`] is implemented for all range
+/// types with the same generic type argument.
+///
+/// # Safety
+///
+/// The implementation of [`Step`] for the given type must guarantee all
+/// invariants of all methods are upheld. See the [`Step`] trait's documentation
+/// for details. Consumers are free to rely on the invariants in unsafe code.
+#[unstable(feature = "trusted_step", issue = "85731")]
+#[rustc_specialization_trait]
+pub unsafe trait TrustedStep: Step {}
diff --git a/library/core/src/iter/traits/mod.rs b/library/core/src/iter/traits/mod.rs
index 880f8d831fd..ffd745a46b1 100644
--- a/library/core/src/iter/traits/mod.rs
+++ b/library/core/src/iter/traits/mod.rs
@@ -13,5 +13,7 @@ pub use self::exact_size::ExactSizeIterator;
 pub use self::iterator::Iterator;
 #[unstable(issue = "none", feature = "inplace_iteration")]
 pub use self::marker::InPlaceIterable;
+#[unstable(feature = "trusted_step", issue = "85731")]
+pub use self::marker::TrustedStep;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::marker::{FusedIterator, TrustedLen};
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 6a4f2d5a544..a023edaca9e 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -82,12 +82,12 @@
 #![feature(const_refs_to_cell)]
 #![feature(const_panic)]
 #![feature(const_pin)]
-#![cfg_attr(bootstrap, feature(const_fn))]
 #![feature(const_fn_union)]
 #![feature(const_impl_trait)]
 #![feature(const_fn_floating_point_arithmetic)]
 #![feature(const_fn_fn_ptr_basics)]
-#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))]
+#![feature(const_fn_trait_bound)]
+#![cfg_attr(bootstrap, feature(const_fn))]
 #![feature(const_option)]
 #![feature(const_precise_live_drops)]
 #![feature(const_ptr_offset)]
@@ -110,10 +110,9 @@
 #![feature(custom_inner_attributes)]
 #![feature(decl_macro)]
 #![feature(doc_cfg)]
-#![cfg_attr(bootstrap, feature(doc_spotlight))]
-#![cfg_attr(not(bootstrap), feature(doc_notable_trait))]
+#![feature(doc_notable_trait)]
 #![feature(duration_consts_2)]
-#![feature(extended_key_value_attributes)]
+#![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
 #![feature(extern_types)]
 #![feature(fundamental)]
 #![feature(intra_doc_pointers)]
@@ -127,7 +126,6 @@
 #![feature(exhaustive_patterns)]
 #![feature(no_core)]
 #![feature(auto_traits)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(prelude_import)]
 #![feature(ptr_metadata)]
 #![feature(repr_simd, platform_intrinsics)]
@@ -167,9 +165,10 @@
 #![feature(const_caller_location)]
 #![feature(slice_ptr_get)]
 #![feature(no_niche)] // rust-lang/rust#68303
-#![cfg_attr(not(bootstrap), feature(no_coverage))] // rust-lang/rust#84605
+#![feature(no_coverage)] // rust-lang/rust#84605
 #![feature(int_error_matching)]
 #![deny(unsafe_op_in_unsafe_fn)]
+#![deny(or_patterns_back_compat)]
 
 // allow using `core::` in intra-doc links
 #[allow(unused_extern_crates)]
@@ -304,8 +303,7 @@ pub mod primitive;
     unused_imports,
     unsafe_op_in_unsafe_fn
 )]
-#[cfg_attr(bootstrap, allow(rustdoc::non_autolinks))]
-#[cfg_attr(not(bootstrap), allow(rustdoc::bare_urls))]
+#[allow(rustdoc::bare_urls)]
 // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is
 // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet.
 #[allow(clashing_extern_declarations)]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index b46a7aa138c..7eb65483b99 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -138,7 +138,7 @@ macro_rules! assert_ne {
 #[unstable(feature = "assert_matches", issue = "82775")]
 #[allow_internal_unstable(core_panic)]
 macro_rules! assert_matches {
-    ($left:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => ({
+    ($left:expr, $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => ({
         match $left {
             $( $pattern )|+ $( if $guard )? => {}
             ref left_val => {
@@ -150,7 +150,7 @@ macro_rules! assert_matches {
             }
         }
     });
-    ($left:expr, $( $pattern:pat )|+ $( if $guard: expr )?, $($arg:tt)+) => ({
+    ($left:expr, $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => ({
         match $left {
             $( $pattern )|+ $( if $guard )? => {}
             ref left_val => {
@@ -315,7 +315,7 @@ macro_rules! debug_assert_matches {
 #[macro_export]
 #[stable(feature = "matches_macro", since = "1.42.0")]
 macro_rules! matches {
-    ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => {
+    ($expression:expr, $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
         match $expression {
             $( $pattern )|+ $( if $guard )? => true,
             _ => false
@@ -595,7 +595,7 @@ macro_rules! unreachable {
 /// Indicates unimplemented code by panicking with a message of "not implemented".
 ///
 /// This allows your code to type-check, which is useful if you are prototyping or
-/// implementing a trait that requires multiple methods which you don't plan of using all of.
+/// implementing a trait that requires multiple methods which you don't plan to use all of.
 ///
 /// The difference between `unimplemented!` and [`todo!`] is that while `todo!`
 /// conveys an intent of implementing the functionality later and the message is "not yet
diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs
index d86939454be..5b99f6954e6 100644
--- a/library/core/src/mem/manually_drop.rs
+++ b/library/core/src/mem/manually_drop.rs
@@ -44,7 +44,7 @@ use crate::ptr;
 /// [`MaybeUninit<T>`]: crate::mem::MaybeUninit
 #[stable(feature = "manually_drop", since = "1.20.0")]
 #[lang = "manually_drop"]
-#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[repr(transparent)]
 pub struct ManuallyDrop<T: ?Sized> {
     value: T,
@@ -160,3 +160,16 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> {
         &mut self.value
     }
 }
+
+#[stable(feature = "manually_drop", since = "1.20.0")]
+impl<T: Clone> Clone for ManuallyDrop<T> {
+    #[inline]
+    fn clone(&self) -> ManuallyDrop<T> {
+        ManuallyDrop { value: self.value.clone() }
+    }
+
+    #[inline]
+    fn clone_from(&mut self, other: &Self) {
+        self.value.clone_from(&other.value)
+    }
+}
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 0d6d919d998..c47a2e8b05c 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -727,8 +727,8 @@ impl f32 {
     ///
     /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
     ///
-    /// See `from_bits` for some discussion of the portability of this operation
-    /// (there are almost no issues).
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
     ///
     /// Note that this function is distinct from `as` casting, which attempts to
     /// preserve the *numeric* value, and not the bitwise value.
@@ -854,35 +854,6 @@ impl f32 {
         self.to_bits().to_ne_bytes()
     }
 
-    /// Return the memory representation of this floating point number as a byte array in
-    /// native byte order.
-    ///
-    /// [`to_ne_bytes`] should be preferred over this whenever possible.
-    ///
-    /// [`to_ne_bytes`]: f32::to_ne_bytes
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(num_as_ne_bytes)]
-    /// let num = 12.5f32;
-    /// let bytes = num.as_ne_bytes();
-    /// assert_eq!(
-    ///     bytes,
-    ///     if cfg!(target_endian = "big") {
-    ///         &[0x41, 0x48, 0x00, 0x00]
-    ///     } else {
-    ///         &[0x00, 0x00, 0x48, 0x41]
-    ///     }
-    /// );
-    /// ```
-    #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
-    #[inline]
-    pub fn as_ne_bytes(&self) -> &[u8; 4] {
-        // SAFETY: `f32` is a plain old datatype so we can always transmute to it
-        unsafe { &*(self as *const Self as *const _) }
-    }
-
     /// Create a floating point value from its representation as a byte array in big endian.
     ///
     /// # Examples
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 42214e7b50d..cfcc08b9add 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -741,8 +741,8 @@ impl f64 {
     ///
     /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
     ///
-    /// See `from_bits` for some discussion of the portability of this operation
-    /// (there are almost no issues).
+    /// See [`from_bits`](Self::from_bits) for some discussion of the
+    /// portability of this operation (there are almost no issues).
     ///
     /// Note that this function is distinct from `as` casting, which attempts to
     /// preserve the *numeric* value, and not the bitwise value.
@@ -868,35 +868,6 @@ impl f64 {
         self.to_bits().to_ne_bytes()
     }
 
-    /// Return the memory representation of this floating point number as a byte array in
-    /// native byte order.
-    ///
-    /// [`to_ne_bytes`] should be preferred over this whenever possible.
-    ///
-    /// [`to_ne_bytes`]: f64::to_ne_bytes
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(num_as_ne_bytes)]
-    /// let num = 12.5f64;
-    /// let bytes = num.as_ne_bytes();
-    /// assert_eq!(
-    ///     bytes,
-    ///     if cfg!(target_endian = "big") {
-    ///         &[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
-    ///     } else {
-    ///         &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40]
-    ///     }
-    /// );
-    /// ```
-    #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
-    #[inline]
-    pub fn as_ne_bytes(&self) -> &[u8; 8] {
-        // SAFETY: `f64` is a plain old datatype so we can always transmute to it
-        unsafe { &*(self as *const Self as *const _) }
-    }
-
     /// Create a floating point value from its representation as a byte array in big endian.
     ///
     /// # Examples
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 47b2b30563c..a0efe681285 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -407,8 +407,15 @@ macro_rules! int_impl {
         }
 
         /// Unchecked integer addition. Computes `self + rhs`, assuming overflow
-        /// cannot occur. This results in undefined behavior when
-        #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")]
+        /// cannot occur.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when
+        #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")]
+        /// i.e. when [`checked_add`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")]
         #[unstable(
             feature = "unchecked_math",
             reason = "niche optimization path",
@@ -446,8 +453,15 @@ macro_rules! int_impl {
         }
 
         /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
-        /// cannot occur. This results in undefined behavior when
-        #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")]
+        /// cannot occur.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when
+        #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")]
+        /// i.e. when [`checked_sub`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")]
         #[unstable(
             feature = "unchecked_math",
             reason = "niche optimization path",
@@ -485,8 +499,15 @@ macro_rules! int_impl {
         }
 
         /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
-        /// cannot occur. This results in undefined behavior when
-        #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")]
+        /// cannot occur.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when
+        #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")]
+        /// i.e. when [`checked_mul`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")]
         #[unstable(
             feature = "unchecked_math",
             reason = "niche optimization path",
@@ -645,6 +666,31 @@ macro_rules! int_impl {
             if unlikely!(b) {None} else {Some(a)}
         }
 
+        /// Unchecked shift left. Computes `self << rhs`, assuming that
+        /// `rhs` is less than the number of bits in `self`.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior if `rhs` is larger than
+        /// or equal to the number of bits in `self`,
+        /// i.e. when [`checked_shl`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "85122",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+        #[inline(always)]
+        pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_shl`.
+            unsafe { intrinsics::unchecked_shl(self, rhs) }
+        }
+
         /// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is
         /// larger than or equal to the number of bits in `self`.
         ///
@@ -666,6 +712,31 @@ macro_rules! int_impl {
             if unlikely!(b) {None} else {Some(a)}
         }
 
+        /// Unchecked shift right. Computes `self >> rhs`, assuming that
+        /// `rhs` is less than the number of bits in `self`.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior if `rhs` is larger than
+        /// or equal to the number of bits in `self`,
+        /// i.e. when [`checked_shr`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "85122",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+        #[inline(always)]
+        pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_shr`.
+            unsafe { intrinsics::unchecked_shr(self, rhs) }
+        }
+
         /// Checked absolute value. Computes `self.abs()`, returning `None` if
         /// `self == MIN`.
         ///
@@ -1842,36 +1913,6 @@ macro_rules! int_impl {
             unsafe { mem::transmute(self) }
         }
 
-        /// Return the memory representation of this integer as a byte array in
-        /// native byte order.
-        ///
-        /// [`to_ne_bytes`] should be preferred over this whenever possible.
-        ///
-        /// [`to_ne_bytes`]: Self::to_ne_bytes
-        ///
-        /// # Examples
-        ///
-        /// ```
-        /// #![feature(num_as_ne_bytes)]
-        #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")]
-        /// let bytes = num.as_ne_bytes();
-        /// assert_eq!(
-        ///     bytes,
-        ///     if cfg!(target_endian = "big") {
-        #[doc = concat!("        &", $be_bytes)]
-        ///     } else {
-        #[doc = concat!("        &", $le_bytes)]
-        ///     }
-        /// );
-        /// ```
-        #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
-        #[inline]
-        pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
-            // SAFETY: integers are plain old datatypes so we can always transmute them to
-            // arrays of bytes
-            unsafe { &*(self as *const Self as *const _) }
-        }
-
         /// Create an integer value from its representation as a byte array in
         /// big endian.
         ///
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index f9fd28b6a8c..e512d90ef37 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -417,8 +417,15 @@ macro_rules! uint_impl {
         }
 
         /// Unchecked integer addition. Computes `self + rhs`, assuming overflow
-        /// cannot occur. This results in undefined behavior when
-        #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")]
+        /// cannot occur.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when
+        #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")]
+        /// i.e. when [`checked_add`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")]
         #[unstable(
             feature = "unchecked_math",
             reason = "niche optimization path",
@@ -456,8 +463,15 @@ macro_rules! uint_impl {
         }
 
         /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow
-        /// cannot occur. This results in undefined behavior when
-        #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")]
+        /// cannot occur.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when
+        #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")]
+        /// i.e. when [`checked_sub`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")]
         #[unstable(
             feature = "unchecked_math",
             reason = "niche optimization path",
@@ -495,8 +509,15 @@ macro_rules! uint_impl {
         }
 
         /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow
-        /// cannot occur. This results in undefined behavior when
-        #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")]
+        /// cannot occur.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior when
+        #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")]
+        /// i.e. when [`checked_mul`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")]
         #[unstable(
             feature = "unchecked_math",
             reason = "niche optimization path",
@@ -655,6 +676,31 @@ macro_rules! uint_impl {
             if unlikely!(b) {None} else {Some(a)}
         }
 
+        /// Unchecked shift left. Computes `self << rhs`, assuming that
+        /// `rhs` is less than the number of bits in `self`.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior if `rhs` is larger than
+        /// or equal to the number of bits in `self`,
+        /// i.e. when [`checked_shl`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "85122",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+        #[inline(always)]
+        pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_shl`.
+            unsafe { intrinsics::unchecked_shl(self, rhs) }
+        }
+
         /// Checked shift right. Computes `self >> rhs`, returning `None`
         /// if `rhs` is larger than or equal to the number of bits in `self`.
         ///
@@ -676,6 +722,31 @@ macro_rules! uint_impl {
             if unlikely!(b) {None} else {Some(a)}
         }
 
+        /// Unchecked shift right. Computes `self >> rhs`, assuming that
+        /// `rhs` is less than the number of bits in `self`.
+        ///
+        /// # Safety
+        ///
+        /// This results in undefined behavior if `rhs` is larger than
+        /// or equal to the number of bits in `self`,
+        /// i.e. when [`checked_shr`] would return `None`.
+        ///
+        #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")]
+        #[unstable(
+            feature = "unchecked_math",
+            reason = "niche optimization path",
+            issue = "85122",
+        )]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")]
+        #[inline(always)]
+        pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self {
+            // SAFETY: the caller must uphold the safety contract for
+            // `unchecked_shr`.
+            unsafe { intrinsics::unchecked_shr(self, rhs) }
+        }
+
         /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if
         /// overflow occurred.
         ///
@@ -1672,36 +1743,6 @@ macro_rules! uint_impl {
             unsafe { mem::transmute(self) }
         }
 
-        /// Return the memory representation of this integer as a byte array in
-        /// native byte order.
-        ///
-        /// [`to_ne_bytes`] should be preferred over this whenever possible.
-        ///
-        /// [`to_ne_bytes`]: Self::to_ne_bytes
-        ///
-        /// # Examples
-        ///
-        /// ```
-        /// #![feature(num_as_ne_bytes)]
-        #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")]
-        /// let bytes = num.as_ne_bytes();
-        /// assert_eq!(
-        ///     bytes,
-        ///     if cfg!(target_endian = "big") {
-        #[doc = concat!("        &", $be_bytes)]
-        ///     } else {
-        #[doc = concat!("        &", $le_bytes)]
-        ///     }
-        /// );
-        /// ```
-        #[unstable(feature = "num_as_ne_bytes", issue = "76976")]
-        #[inline]
-        pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] {
-            // SAFETY: integers are plain old datatypes so we can always transmute them to
-            // arrays of bytes
-            unsafe { &*(self as *const Self as *const _) }
-        }
-
         /// Create a native endian integer value from its representation
         /// as a byte array in big endian.
         ///
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index ecaff053bd5..9d9398fb56d 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -1,5 +1,4 @@
-use crate::convert;
-use crate::ops::{self, Try};
+use crate::{convert, ops};
 
 /// Used to tell an operation whether it should exit early or go on as usual.
 ///
@@ -53,8 +52,10 @@ use crate::ops::{self, Try};
 #[derive(Debug, Clone, Copy, PartialEq)]
 pub enum ControlFlow<B, C = ()> {
     /// Move on to the next phase of the operation as normal.
+    #[cfg_attr(not(bootstrap), lang = "Continue")]
     Continue(C),
     /// Exit the operation without running subsequent phases.
+    #[cfg_attr(not(bootstrap), lang = "Break")]
     Break(B),
     // Yes, the order of the variants doesn't match the type parameters.
     // They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>`
@@ -62,11 +63,12 @@ pub enum ControlFlow<B, C = ()> {
 }
 
 #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
-impl<B, C> Try for ControlFlow<B, C> {
-    type Ok = C;
+#[cfg(bootstrap)]
+impl<B, C> ops::TryV1 for ControlFlow<B, C> {
+    type Output = C;
     type Error = B;
     #[inline]
-    fn into_result(self) -> Result<Self::Ok, Self::Error> {
+    fn into_result(self) -> Result<Self::Output, Self::Error> {
         match self {
             ControlFlow::Continue(y) => Ok(y),
             ControlFlow::Break(x) => Err(x),
@@ -77,7 +79,7 @@ impl<B, C> Try for ControlFlow<B, C> {
         ControlFlow::Break(v)
     }
     #[inline]
-    fn from_ok(v: Self::Ok) -> Self {
+    fn from_ok(v: Self::Output) -> Self {
         ControlFlow::Continue(v)
     }
 }
@@ -182,23 +184,46 @@ impl<B, C> ControlFlow<B, C> {
     }
 }
 
-impl<R: Try> ControlFlow<R, R::Ok> {
+#[cfg(bootstrap)]
+impl<R: ops::TryV1> ControlFlow<R, R::Output> {
     /// Create a `ControlFlow` from any type implementing `Try`.
-    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
     #[inline]
-    pub fn from_try(r: R) -> Self {
-        match Try::into_result(r) {
+    pub(crate) fn from_try(r: R) -> Self {
+        match R::into_result(r) {
             Ok(v) => ControlFlow::Continue(v),
-            Err(v) => ControlFlow::Break(Try::from_error(v)),
+            Err(v) => ControlFlow::Break(R::from_error(v)),
+        }
+    }
+
+    /// Convert a `ControlFlow` into any type implementing `Try`;
+    #[inline]
+    pub(crate) fn into_try(self) -> R {
+        match self {
+            ControlFlow::Continue(v) => R::from_ok(v),
+            ControlFlow::Break(v) => v,
+        }
+    }
+}
+
+/// These are used only as part of implementing the iterator adapters.
+/// They have mediocre names and non-obvious semantics, so aren't
+/// currently on a path to potential stabilization.
+#[cfg(not(bootstrap))]
+impl<R: ops::TryV2> ControlFlow<R, R::Output> {
+    /// Create a `ControlFlow` from any type implementing `Try`.
+    #[inline]
+    pub(crate) fn from_try(r: R) -> Self {
+        match R::branch(r) {
+            ControlFlow::Continue(v) => ControlFlow::Continue(v),
+            ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
         }
     }
 
     /// Convert a `ControlFlow` into any type implementing `Try`;
-    #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
     #[inline]
-    pub fn into_try(self) -> R {
+    pub(crate) fn into_try(self) -> R {
         match self {
-            ControlFlow::Continue(v) => Try::from_ok(v),
+            ControlFlow::Continue(v) => R::from_output(v),
             ControlFlow::Break(v) => v,
         }
     }
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index 1b07936ccde..139a8c0eec9 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -147,6 +147,7 @@ mod function;
 mod generator;
 mod index;
 mod range;
+#[cfg(bootstrap)]
 mod r#try;
 mod try_trait;
 mod unsize;
@@ -183,13 +184,22 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
 pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
 
 #[unstable(feature = "try_trait", issue = "42327")]
+#[cfg(bootstrap)]
 pub use self::r#try::Try;
 
+#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
+#[cfg(bootstrap)]
+pub(crate) use self::r#try::Try as TryV1;
+
 #[unstable(feature = "try_trait_v2", issue = "84277")]
 pub use self::try_trait::FromResidual;
 
+#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[cfg(not(bootstrap))]
+pub use self::try_trait::Try;
+
 #[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")]
-pub use self::try_trait::Try as TryV2;
+pub(crate) use self::try_trait::Try as TryV2;
 
 #[unstable(feature = "generator_trait", issue = "43122")]
 pub use self::generator::{Generator, GeneratorState};
diff --git a/library/core/src/ops/try.rs b/library/core/src/ops/try.rs
index 3bede569978..9d659e78d3c 100644
--- a/library/core/src/ops/try.rs
+++ b/library/core/src/ops/try.rs
@@ -25,11 +25,11 @@
     )
 )]
 #[doc(alias = "?")]
-#[lang = "try"]
+#[cfg_attr(bootstrap, lang = "try")]
 pub trait Try {
     /// The type of this value when viewed as successful.
     #[unstable(feature = "try_trait", issue = "42327")]
-    type Ok;
+    type Output; // This no longer follows its RFC, but is only used in bootstrap.
     /// The type of this value when viewed as failed.
     #[unstable(feature = "try_trait", issue = "42327")]
     type Error;
@@ -43,19 +43,19 @@ pub trait Try {
     /// in the return type of the enclosing scope (which must itself implement
     /// `Try`). Specifically, the value `X::from_error(From::from(e))`
     /// is returned, where `X` is the return type of the enclosing function.
-    #[lang = "into_result"]
+    #[cfg_attr(bootstrap, lang = "into_result")]
     #[unstable(feature = "try_trait", issue = "42327")]
-    fn into_result(self) -> Result<Self::Ok, Self::Error>;
+    fn into_result(self) -> Result<Self::Output, Self::Error>;
 
     /// Wrap an error value to construct the composite result. For example,
     /// `Result::Err(x)` and `Result::from_error(x)` are equivalent.
-    #[lang = "from_error"]
+    #[cfg_attr(bootstrap, lang = "from_error")]
     #[unstable(feature = "try_trait", issue = "42327")]
     fn from_error(v: Self::Error) -> Self;
 
     /// Wrap an OK value to construct the composite result. For example,
     /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent.
-    #[lang = "from_ok"]
+    #[cfg_attr(bootstrap, lang = "from_ok")]
     #[unstable(feature = "try_trait", issue = "42327")]
-    fn from_ok(v: Self::Ok) -> Self;
+    fn from_ok(v: Self::Output) -> Self;
 }
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 0c819b000aa..1d9bc452618 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -41,8 +41,7 @@ use crate::ops::ControlFlow;
 /// output type that we want:
 /// ```
 /// # #![feature(try_trait_v2)]
-/// # #![feature(try_trait_transition)]
-/// # use std::ops::TryV2 as Try;
+/// # use std::ops::Try;
 /// fn simple_try_fold_1<A, T, R: Try<Output = A>>(
 ///     iter: impl Iterator<Item = T>,
 ///     mut accum: A,
@@ -56,9 +55,8 @@ use crate::ops::ControlFlow;
 /// into the return type using [`Try::from_output`]:
 /// ```
 /// # #![feature(try_trait_v2)]
-/// # #![feature(try_trait_transition)]
 /// # #![feature(control_flow_enum)]
-/// # use std::ops::{ControlFlow, TryV2 as Try};
+/// # use std::ops::{ControlFlow, Try};
 /// fn simple_try_fold_2<A, T, R: Try<Output = A>>(
 ///     iter: impl Iterator<Item = T>,
 ///     mut accum: A,
@@ -81,9 +79,8 @@ use crate::ops::ControlFlow;
 /// recreated from their corresponding residual, so we'll just call it:
 /// ```
 /// # #![feature(try_trait_v2)]
-/// # #![feature(try_trait_transition)]
 /// # #![feature(control_flow_enum)]
-/// # use std::ops::{ControlFlow, TryV2 as Try};
+/// # use std::ops::{ControlFlow, Try};
 /// pub fn simple_try_fold_3<A, T, R: Try<Output = A>>(
 ///     iter: impl Iterator<Item = T>,
 ///     mut accum: A,
@@ -103,10 +100,9 @@ use crate::ops::ControlFlow;
 /// But this "call `branch`, then `match` on it, and `return` if it was a
 /// `Break`" is exactly what happens inside the `?` operator.  So rather than
 /// do all this manually, we can just use `?` instead:
-/// ```compile_fail (enable again once ? converts to the new trait)
+/// ```
 /// # #![feature(try_trait_v2)]
-/// # #![feature(try_trait_transition)]
-/// # use std::ops::TryV2 as Try;
+/// # use std::ops::Try;
 /// fn simple_try_fold<A, T, R: Try<Output = A>>(
 ///     iter: impl Iterator<Item = T>,
 ///     mut accum: A,
@@ -119,6 +115,22 @@ use crate::ops::ControlFlow;
 /// }
 /// ```
 #[unstable(feature = "try_trait_v2", issue = "84277")]
+#[rustc_on_unimplemented(
+    on(
+        all(from_method = "from_output", from_desugaring = "TryBlock"),
+        message = "a `try` block must return `Result` or `Option` \
+                    (or another type that implements `{Try}`)",
+        label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`",
+    ),
+    on(
+        all(from_method = "branch", from_desugaring = "QuestionMark"),
+        message = "the `?` operator can only be applied to values \
+                    that implement `{Try}`",
+        label = "the `?` operator cannot be applied to type `{Self}`"
+    )
+)]
+#[doc(alias = "?")]
+#[cfg_attr(not(bootstrap), lang = "Try")]
 pub trait Try: FromResidual {
     /// The type of the value produced by `?` when *not* short-circuiting.
     #[unstable(feature = "try_trait_v2", issue = "84277")]
@@ -159,8 +171,7 @@ pub trait Try: FromResidual {
     /// ```
     /// #![feature(try_trait_v2)]
     /// #![feature(control_flow_enum)]
-    /// #![feature(try_trait_transition)]
-    /// use std::ops::TryV2 as Try;
+    /// use std::ops::Try;
     ///
     /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3));
     /// assert_eq!(<Option<_> as Try>::from_output(4), Some(4));
@@ -178,6 +189,7 @@ pub trait Try: FromResidual {
     /// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() });
     /// assert_eq!(r, Some(4));
     /// ```
+    #[cfg_attr(not(bootstrap), lang = "from_output")]
     #[unstable(feature = "try_trait_v2", issue = "84277")]
     fn from_output(output: Self::Output) -> Self;
 
@@ -191,8 +203,7 @@ pub trait Try: FromResidual {
     /// ```
     /// #![feature(try_trait_v2)]
     /// #![feature(control_flow_enum)]
-    /// #![feature(try_trait_transition)]
-    /// use std::ops::{ControlFlow, TryV2 as Try};
+    /// use std::ops::{ControlFlow, Try};
     ///
     /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3));
     /// assert_eq!(Err::<String, _>(3).branch(), ControlFlow::Break(Err(3)));
@@ -206,15 +217,105 @@ pub trait Try: FromResidual {
     ///     ControlFlow::Break(ControlFlow::Break(3)),
     /// );
     /// ```
+    #[cfg_attr(not(bootstrap), lang = "branch")]
     #[unstable(feature = "try_trait_v2", issue = "84277")]
     fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
 }
 
-/// Used to specify which residuals can be converted into which [`Try`] types.
+/// Used to specify which residuals can be converted into which [`crate::ops::Try`] types.
 ///
 /// Every `Try` type needs to be recreatable from its own associated
 /// `Residual` type, but can also have additional `FromResidual` implementations
 /// to support interconversion with other `Try` types.
+#[rustc_on_unimplemented(
+    on(
+        all(
+            from_method = "from_residual",
+            from_desugaring = "QuestionMark",
+            _Self = "std::result::Result<T, E>",
+            R = "std::option::Option<std::convert::Infallible>"
+        ),
+        message = "the `?` operator can only be used on `Result`s, not `Option`s, \
+            in {ItemContext} that returns `Result`",
+        label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`",
+        enclosing_scope = "this function returns a `Result`"
+    ),
+    on(
+        all(
+            from_method = "from_residual",
+            from_desugaring = "QuestionMark",
+            _Self = "std::result::Result<T, E>",
+        ),
+        // There's a special error message in the trait selection code for
+        // `From` in `?`, so this is not shown for result-in-result errors,
+        // and thus it can be phrased more strongly than `ControlFlow`'s.
+        message = "the `?` operator can only be used on `Result`s \
+            in {ItemContext} that returns `Result`",
+        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+        enclosing_scope = "this function returns a `Result`"
+    ),
+    on(
+        all(
+            from_method = "from_residual",
+            from_desugaring = "QuestionMark",
+            _Self = "std::option::Option<T>",
+            R = "std::result::Result<T, E>",
+        ),
+        message = "the `?` operator can only be used on `Option`s, not `Result`s, \
+            in {ItemContext} that returns `Option`",
+        label = "use `.ok()?` if you want to discard the `{R}` error information",
+        enclosing_scope = "this function returns an `Option`"
+    ),
+    on(
+        all(
+            from_method = "from_residual",
+            from_desugaring = "QuestionMark",
+            _Self = "std::option::Option<T>",
+        ),
+        // `Option`-in-`Option` always works, as there's only one possible
+        // residual, so this can also be phrased strongly.
+        message = "the `?` operator can only be used on `Option`s \
+            in {ItemContext} that returns `Option`",
+        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+        enclosing_scope = "this function returns an `Option`"
+    ),
+    on(
+        all(
+            from_method = "from_residual",
+            from_desugaring = "QuestionMark",
+            _Self = "std::ops::ControlFlow<B, C>",
+            R = "std::ops::ControlFlow<B, C>",
+        ),
+        message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \
+            can only be used on other `ControlFlow<B, _>`s (with the same Break type)",
+        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+        enclosing_scope = "this function returns a `ControlFlow`",
+        note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`"
+    ),
+    on(
+        all(
+            from_method = "from_residual",
+            from_desugaring = "QuestionMark",
+            _Self = "std::ops::ControlFlow<B, C>",
+            // `R` is not a `ControlFlow`, as that case was matched previously
+        ),
+        message = "the `?` operator can only be used on `ControlFlow`s \
+            in {ItemContext} that returns `ControlFlow`",
+        label = "this `?` produces `{R}`, which is incompatible with `{Self}`",
+        enclosing_scope = "this function returns a `ControlFlow`",
+    ),
+    on(
+        all(
+            from_method = "from_residual",
+            from_desugaring = "QuestionMark"
+        ),
+        message = "the `?` operator can only be used in {ItemContext} \
+                    that returns `Result` or `Option` \
+                    (or another type that implements `{FromResidual}`)",
+        label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
+        enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
+    ),
+)]
 #[unstable(feature = "try_trait_v2", issue = "84277")]
 pub trait FromResidual<R = <Self as Try>::Residual> {
     /// Constructs the type from a compatible `Residual` type.
@@ -238,6 +339,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
     ///     ControlFlow::Break(5),
     /// );
     /// ```
+    #[cfg_attr(not(bootstrap), lang = "from_residual")]
     #[unstable(feature = "try_trait_v2", issue = "84277")]
     fn from_residual(residual: R) -> Self;
 }
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index 04551dded8c..4e7afca6a49 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -83,6 +83,8 @@
 //! * [`ptr::NonNull<U>`]
 //! * `#[repr(transparent)]` struct around one of the types in this list.
 //!
+//! This is called the "null pointer optimization" or NPO.
+//!
 //! It is further guaranteed that, for the cases above, one can
 //! [`mem::transmute`] from all valid values of `T` to `Option<T>` and
 //! from `Some::<T>(_)` to `T` (but transmuting `None::<T>` to `T`
@@ -209,7 +211,7 @@ impl<T> Option<T> {
     /// assert_eq!(x.is_none(), true);
     /// ```
     #[must_use = "if you intended to assert that this doesn't have a value, consider \
-                  `.and_then(|| panic!(\"`Option` had a value when expected `None`\"))` instead"]
+                  `.and_then(|_| panic!(\"`Option` had a value when expected `None`\"))` instead"]
     #[inline]
     #[rustc_const_stable(feature = "const_option", since = "1.48.0")]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1641,11 +1643,13 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
 #[rustc_diagnostic_item = "none_error"]
 #[unstable(feature = "try_trait", issue = "42327")]
 #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
+#[cfg(bootstrap)]
 pub struct NoneError;
 
 #[unstable(feature = "try_trait", issue = "42327")]
-impl<T> ops::Try for Option<T> {
-    type Ok = T;
+#[cfg(bootstrap)]
+impl<T> ops::TryV1 for Option<T> {
+    type Output = T;
     type Error = NoneError;
 
     #[inline]
diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs
index 8f57db49496..79753c1fb66 100644
--- a/library/core/src/prelude/mod.rs
+++ b/library/core/src/prelude/mod.rs
@@ -11,9 +11,9 @@ pub mod v1;
 /// The 2015 version of the core prelude.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2015", issue = "none")]
+#[unstable(feature = "prelude_2015", issue = "85684")]
 pub mod rust_2015 {
-    #[unstable(feature = "prelude_2015", issue = "none")]
+    #[unstable(feature = "prelude_2015", issue = "85684")]
     #[doc(no_inline)]
     pub use super::v1::*;
 }
@@ -21,9 +21,9 @@ pub mod rust_2015 {
 /// The 2018 version of the core prelude.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2018", issue = "none")]
+#[unstable(feature = "prelude_2018", issue = "85684")]
 pub mod rust_2018 {
-    #[unstable(feature = "prelude_2018", issue = "none")]
+    #[unstable(feature = "prelude_2018", issue = "85684")]
     #[doc(no_inline)]
     pub use super::v1::*;
 }
@@ -31,11 +31,17 @@ pub mod rust_2018 {
 /// The 2021 version of the core prelude.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2021", issue = "none")]
+#[unstable(feature = "prelude_2021", issue = "85684")]
 pub mod rust_2021 {
-    #[unstable(feature = "prelude_2021", issue = "none")]
+    #[unstable(feature = "prelude_2021", issue = "85684")]
     #[doc(no_inline)]
     pub use super::v1::*;
 
-    // FIXME: Add more things.
+    #[unstable(feature = "prelude_2021", issue = "85684")]
+    #[doc(no_inline)]
+    pub use crate::iter::FromIterator;
+
+    #[unstable(feature = "prelude_2021", issue = "85684")]
+    #[doc(no_inline)]
+    pub use crate::convert::{TryFrom, TryInto};
 }
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 2c324b15a1a..214d7c8bc15 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -342,10 +342,12 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
 /// ```
 /// use std::ptr;
 ///
-/// let mut array = [0, 1, 2, 3];
+/// let mut array: [i32; 4] = [0, 1, 2, 3];
+///
+/// let array_ptr: *mut i32 = array.as_mut_ptr();
 ///
-/// let x = array[0..].as_mut_ptr() as *mut [u32; 3]; // this is `array[0..3]`
-/// let y = array[1..].as_mut_ptr() as *mut [u32; 3]; // this is `array[1..4]`
+/// let x = array_ptr as *mut [i32; 3]; // this is `array[0..3]`
+/// let y = unsafe { array_ptr.add(1) } as *mut [i32; 3]; // this is `array[1..4]`
 ///
 /// unsafe {
 ///     ptr::swap(x, y);
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index e0071f806aa..babd0a0b552 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1627,8 +1627,9 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
 }
 
 #[unstable(feature = "try_trait", issue = "42327")]
-impl<T, E> ops::Try for Result<T, E> {
-    type Ok = T;
+#[cfg(bootstrap)]
+impl<T, E> ops::TryV1 for Result<T, E> {
+    type Output = T;
     type Error = E;
 
     #[inline]
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index 906dcb1e8bc..b92ab7e3475 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -110,7 +110,7 @@ impl<'a> iter::Iterator for EscapeAscii<'a> {
     fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
     where
         Fold: FnMut(Acc, Self::Item) -> R,
-        R: ops::Try<Ok = Acc>,
+        R: ops::Try<Output = Acc>,
     {
         self.inner.try_fold(init, fold)
     }
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 0923175414e..3bcea4e6d25 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -3096,7 +3096,11 @@ impl<T> [T] {
         // SAFETY: the conditions for `ptr::copy` have all been checked above,
         // as have those for `ptr::add`.
         unsafe {
-            ptr::copy(self.as_ptr().add(src_start), self.as_mut_ptr().add(dest), count);
+            // Derive both `src_ptr` and `dest_ptr` from the same loan
+            let ptr = self.as_mut_ptr();
+            let src_ptr = ptr.add(src_start);
+            let dest_ptr = ptr.add(dest);
+            ptr::copy(src_ptr, dest_ptr, count);
         }
     }
 
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index 724137aba9f..6ec6b70b571 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -1467,7 +1467,7 @@ macro_rules! escape_types_impls {
 
             #[inline]
             fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where
-                Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
+                Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc>
             {
                 self.inner.try_fold(init, fold)
             }
diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs
index 2765c21a46d..9cf89623d88 100644
--- a/library/core/src/task/poll.rs
+++ b/library/core/src/task/poll.rs
@@ -1,7 +1,7 @@
 #![stable(feature = "futures_api", since = "1.36.0")]
 
 use crate::convert;
-use crate::ops::{self, ControlFlow, Try};
+use crate::ops::{self, ControlFlow};
 use crate::result::Result;
 
 /// Indicates whether a value is available or if the current task has been
@@ -129,12 +129,13 @@ impl<T> From<T> for Poll<T> {
 }
 
 #[stable(feature = "futures_api", since = "1.36.0")]
-impl<T, E> Try for Poll<Result<T, E>> {
-    type Ok = Poll<T>;
+#[cfg(bootstrap)]
+impl<T, E> ops::TryV1 for Poll<Result<T, E>> {
+    type Output = Poll<T>;
     type Error = E;
 
     #[inline]
-    fn into_result(self) -> Result<Self::Ok, Self::Error> {
+    fn into_result(self) -> Result<Self::Output, Self::Error> {
         match self {
             Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)),
             Poll::Ready(Err(e)) => Err(e),
@@ -148,7 +149,7 @@ impl<T, E> Try for Poll<Result<T, E>> {
     }
 
     #[inline]
-    fn from_ok(x: Self::Ok) -> Self {
+    fn from_ok(x: Self::Output) -> Self {
         x.map(Ok)
     }
 }
@@ -184,12 +185,13 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Pol
 }
 
 #[stable(feature = "futures_api", since = "1.36.0")]
-impl<T, E> Try for Poll<Option<Result<T, E>>> {
-    type Ok = Poll<Option<T>>;
+#[cfg(bootstrap)]
+impl<T, E> ops::TryV1 for Poll<Option<Result<T, E>>> {
+    type Output = Poll<Option<T>>;
     type Error = E;
 
     #[inline]
-    fn into_result(self) -> Result<Self::Ok, Self::Error> {
+    fn into_result(self) -> Result<Self::Output, Self::Error> {
         match self {
             Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))),
             Poll::Ready(Some(Err(e))) => Err(e),
@@ -204,7 +206,7 @@ impl<T, E> Try for Poll<Option<Result<T, E>>> {
     }
 
     #[inline]
-    fn from_ok(x: Self::Ok) -> Self {
+    fn from_ok(x: Self::Output) -> Self {
         x.map(|x| x.map(Ok))
     }
 }
diff --git a/library/core/tests/any.rs b/library/core/tests/any.rs
index b0dc9903464..b36d6f0d404 100644
--- a/library/core/tests/any.rs
+++ b/library/core/tests/any.rs
@@ -114,3 +114,16 @@ fn any_unsized() {
     fn is_any<T: Any + ?Sized>() {}
     is_any::<[i32]>();
 }
+
+#[test]
+fn distinct_type_names() {
+    // https://github.com/rust-lang/rust/issues/84666
+
+    struct Velocity(f32, f32);
+
+    fn type_name_of_val<T>(_: T) -> &'static str {
+        type_name::<T>()
+    }
+
+    assert_ne!(type_name_of_val(Velocity), type_name_of_val(Velocity(0.0, -9.8)),);
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 35e4d213dde..16051b3bc36 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -40,11 +40,10 @@
 #![feature(maybe_uninit_write_slice)]
 #![feature(min_specialization)]
 #![feature(step_trait)]
-#![feature(step_trait_ext)]
 #![feature(str_internals)]
 #![feature(test)]
 #![feature(trusted_len)]
-#![feature(try_trait)]
+#![feature(try_trait_v2)]
 #![feature(slice_internals)]
 #![feature(slice_partition_dedup)]
 #![feature(int_error_matching)]
diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs
index 9470451278c..88ea15a3b33 100644
--- a/library/core/tests/option.rs
+++ b/library/core/tests/option.rs
@@ -301,18 +301,6 @@ fn test_try() {
         Some(val)
     }
     assert_eq!(try_option_none(), None);
-
-    fn try_option_ok() -> Result<u8, NoneError> {
-        let val = Some(1)?;
-        Ok(val)
-    }
-    assert_eq!(try_option_ok(), Ok(1));
-
-    fn try_option_err() -> Result<u8, NoneError> {
-        let val = None?;
-        Ok(val)
-    }
-    assert_eq!(try_option_err(), Err(NoneError));
 }
 
 #[test]
diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs
index c461ab380ad..f4e5e7751b8 100644
--- a/library/core/tests/result.rs
+++ b/library/core/tests/result.rs
@@ -249,26 +249,14 @@ pub fn test_into_err() {
 
 #[test]
 fn test_try() {
-    fn try_result_some() -> Option<u8> {
-        let val = Ok(1)?;
-        Some(val)
-    }
-    assert_eq!(try_result_some(), Some(1));
-
-    fn try_result_none() -> Option<u8> {
-        let val = Err(NoneError)?;
-        Some(val)
-    }
-    assert_eq!(try_result_none(), None);
-
-    fn try_result_ok() -> Result<u8, u8> {
+    fn try_result_ok() -> Result<u8, u32> {
         let result: Result<u8, u8> = Ok(1);
         let val = result?;
         Ok(val)
     }
     assert_eq!(try_result_ok(), Ok(1));
 
-    fn try_result_err() -> Result<u8, u8> {
+    fn try_result_err() -> Result<u8, u32> {
         let result: Result<u8, u8> = Err(1);
         let val = result?;
         Ok(val)
@@ -401,3 +389,17 @@ fn result_opt_conversions() {
 
     assert_eq!(res, Err(BadNumErr))
 }
+
+#[test]
+#[cfg(not(bootstrap))] // Needs the V2 trait
+fn result_try_trait_v2_branch() {
+    use core::num::NonZeroU32;
+    use core::ops::{ControlFlow::*, Try};
+    assert_eq!(Ok::<i32, i32>(4).branch(), Continue(4));
+    assert_eq!(Err::<i32, i32>(4).branch(), Break(Err(4)));
+    let one = NonZeroU32::new(1).unwrap();
+    assert_eq!(Ok::<(), NonZeroU32>(()).branch(), Continue(()));
+    assert_eq!(Err::<(), NonZeroU32>(one).branch(), Break(Err(one)));
+    assert_eq!(Ok::<NonZeroU32, ()>(one).branch(), Continue(one));
+    assert_eq!(Err::<NonZeroU32, ()>(()).branch(), Break(Err(())));
+}
diff --git a/library/proc_macro/src/bridge/buffer.rs b/library/proc_macro/src/bridge/buffer.rs
index aeecbd49662..717201aef10 100644
--- a/library/proc_macro/src/bridge/buffer.rs
+++ b/library/proc_macro/src/bridge/buffer.rs
@@ -39,7 +39,7 @@ pub struct Buffer<T: Copy> {
     data: *mut T,
     len: usize,
     capacity: usize,
-    extend_from_slice: extern "C" fn(Buffer<T>, Slice<'_, T>) -> Buffer<T>,
+    reserve: extern "C" fn(Buffer<T>, usize) -> Buffer<T>,
     drop: extern "C" fn(Buffer<T>),
 }
 
@@ -78,18 +78,44 @@ impl<T: Copy> Buffer<T> {
         mem::take(self)
     }
 
+    // We have the array method separate from extending from a slice. This is
+    // because in the case of small arrays, codegen can be more efficient
+    // (avoiding a memmove call). With extend_from_slice, LLVM at least
+    // currently is not able to make that optimization.
+    pub(super) fn extend_from_array<const N: usize>(&mut self, xs: &[T; N]) {
+        if xs.len() > (self.capacity - self.len) {
+            let b = self.take();
+            *self = (b.reserve)(b, xs.len());
+        }
+        unsafe {
+            xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
+            self.len += xs.len();
+        }
+    }
+
     pub(super) fn extend_from_slice(&mut self, xs: &[T]) {
-        // Fast path to avoid going through an FFI call.
-        if let Some(final_len) = self.len.checked_add(xs.len()) {
-            if final_len <= self.capacity {
-                let dst = unsafe { slice::from_raw_parts_mut(self.data, self.capacity) };
-                dst[self.len..][..xs.len()].copy_from_slice(xs);
-                self.len = final_len;
-                return;
-            }
+        if xs.len() > (self.capacity - self.len) {
+            let b = self.take();
+            *self = (b.reserve)(b, xs.len());
+        }
+        unsafe {
+            xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len());
+            self.len += xs.len();
+        }
+    }
+
+    pub(super) fn push(&mut self, v: T) {
+        // The code here is taken from Vec::push, and we know that reserve()
+        // will panic if we're exceeding isize::MAX bytes and so there's no need
+        // to check for overflow.
+        if self.len == self.capacity {
+            let b = self.take();
+            *self = (b.reserve)(b, 1);
+        }
+        unsafe {
+            *self.data.add(self.len) = v;
+            self.len += 1;
         }
-        let b = self.take();
-        *self = (b.extend_from_slice)(b, Slice::from(xs));
     }
 }
 
@@ -131,9 +157,9 @@ impl<T: Copy> From<Vec<T>> for Buffer<T> {
             }
         }
 
-        extern "C" fn extend_from_slice<T: Copy>(b: Buffer<T>, xs: Slice<'_, T>) -> Buffer<T> {
+        extern "C" fn reserve<T: Copy>(b: Buffer<T>, additional: usize) -> Buffer<T> {
             let mut v = to_vec(b);
-            v.extend_from_slice(&xs);
+            v.reserve(additional);
             Buffer::from(v)
         }
 
@@ -141,6 +167,6 @@ impl<T: Copy> From<Vec<T>> for Buffer<T> {
             mem::drop(to_vec(b));
         }
 
-        Buffer { data, len, capacity, extend_from_slice, drop }
+        Buffer { data, len, capacity, reserve, drop }
     }
 }
diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs
index 355ad1f9f88..a2953b68564 100644
--- a/library/proc_macro/src/bridge/mod.rs
+++ b/library/proc_macro/src/bridge/mod.rs
@@ -107,6 +107,7 @@ macro_rules! with_api {
             Literal {
                 fn drop($self: $S::Literal);
                 fn clone($self: &$S::Literal) -> $S::Literal;
+                fn from_str(s: &str) -> Result<$S::Literal, ()>;
                 fn debug_kind($self: &$S::Literal) -> String;
                 fn symbol($self: &$S::Literal) -> String;
                 fn suffix($self: &$S::Literal) -> Option<String>;
@@ -315,6 +316,19 @@ impl<T: Unmark> Unmark for Option<T> {
     }
 }
 
+impl<T: Mark, E: Mark> Mark for Result<T, E> {
+    type Unmarked = Result<T::Unmarked, E::Unmarked>;
+    fn mark(unmarked: Self::Unmarked) -> Self {
+        unmarked.map(T::mark).map_err(E::mark)
+    }
+}
+impl<T: Unmark, E: Unmark> Unmark for Result<T, E> {
+    type Unmarked = Result<T::Unmarked, E::Unmarked>;
+    fn unmark(self) -> Self::Unmarked {
+        self.map(T::unmark).map_err(E::unmark)
+    }
+}
+
 macro_rules! mark_noop {
     ($($ty:ty),* $(,)?) => {
         $(
diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs
index 5c2f9ec9848..588e6ded0f4 100644
--- a/library/proc_macro/src/bridge/rpc.rs
+++ b/library/proc_macro/src/bridge/rpc.rs
@@ -27,7 +27,7 @@ macro_rules! rpc_encode_decode {
     (le $ty:ty) => {
         impl<S> Encode<S> for $ty {
             fn encode(self, w: &mut Writer, _: &mut S) {
-                w.write_all(&self.to_le_bytes()).unwrap();
+                w.extend_from_array(&self.to_le_bytes());
             }
         }
 
@@ -114,7 +114,7 @@ impl<S> DecodeMut<'_, '_, S> for () {
 
 impl<S> Encode<S> for u8 {
     fn encode(self, w: &mut Writer, _: &mut S) {
-        w.write_all(&[self]).unwrap();
+        w.push(self);
     }
 }
 
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 525fd0fbe34..04a165e09f1 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -21,8 +21,7 @@
 #![feature(rustc_allow_const_fn_unstable)]
 #![feature(nll)]
 #![feature(staged_api)]
-#![cfg_attr(bootstrap, feature(const_fn))]
-#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))]
+#![feature(const_fn_trait_bound)]
 #![feature(const_fn_fn_ptr_basics)]
 #![feature(allow_internal_unstable)]
 #![feature(decl_macro)]
@@ -91,6 +90,12 @@ pub struct LexError {
     _inner: (),
 }
 
+impl LexError {
+    fn new() -> Self {
+        LexError { _inner: () }
+    }
+}
+
 #[stable(feature = "proc_macro_lexerror_impls", since = "1.44.0")]
 impl fmt::Display for LexError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1171,6 +1176,28 @@ impl Literal {
     }
 }
 
+/// Parse a single literal from its stringified representation.
+///
+/// In order to parse successfully, the input string must not contain anything
+/// but the literal token. Specifically, it must not contain whitespace or
+/// comments in addition to the literal.
+///
+/// The resulting literal token will have a `Span::call_site()` span.
+///
+/// NOTE: some errors may cause panics instead of returning `LexError`. We
+/// reserve the right to change these errors into `LexError`s later.
+#[stable(feature = "proc_macro_literal_parse", since = "1.54.0")]
+impl FromStr for Literal {
+    type Err = LexError;
+
+    fn from_str(src: &str) -> Result<Self, LexError> {
+        match bridge::client::Literal::from_str(src) {
+            Ok(literal) => Ok(Literal(literal)),
+            Err(()) => Err(LexError::new()),
+        }
+    }
+}
+
 // N.B., the bridge only provides `to_string`, implement `fmt::Display`
 // based on it (the reverse of the usual relationship between the two).
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
diff --git a/library/profiler_builtins/Cargo.toml b/library/profiler_builtins/Cargo.toml
index 474058a547f..7b7ca8029b4 100644
--- a/library/profiler_builtins/Cargo.toml
+++ b/library/profiler_builtins/Cargo.toml
@@ -14,4 +14,4 @@ core = { path = "../core" }
 compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] }
 
 [build-dependencies]
-cc = "1.0.67"
+cc = "1.0.68"
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 922c2c2bb8c..415d874c7fa 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -17,7 +17,7 @@ panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
 libc = { version = "0.2.93", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.43" }
+compiler_builtins = { version = "0.1.44" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
 hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] }
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index 843ef09a584..8ee55234cea 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -63,8 +63,6 @@ use core::ptr::NonNull;
 use core::sync::atomic::{AtomicPtr, Ordering};
 use core::{mem, ptr};
 
-use crate::sys_common::util::dumb_print;
-
 #[stable(feature = "alloc_module", since = "1.28.0")]
 #[doc(inline)]
 pub use alloc_crate::alloc::*;
@@ -317,7 +315,7 @@ pub fn take_alloc_error_hook() -> fn(Layout) {
 }
 
 fn default_alloc_error_hook(layout: Layout) {
-    dumb_print(format_args!("memory allocation of {} bytes failed\n", layout.size()));
+    rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
 }
 
 #[cfg(not(test))]
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index 2f9845d7536..be7e099b73a 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -10,7 +10,6 @@ use crate::error::Error;
 use crate::fmt::{self, Write};
 use crate::io;
 use crate::mem;
-use crate::memchr;
 use crate::num::NonZeroU8;
 use crate::ops;
 use crate::os::raw::c_char;
@@ -20,6 +19,7 @@ use crate::slice;
 use crate::str::{self, Utf8Error};
 use crate::sync::Arc;
 use crate::sys;
+use crate::sys_common::memchr;
 
 /// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the
 /// middle.
@@ -185,6 +185,7 @@ pub struct CString {
 ///
 /// [`&str`]: prim@str
 #[derive(Hash)]
+#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
 #[stable(feature = "rust1", since = "1.0.0")]
 // FIXME:
 // `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies
@@ -671,6 +672,7 @@ impl CString {
     }
 
     /// Bypass "move out of struct which implements [`Drop`] trait" restriction.
+    #[inline]
     fn into_inner(self) -> Box<[u8]> {
         // Rationale: `mem::forget(self)` invalidates the previous call to `ptr::read(&self.inner)`
         // so we use `ManuallyDrop` to ensure `self` is not dropped.
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index e6120b8ee31..a1636e2f604 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -2208,3 +2208,29 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
         &mut self.inner
     }
 }
+
+/// Returns `Ok(true)` if the path points at an existing entity.
+///
+/// This function will traverse symbolic links to query information about the
+/// destination file. In case of broken symbolic links this will return `Ok(false)`.
+///
+/// As opposed to the `exists()` method, this one doesn't silently ignore errors
+/// unrelated to the path not existing. (E.g. it will return `Err(_)` in case of permission
+/// denied on some of the parent directories.)
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(path_try_exists)]
+/// use std::fs;
+///
+/// assert!(!fs::try_exists("does_not_exist.txt").expect("Can't check existence of file does_not_exist.txt"));
+/// assert!(fs::try_exists("/root/secret_file.txt").is_err());
+/// ```
+// FIXME: stabilization should modify documentation of `exists()` to recommend this method
+// instead.
+#[unstable(feature = "path_try_exists", issue = "83186")]
+#[inline]
+pub fn try_exists<P: AsRef<Path>>(path: P) -> io::Result<bool> {
+    fs_imp::try_exists(path.as_ref())
+}
diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs
index d0c859d2e0c..0175d2693e8 100644
--- a/library/std/src/io/buffered/linewritershim.rs
+++ b/library/std/src/io/buffered/linewritershim.rs
@@ -1,5 +1,5 @@
 use crate::io::{self, BufWriter, IoSlice, Write};
-use crate::memchr;
+use crate::sys_common::memchr;
 
 /// Private helper struct for implementing the line-buffered writing logic.
 /// This shim temporarily wraps a BufWriter, and uses its internals to
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 9021b470065..9527254c947 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -71,7 +71,7 @@ use core::convert::TryInto;
 /// }
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone, Debug, Default, Eq, PartialEq)]
+#[derive(Debug, Default, Eq, PartialEq)]
 pub struct Cursor<T> {
     inner: T,
     pos: u64,
@@ -206,6 +206,23 @@ impl<T> Cursor<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Clone for Cursor<T>
+where
+    T: Clone,
+{
+    #[inline]
+    fn clone(&self) -> Self {
+        Cursor { inner: self.inner.clone(), pos: self.pos }
+    }
+
+    #[inline]
+    fn clone_from(&mut self, other: &Self) {
+        self.inner.clone_from(&other.inner);
+        self.pos = other.pos;
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
 impl<T> io::Seek for Cursor<T>
 where
     T: AsRef<[u8]>,
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 9f43379aff7..4c154dbe01a 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -253,12 +253,12 @@ mod tests;
 
 use crate::cmp;
 use crate::fmt;
-use crate::memchr;
 use crate::ops::{Deref, DerefMut};
 use crate::ptr;
 use crate::slice;
 use crate::str;
 use crate::sys;
+use crate::sys_common::memchr;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::buffered::IntoInnerError;
@@ -509,8 +509,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
 /// [`std::io`]: self
 /// [`File`]: crate::fs::File
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(bootstrap, doc(spotlight))]
-#[cfg_attr(not(bootstrap), doc(notable_trait))]
+#[doc(notable_trait)]
 pub trait Read {
     /// Pull some bytes from this source into the specified buffer, returning
     /// how many bytes were read.
@@ -526,7 +525,12 @@ pub trait Read {
     ///
     /// 1. This reader has reached its "end of file" and will likely no longer
     ///    be able to produce bytes. Note that this does not mean that the
-    ///    reader will *always* no longer be able to produce bytes.
+    ///    reader will *always* no longer be able to produce bytes. As an example,
+    ///    on Linux, this method will call the `recv` syscall for a [`TcpStream`],
+    ///    where returning zero indicates the connection was shut down correctly. While
+    ///    for [`File`], it is possible to reach the end of file and get zero as result,
+    ///    but if more data is appended to the file, future calls to `read` will return
+    ///    more data.
     /// 2. The buffer specified was 0 bytes in length.
     ///
     /// It is not an error if the returned value `n` is smaller than the buffer size,
@@ -568,6 +572,7 @@ pub trait Read {
     ///
     /// [`Ok(n)`]: Ok
     /// [`File`]: crate::fs::File
+    /// [`TcpStream`]: crate::net::TcpStream
     ///
     /// ```no_run
     /// use std::io;
@@ -1301,8 +1306,7 @@ impl Initializer {
 ///
 /// [`write_all`]: Write::write_all
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(bootstrap, doc(spotlight))]
-#[cfg_attr(not(bootstrap), doc(notable_trait))]
+#[doc(notable_trait)]
 pub trait Write {
     /// Write a buffer into this writer, returning how many bytes were written.
     ///
@@ -1663,7 +1667,7 @@ pub trait Seek {
     ///
     /// # Errors
     ///
-    /// Seeking can fail, for example becaue it might involve flushing a buffer.
+    /// Seeking can fail, for example because it might involve flushing a buffer.
     ///
     /// Seeking to a negative offset is considered an error.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1675,7 +1679,7 @@ pub trait Seek {
     ///
     /// # Errors
     ///
-    /// Rewinding can fail, for example becaue it might involve flushing a buffer.
+    /// Rewinding can fail, for example because it might involve flushing a buffer.
     ///
     /// # Example
     ///
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 39ed62425ce..ba2b8b6955d 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -1008,9 +1008,9 @@ mod mod_keyword {}
 ///     move || println!("This is a: {}", text)
 /// }
 ///
-///     let fn_plain = create_fn();
+/// let fn_plain = create_fn();
 ///
-///     fn_plain();
+/// fn_plain();
 /// ```
 ///
 /// `move` is often used when [threads] are involved.
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 5f89ac059fd..8e4c63762fd 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -260,15 +260,14 @@
 #![feature(doc_cfg)]
 #![feature(doc_keyword)]
 #![feature(doc_masked)]
-#![cfg_attr(bootstrap, feature(doc_spotlight))]
-#![cfg_attr(not(bootstrap), feature(doc_notable_trait))]
+#![feature(doc_notable_trait)]
 #![feature(dropck_eyepatch)]
 #![feature(duration_constants)]
 #![feature(edition_panic)]
 #![feature(exact_size_is_empty)]
 #![feature(exhaustive_patterns)]
 #![feature(extend_one)]
-#![feature(extended_key_value_attributes)]
+#![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
 #![feature(fn_traits)]
 #![feature(format_args_nl)]
 #![feature(gen_future)]
@@ -300,7 +299,6 @@
 #![feature(nonnull_slice_from_raw_parts)]
 #![feature(once_cell)]
 #![feature(auto_traits)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
 #![feature(panic_unwind)]
@@ -530,7 +528,6 @@ mod sys;
 pub mod alloc;
 
 // Private support modules
-mod memchr;
 mod panicking;
 
 // The runtime entry point and a few unstable public functions used by the
diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs
index 9b629e19be5..6c2f2eeabd6 100644
--- a/library/std/src/net/ip.rs
+++ b/library/std/src/net/ip.rs
@@ -1,11 +1,3 @@
-#![unstable(
-    feature = "ip",
-    reason = "extra functionality has not been \
-                                      scrutinized to the level that it should \
-                                      be to be stable",
-    issue = "27709"
-)]
-
 // Tests for this module
 #[cfg(all(test, not(target_os = "emscripten")))]
 mod tests;
@@ -126,6 +118,7 @@ pub struct Ipv6Addr {
 
 #[allow(missing_docs)]
 #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+#[unstable(feature = "ip", issue = "27709")]
 pub enum Ipv6MulticastScope {
     InterfaceLocal,
     LinkLocal,
@@ -199,6 +192,7 @@ impl IpAddr {
     /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true);
     /// ```
     #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_global(&self) -> bool {
         match self {
@@ -249,6 +243,7 @@ impl IpAddr {
     /// );
     /// ```
     #[rustc_const_unstable(feature = "const_ip", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_documentation(&self) -> bool {
         match self {
@@ -549,6 +544,7 @@ impl Ipv4Addr {
     /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_global(&self) -> bool {
         // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
@@ -587,6 +583,7 @@ impl Ipv4Addr {
     /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_shared(&self) -> bool {
         self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
@@ -620,6 +617,7 @@ impl Ipv4Addr {
     /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_ietf_protocol_assignment(&self) -> bool {
         self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
@@ -644,6 +642,7 @@ impl Ipv4Addr {
     /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_benchmarking(&self) -> bool {
         self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
@@ -677,6 +676,7 @@ impl Ipv4Addr {
     /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_reserved(&self) -> bool {
         self.octets()[0] & 240 == 240 && !self.is_broadcast()
@@ -1234,6 +1234,7 @@ impl Ipv6Addr {
     /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_global(&self) -> bool {
         match self.multicast_scope() {
@@ -1260,83 +1261,37 @@ impl Ipv6Addr {
     /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_unique_local(&self) -> bool {
         (self.segments()[0] & 0xfe00) == 0xfc00
     }
 
-    /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`).
+    /// Returns `true` if the address is a unicast address with link-local scope,
+    /// as defined in [RFC 4291].
     ///
-    /// A common misconception is to think that "unicast link-local addresses start with
-    /// `fe80::`", but [IETF RFC 4291] actually defines a stricter format for these addresses:
+    /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4].
+    /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6],
+    /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format:
     ///
-    /// ```no_rust
-    /// |   10     |
-    /// |  bits    |         54 bits         |          64 bits           |
+    /// ```text
+    /// | 10 bits  |         54 bits         |          64 bits           |
     /// +----------+-------------------------+----------------------------+
     /// |1111111010|           0             |       interface ID         |
     /// +----------+-------------------------+----------------------------+
     /// ```
+    /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`,
+    /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated,
+    /// and those addresses will have link-local scope.
     ///
-    /// This method validates the format defined in the RFC and won't recognize addresses
-    /// like `fe80:0:0:1::` or `fe81::` as unicast link-local addresses.
-    /// If you need a less strict validation, use [`Ipv6Addr::is_unicast_link_local()`] instead.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(ip)]
-    ///
-    /// use std::net::Ipv6Addr;
-    ///
-    /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
-    /// assert!(ip.is_unicast_link_local_strict());
-    ///
-    /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
-    /// assert!(ip.is_unicast_link_local_strict());
-    ///
-    /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
-    /// assert!(!ip.is_unicast_link_local_strict());
-    /// assert!(ip.is_unicast_link_local());
-    ///
-    /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
-    /// assert!(!ip.is_unicast_link_local_strict());
-    /// assert!(ip.is_unicast_link_local());
-    /// ```
-    ///
-    /// # See also
-    ///
-    /// - [IETF RFC 4291 section 2.5.6]
-    /// - [RFC 4291 errata 4406] (which has been rejected but provides useful
-    ///   insight)
-    /// - [`Ipv6Addr::is_unicast_link_local()`]
+    /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope",
+    /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it.
     ///
-    /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291
-    /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
-    /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
-    #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
-    #[inline]
-    pub const fn is_unicast_link_local_strict(&self) -> bool {
-        matches!(self.segments(), [0xfe80, 0, 0, 0, ..])
-    }
-
-    /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`).
-    ///
-    /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4],
-    /// i.e. addresses with the following format:
-    ///
-    /// ```no_rust
-    /// |   10     |
-    /// |  bits    |         54 bits         |          64 bits           |
-    /// +----------+-------------------------+----------------------------+
-    /// |1111111010|    arbitratry value     |       interface ID         |
-    /// +----------+-------------------------+----------------------------+
-    /// ```
-    ///
-    /// As a result, this method considers addresses such as `fe80:0:0:1::` or `fe81::` to be
-    /// unicast link-local addresses, whereas [`Ipv6Addr::is_unicast_link_local_strict()`] does not.
-    /// If you need a strict validation fully compliant with the RFC, use
-    /// [`Ipv6Addr::is_unicast_link_local_strict()`] instead.
+    /// [RFC 4291]: https://tools.ietf.org/html/rfc4291
+    /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
+    /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3
+    /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6
+    /// [loopback address]: Ipv6Addr::LOCALHOST
     ///
     /// # Examples
     ///
@@ -1345,30 +1300,19 @@ impl Ipv6Addr {
     ///
     /// use std::net::Ipv6Addr;
     ///
-    /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0);
-    /// assert!(ip.is_unicast_link_local());
+    /// // The loopback address (`::1`) does not actually have link-local scope.
+    /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false);
     ///
-    /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff);
-    /// assert!(ip.is_unicast_link_local());
+    /// // Only addresses in `fe80::/10` have link-local scope.
+    /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false);
+    /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
     ///
-    /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0);
-    /// assert!(ip.is_unicast_link_local());
-    /// assert!(!ip.is_unicast_link_local_strict());
-    ///
-    /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0);
-    /// assert!(ip.is_unicast_link_local());
-    /// assert!(!ip.is_unicast_link_local_strict());
+    /// // Addresses outside the stricter `fe80::/64` also have link-local scope.
+    /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true);
+    /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true);
     /// ```
-    ///
-    /// # See also
-    ///
-    /// - [IETF RFC 4291 section 2.4]
-    /// - [RFC 4291 errata 4406] (which has been rejected but provides useful
-    ///   insight)
-    ///
-    /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4
-    /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_unicast_link_local(&self) -> bool {
         (self.segments()[0] & 0xffc0) == 0xfe80
@@ -1409,6 +1353,7 @@ impl Ipv6Addr {
     ///
     /// [RFC 3879]: https://tools.ietf.org/html/rfc3879
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_unicast_site_local(&self) -> bool {
         (self.segments()[0] & 0xffc0) == 0xfec0
@@ -1432,6 +1377,7 @@ impl Ipv6Addr {
     /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_documentation(&self) -> bool {
         (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8)
@@ -1468,6 +1414,7 @@ impl Ipv6Addr {
     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn is_unicast_global(&self) -> bool {
         !self.is_multicast()
@@ -1494,6 +1441,7 @@ impl Ipv6Addr {
     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
         if self.is_multicast() {
@@ -1555,6 +1503,7 @@ impl Ipv6Addr {
     /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None);
     /// ```
     #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
+    #[unstable(feature = "ip", issue = "27709")]
     #[inline]
     pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> {
         match self.octets() {
diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs
index ef0d4edc434..05f8dea0b7c 100644
--- a/library/std/src/net/ip/tests.rs
+++ b/library/std/src/net/ip/tests.rs
@@ -480,7 +480,6 @@ fn ipv6_properties() {
             let unique_local: u16 = 1 << 2;
             let global: u16 = 1 << 3;
             let unicast_link_local: u16 = 1 << 4;
-            let unicast_link_local_strict: u16 = 1 << 5;
             let unicast_site_local: u16 = 1 << 6;
             let unicast_global: u16 = 1 << 7;
             let documentation: u16 = 1 << 8;
@@ -524,11 +523,6 @@ fn ipv6_properties() {
             } else {
                 assert!(!ip!($s).is_unicast_link_local());
             }
-            if ($mask & unicast_link_local_strict) == unicast_link_local_strict {
-                assert!(ip!($s).is_unicast_link_local_strict());
-            } else {
-                assert!(!ip!($s).is_unicast_link_local_strict());
-            }
             if ($mask & unicast_site_local) == unicast_site_local {
                 assert!(ip!($s).is_unicast_site_local());
             } else {
@@ -587,7 +581,6 @@ fn ipv6_properties() {
     let unique_local: u16 = 1 << 2;
     let global: u16 = 1 << 3;
     let unicast_link_local: u16 = 1 << 4;
-    let unicast_link_local_strict: u16 = 1 << 5;
     let unicast_site_local: u16 = 1 << 6;
     let unicast_global: u16 = 1 << 7;
     let documentation: u16 = 1 << 8;
@@ -621,11 +614,7 @@ fn ipv6_properties() {
         unicast_link_local
     );
 
-    check!(
-        "fe80::",
-        &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-        unicast_link_local | unicast_link_local_strict
-    );
+    check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local);
 
     check!(
         "febf:ffff::",
@@ -650,7 +639,7 @@ fn ipv6_properties() {
             0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
             0xff, 0xff
         ],
-        unicast_link_local | unicast_link_local_strict
+        unicast_link_local
     );
 
     check!(
@@ -897,9 +886,6 @@ fn ipv6_const() {
     const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local();
     assert!(!IS_UNIQUE_LOCAL);
 
-    const IS_UNICAST_LINK_LOCAL_STRICT: bool = IP_ADDRESS.is_unicast_link_local_strict();
-    assert!(!IS_UNICAST_LINK_LOCAL_STRICT);
-
     const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local();
     assert!(!IS_UNICAST_LINK_LOCAL);
 
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 9cf51be2836..913c71d4108 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -906,7 +906,7 @@ impl DirBuilderExt for fs::DirBuilder {
 /// }
 /// ```
 #[unstable(feature = "unix_chroot", issue = "84715")]
-#[cfg(not(target_os = "fuchsia"))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
 pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> {
     sys::fs::chroot(dir.as_ref())
 }
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index f014a3d7b25..3dc389b7582 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -201,22 +201,32 @@ impl CommandExt for process::Command {
     }
 }
 
-/// Unix-specific extensions to [`process::ExitStatus`].
+/// Unix-specific extensions to [`process::ExitStatus`] and
+/// [`ExitStatusError`](process::ExitStatusError).
 ///
-/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as passed to the
-/// `exit` system call or returned by [`ExitStatus::code()`](crate::process::ExitStatus::code).
-/// It represents **any wait status**, as returned by one of the `wait` family of system calls.
+/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as
+/// passed to the `exit` system call or returned by
+/// [`ExitStatus::code()`](crate::process::ExitStatus::code).  It represents **any wait status**
+/// as returned by one of the `wait` family of system
+/// calls.
 ///
-/// This is because a Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but
-/// can also represent other kinds of process event.
+/// A Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but can also
+/// represent other kinds of process event.
 ///
 /// This trait is sealed: it cannot be implemented outside the standard library.
 /// This is so that future additional methods are not breaking changes.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait ExitStatusExt: Sealed {
-    /// Creates a new `ExitStatus` from the raw underlying integer status value from `wait`
+    /// Creates a new `ExitStatus` or `ExitStatusError` from the raw underlying integer status
+    /// value from `wait`
     ///
     /// The value should be a **wait status, not an exit status**.
+    ///
+    /// # Panics
+    ///
+    /// Panics on an attempt to make an `ExitStatusError` from a wait status of `0`.
+    ///
+    /// Making an `ExitStatus` always succeds and never panics.
     #[stable(feature = "exit_status_from", since = "1.12.0")]
     fn from_raw(raw: i32) -> Self;
 
@@ -278,6 +288,35 @@ impl ExitStatusExt for process::ExitStatus {
     }
 }
 
+#[unstable(feature = "exit_status_error", issue = "84908")]
+impl ExitStatusExt for process::ExitStatusError {
+    fn from_raw(raw: i32) -> Self {
+        process::ExitStatus::from_raw(raw)
+            .exit_ok()
+            .expect_err("<ExitStatusError as ExitStatusExt>::from_raw(0) but zero is not an error")
+    }
+
+    fn signal(&self) -> Option<i32> {
+        self.into_status().signal()
+    }
+
+    fn core_dumped(&self) -> bool {
+        self.into_status().core_dumped()
+    }
+
+    fn stopped_signal(&self) -> Option<i32> {
+        self.into_status().stopped_signal()
+    }
+
+    fn continued(&self) -> bool {
+        self.into_status().continued()
+    }
+
+    fn into_raw(self) -> i32 {
+        self.into_status().into_raw()
+    }
+}
+
 #[stable(feature = "process_extensions", since = "1.2.0")]
 impl FromRawFd for process::Stdio {
     #[inline]
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index b10dde42482..9e3880dfd41 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -55,6 +55,7 @@ pub use core::panic::{Location, PanicInfo};
 /// See the [`panic!`] macro for more information about panicking.
 #[stable(feature = "panic_any", since = "1.51.0")]
 #[inline]
+#[track_caller]
 pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! {
     crate::panicking::begin_panic(msg);
 }
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index a8410bea734..02957e75a74 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -20,7 +20,7 @@ use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sys::stdio::panic_output;
 use crate::sys_common::backtrace::{self, RustBacktrace};
 use crate::sys_common::rwlock::RWLock;
-use crate::sys_common::{thread_info, util};
+use crate::sys_common::thread_info;
 use crate::thread;
 
 #[cfg(not(test))]
@@ -596,15 +596,12 @@ fn rust_panic_with_hook(
         if panics > 2 {
             // Don't try to print the message in this case
             // - perhaps that is causing the recursive panics.
-            util::dumb_print(format_args!("thread panicked while processing panic. aborting.\n"));
+            rtprintpanic!("thread panicked while processing panic. aborting.\n");
         } else {
             // Unfortunately, this does not print a backtrace, because creating
             // a `Backtrace` will allocate, which we must to avoid here.
             let panicinfo = PanicInfo::internal_constructor(message, location);
-            util::dumb_print(format_args!(
-                "{}\npanicked after panic::always_abort(), aborting.\n",
-                panicinfo
-            ));
+            rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo);
         }
         intrinsics::abort()
     }
@@ -637,7 +634,7 @@ fn rust_panic_with_hook(
         // have limited options. Currently our preference is to
         // just abort. In the future we may consider resuming
         // unwinding or otherwise exiting the thread cleanly.
-        util::dumb_print(format_args!("thread panicked while panicking. aborting.\n"));
+        rtprintpanic!("thread panicked while panicking. aborting.\n");
         intrinsics::abort()
     }
 
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index cbe14767bd3..9c5615f58c4 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2507,11 +2507,7 @@ impl Path {
     #[unstable(feature = "path_try_exists", issue = "83186")]
     #[inline]
     pub fn try_exists(&self) -> io::Result<bool> {
-        match fs::metadata(self) {
-            Ok(_) => Ok(true),
-            Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),
-            Err(error) => Err(error),
-        }
+        fs::try_exists(self)
     }
 
     /// Returns `true` if the path exists on disk and is pointing at a regular file.
diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs
index 1b4facdd049..12d52cc8e0b 100644
--- a/library/std/src/prelude/mod.rs
+++ b/library/std/src/prelude/mod.rs
@@ -88,9 +88,9 @@ pub mod v1;
 /// The 2015 version of the prelude of The Rust Standard Library.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2015", issue = "none")]
+#[unstable(feature = "prelude_2015", issue = "85684")]
 pub mod rust_2015 {
-    #[unstable(feature = "prelude_2015", issue = "none")]
+    #[unstable(feature = "prelude_2015", issue = "85684")]
     #[doc(no_inline)]
     pub use super::v1::*;
 }
@@ -98,9 +98,9 @@ pub mod rust_2015 {
 /// The 2018 version of the prelude of The Rust Standard Library.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2018", issue = "none")]
+#[unstable(feature = "prelude_2018", issue = "85684")]
 pub mod rust_2018 {
-    #[unstable(feature = "prelude_2018", issue = "none")]
+    #[unstable(feature = "prelude_2018", issue = "85684")]
     #[doc(no_inline)]
     pub use super::v1::*;
 }
@@ -108,13 +108,13 @@ pub mod rust_2018 {
 /// The 2021 version of the prelude of The Rust Standard Library.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2021", issue = "none")]
+#[unstable(feature = "prelude_2021", issue = "85684")]
 pub mod rust_2021 {
-    #[unstable(feature = "prelude_2021", issue = "none")]
+    #[unstable(feature = "prelude_2021", issue = "85684")]
     #[doc(no_inline)]
     pub use super::v1::*;
 
-    #[unstable(feature = "prelude_2021", issue = "none")]
+    #[unstable(feature = "prelude_2021", issue = "85684")]
     #[doc(no_inline)]
     pub use core::prelude::rust_2021::*;
 }
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
index 96ab32104ea..8a3e425350a 100644
--- a/library/std/src/primitive_docs.rs
+++ b/library/std/src/primitive_docs.rs
@@ -345,6 +345,9 @@ mod prim_never {}
 mod prim_char {}
 
 #[doc(primitive = "unit")]
+#[doc(alias = "(")]
+#[doc(alias = ")")]
+#[doc(alias = "()")]
 //
 /// The `()` type, also called "unit".
 ///
@@ -537,8 +540,7 @@ mod prim_pointer {}
 ///
 /// # Examples
 ///
-#[cfg_attr(bootstrap, doc = "```ignore")]
-#[cfg_attr(not(bootstrap), doc = "```")]
+/// ```
 /// let mut array: [i32; 3] = [0; 3];
 ///
 /// array[1] = 1;
@@ -578,8 +580,7 @@ mod prim_pointer {}
 /// `IntoIterator` by value. In the future, the behavior on the 2015 and 2018 edition
 /// might be made consistent to the behavior of later editions.
 ///
-#[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")]
-#[cfg_attr(not(bootstrap), doc = "```rust,edition2018")]
+/// ```rust,edition2018
 /// # #![allow(array_into_iter)] // override our `deny(warnings)`
 /// let array: [i32; 3] = [0; 3];
 ///
@@ -634,8 +635,7 @@ mod prim_pointer {}
 /// * replace `for ... in array.into_iter() {` with `for ... in array {`,
 ///   equivalent to the post-2021 behavior (Rust 1.53+)
 ///
-#[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")]
-#[cfg_attr(not(bootstrap), doc = "```rust,edition2018")]
+/// ```rust,edition2018
 /// use std::array::IntoIter;
 ///
 /// let array: [i32; 3] = [0; 3];
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index b45c620fd0b..6903ba90560 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -110,6 +110,7 @@ use crate::ffi::OsStr;
 use crate::fmt;
 use crate::fs;
 use crate::io::{self, Initializer, IoSlice, IoSliceMut};
+use crate::num::NonZeroI32;
 use crate::path::Path;
 use crate::str;
 use crate::sys::pipe::{read2, AnonPipe};
@@ -1387,8 +1388,8 @@ impl From<fs::File> for Stdio {
 /// An `ExitStatus` represents every possible disposition of a process.  On Unix this
 /// is the **wait status**.  It is *not* simply an *exit status* (a value passed to `exit`).
 ///
-/// For proper error reporting of failed processes, print the value of `ExitStatus` using its
-/// implementation of [`Display`](crate::fmt::Display).
+/// For proper error reporting of failed processes, print the value of `ExitStatus` or
+/// `ExitStatusError` using their implementations of [`Display`](crate::fmt::Display).
 ///
 /// [`status`]: Command::status
 /// [`wait`]: Child::wait
@@ -1401,6 +1402,29 @@ pub struct ExitStatus(imp::ExitStatus);
 impl crate::sealed::Sealed for ExitStatus {}
 
 impl ExitStatus {
+    /// Was termination successful?  Returns a `Result`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(exit_status_error)]
+    /// # if cfg!(unix) {
+    /// use std::process::Command;
+    ///
+    /// let status = Command::new("ls")
+    ///                      .arg("/dev/nonexistent")
+    ///                      .status()
+    ///                      .expect("ls could not be executed");
+    ///
+    /// println!("ls: {}", status);
+    /// status.exit_ok().expect_err("/dev/nonexistent could be listed!");
+    /// # } // cfg!(unix)
+    /// ```
+    #[unstable(feature = "exit_status_error", issue = "84908")]
+    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
+        self.0.exit_ok().map_err(ExitStatusError)
+    }
+
     /// Was termination successful? Signal termination is not considered a
     /// success, and success is defined as a zero exit status.
     ///
@@ -1422,7 +1446,7 @@ impl ExitStatus {
     /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn success(&self) -> bool {
-        self.0.success()
+        self.0.exit_ok().is_ok()
     }
 
     /// Returns the exit code of the process, if any.
@@ -1476,6 +1500,120 @@ impl fmt::Display for ExitStatus {
     }
 }
 
+/// Allows extension traits within `std`.
+#[unstable(feature = "sealed", issue = "none")]
+impl crate::sealed::Sealed for ExitStatusError {}
+
+/// Describes the result of a process after it has failed
+///
+/// Produced by the [`.exit_ok`](ExitStatus::exit_ok) method on [`ExitStatus`].
+///
+/// # Examples
+///
+/// ```
+/// #![feature(exit_status_error)]
+/// # if cfg!(unix) {
+/// use std::process::{Command, ExitStatusError};
+///
+/// fn run(cmd: &str) -> Result<(),ExitStatusError> {
+///     Command::new(cmd).status().unwrap().exit_ok()?;
+///     Ok(())
+/// }
+///
+/// run("true").unwrap();
+/// run("false").unwrap_err();
+/// # } // cfg!(unix)
+/// ```
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[unstable(feature = "exit_status_error", issue = "84908")]
+// The definition of imp::ExitStatusError should ideally be such that
+// Result<(), imp::ExitStatusError> has an identical representation to imp::ExitStatus.
+pub struct ExitStatusError(imp::ExitStatusError);
+
+#[unstable(feature = "exit_status_error", issue = "84908")]
+impl ExitStatusError {
+    /// Reports the exit code, if applicable, from an `ExitStatusError`.
+    ///
+    /// In Unix terms the return value is the **exit status**: the value passed to `exit`, if the
+    /// process finished by calling `exit`.  Note that on Unix the exit status is truncated to 8
+    /// bits, and that values that didn't come from a program's call to `exit` may be invented by the
+    /// runtime system (often, for example, 255, 254, 127 or 126).
+    ///
+    /// On Unix, this will return `None` if the process was terminated by a signal.  If you want to
+    /// handle such situations specially, consider using methods from
+    /// [`ExitStatusExt`](crate::os::unix::process::ExitStatusExt).
+    ///
+    /// If the process finished by calling `exit` with a nonzero value, this will return
+    /// that exit status.
+    ///
+    /// If the error was something else, it will return `None`.
+    ///
+    /// If the process exited successfully (ie, by calling `exit(0)`), there is no
+    /// `ExitStatusError`.  So the return value from `ExitStatusError::code()` is always nonzero.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(exit_status_error)]
+    /// # #[cfg(unix)] {
+    /// use std::process::Command;
+    ///
+    /// let bad = Command::new("false").status().unwrap().exit_ok().unwrap_err();
+    /// assert_eq!(bad.code(), Some(1));
+    /// # } // #[cfg(unix)]
+    /// ```
+    pub fn code(&self) -> Option<i32> {
+        self.code_nonzero().map(Into::into)
+    }
+
+    /// Reports the exit code, if applicable, from an `ExitStatusError`, as a `NonZero`
+    ///
+    /// This is exaclty like [`code()`](Self::code), except that it returns a `NonZeroI32`.
+    ///
+    /// Plain `code`, returning a plain integer, is provided because is is often more convenient.
+    /// The returned value from `code()` is indeed also nonzero; use `code_nonzero()` when you want
+    /// a type-level guarantee of nonzeroness.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(exit_status_error)]
+    /// # if cfg!(unix) {
+    /// use std::convert::TryFrom;
+    /// use std::num::NonZeroI32;
+    /// use std::process::Command;
+    ///
+    /// let bad = Command::new("false").status().unwrap().exit_ok().unwrap_err();
+    /// assert_eq!(bad.code_nonzero().unwrap(), NonZeroI32::try_from(1).unwrap());
+    /// # } // cfg!(unix)
+    /// ```
+    pub fn code_nonzero(&self) -> Option<NonZeroI32> {
+        self.0.code()
+    }
+
+    /// Converts an `ExitStatusError` (back) to an `ExitStatus`.
+    pub fn into_status(&self) -> ExitStatus {
+        ExitStatus(self.0.into())
+    }
+}
+
+#[unstable(feature = "exit_status_error", issue = "84908")]
+impl Into<ExitStatus> for ExitStatusError {
+    fn into(self) -> ExitStatus {
+        ExitStatus(self.0.into())
+    }
+}
+
+#[unstable(feature = "exit_status_error", issue = "84908")]
+impl fmt::Display for ExitStatusError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "process exited unsuccessfully: {}", self.into_status())
+    }
+}
+
+#[unstable(feature = "exit_status_error", issue = "84908")]
+impl crate::error::Error for ExitStatusError {}
+
 /// This type represents the status code a process can return to its
 /// parent under normal termination.
 ///
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index 773ab18b2ce..e7c5479ab9b 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -294,8 +294,14 @@ impl<T: ?Sized> Mutex<T> {
     /// # Errors
     ///
     /// If another user of this mutex panicked while holding the mutex, then
-    /// this call will return an error if the mutex would otherwise be
-    /// acquired.
+    /// this call will return the [`Poisoned`] error if the mutex would
+    /// otherwise be acquired.
+    ///
+    /// If the mutex could not be acquired because it is already locked, then
+    /// this call will return the [`WouldBlock`] error.
+    ///
+    /// [`Poisoned`]: TryLockError::Poisoned
+    /// [`WouldBlock`]: TryLockError::WouldBlock
     ///
     /// # Examples
     ///
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index b01bcec1361..9d521ab14cb 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -199,11 +199,17 @@ impl<T: ?Sized> RwLock<T> {
     ///
     /// # Errors
     ///
-    /// This function will return an error if the RwLock is poisoned. An RwLock
-    /// is poisoned whenever a writer panics while holding an exclusive lock. An
-    /// error will only be returned if the lock would have otherwise been
+    /// This function will return the [`Poisoned`] error if the RwLock is poisoned.
+    /// An RwLock is poisoned whenever a writer panics while holding an exclusive
+    /// lock. `Poisoned` will only be returned if the lock would have otherwise been
     /// acquired.
     ///
+    /// This function will return the [`WouldBlock`] error if the RwLock could not
+    /// be acquired because it was already locked exclusively.
+    ///
+    /// [`Poisoned`]: TryLockError::Poisoned
+    /// [`WouldBlock`]: TryLockError::WouldBlock
+    ///
     /// # Examples
     ///
     /// ```
@@ -281,10 +287,17 @@ impl<T: ?Sized> RwLock<T> {
     ///
     /// # Errors
     ///
-    /// This function will return an error if the RwLock is poisoned. An RwLock
-    /// is poisoned whenever a writer panics while holding an exclusive lock. An
-    /// error will only be returned if the lock would have otherwise been
-    /// acquired.
+    /// This function will return the [`Poisoned`] error if the RwLock is
+    /// poisoned. An RwLock is poisoned whenever a writer panics while holding
+    /// an exclusive lock. `Poisoned` will only be returned if the lock would have
+    /// otherwise been acquired.
+    ///
+    /// This function will return the [`WouldBlock`] error if the RwLock could not
+    /// be acquired because it was already locked exclusively.
+    ///
+    /// [`Poisoned`]: TryLockError::Poisoned
+    /// [`WouldBlock`]: TryLockError::WouldBlock
+    ///
     ///
     /// # Examples
     ///
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index 5b3f2fa4e82..76ea70d997f 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -12,7 +12,7 @@ use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
 use crate::sys_common::os_str_bytes::OsStrExt;
 
-pub use crate::sys_common::fs::copy;
+pub use crate::sys_common::fs::{copy, try_exists};
 //pub use crate::sys_common::fs::remove_dir_all;
 
 fn cstr(path: &Path) -> io::Result<CString> {
diff --git a/library/std/src/sys/hermit/os.rs b/library/std/src/sys/hermit/os.rs
index 81cd68a74e6..40bd393098f 100644
--- a/library/std/src/sys/hermit/os.rs
+++ b/library/std/src/sys/hermit/os.rs
@@ -4,11 +4,11 @@ use crate::ffi::{CStr, OsStr, OsString};
 use crate::fmt;
 use crate::io;
 use crate::marker::PhantomData;
-use crate::memchr;
 use crate::path::{self, PathBuf};
 use crate::str;
 use crate::sync::Mutex;
 use crate::sys::hermit::abi;
+use crate::sys::memchr;
 use crate::sys::unsupported;
 use crate::sys_common::os_str_bytes::*;
 use crate::vec;
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 79617aa77b7..f8ca67c844c 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -48,7 +48,7 @@ use libc::{
     dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, readdir64_r, stat64,
 };
 
-pub use crate::sys_common::fs::remove_dir_all;
+pub use crate::sys_common::fs::{remove_dir_all, try_exists};
 
 pub struct File(FileDesc);
 
@@ -1329,7 +1329,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
     Ok(bytes_copied as u64)
 }
 
-#[cfg(not(target_os = "fuchsia"))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))]
 pub fn chroot(dir: &Path) -> io::Result<()> {
     let dir = cstr(dir)?;
     cvt(unsafe { libc::chroot(dir.as_ptr()) })?;
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 57d91441b6f..ca9cc8ca7ba 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -210,7 +210,6 @@ cfg_if::cfg_if! {
     if #[cfg(target_os = "android")] {
         #[link(name = "dl")]
         #[link(name = "log")]
-        #[link(name = "gcc")]
         extern "C" {}
     } else if #[cfg(target_os = "freebsd")] {
         #[link(name = "execinfo")]
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index e6b61062d15..d5a15964c08 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -62,7 +62,7 @@ impl Socket {
                     target_os = "illumos",
                     target_os = "linux",
                     target_os = "netbsd",
-                    target_os = "opensbd",
+                    target_os = "openbsd",
                 ))] {
                     // On platforms that support it we pass the SOCK_CLOEXEC
                     // flag to atomically create the socket and set it as
@@ -99,7 +99,7 @@ impl Socket {
                     target_os = "illumos",
                     target_os = "linux",
                     target_os = "netbsd",
-                    target_os = "opensbd",
+                    target_os = "openbsd",
                 ))] {
                     // Like above, set cloexec atomically
                     cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
@@ -204,7 +204,7 @@ impl Socket {
                 target_os = "illumos",
                 target_os = "linux",
                 target_os = "netbsd",
-                target_os = "opensbd",
+                target_os = "openbsd",
             ))] {
                 let fd = cvt_r(|| unsafe {
                     libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 51c3e5d175c..bbc4691d963 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -13,13 +13,13 @@ use crate::fmt;
 use crate::io;
 use crate::iter;
 use crate::mem;
-use crate::memchr;
 use crate::path::{self, PathBuf};
 use crate::ptr;
 use crate::slice;
 use crate::str;
 use crate::sys::cvt;
 use crate::sys::fd;
+use crate::sys::memchr;
 use crate::sys::rwlock::{RWLockReadGuard, StaticRWLock};
 use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard};
 use crate::vec;
diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs
index f67c70c0177..b5a19ed54a2 100644
--- a/library/std/src/sys/unix/process/mod.rs
+++ b/library/std/src/sys/unix/process/mod.rs
@@ -1,5 +1,5 @@
 pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes};
-pub use self::process_inner::{ExitStatus, Process};
+pub use self::process_inner::{ExitStatus, ExitStatusError, Process};
 pub use crate::ffi::OsString as EnvKey;
 pub use crate::sys_common::process::CommandEnvs;
 
diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs
index b19ad4ccdc7..507abb27871 100644
--- a/library/std/src/sys/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/unix/process/process_fuchsia.rs
@@ -1,7 +1,8 @@
-use crate::convert::TryInto;
+use crate::convert::{TryFrom, TryInto};
 use crate::fmt;
 use crate::io;
 use crate::mem;
+use crate::num::{NonZeroI32, NonZeroI64};
 use crate::ptr;
 
 use crate::sys::process::process_common::*;
@@ -236,8 +237,11 @@ impl Process {
 pub struct ExitStatus(i64);
 
 impl ExitStatus {
-    pub fn success(&self) -> bool {
-        self.code() == Some(0)
+    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
+        match NonZeroI64::try_from(self.0) {
+            /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
+            /* was zero, couldn't convert */ Err(_) => Ok(()),
+        }
     }
 
     pub fn code(&self) -> Option<i32> {
@@ -306,3 +310,19 @@ impl fmt::Display for ExitStatus {
         write!(f, "exit code: {}", self.0)
     }
 }
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatusError(NonZeroI64);
+
+impl Into<ExitStatus> for ExitStatusError {
+    fn into(self) -> ExitStatus {
+        ExitStatus(self.0.into())
+    }
+}
+
+impl ExitStatusError {
+    pub fn code(self) -> Option<NonZeroI32> {
+        // fixme: affected by the same bug as ExitStatus::code()
+        ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
+    }
+}
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 08b500b9c82..ed55e1aa715 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -1,7 +1,9 @@
-use crate::convert::TryInto;
+use crate::convert::{TryFrom, TryInto};
 use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
 use crate::mem;
+use crate::num::NonZeroI32;
+use crate::os::raw::NonZero_c_int;
 use crate::ptr;
 use crate::sys;
 use crate::sys::cvt;
@@ -491,8 +493,16 @@ impl ExitStatus {
         libc::WIFEXITED(self.0)
     }
 
-    pub fn success(&self) -> bool {
-        self.code() == Some(0)
+    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
+        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0.  This is
+        // true on all actual versions of Unix, is widely assumed, and is specified in SuS
+        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html .  If it is not
+        // true for a platform pretending to be Unix, the tests (our doctests, and also
+        // procsss_unix/tests.rs) will spot it.  `ExitStatusError::code` assumes this too.
+        match NonZero_c_int::try_from(self.0) {
+            /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
+            /* was zero, couldn't convert */ Err(_) => Ok(()),
+        }
     }
 
     pub fn code(&self) -> Option<i32> {
@@ -547,6 +557,21 @@ impl fmt::Display for ExitStatus {
     }
 }
 
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatusError(NonZero_c_int);
+
+impl Into<ExitStatus> for ExitStatusError {
+    fn into(self) -> ExitStatus {
+        ExitStatus(self.0.into())
+    }
+}
+
+impl ExitStatusError {
+    pub fn code(self) -> Option<NonZeroI32> {
+        ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
+    }
+}
+
 #[cfg(test)]
 #[path = "process_unix/tests.rs"]
 mod tests;
diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs
index eecdb624b9c..c17822f5125 100644
--- a/library/std/src/sys/unix/process/process_vxworks.rs
+++ b/library/std/src/sys/unix/process/process_vxworks.rs
@@ -1,5 +1,8 @@
+use crate::convert::{TryFrom, TryInto};
 use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
+use crate::num::NonZeroI32;
+use crate::os::raw::NonZero_c_int;
 use crate::sys;
 use crate::sys::cvt;
 use crate::sys::process::process_common::*;
@@ -187,8 +190,16 @@ impl ExitStatus {
         libc::WIFEXITED(self.0)
     }
 
-    pub fn success(&self) -> bool {
-        self.code() == Some(0)
+    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
+        // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0.  This is
+        // true on all actual versions of Unix, is widely assumed, and is specified in SuS
+        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html .  If it is not
+        // true for a platform pretending to be Unix, the tests (our doctests, and also
+        // procsss_unix/tests.rs) will spot it.  `ExitStatusError::code` assumes this too.
+        match NonZero_c_int::try_from(self.0) {
+            Ok(failure) => Err(ExitStatusError(failure)),
+            Err(_) => Ok(()),
+        }
     }
 
     pub fn code(&self) -> Option<i32> {
@@ -235,3 +246,18 @@ impl fmt::Display for ExitStatus {
         }
     }
 }
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatusError(NonZero_c_int);
+
+impl Into<ExitStatus> for ExitStatusError {
+    fn into(self) -> ExitStatus {
+        ExitStatus(self.0.into())
+    }
+}
+
+impl ExitStatusError {
+    pub fn code(self) -> Option<NonZeroI32> {
+        ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap())
+    }
+}
diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs
index 2a487fff54a..81f47a779d3 100644
--- a/library/std/src/sys/unix/stack_overflow.rs
+++ b/library/std/src/sys/unix/stack_overflow.rs
@@ -42,6 +42,7 @@ mod imp {
     use crate::io;
     use crate::mem;
     use crate::ptr;
+    use crate::thread;
 
     use libc::MAP_FAILED;
     use libc::{mmap, munmap};
@@ -95,15 +96,16 @@ mod imp {
         info: *mut libc::siginfo_t,
         _data: *mut libc::c_void,
     ) {
-        use crate::sys_common::util::report_overflow;
-
         let guard = thread_info::stack_guard().unwrap_or(0..0);
         let addr = siginfo_si_addr(info);
 
         // If the faulting address is within the guard page, then we print a
         // message saying so and abort.
         if guard.start <= addr && addr < guard.end {
-            report_overflow();
+            rtprintpanic!(
+                "\nthread '{}' has overflowed its stack\n",
+                thread::current().name().unwrap_or("<unknown>")
+            );
             rtabort!("stack overflow");
         } else {
             // Unregister ourselves by reverting back to the default behavior.
diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs
index cd533761e37..6b45e29c145 100644
--- a/library/std/src/sys/unsupported/fs.rs
+++ b/library/std/src/sys/unsupported/fs.rs
@@ -275,6 +275,10 @@ pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
     unsupported()
 }
 
+pub fn try_exists(_path: &Path) -> io::Result<bool> {
+    unsupported()
+}
+
 pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
     unsupported()
 }
diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs
index 38ac0a1ddd5..7846e43cfb5 100644
--- a/library/std/src/sys/unsupported/process.rs
+++ b/library/std/src/sys/unsupported/process.rs
@@ -2,6 +2,7 @@ use crate::ffi::OsStr;
 use crate::fmt;
 use crate::io;
 use crate::marker::PhantomData;
+use crate::num::NonZeroI32;
 use crate::path::Path;
 use crate::sys::fs::File;
 use crate::sys::pipe::AnonPipe;
@@ -97,7 +98,7 @@ impl fmt::Debug for Command {
 pub struct ExitStatus(!);
 
 impl ExitStatus {
-    pub fn success(&self) -> bool {
+    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
         self.0
     }
 
@@ -135,6 +136,21 @@ impl fmt::Display for ExitStatus {
 }
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatusError(ExitStatus);
+
+impl Into<ExitStatus> for ExitStatusError {
+    fn into(self) -> ExitStatus {
+        self.0.0
+    }
+}
+
+impl ExitStatusError {
+    pub fn code(self) -> Option<NonZeroI32> {
+        self.0.0
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
 pub struct ExitCode(bool);
 
 impl ExitCode {
diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs
index ed0f03e4b71..45e38f68b8c 100644
--- a/library/std/src/sys/wasi/fs.rs
+++ b/library/std/src/sys/wasi/fs.rs
@@ -14,7 +14,7 @@ use crate::sys::time::SystemTime;
 use crate::sys::unsupported;
 use crate::sys_common::FromInner;
 
-pub use crate::sys_common::fs::remove_dir_all;
+pub use crate::sys_common::fs::{remove_dir_all, try_exists};
 
 pub struct File {
     fd: WasiFd,
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 7ea6048e94a..b7efc884473 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -4,6 +4,7 @@
 #![cfg_attr(test, allow(dead_code))]
 #![unstable(issue = "none", feature = "windows_c")]
 
+use crate::os::raw::NonZero_c_ulong;
 use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort};
 use crate::ptr;
 
@@ -13,6 +14,7 @@ pub use self::EXCEPTION_DISPOSITION::*;
 pub use self::FILE_INFO_BY_HANDLE_CLASS::*;
 
 pub type DWORD = c_ulong;
+pub type NonZeroDWORD = NonZero_c_ulong;
 pub type HANDLE = LPVOID;
 pub type HINSTANCE = HANDLE;
 pub type HMODULE = HINSTANCE;
@@ -171,6 +173,7 @@ pub const ERROR_INVALID_HANDLE: DWORD = 6;
 pub const ERROR_NOT_ENOUGH_MEMORY: DWORD = 8;
 pub const ERROR_OUTOFMEMORY: DWORD = 14;
 pub const ERROR_NO_MORE_FILES: DWORD = 18;
+pub const ERROR_SHARING_VIOLATION: u32 = 32;
 pub const ERROR_HANDLE_EOF: DWORD = 38;
 pub const ERROR_FILE_EXISTS: DWORD = 80;
 pub const ERROR_INVALID_PARAMETER: DWORD = 87;
@@ -628,7 +631,7 @@ pub struct timeval {
     pub tv_usec: c_long,
 }
 
-// Functions forbidden when targeting UWP
+// Desktop specific functions & types
 cfg_if::cfg_if! {
 if #[cfg(not(target_vendor = "uwp"))] {
     pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
@@ -642,7 +645,7 @@ if #[cfg(not(target_vendor = "uwp"))] {
         pub ExceptionRecord: *mut EXCEPTION_RECORD,
         pub ExceptionAddress: LPVOID,
         pub NumberParameters: DWORD,
-        pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS]
+        pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS],
     }
 
     pub enum CONTEXT {}
@@ -653,8 +656,8 @@ if #[cfg(not(target_vendor = "uwp"))] {
         pub ContextRecord: *mut CONTEXT,
     }
 
-    pub type PVECTORED_EXCEPTION_HANDLER = extern "system"
-            fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG;
+    pub type PVECTORED_EXCEPTION_HANDLER =
+        extern "system" fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG;
 
     #[repr(C)]
     #[derive(Copy, Clone)]
@@ -688,44 +691,66 @@ if #[cfg(not(target_vendor = "uwp"))] {
 
     pub const TOKEN_READ: DWORD = 0x20008;
 
+    #[link(name = "advapi32")]
     extern "system" {
+        // Forbidden when targeting UWP
         #[link_name = "SystemFunction036"]
         pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
 
-        pub fn ReadConsoleW(hConsoleInput: HANDLE,
-                            lpBuffer: LPVOID,
-                            nNumberOfCharsToRead: DWORD,
-                            lpNumberOfCharsRead: LPDWORD,
-                            pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL;
+        // Allowed but unused by UWP
+        pub fn OpenProcessToken(
+            ProcessHandle: HANDLE,
+            DesiredAccess: DWORD,
+            TokenHandle: *mut HANDLE,
+        ) -> BOOL;
+    }
 
-        pub fn WriteConsoleW(hConsoleOutput: HANDLE,
-                             lpBuffer: LPCVOID,
-                             nNumberOfCharsToWrite: DWORD,
-                             lpNumberOfCharsWritten: LPDWORD,
-                             lpReserved: LPVOID) -> BOOL;
+    #[link(name = "userenv")]
+    extern "system" {
+        // Allowed but unused by UWP
+        pub fn GetUserProfileDirectoryW(
+            hToken: HANDLE,
+            lpProfileDir: LPWSTR,
+            lpcchSize: *mut DWORD,
+        ) -> BOOL;
+    }
 
-        pub fn GetConsoleMode(hConsoleHandle: HANDLE,
-                              lpMode: LPDWORD) -> BOOL;
+    #[link(name = "kernel32")]
+    extern "system" {
+        // Functions forbidden when targeting UWP
+        pub fn ReadConsoleW(
+            hConsoleInput: HANDLE,
+            lpBuffer: LPVOID,
+            nNumberOfCharsToRead: DWORD,
+            lpNumberOfCharsRead: LPDWORD,
+            pInputControl: PCONSOLE_READCONSOLE_CONTROL,
+        ) -> BOOL;
+
+        pub fn WriteConsoleW(
+            hConsoleOutput: HANDLE,
+            lpBuffer: LPCVOID,
+            nNumberOfCharsToWrite: DWORD,
+            lpNumberOfCharsWritten: LPDWORD,
+            lpReserved: LPVOID,
+        ) -> BOOL;
+
+        pub fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
         // Allowed but unused by UWP
-        pub fn OpenProcessToken(ProcessHandle: HANDLE,
-                                DesiredAccess: DWORD,
-                                TokenHandle: *mut HANDLE) -> BOOL;
-        pub fn GetUserProfileDirectoryW(hToken: HANDLE,
-                                        lpProfileDir: LPWSTR,
-                                        lpcchSize: *mut DWORD) -> BOOL;
-        pub fn GetFileInformationByHandle(hFile: HANDLE,
-                            lpFileInformation: LPBY_HANDLE_FILE_INFORMATION)
-                            -> BOOL;
-        pub fn SetHandleInformation(hObject: HANDLE,
-                                    dwMask: DWORD,
-                                    dwFlags: DWORD) -> BOOL;
-        pub fn AddVectoredExceptionHandler(FirstHandler: ULONG,
-                                           VectoredHandler: PVECTORED_EXCEPTION_HANDLER)
-                                           -> LPVOID;
-        pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR,
-                               lpTargetFileName: LPCWSTR,
-                               lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
-                               -> BOOL;
+        pub fn GetFileInformationByHandle(
+            hFile: HANDLE,
+            lpFileInformation: LPBY_HANDLE_FILE_INFORMATION,
+        ) -> BOOL;
+        pub fn SetHandleInformation(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) -> BOOL;
+        pub fn AddVectoredExceptionHandler(
+            FirstHandler: ULONG,
+            VectoredHandler: PVECTORED_EXCEPTION_HANDLER,
+        ) -> LPVOID;
+        pub fn CreateHardLinkW(
+            lpSymlinkFileName: LPCWSTR,
+            lpTargetFileName: LPCWSTR,
+            lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
+        ) -> BOOL;
+        pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL;
     }
 }
 }
@@ -744,55 +769,32 @@ if #[cfg(target_vendor = "uwp")] {
         pub Directory: BOOLEAN,
     }
 
+    #[link(name = "bcrypt")]
     extern "system" {
-        pub fn GetFileInformationByHandleEx(hFile: HANDLE,
-                                            fileInfoClass: FILE_INFO_BY_HANDLE_CLASS,
-                                            lpFileInformation: LPVOID,
-                                            dwBufferSize: DWORD) -> BOOL;
-        pub fn BCryptGenRandom(hAlgorithm: LPVOID, pBuffer: *mut u8,
-                               cbBuffer: ULONG, dwFlags: ULONG) -> LONG;
+        pub fn BCryptGenRandom(
+            hAlgorithm: LPVOID,
+            pBuffer: *mut u8,
+            cbBuffer: ULONG,
+            dwFlags: ULONG,
+        ) -> LONG;
+    }
+    #[link(name = "kernel32")]
+    extern "system" {
+        pub fn GetFileInformationByHandleEx(
+            hFile: HANDLE,
+            fileInfoClass: FILE_INFO_BY_HANDLE_CLASS,
+            lpFileInformation: LPVOID,
+            dwBufferSize: DWORD,
+        ) -> BOOL;
     }
 }
 }
 
 // Shared between Desktop & UWP
+
+#[link(name = "kernel32")]
 extern "system" {
-    pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int;
-    pub fn WSACleanup() -> c_int;
-    pub fn WSAGetLastError() -> c_int;
-    pub fn WSADuplicateSocketW(
-        s: SOCKET,
-        dwProcessId: DWORD,
-        lpProtocolInfo: LPWSAPROTOCOL_INFO,
-    ) -> c_int;
-    pub fn WSASend(
-        s: SOCKET,
-        lpBuffers: LPWSABUF,
-        dwBufferCount: DWORD,
-        lpNumberOfBytesSent: LPDWORD,
-        dwFlags: DWORD,
-        lpOverlapped: LPWSAOVERLAPPED,
-        lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
-    ) -> c_int;
-    pub fn WSARecv(
-        s: SOCKET,
-        lpBuffers: LPWSABUF,
-        dwBufferCount: DWORD,
-        lpNumberOfBytesRecvd: LPDWORD,
-        lpFlags: LPDWORD,
-        lpOverlapped: LPWSAOVERLAPPED,
-        lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
-    ) -> c_int;
     pub fn GetCurrentProcessId() -> DWORD;
-    pub fn WSASocketW(
-        af: c_int,
-        kind: c_int,
-        protocol: c_int,
-        lpProtocolInfo: LPWSAPROTOCOL_INFO,
-        g: GROUP,
-        dwFlags: DWORD,
-    ) -> SOCKET;
-    pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int;
     pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
     pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
     pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL;
@@ -879,28 +881,6 @@ extern "system" {
     pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
     pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD;
     pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
-
-    pub fn closesocket(socket: SOCKET) -> c_int;
-    pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int;
-    pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int;
-    pub fn recvfrom(
-        socket: SOCKET,
-        buf: *mut c_void,
-        len: c_int,
-        flags: c_int,
-        addr: *mut SOCKADDR,
-        addrlen: *mut c_int,
-    ) -> c_int;
-    pub fn sendto(
-        socket: SOCKET,
-        buf: *const c_void,
-        len: c_int,
-        flags: c_int,
-        addr: *const SOCKADDR,
-        addrlen: c_int,
-    ) -> c_int;
-    pub fn shutdown(socket: SOCKET, how: c_int) -> c_int;
-    pub fn accept(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET;
     pub fn DuplicateHandle(
         hSourceProcessHandle: HANDLE,
         hSourceHandle: HANDLE,
@@ -947,32 +927,6 @@ extern "system" {
     pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE;
     pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL;
     pub fn FindClose(findFile: HANDLE) -> BOOL;
-    pub fn getsockopt(
-        s: SOCKET,
-        level: c_int,
-        optname: c_int,
-        optval: *mut c_char,
-        optlen: *mut c_int,
-    ) -> c_int;
-    pub fn setsockopt(
-        s: SOCKET,
-        level: c_int,
-        optname: c_int,
-        optval: *const c_void,
-        optlen: c_int,
-    ) -> c_int;
-    pub fn getsockname(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int;
-    pub fn getpeername(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int;
-    pub fn bind(socket: SOCKET, address: *const SOCKADDR, address_len: socklen_t) -> c_int;
-    pub fn listen(socket: SOCKET, backlog: c_int) -> c_int;
-    pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int;
-    pub fn getaddrinfo(
-        node: *const c_char,
-        service: *const c_char,
-        hints: *const ADDRINFOA,
-        res: *mut *mut ADDRINFOA,
-    ) -> c_int;
-    pub fn freeaddrinfo(res: *mut ADDRINFOA);
 
     pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void;
     pub fn GetModuleHandleA(lpModuleName: LPCSTR) -> HMODULE;
@@ -1009,47 +963,23 @@ extern "system" {
         lpNumberOfBytesTransferred: LPDWORD,
         bWait: BOOL,
     ) -> BOOL;
-    pub fn select(
-        nfds: c_int,
-        readfds: *mut fd_set,
-        writefds: *mut fd_set,
-        exceptfds: *mut fd_set,
-        timeout: *const timeval,
-    ) -> c_int;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
     pub fn CreateSymbolicLinkW(
         lpSymlinkFileName: LPCWSTR,
         lpTargetFileName: LPCWSTR,
         dwFlags: DWORD,
     ) -> BOOLEAN;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
     pub fn GetFinalPathNameByHandleW(
         hFile: HANDLE,
         lpszFilePath: LPCWSTR,
         cchFilePath: DWORD,
         dwFlags: DWORD,
     ) -> DWORD;
-
-    // >= Vista / Server 2003
-    // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadstackguarantee
-    #[cfg(not(target_vendor = "uwp"))]
-    pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle
     pub fn SetFileInformationByHandle(
         hFile: HANDLE,
         FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
         lpFileInformation: LPVOID,
         dwBufferSize: DWORD,
     ) -> BOOL;
-
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleepconditionvariablesrw
     pub fn SleepConditionVariableSRW(
         ConditionVariable: PCONDITION_VARIABLE,
         SRWLock: PSRWLOCK,
@@ -1057,13 +987,9 @@ extern "system" {
         Flags: ULONG,
     ) -> BOOL;
 
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakeconditionvariable
     pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE);
     pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE);
 
-    // >= Vista / Server 2008
-    // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-acquiresrwlockexclusive
     pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK);
     pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK);
     pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK);
@@ -1072,6 +998,99 @@ extern "system" {
     pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN;
 }
 
+#[link(name = "ws2_32")]
+extern "system" {
+    pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int;
+    pub fn WSACleanup() -> c_int;
+    pub fn WSAGetLastError() -> c_int;
+    pub fn WSADuplicateSocketW(
+        s: SOCKET,
+        dwProcessId: DWORD,
+        lpProtocolInfo: LPWSAPROTOCOL_INFO,
+    ) -> c_int;
+    pub fn WSASend(
+        s: SOCKET,
+        lpBuffers: LPWSABUF,
+        dwBufferCount: DWORD,
+        lpNumberOfBytesSent: LPDWORD,
+        dwFlags: DWORD,
+        lpOverlapped: LPWSAOVERLAPPED,
+        lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
+    ) -> c_int;
+    pub fn WSARecv(
+        s: SOCKET,
+        lpBuffers: LPWSABUF,
+        dwBufferCount: DWORD,
+        lpNumberOfBytesRecvd: LPDWORD,
+        lpFlags: LPDWORD,
+        lpOverlapped: LPWSAOVERLAPPED,
+        lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
+    ) -> c_int;
+    pub fn WSASocketW(
+        af: c_int,
+        kind: c_int,
+        protocol: c_int,
+        lpProtocolInfo: LPWSAPROTOCOL_INFO,
+        g: GROUP,
+        dwFlags: DWORD,
+    ) -> SOCKET;
+    pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int;
+    pub fn closesocket(socket: SOCKET) -> c_int;
+    pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int;
+    pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int;
+    pub fn recvfrom(
+        socket: SOCKET,
+        buf: *mut c_void,
+        len: c_int,
+        flags: c_int,
+        addr: *mut SOCKADDR,
+        addrlen: *mut c_int,
+    ) -> c_int;
+    pub fn sendto(
+        socket: SOCKET,
+        buf: *const c_void,
+        len: c_int,
+        flags: c_int,
+        addr: *const SOCKADDR,
+        addrlen: c_int,
+    ) -> c_int;
+    pub fn shutdown(socket: SOCKET, how: c_int) -> c_int;
+    pub fn accept(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET;
+    pub fn getsockopt(
+        s: SOCKET,
+        level: c_int,
+        optname: c_int,
+        optval: *mut c_char,
+        optlen: *mut c_int,
+    ) -> c_int;
+    pub fn setsockopt(
+        s: SOCKET,
+        level: c_int,
+        optname: c_int,
+        optval: *const c_void,
+        optlen: c_int,
+    ) -> c_int;
+    pub fn getsockname(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int;
+    pub fn getpeername(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int;
+    pub fn bind(socket: SOCKET, address: *const SOCKADDR, address_len: socklen_t) -> c_int;
+    pub fn listen(socket: SOCKET, backlog: c_int) -> c_int;
+    pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int;
+    pub fn getaddrinfo(
+        node: *const c_char,
+        service: *const c_char,
+        hints: *const ADDRINFOA,
+        res: *mut *mut ADDRINFOA,
+    ) -> c_int;
+    pub fn freeaddrinfo(res: *mut ADDRINFOA);
+    pub fn select(
+        nfds: c_int,
+        readfds: *mut fd_set,
+        writefds: *mut fd_set,
+        exceptfds: *mut fd_set,
+        timeout: *const timeval,
+    ) -> c_int;
+}
+
 // Functions that aren't available on every version of Windows that we support,
 // but we still use them and just provide some form of a fallback implementation.
 compat_fn! {
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index 8e6bd76f85f..2b6143de960 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -944,3 +944,32 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
         .map(drop)
     }
 }
+
+// Try to see if a file exists but, unlike `exists`, report I/O errors.
+pub fn try_exists(path: &Path) -> io::Result<bool> {
+    // Open the file to ensure any symlinks are followed to their target.
+    let mut opts = OpenOptions::new();
+    // No read, write, etc access rights are needed.
+    opts.access_mode(0);
+    // Backup semantics enables opening directories as well as files.
+    opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
+    match File::open(path, &opts) {
+        Err(e) => match e.kind() {
+            // The file definitely does not exist
+            io::ErrorKind::NotFound => Ok(false),
+
+            // `ERROR_SHARING_VIOLATION` means that the file has been locked by
+            // another process. This is often temporary so we simply report it
+            // as the file existing.
+            io::ErrorKind::Other if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as i32) => {
+                Ok(true)
+            }
+            // Other errors such as `ERROR_ACCESS_DENIED` may indicate that the
+            // file exists. However, these types of errors are usually more
+            // permanent so we report them here.
+            _ => Err(e),
+        },
+        // The file was opened successfully therefore it must exist,
+        Ok(_) => Ok(true),
+    }
+}
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index cc60ca375ea..f23e874f249 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -281,17 +281,3 @@ pub fn abort_internal() -> ! {
     }
     crate::intrinsics::abort();
 }
-
-cfg_if::cfg_if! {
-    if #[cfg(target_vendor = "uwp")] {
-        #[link(name = "ws2_32")]
-        // For BCryptGenRandom
-        #[link(name = "bcrypt")]
-        extern "C" {}
-    } else {
-        #[link(name = "advapi32")]
-        #[link(name = "ws2_32")]
-        #[link(name = "userenv")]
-        extern "C" {}
-    }
-}
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index a5799606142..81dbea4a067 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -5,6 +5,7 @@ mod tests;
 
 use crate::borrow::Borrow;
 use crate::collections::BTreeMap;
+use crate::convert::{TryFrom, TryInto};
 use crate::env;
 use crate::env::split_paths;
 use crate::ffi::{OsStr, OsString};
@@ -12,10 +13,12 @@ use crate::fmt;
 use crate::fs;
 use crate::io::{self, Error, ErrorKind};
 use crate::mem;
+use crate::num::NonZeroI32;
 use crate::os::windows::ffi::OsStrExt;
 use crate::path::Path;
 use crate::ptr;
 use crate::sys::c;
+use crate::sys::c::NonZeroDWORD;
 use crate::sys::cvt;
 use crate::sys::fs::{File, OpenOptions};
 use crate::sys::handle::Handle;
@@ -376,8 +379,11 @@ impl Process {
 pub struct ExitStatus(c::DWORD);
 
 impl ExitStatus {
-    pub fn success(&self) -> bool {
-        self.0 == 0
+    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
+        match NonZeroDWORD::try_from(self.0) {
+            /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)),
+            /* was zero, couldn't convert */ Err(_) => Ok(()),
+        }
     }
     pub fn code(&self) -> Option<i32> {
         Some(self.0 as i32)
@@ -407,6 +413,21 @@ impl fmt::Display for ExitStatus {
 }
 
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatusError(c::NonZeroDWORD);
+
+impl Into<ExitStatus> for ExitStatusError {
+    fn into(self) -> ExitStatus {
+        ExitStatus(self.0.into())
+    }
+}
+
+impl ExitStatusError {
+    pub fn code(self) -> Option<NonZeroI32> {
+        Some((u32::from(self.0) as i32).try_into().unwrap())
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
 pub struct ExitCode(c::DWORD);
 
 impl ExitCode {
diff --git a/library/std/src/sys/windows/stack_overflow.rs b/library/std/src/sys/windows/stack_overflow.rs
index 39efb778207..755dc0a6c8b 100644
--- a/library/std/src/sys/windows/stack_overflow.rs
+++ b/library/std/src/sys/windows/stack_overflow.rs
@@ -1,7 +1,7 @@
 #![cfg_attr(test, allow(dead_code))]
 
 use crate::sys::c;
-use crate::sys_common::util::report_overflow;
+use crate::thread;
 
 pub struct Handler;
 
@@ -24,7 +24,10 @@ extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) -
         let code = rec.ExceptionCode;
 
         if code == c::EXCEPTION_STACK_OVERFLOW {
-            report_overflow();
+            rtprintpanic!(
+                "\nthread '{}' has overflowed its stack\n",
+                thread::current().name().unwrap_or("<unknown>")
+            );
         }
         c::EXCEPTION_CONTINUE_SEARCH
     }
diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys_common/fs.rs
index 30908824dd6..309f5483874 100644
--- a/library/std/src/sys_common/fs.rs
+++ b/library/std/src/sys_common/fs.rs
@@ -41,3 +41,11 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
     }
     fs::remove_dir(path)
 }
+
+pub fn try_exists(path: &Path) -> io::Result<bool> {
+    match fs::metadata(path) {
+        Ok(_) => Ok(true),
+        Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),
+        Err(error) => Err(error),
+    }
+}
diff --git a/library/std/src/memchr.rs b/library/std/src/sys_common/memchr.rs
index 86a08f75a8d..b219e878912 100644
--- a/library/std/src/memchr.rs
+++ b/library/std/src/sys_common/memchr.rs
@@ -1,6 +1,8 @@
 // Original implementation taken from rust-memchr.
 // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
 
+use crate::sys::memchr as sys;
+
 #[cfg(test)]
 mod tests;
 
@@ -25,7 +27,7 @@ mod tests;
 /// ```
 #[inline]
 pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
-    crate::sys::memchr::memchr(needle, haystack)
+    sys::memchr(needle, haystack)
 }
 
 /// A safe interface to `memrchr`.
@@ -45,5 +47,5 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
 /// ```
 #[inline]
 pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
-    crate::sys::memchr::memrchr(needle, haystack)
+    sys::memrchr(needle, haystack)
 }
diff --git a/library/std/src/memchr/tests.rs b/library/std/src/sys_common/memchr/tests.rs
index 557d749c7f6..557d749c7f6 100644
--- a/library/std/src/memchr/tests.rs
+++ b/library/std/src/sys_common/memchr/tests.rs
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index 7fa6977f2af..1a9caa22c92 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -25,6 +25,7 @@ pub mod bytestring;
 pub mod condvar;
 pub mod fs;
 pub mod io;
+pub mod memchr;
 pub mod mutex;
 // `doc` is required because `sys/mod.rs` imports `unix/ext/mod.rs` on Windows
 // when generating documentation.
@@ -40,7 +41,6 @@ pub mod thread_info;
 pub mod thread_local_dtor;
 pub mod thread_local_key;
 pub mod thread_parker;
-pub mod util;
 pub mod wtf8;
 
 cfg_if::cfg_if! {
diff --git a/library/std/src/sys_common/rt.rs b/library/std/src/sys_common/rt.rs
index c70f2ecc04e..02013ecc4ce 100644
--- a/library/std/src/sys_common/rt.rs
+++ b/library/std/src/sys_common/rt.rs
@@ -1,4 +1,5 @@
 #![deny(unsafe_op_in_unsafe_fn)]
+#![allow(unused_macros)]
 
 use crate::sync::Once;
 use crate::sys;
@@ -38,8 +39,25 @@ pub fn cleanup() {
     });
 }
 
+// Prints to the "panic output", depending on the platform this may be:
+// - the standard error output
+// - some dedicated platform specific output
+// - nothing (so this macro is a no-op)
+macro_rules! rtprintpanic {
+    ($($t:tt)*) => {
+        if let Some(mut out) = crate::sys::stdio::panic_output() {
+            let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*));
+        }
+    }
+}
+
 macro_rules! rtabort {
-    ($($t:tt)*) => (crate::sys_common::util::abort(format_args!($($t)*)))
+    ($($t:tt)*) => {
+        {
+            rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*));
+            crate::sys::abort_internal();
+        }
+    }
 }
 
 macro_rules! rtassert {
@@ -50,7 +68,6 @@ macro_rules! rtassert {
     };
 }
 
-#[allow(unused_macros)] // not used on all platforms
 macro_rules! rtunwrap {
     ($ok:ident, $e:expr) => {
         match $e {
diff --git a/library/std/src/sys_common/util.rs b/library/std/src/sys_common/util.rs
deleted file mode 100644
index 9f7c3bd8795..00000000000
--- a/library/std/src/sys_common/util.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-use crate::fmt;
-use crate::io::prelude::*;
-use crate::sys::stdio::panic_output;
-use crate::thread;
-
-pub fn dumb_print(args: fmt::Arguments<'_>) {
-    if let Some(mut out) = panic_output() {
-        let _ = out.write_fmt(args);
-    }
-}
-
-// Other platforms should use the appropriate platform-specific mechanism for
-// aborting the process.  If no platform-specific mechanism is available,
-// crate::intrinsics::abort() may be used instead.  The above implementations cover
-// all targets currently supported by libstd.
-
-pub fn abort(args: fmt::Arguments<'_>) -> ! {
-    dumb_print(format_args!("fatal runtime error: {}\n", args));
-    crate::sys::abort_internal();
-}
-
-#[allow(dead_code)] // stack overflow detection not enabled on all platforms
-pub unsafe fn report_overflow() {
-    dumb_print(format_args!(
-        "\nthread '{}' has overflowed its stack\n",
-        thread::current().name().unwrap_or("<unknown>")
-    ));
-}
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index 1f5f26e3e14..e62f4440b36 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -162,6 +162,7 @@ macro_rules! thread_local {
 macro_rules! __thread_local_inner {
     // used to generate the `LocalKey` value for const-initialized thread locals
     (@key $t:ty, const $init:expr) => {{
+        #[cfg_attr(not(windows), inline)] // see comments below
         unsafe fn __getit() -> $crate::option::Option<&'static $t> {
             const _REQUIRE_UNSTABLE: () = $crate::thread::require_unstable_const_init_thread_local();
 
@@ -260,6 +261,29 @@ macro_rules! __thread_local_inner {
             #[inline]
             fn __init() -> $t { $init }
 
+            // When reading this function you might ask "why is this inlined
+            // everywhere other than Windows?", and that's a very reasonable
+            // question to ask. The short story is that it segfaults rustc if
+            // this function is inlined. The longer story is that Windows looks
+            // to not support `extern` references to thread locals across DLL
+            // boundaries. This appears to at least not be supported in the ABI
+            // that LLVM implements.
+            //
+            // Because of this we never inline on Windows, but we do inline on
+            // other platforms (where external references to thread locals
+            // across DLLs are supported). A better fix for this would be to
+            // inline this function on Windows, but only for "statically linked"
+            // components. For example if two separately compiled rlibs end up
+            // getting linked into a DLL then it's fine to inline this function
+            // across that boundary. It's only not fine to inline this function
+            // across a DLL boundary. Unfortunately rustc doesn't currently
+            // have this sort of logic available in an attribute, and it's not
+            // clear that rustc is even equipped to answer this (it's more of a
+            // Cargo question kinda). This means that, unfortunately, Windows
+            // gets the pessimistic path for now where it's never inlined.
+            //
+            // The issue of "should enable on Windows sometimes" is #84933
+            #[cfg_attr(not(windows), inline)]
             unsafe fn __getit() -> $crate::option::Option<&'static $t> {
                 #[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))]
                 static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs
index 61a04c46722..c7107b5d0a3 100644
--- a/library/std/tests/run-time-detect.rs
+++ b/library/std/tests/run-time-detect.rs
@@ -27,7 +27,6 @@ fn aarch64_linux() {
     println!("asimd: {}", is_aarch64_feature_detected!("asimd"));
     println!("sve: {}", is_aarch64_feature_detected!("sve"));
     println!("crc: {}", is_aarch64_feature_detected!("crc"));
-    println!("crypto: {}", is_aarch64_feature_detected!("crypto"));
     println!("lse: {}", is_aarch64_feature_detected!("lse"));
     println!("rdm: {}", is_aarch64_feature_detected!("rdm"));
     println!("rcpc: {}", is_aarch64_feature_detected!("rcpc"));
diff --git a/library/stdarch b/library/stdarch
-Subproject c14e98417feb406df66e821ccd81e1293b4baa6
+Subproject 37d6e1886369ea0176356286dc7fbd42ee5aa79
diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs
index b7791b1b24d..84874a2d225 100644
--- a/library/test/src/cli.rs
+++ b/library/test/src/cli.rs
@@ -95,8 +95,9 @@ fn optgroups() -> getopts::Options {
             "Configure formatting of output:
             pretty = Print verbose output;
             terse  = Display one character per test;
-            json   = Output a json document",
-            "pretty|terse|json",
+            json   = Output a json document;
+            junit  = Output a JUnit document",
+            "pretty|terse|json|junit",
         )
         .optflag("", "show-output", "Show captured stdout of successful tests")
         .optopt(
@@ -336,10 +337,15 @@ fn get_format(
             }
             OutputFormat::Json
         }
-
+        Some("junit") => {
+            if !allow_unstable {
+                return Err("The \"junit\" format is only accepted on the nightly compiler".into());
+            }
+            OutputFormat::Junit
+        }
         Some(v) => {
             return Err(format!(
-                "argument for --format must be pretty, terse, or json (was \
+                "argument for --format must be pretty, terse, json or junit (was \
                  {})",
                 v
             ));
diff --git a/library/test/src/console.rs b/library/test/src/console.rs
index 1721c3c14f9..9cfc7eaf4bc 100644
--- a/library/test/src/console.rs
+++ b/library/test/src/console.rs
@@ -10,7 +10,7 @@ use super::{
     cli::TestOpts,
     event::{CompletedTest, TestEvent},
     filter_tests,
-    formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter},
+    formatters::{JsonFormatter, JunitFormatter, OutputFormatter, PrettyFormatter, TerseFormatter},
     helpers::{concurrency::get_concurrency, metrics::MetricMap},
     options::{Options, OutputFormat},
     run_tests,
@@ -277,6 +277,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu
             Box::new(TerseFormatter::new(output, opts.use_color(), max_name_len, is_multithreaded))
         }
         OutputFormat::Json => Box::new(JsonFormatter::new(output)),
+        OutputFormat::Junit => Box::new(JunitFormatter::new(output)),
     };
     let mut st = ConsoleTestState::new(opts)?;
 
diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs
new file mode 100644
index 00000000000..ec66fc1219f
--- /dev/null
+++ b/library/test/src/formatters/junit.rs
@@ -0,0 +1,174 @@
+use std::io::{self, prelude::Write};
+use std::time::Duration;
+
+use super::OutputFormatter;
+use crate::{
+    console::{ConsoleTestState, OutputLocation},
+    test_result::TestResult,
+    time,
+    types::{TestDesc, TestType},
+};
+
+pub struct JunitFormatter<T> {
+    out: OutputLocation<T>,
+    results: Vec<(TestDesc, TestResult, Duration)>,
+}
+
+impl<T: Write> JunitFormatter<T> {
+    pub fn new(out: OutputLocation<T>) -> Self {
+        Self { out, results: Vec::new() }
+    }
+
+    fn write_message(&mut self, s: &str) -> io::Result<()> {
+        assert!(!s.contains('\n'));
+
+        self.out.write_all(s.as_ref())
+    }
+}
+
+impl<T: Write> OutputFormatter for JunitFormatter<T> {
+    fn write_run_start(&mut self, _test_count: usize) -> io::Result<()> {
+        // We write xml header on run start
+        self.write_message(&"<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
+    }
+
+    fn write_test_start(&mut self, _desc: &TestDesc) -> io::Result<()> {
+        // We do not output anything on test start.
+        Ok(())
+    }
+
+    fn write_timeout(&mut self, _desc: &TestDesc) -> io::Result<()> {
+        // We do not output anything on test timeout.
+        Ok(())
+    }
+
+    fn write_result(
+        &mut self,
+        desc: &TestDesc,
+        result: &TestResult,
+        exec_time: Option<&time::TestExecTime>,
+        _stdout: &[u8],
+        _state: &ConsoleTestState,
+    ) -> io::Result<()> {
+        // Because the testsuit node holds some of the information as attributes, we can't write it
+        // until all of the tests has ran. Instead of writting every result as they come in, we add
+        // them to a Vec and write them all at once when run is complete.
+        let duration = exec_time.map(|t| t.0.clone()).unwrap_or_default();
+        self.results.push((desc.clone(), result.clone(), duration));
+        Ok(())
+    }
+    fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
+        self.write_message("<testsuites>")?;
+
+        self.write_message(&*format!(
+            "<testsuite name=\"test\" package=\"test\" id=\"0\" \
+             errors=\"0\" \
+             failures=\"{}\" \
+             tests=\"{}\" \
+             skipped=\"{}\" \
+             >",
+            state.failed, state.total, state.ignored
+        ))?;
+        for (desc, result, duration) in std::mem::replace(&mut self.results, Vec::new()) {
+            let (class_name, test_name) = parse_class_name(&desc);
+            match result {
+                TestResult::TrIgnored => { /* no-op */ }
+                TestResult::TrFailed => {
+                    self.write_message(&*format!(
+                        "<testcase classname=\"{}\" \
+                         name=\"{}\" time=\"{}\">",
+                        class_name,
+                        test_name,
+                        duration.as_secs()
+                    ))?;
+                    self.write_message("<failure type=\"assert\"/>")?;
+                    self.write_message("</testcase>")?;
+                }
+
+                TestResult::TrFailedMsg(ref m) => {
+                    self.write_message(&*format!(
+                        "<testcase classname=\"{}\" \
+                         name=\"{}\" time=\"{}\">",
+                        class_name,
+                        test_name,
+                        duration.as_secs()
+                    ))?;
+                    self.write_message(&*format!("<failure message=\"{}\" type=\"assert\"/>", m))?;
+                    self.write_message("</testcase>")?;
+                }
+
+                TestResult::TrTimedFail => {
+                    self.write_message(&*format!(
+                        "<testcase classname=\"{}\" \
+                         name=\"{}\" time=\"{}\">",
+                        class_name,
+                        test_name,
+                        duration.as_secs()
+                    ))?;
+                    self.write_message("<failure type=\"timeout\"/>")?;
+                    self.write_message("</testcase>")?;
+                }
+
+                TestResult::TrBench(ref b) => {
+                    self.write_message(&*format!(
+                        "<testcase classname=\"benchmark::{}\" \
+                         name=\"{}\" time=\"{}\" />",
+                        class_name, test_name, b.ns_iter_summ.sum
+                    ))?;
+                }
+
+                TestResult::TrOk | TestResult::TrAllowedFail => {
+                    self.write_message(&*format!(
+                        "<testcase classname=\"{}\" \
+                         name=\"{}\" time=\"{}\"/>",
+                        class_name,
+                        test_name,
+                        duration.as_secs()
+                    ))?;
+                }
+            }
+        }
+        self.write_message("<system-out/>")?;
+        self.write_message("<system-err/>")?;
+        self.write_message("</testsuite>")?;
+        self.write_message("</testsuites>")?;
+
+        Ok(state.failed == 0)
+    }
+}
+
+fn parse_class_name(desc: &TestDesc) -> (String, String) {
+    match desc.test_type {
+        TestType::UnitTest => parse_class_name_unit(desc),
+        TestType::DocTest => parse_class_name_doc(desc),
+        TestType::IntegrationTest => parse_class_name_integration(desc),
+        TestType::Unknown => (String::from("unknown"), String::from(desc.name.as_slice())),
+    }
+}
+
+fn parse_class_name_unit(desc: &TestDesc) -> (String, String) {
+    // Module path => classname
+    // Function name => name
+    let module_segments: Vec<&str> = desc.name.as_slice().split("::").collect();
+    let (class_name, test_name) = match module_segments[..] {
+        [test] => (String::from("crate"), String::from(test)),
+        [ref path @ .., test] => (path.join("::"), String::from(test)),
+        [..] => unreachable!(),
+    };
+    (class_name, test_name)
+}
+
+fn parse_class_name_doc(desc: &TestDesc) -> (String, String) {
+    // File path => classname
+    // Line # => test name
+    let segments: Vec<&str> = desc.name.as_slice().split(" - ").collect();
+    let (class_name, test_name) = match segments[..] {
+        [file, line] => (String::from(file.trim()), String::from(line.trim())),
+        [..] => unreachable!(),
+    };
+    (class_name, test_name)
+}
+
+fn parse_class_name_integration(desc: &TestDesc) -> (String, String) {
+    (String::from("integration"), String::from(desc.name.as_slice()))
+}
diff --git a/library/test/src/formatters/mod.rs b/library/test/src/formatters/mod.rs
index 1fb840520a6..2e03581b3af 100644
--- a/library/test/src/formatters/mod.rs
+++ b/library/test/src/formatters/mod.rs
@@ -8,10 +8,12 @@ use crate::{
 };
 
 mod json;
+mod junit;
 mod pretty;
 mod terse;
 
 pub(crate) use self::json::JsonFormatter;
+pub(crate) use self::junit::JunitFormatter;
 pub(crate) use self::pretty::PrettyFormatter;
 pub(crate) use self::terse::TerseFormatter;
 
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 9adc099aaa5..bda5ed888d7 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -49,7 +49,7 @@ pub mod test {
         cli::{parse_opts, TestOpts},
         filter_tests,
         helpers::metrics::{Metric, MetricMap},
-        options::{Options, RunIgnored, RunStrategy, ShouldPanic},
+        options::{Concurrent, Options, RunIgnored, RunStrategy, ShouldPanic},
         run_test, test_main, test_main_static,
         test_result::{TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk},
         time::{TestExecTime, TestTimeOptions},
diff --git a/library/test/src/options.rs b/library/test/src/options.rs
index 8e7bd8de924..baf36b5f1d8 100644
--- a/library/test/src/options.rs
+++ b/library/test/src/options.rs
@@ -39,6 +39,8 @@ pub enum OutputFormat {
     Terse,
     /// JSON output
     Json,
+    /// JUnit output
+    Junit,
 }
 
 /// Whether ignored test should be run or not
diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml
index f42ded62585..c76ba7667d4 100644
--- a/library/unwind/Cargo.toml
+++ b/library/unwind/Cargo.toml
@@ -21,8 +21,15 @@ compiler_builtins = "0.1.0"
 cfg-if = "0.1.8"
 
 [build-dependencies]
-cc = "1.0.67"
+cc = "1.0.68"
 
 [features]
+
+# Only applies for Linux and Fuchsia targets
+# Static link to the in-tree build of llvm libunwind
 llvm-libunwind = []
+
+# Only applies for Linux and Fuchsia targets
+# If crt-static is enabled, static link to `libunwind.a` provided by system
+# If crt-static is disabled, dynamic link to `libunwind.so` provided by system
 system-llvm-libunwind = []
diff --git a/library/unwind/build.rs b/library/unwind/build.rs
index d8bf152e4d6..0529d24a274 100644
--- a/library/unwind/build.rs
+++ b/library/unwind/build.rs
@@ -4,7 +4,8 @@ fn main() {
     println!("cargo:rerun-if-changed=build.rs");
     let target = env::var("TARGET").expect("TARGET was not set");
 
-    if cfg!(feature = "system-llvm-libunwind") {
+    if cfg!(target_os = "linux") && cfg!(feature = "system-llvm-libunwind") {
+        // linking for Linux is handled in lib.rs
         return;
     }
 
@@ -19,6 +20,20 @@ fn main() {
         // linking for Linux is handled in lib.rs
         if target.contains("musl") {
             llvm_libunwind::compile();
+        } else if target.contains("android") {
+            let build = cc::Build::new();
+
+            // Since ndk r23 beta 3 `libgcc` was replaced with `libunwind` thus
+            // check if we have `libunwind` available and if so use it. Otherwise
+            // fall back to `libgcc` to support older ndk versions.
+            let has_unwind =
+                build.is_flag_supported("-lunwind").expect("Unable to invoke compiler");
+
+            if has_unwind {
+                println!("cargo:rustc-link-lib=unwind");
+            } else {
+                println!("cargo:rustc-link-lib=gcc");
+            }
         }
     } else if target.contains("freebsd") {
         println!("cargo:rustc-link-lib=gcc_s");
@@ -57,101 +72,102 @@ mod llvm_libunwind {
     pub fn compile() {
         let target = env::var("TARGET").expect("TARGET was not set");
         let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
-        let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
-        let target_endian_little = env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "big";
-        let cfg = &mut cc::Build::new();
-
-        cfg.cpp(true);
-        cfg.cpp_set_stdlib(None);
-        cfg.warnings(false);
+        let mut cc_cfg = cc::Build::new();
+        let mut cpp_cfg = cc::Build::new();
+        let root = Path::new("../../src/llvm-project/libunwind");
 
-        // libunwind expects a __LITTLE_ENDIAN__ macro to be set for LE archs, cf. #65765
-        if target_endian_little {
-            cfg.define("__LITTLE_ENDIAN__", Some("1"));
+        cpp_cfg.cpp(true);
+        cpp_cfg.cpp_set_stdlib(None);
+        cpp_cfg.flag("-nostdinc++");
+        cpp_cfg.flag("-fno-exceptions");
+        cpp_cfg.flag("-fno-rtti");
+        cpp_cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
+
+        // Don't set this for clang
+        // By default, Clang builds C code in GNU C17 mode.
+        // By default, Clang builds C++ code according to the C++98 standard,
+        // with many C++11 features accepted as extensions.
+        if cpp_cfg.get_compiler().is_like_gnu() {
+            cpp_cfg.flag("-std=c++11");
+            cc_cfg.flag("-std=c99");
         }
 
-        if target_env == "msvc" {
-            // Don't pull in extra libraries on MSVC
-            cfg.flag("/Zl");
-            cfg.flag("/EHsc");
-            cfg.define("_CRT_SECURE_NO_WARNINGS", None);
-            cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
-        } else if target.contains("x86_64-fortanix-unknown-sgx") {
-            cfg.cpp(false);
-
-            cfg.static_flag(true);
-            cfg.opt_level(3);
-
-            cfg.flag("-nostdinc++");
-            cfg.flag("-fno-exceptions");
-            cfg.flag("-fno-rtti");
-            cfg.flag("-fstrict-aliasing");
-            cfg.flag("-funwind-tables");
-            cfg.flag("-fvisibility=hidden");
-            cfg.flag("-fno-stack-protector");
-            cfg.flag("-ffreestanding");
-            cfg.flag("-fexceptions");
-
-            // easiest way to undefine since no API available in cc::Build to undefine
-            cfg.flag("-U_FORTIFY_SOURCE");
-            cfg.define("_FORTIFY_SOURCE", "0");
-
-            cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
+        if target.contains("x86_64-fortanix-unknown-sgx") || target_env == "musl" {
+            // use the same GCC C compiler command to compile C++ code so we do not need to setup the
+            // C++ compiler env variables on the builders.
+            // Don't set this for clang++, as clang++ is able to compile this without libc++.
+            if cpp_cfg.get_compiler().is_like_gnu() {
+                cpp_cfg.cpp(false);
+            }
+        }
 
-            cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
-            cfg.define("RUST_SGX", "1");
-            cfg.define("__NO_STRING_INLINES", None);
-            cfg.define("__NO_MATH_INLINES", None);
-            cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
-            cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
-            cfg.define("NDEBUG", None);
-        } else {
-            cfg.flag("-std=c99");
-            cfg.flag("-std=c++11");
-            cfg.flag("-nostdinc++");
-            cfg.flag("-fno-exceptions");
-            cfg.flag("-fno-rtti");
+        for cfg in [&mut cc_cfg, &mut cpp_cfg].iter_mut() {
+            cfg.warnings(false);
             cfg.flag("-fstrict-aliasing");
             cfg.flag("-funwind-tables");
             cfg.flag("-fvisibility=hidden");
-            cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
             cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None);
+            cfg.include(root.join("include"));
+            cfg.cargo_metadata(false);
+
+            if target.contains("x86_64-fortanix-unknown-sgx") {
+                cfg.static_flag(true);
+                cfg.opt_level(3);
+                cfg.flag("-fno-stack-protector");
+                cfg.flag("-ffreestanding");
+                cfg.flag("-fexceptions");
+
+                // easiest way to undefine since no API available in cc::Build to undefine
+                cfg.flag("-U_FORTIFY_SOURCE");
+                cfg.define("_FORTIFY_SOURCE", "0");
+                cfg.define("RUST_SGX", "1");
+                cfg.define("__NO_STRING_INLINES", None);
+                cfg.define("__NO_MATH_INLINES", None);
+                cfg.define("_LIBUNWIND_IS_BAREMETAL", None);
+                cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None);
+                cfg.define("NDEBUG", None);
+            }
         }
 
-        let mut unwind_sources = vec![
-            "Unwind-EHABI.cpp",
-            "Unwind-seh.cpp",
+        let mut c_sources = vec![
             "Unwind-sjlj.c",
             "UnwindLevel1-gcc-ext.c",
             "UnwindLevel1.c",
             "UnwindRegistersRestore.S",
             "UnwindRegistersSave.S",
-            "libunwind.cpp",
         ];
 
-        if target_vendor == "apple" {
-            unwind_sources.push("Unwind_AppleExtras.cpp");
-        }
+        let cpp_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
+        let cpp_len = cpp_sources.len();
 
         if target.contains("x86_64-fortanix-unknown-sgx") {
-            unwind_sources.push("UnwindRustSgx.c");
+            c_sources.push("UnwindRustSgx.c");
         }
 
-        let root = Path::new("../../src/llvm-project/libunwind");
-        cfg.include(root.join("include"));
-        for src in unwind_sources {
-            cfg.file(root.join("src").join(src));
+        for src in c_sources {
+            cc_cfg.file(root.join("src").join(src).canonicalize().unwrap());
         }
 
-        if target_env == "musl" {
-            // use the same C compiler command to compile C++ code so we do not need to setup the
-            // C++ compiler env variables on the builders
-            cfg.cpp(false);
-            // linking for musl is handled in lib.rs
-            cfg.cargo_metadata(false);
-            println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap());
+        for src in cpp_sources {
+            cpp_cfg.file(root.join("src").join(src).canonicalize().unwrap());
         }
 
-        cfg.compile("unwind");
+        let out_dir = env::var("OUT_DIR").unwrap();
+        println!("cargo:rustc-link-search=native={}", &out_dir);
+
+        cpp_cfg.compile("unwind-cpp");
+
+        let mut count = 0;
+        for entry in std::fs::read_dir(&out_dir).unwrap() {
+            let obj = entry.unwrap().path().canonicalize().unwrap();
+            if let Some(ext) = obj.extension() {
+                if ext == "o" {
+                    cc_cfg.object(&obj);
+                    count += 1;
+                }
+            }
+        }
+        assert_eq!(cpp_len, count, "Can't get object files from {:?}", &out_dir);
+        cc_cfg.compile("unwind");
     }
 }
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index be5e56c71e3..eaeec72fbb5 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -37,9 +37,22 @@ cfg_if::cfg_if! {
 }
 
 #[cfg(target_env = "musl")]
-#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
-#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
-extern "C" {}
+cfg_if::cfg_if! {
+    if #[cfg(all(feature = "llvm-libunwind", feature = "system-llvm-libunwind"))] {
+        compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time");
+    } else if #[cfg(feature = "llvm-libunwind")] {
+        #[link(name = "unwind", kind = "static")]
+        extern "C" {}
+    } else if #[cfg(feature = "system-llvm-libunwind")] {
+        #[link(name = "unwind", kind = "static-nobundle", cfg(target_feature = "crt-static"))]
+        #[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
+        extern "C" {}
+    } else {
+        #[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))]
+        #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))]
+        extern "C" {}
+    }
+}
 
 // When building with crt-static, we get `gcc_eh` from the `libc` crate, since
 // glibc needs it, and needs it listed later on the linker command line. We
@@ -68,5 +81,5 @@ extern "C" {}
 extern "C" {}
 
 #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
-#[link(name = "unwind", kind = "static-nobundle")]
+#[link(name = "unwind", kind = "static")]
 extern "C" {}
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index a74df97a5c7..8445d811e0f 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -40,7 +40,7 @@ cmake = "0.1.38"
 filetime = "0.2"
 num_cpus = "1.0"
 getopts = "0.2.19"
-cc = "1.0.67"
+cc = "1.0.68"
 libc = "0.2"
 serde = { version = "1.0.8", features = ["derive"] }
 serde_json = "1.0.2"
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs
index d462dc4d116..4b98abfb308 100644
--- a/src/bootstrap/bin/rustc.rs
+++ b/src/bootstrap/bin/rustc.rs
@@ -305,7 +305,7 @@ fn format_rusage_data(_child: Child) -> Option<String> {
     };
     // Mac OS X reports the maxrss in bytes, not kb.
     let divisor = if env::consts::OS == "macos" { 1024 } else { 1 };
-    let maxrss = rusage.ru_maxrss + (divisor - 1) / divisor;
+    let maxrss = (rusage.ru_maxrss + (divisor - 1)) / divisor;
 
     let mut init_str = format!(
         "user: {USER_SEC}.{USER_USEC:03} \
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index f39e89a9d01..da298f7edb9 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -369,7 +369,8 @@ impl<'a> Builder<'a> {
                 tool::Rustfmt,
                 tool::Miri,
                 tool::CargoMiri,
-                native::Lld
+                native::Lld,
+                native::CrtBeginEnd
             ),
             Kind::Check | Kind::Clippy { .. } | Kind::Fix | Kind::Format => describe!(
                 check::Std,
@@ -708,7 +709,15 @@ impl<'a> Builder<'a> {
             return;
         }
 
-        add_dylib_path(vec![self.rustc_libdir(compiler)], cmd);
+        let mut dylib_dirs = vec![self.rustc_libdir(compiler)];
+
+        // Ensure that the downloaded LLVM libraries can be found.
+        if self.config.llvm_from_ci {
+            let ci_llvm_lib = self.out.join(&*compiler.host.triple).join("ci-llvm").join("lib");
+            dylib_dirs.push(ci_llvm_lib);
+        }
+
+        add_dylib_path(dylib_dirs, cmd);
     }
 
     /// Gets a path to the compiler specified.
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 2676b3bf8e0..e5258d08956 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -199,8 +199,9 @@ fn copy_self_contained_objects(
                 DependencyType::TargetSelfContained,
             );
         }
+        let crt_path = builder.ensure(native::CrtBeginEnd { target });
         for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] {
-            let src = compiler_file(builder, builder.cc(target), target, obj);
+            let src = crt_path.join(obj);
             let target = libdir_self_contained.join(obj);
             builder.copy(&src, &target);
             target_deps.push((target, DependencyType::TargetSelfContained));
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index f9972ac7b9d..d2fabf9967f 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -434,6 +434,7 @@ impl Step for Std {
             cargo
                 .arg("-p")
                 .arg(package)
+                .arg("-Zskip-rustdoc-fingerprint")
                 .arg("--")
                 .arg("--markdown-css")
                 .arg("rust.css")
@@ -564,6 +565,7 @@ impl Step for Rustc {
         cargo.rustdocflag("-Znormalize-docs");
         cargo.rustdocflag("--show-type-layout");
         compile::rustc_cargo(builder, &mut cargo, target);
+        cargo.arg("-Zskip-rustdoc-fingerprint");
 
         // Only include compiler crates, no dependencies of those, such as `libc`.
         cargo.arg("--no-deps");
@@ -655,6 +657,7 @@ impl Step for Rustdoc {
             &[],
         );
 
+        cargo.arg("-Zskip-rustdoc-fingerprint");
         // Only include compiler crates, no dependencies of those, such as `libc`.
         cargo.arg("--no-deps");
         cargo.arg("-p").arg("rustdoc");
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index 47cf1172d36..fd39944e176 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -45,10 +45,6 @@ check-aux:
 		src/tools/cargo \
 		src/tools/cargotest \
 		$(BOOTSTRAP_ARGS)
-check-aux-and-gui: check-aux
-	$(Q)$(BOOTSTRAP) test --stage 2 \
-		src/test/rustdoc-gui \
-		$(BOOTSTRAP_ARGS)
 check-bootstrap:
 	$(Q)$(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap_test.py
 dist:
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index bde0a96f030..4f33a13c253 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -181,7 +181,7 @@ impl Step for Llvm {
             .define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap())
             .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native);
 
-        if target != "aarch64-apple-darwin" {
+        if target != "aarch64-apple-darwin" && !target.contains("windows") {
             cfg.define("LLVM_ENABLE_ZLIB", "ON");
         } else {
             cfg.define("LLVM_ENABLE_ZLIB", "OFF");
@@ -858,3 +858,69 @@ impl HashStamp {
         fs::write(&self.path, self.hash.as_deref().unwrap_or(b""))
     }
 }
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct CrtBeginEnd {
+    pub target: TargetSelection,
+}
+
+impl Step for CrtBeginEnd {
+    type Output = PathBuf;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/llvm-project/compiler-rt/lib/crt")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(CrtBeginEnd { target: run.target });
+    }
+
+    /// Build crtbegin.o/crtend.o for musl target.
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        let out_dir = builder.native_dir(self.target).join("crt");
+
+        if builder.config.dry_run {
+            return out_dir;
+        }
+
+        let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtbegin.c");
+        let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtend.c");
+        if up_to_date(&crtbegin_src, &out_dir.join("crtbegin.o"))
+            && up_to_date(&crtend_src, &out_dir.join("crtendS.o"))
+        {
+            return out_dir;
+        }
+
+        builder.info("Building crtbegin.o and crtend.o");
+        t!(fs::create_dir_all(&out_dir));
+
+        let mut cfg = cc::Build::new();
+
+        if let Some(ar) = builder.ar(self.target) {
+            cfg.archiver(ar);
+        }
+        cfg.compiler(builder.cc(self.target));
+        cfg.cargo_metadata(false)
+            .out_dir(&out_dir)
+            .target(&self.target.triple)
+            .host(&builder.config.build.triple)
+            .warnings(false)
+            .debug(false)
+            .opt_level(3)
+            .file(crtbegin_src)
+            .file(crtend_src);
+
+        // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt
+        // Currently only consumer of those objects is musl, which use .init_array/.fini_array
+        // instead of .ctors/.dtors
+        cfg.flag("-std=c11")
+            .define("CRT_HAS_INITFINI_ARRAY", None)
+            .define("EH_USE_FRAME_REGISTRY", None);
+
+        cfg.compile("crt");
+
+        t!(fs::copy(out_dir.join("crtbegin.o"), out_dir.join("crtbeginS.o")));
+        t!(fs::copy(out_dir.join("crtend.o"), out_dir.join("crtendS.o")));
+        out_dir
+    }
+}
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index ed0cbdf97b0..a28762ac485 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -93,7 +93,8 @@ pub fn check(build: &mut Build) {
                     .unwrap_or(true)
             })
             .any(|build_llvm_ourselves| build_llvm_ourselves);
-    if building_llvm || build.config.any_sanitizers_enabled() {
+    let need_cmake = building_llvm || build.config.any_sanitizers_enabled();
+    if need_cmake {
         cmd_finder.must_have("cmake");
     }
 
@@ -204,7 +205,7 @@ pub fn check(build: &mut Build) {
             }
         }
 
-        if target.contains("msvc") {
+        if need_cmake && target.contains("msvc") {
             // There are three builds of cmake on windows: MSVC, MinGW, and
             // Cygwin. The Cygwin build does not have generators for Visual
             // Studio, so detect that here and error.
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 98f753b25f0..7bd29c61b0c 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -449,6 +449,7 @@ impl Step for Miri {
                 SourceType::Submodule,
                 &[],
             );
+            cargo.add_rustc_lib_path(builder, compiler);
             cargo.arg("--").arg("miri").arg("setup");
 
             // Tell `cargo miri setup` where to find the sources.
@@ -500,6 +501,7 @@ impl Step for Miri {
                 SourceType::Submodule,
                 &[],
             );
+            cargo.add_rustc_lib_path(builder, compiler);
 
             // miri tests need to know about the stage sysroot
             cargo.env("MIRI_SYSROOT", miri_sysroot);
@@ -508,8 +510,6 @@ impl Step for Miri {
 
             cargo.arg("--").args(builder.config.cmd.test_args());
 
-            cargo.add_rustc_lib_path(builder, compiler);
-
             let mut cargo = Command::from(cargo);
             if !try_run(builder, &mut cargo) {
                 return;
@@ -774,6 +774,24 @@ impl Step for RustdocJSNotStd {
     }
 }
 
+fn check_if_browser_ui_test_is_installed_global(npm: &Path, global: bool) -> bool {
+    let mut command = Command::new(&npm);
+    command.arg("list").arg("--depth=0");
+    if global {
+        command.arg("--global");
+    }
+    let lines = command
+        .output()
+        .map(|output| String::from_utf8_lossy(&output.stdout).into_owned())
+        .unwrap_or(String::new());
+    lines.contains(&" browser-ui-test@")
+}
+
+fn check_if_browser_ui_test_is_installed(npm: &Path) -> bool {
+    check_if_browser_ui_test_is_installed_global(npm, false)
+        || check_if_browser_ui_test_is_installed_global(npm, true)
+}
+
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct RustdocGUI {
     pub target: TargetSelection,
@@ -786,7 +804,17 @@ impl Step for RustdocGUI {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/test/rustdoc-gui")
+        let builder = run.builder;
+        let run = run.path("src/test/rustdoc-gui");
+        run.default_condition(
+            builder.config.nodejs.is_some()
+                && builder
+                    .config
+                    .npm
+                    .as_ref()
+                    .map(|p| check_if_browser_ui_test_is_installed(p))
+                    .unwrap_or(false),
+        )
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -795,58 +823,54 @@ impl Step for RustdocGUI {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        if let (Some(nodejs), Some(npm)) = (&builder.config.nodejs, &builder.config.npm) {
-            builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
-
-            // The goal here is to check if the necessary packages are installed, and if not, we
-            // display a warning and move on.
-            let mut command = Command::new(&npm);
-            command.arg("list").arg("--depth=0");
-            let lines = command
-                .output()
-                .map(|output| String::from_utf8_lossy(&output.stdout).to_string())
-                .unwrap_or(String::new());
-            if !lines.contains(&" browser-ui-test@") {
-                println!(
-                    "warning: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \
-                     dependency is missing",
-                );
-                println!(
-                    "If you want to install the `{0}` dependency, run `npm install {0}`",
-                    "browser-ui-test",
-                );
-                return;
-            }
+        let nodejs = builder.config.nodejs.as_ref().expect("nodejs isn't available");
+        let npm = builder.config.npm.as_ref().expect("npm isn't available");
 
-            let out_dir = builder.test_out(self.target).join("rustdoc-gui");
+        builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
 
-            // We remove existing folder to be sure there won't be artifacts remaining.
-            let _ = fs::remove_dir_all(&out_dir);
+        // The goal here is to check if the necessary packages are installed, and if not, we
+        // panic.
+        if !check_if_browser_ui_test_is_installed(&npm) {
+            eprintln!(
+                "error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \
+                 dependency is missing",
+            );
+            eprintln!(
+                "If you want to install the `{0}` dependency, run `npm install {0}`",
+                "browser-ui-test",
+            );
+            panic!("Cannot run rustdoc-gui tests");
+        }
 
-            // We generate docs for the libraries present in the rustdoc-gui's src folder.
-            let libs_dir = builder.build.src.join("src/test/rustdoc-gui/src");
-            for entry in libs_dir.read_dir().expect("read_dir call failed") {
-                let entry = entry.expect("invalid entry");
-                let path = entry.path();
-                if path.extension().map(|e| e == "rs").unwrap_or(false) {
-                    let mut command = builder.rustdoc_cmd(self.compiler);
-                    command.arg(path).arg("-o").arg(&out_dir);
-                    builder.run(&mut command);
-                }
-            }
+        let out_dir = builder.test_out(self.target).join("rustdoc-gui");
 
-            // We now run GUI tests.
-            let mut command = Command::new(&nodejs);
-            command
-                .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js"))
-                .arg("--doc-folder")
-                .arg(out_dir)
-                .arg("--tests-folder")
-                .arg(builder.build.src.join("src/test/rustdoc-gui"));
-            builder.run(&mut command);
-        } else {
-            builder.info("No nodejs found, skipping \"src/test/rustdoc-gui\" tests");
+        // We remove existing folder to be sure there won't be artifacts remaining.
+        let _ = fs::remove_dir_all(&out_dir);
+
+        let mut nb_generated = 0;
+        // We generate docs for the libraries present in the rustdoc-gui's src folder.
+        let libs_dir = builder.build.src.join("src/test/rustdoc-gui/src");
+        for entry in libs_dir.read_dir().expect("read_dir call failed") {
+            let entry = entry.expect("invalid entry");
+            let path = entry.path();
+            if path.extension().map(|e| e == "rs").unwrap_or(false) {
+                let mut command = builder.rustdoc_cmd(self.compiler);
+                command.arg(path).arg("-o").arg(&out_dir);
+                builder.run(&mut command);
+                nb_generated += 1;
+            }
         }
+        assert!(nb_generated > 0, "no documentation was generated...");
+
+        // We now run GUI tests.
+        let mut command = Command::new(&nodejs);
+        command
+            .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js"))
+            .arg("--doc-folder")
+            .arg(out_dir)
+            .arg("--tests-folder")
+            .arg(builder.build.src.join("src/test/rustdoc-gui"));
+        builder.run(&mut command);
     }
 }
 
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index 12571c1b97d..64e4be6863a 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -52,7 +52,10 @@ impl Step for ToolBuild {
         let is_optional_tool = self.is_optional_tool;
 
         match self.mode {
-            Mode::ToolRustc => builder.ensure(compile::Rustc { compiler, target }),
+            Mode::ToolRustc => {
+                builder.ensure(compile::Std { compiler, target: compiler.host });
+                builder.ensure(compile::Rustc { compiler, target });
+            }
             Mode::ToolStd => builder.ensure(compile::Std { compiler, target }),
             Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs
             _ => panic!("unexpected Mode for tool build"),
@@ -214,9 +217,8 @@ impl Step for ToolBuild {
             if tool == "tidy" {
                 tool = "rust-tidy";
             }
-            let cargo_out =
-                builder.cargo_out(compiler, self.mode, target).join(exe(tool, compiler.host));
-            let bin = builder.tools_dir(compiler).join(exe(tool, compiler.host));
+            let cargo_out = builder.cargo_out(compiler, self.mode, target).join(exe(tool, target));
+            let bin = builder.tools_dir(compiler).join(exe(tool, target));
             builder.copy(&cargo_out, &bin);
             Some(bin)
         }
@@ -593,7 +595,14 @@ impl Step for Cargo {
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
         let builder = run.builder;
-        run.path("src/tools/cargo").default_condition(builder.config.extended)
+        run.path("src/tools/cargo").default_condition(
+            builder.config.extended
+                && builder.config.tools.as_ref().map_or(
+                    true,
+                    // If `tools` is set, search list for this tool.
+                    |tools| tools.iter().any(|tool| tool == "cargo"),
+                ),
+        )
     }
 
     fn make_run(run: RunConfig<'_>) {
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index b4421a82714..4c1cd758f0d 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -45,6 +45,7 @@ pub fn libdir(target: TargetSelection) -> &'static str {
 }
 
 /// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
+/// If The dylib_path_par is already set for this cmd, the old value will be overwritten!
 pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) {
     let mut list = dylib_path();
     for path in path {
diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
index 1f8f9fc518a..cd0f01faa1b 100644
--- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile
@@ -144,7 +144,11 @@ ENV TARGETS=$TARGETS,armv7a-none-eabi
 # riscv targets currently do not need a C compiler, as compiler_builtins
 # doesn't currently have it enabled, and the riscv gcc compiler is not
 # installed.
-ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
+ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft" \
+    CFLAGS_arm_unknown_linux_musleabi="-march=armv6 -marm" \
+    CFLAGS_arm_unknown_linux_musleabihf="-march=armv6 -marm -mfpu=vfp" \
+    CFLAGS_armv7_unknown_linux_musleabihf="-march=armv7-a" \
+    CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
     CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \
     CC_mips64el_unknown_linux_muslabi64=mips64el-linux-gnuabi64-gcc \
     CC_mips64_unknown_linux_muslabi64=mips64-linux-gnuabi64-gcc \
diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
index de3a99f34fc..b7f181adf2a 100644
--- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile
@@ -42,6 +42,9 @@ ENV \
     AR_x86_64_pc_solaris=x86_64-pc-solaris2.10-ar \
     CC_x86_64_pc_solaris=x86_64-pc-solaris2.10-gcc \
     CXX_x86_64_pc_solaris=x86_64-pc-solaris2.10-g++ \
+    AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \
+    CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \
+    CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ \
     CC_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-gcc-8 \
     CXX_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-g++-8 \
     AR_x86_64_fortanix_unknown_sgx=ar \
@@ -68,8 +71,10 @@ COPY host-x86_64/dist-various-2/shared.sh /tmp/
 COPY host-x86_64/dist-various-2/build-fuchsia-toolchain.sh /tmp/
 RUN /tmp/build-fuchsia-toolchain.sh
 COPY host-x86_64/dist-various-2/build-solaris-toolchain.sh /tmp/
-RUN /tmp/build-solaris-toolchain.sh x86_64  amd64   solaris-i386
-RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc
+RUN /tmp/build-solaris-toolchain.sh x86_64  amd64   solaris-i386  pc
+# Build deprecated target 'x86_64-sun-solaris2.10' until removed
+RUN /tmp/build-solaris-toolchain.sh x86_64  amd64   solaris-i386  sun
+RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc sun
 COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
 RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh
 
@@ -99,6 +104,7 @@ ENV TARGETS=$TARGETS,wasm32-unknown-unknown
 ENV TARGETS=$TARGETS,wasm32-wasi
 ENV TARGETS=$TARGETS,sparcv9-sun-solaris
 ENV TARGETS=$TARGETS,x86_64-pc-solaris
+ENV TARGETS=$TARGETS,x86_64-sun-solaris
 ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32
 ENV TARGETS=$TARGETS,x86_64-fortanix-unknown-sgx
 ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda
diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh
index ee76fafb1f9..4cbc2ccfe38 100755
--- a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh
+++ b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh
@@ -6,21 +6,11 @@ source shared.sh
 ARCH=$1
 LIB_ARCH=$2
 APT_ARCH=$3
+MANUFACTURER=$4
 BINUTILS=2.28.1
 GCC=6.5.0
 
-# Choose correct target based on the $ARCH
-case "$ARCH" in
-x86_64)
-  TARGET=x86_64-pc-solaris2.10
-  ;;
-sparcv9)
-  TARGET=sparcv9-sun-solaris2.10
-  ;;
-*)
-  printf 'ERROR: unknown architecture: %s\n' "$ARCH"
-  exit 1
-esac
+TARGET=${ARCH}-${MANUFACTURER}-solaris2.10
 
 # First up, build binutils
 mkdir binutils
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index fd6dc563a0e..66afe84be4a 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -22,6 +22,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
 # Install es-check
 # Pin its version to prevent unrelated CI failures due to future es-check versions.
 RUN npm install es-check@5.2.3 -g
+RUN npm install eslint@7.20.0 -g
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
@@ -37,4 +38,5 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
            python3 ../x.py doc --stage 0 library/test && \
            /scripts/validate-toolstate.sh && \
            # Runs checks to ensure that there are no ES5 issues in our JS code.
-           es-check es5 ../src/librustdoc/html/static/*.js
+           es-check es5 ../src/librustdoc/html/static/*.js && \
+           eslint ../src/librustdoc/html/static/*.js
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
index 00ad7b0a710..7f1a5820e22 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
@@ -17,27 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   libgl1-mesa-dev \
   llvm-dev \
   libfreetype6-dev \
-  libexpat1-dev \
-  libexpat1-dev \
-  gnupg \
-  apt-utils \
-  wget \
-  fonts-ipafont-gothic \
-  fonts-wqy-zenhei \
-  fonts-thai-tlwg \
-  fonts-kacst \
-  fonts-freefont-ttf \
-  libxss1 \
-  libxtst6
-
-RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ
-ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
-
-# Install required dependencies from browser-UI-test framework
-# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
-# to create a new folder. For reference:
-# https://github.com/puppeteer/puppeteer/issues/375
-RUN npm install browser-ui-test -g --unsafe-perm=true
+  libexpat1-dev
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
@@ -46,4 +26,4 @@ COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
 ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
-ENV RUST_CHECK_TARGET check-aux-and-gui
+ENV RUST_CHECK_TARGET check-aux
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
index d4838c0d6f8..605d988dad7 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
@@ -12,8 +12,48 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   cmake \
   libssl-dev \
   sudo \
-  xz-utils \
-  pkg-config
+  xz-utils
+
+# Install dependencies for chromium browser
+RUN apt-get install -y \
+  gconf-service \
+  libasound2 \
+  libatk1.0-0 \
+  libatk-bridge2.0-0 \
+  libc6 \
+  libcairo2 \
+  libcups2 \
+  libdbus-1-3 \
+  libexpat1 \
+  libfontconfig1 \
+  libgcc1 \
+  libgconf-2-4 \
+  libgdk-pixbuf2.0-0 \
+  libglib2.0-0 \
+  libgtk-3-0 \
+  libnspr4 \
+  libpango-1.0-0 \
+  libpangocairo-1.0-0 \
+  libstdc++6 \
+  libx11-6 \
+  libx11-xcb1 \
+  libxcb1 \
+  libxcomposite1 \
+  libxcursor1 \
+  libxdamage1 \
+  libxext6 \
+  libxfixes3 \
+  libxi6 \
+  libxrandr2 \
+  libxrender1 \
+  libxss1 \
+  libxtst6 \
+  fonts-liberation \
+  libappindicator1 \
+  libnss3 \
+  lsb-release \
+  xdg-utils \
+  wget
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
@@ -23,7 +63,19 @@ RUN /scripts/cmake.sh
 
 COPY host-x86_64/x86_64-gnu-tools/checktools.sh /tmp/
 
+RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ
+ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
+
+# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries
+# to create a new folder. For reference:
+# https://github.com/puppeteer/puppeteer/issues/375
+#
+# We also specify the version in case we need to update it to go around cache limitations.
+RUN npm install -g browser-ui-test@0.2.12 --unsafe-perm=true
+
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
   --save-toolstates=/tmp/toolstate/toolstates.json
-ENV SCRIPT /tmp/checktools.sh ../x.py
+
+ENV SCRIPT /tmp/checktools.sh ../x.py && \
+  NODE_PATH=`npm root -g` python3 ../x.py test src/test/rustdoc-gui --stage 2
diff --git a/src/ci/scripts/should-skip-this.sh b/src/ci/scripts/should-skip-this.sh
index 631a7b247d5..fa738fe70c8 100755
--- a/src/ci/scripts/should-skip-this.sh
+++ b/src/ci/scripts/should-skip-this.sh
@@ -26,6 +26,12 @@ elif ! git diff --quiet "$BASE_COMMIT" -- src/tools/clippy src/tools/rustfmt; th
     # There is not an easy blanket search for subtrees. For now, manually list
     # the subtrees.
     echo "Executing the job since clippy or rustfmt subtree was updated"
+elif ! (git diff --quiet "$BASE_COMMIT" -- \
+         src/test/rustdoc-gui \
+         src/librustdoc \
+         src/tools/rustdoc-gui); then
+    # There was a change in either rustdoc or in its GUI tests.
+    echo "Executing the job since rustdoc was updated"
 else
     echo "Not executing this job since no submodules nor subtrees were updated"
     ciCommandSetEnv SKIP_JOB 1
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 1da3c411f17adb1ba5de1683bb6acee83362b54
+Subproject 302a115e8f71876dfc884aebb0ca5ccb02b8a96
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject 569c3391f5c0cc43433bc77831d17f8ff4d7660
+Subproject 7349d173fa28a0bb834cf0264a05286620ef092
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 5aa457bf1b54bd2cd5d4cf49797f29299bdf89a
+Subproject 9c68af3ce6ccca2395e1868addef26a0542e9dd
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 5f8c6da200ada77760a2fe1096938ef58151c9a
+Subproject 805e016c5792ad2adabb66e348233067d5ea9f1
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
-Subproject 1e6c7fbda4c45e85adf63ff3f82fa9c870b1447
+Subproject 50de7f0682adc5d95ce858fe6318d19b4b95155
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index b269aab9814..bc1873b6836 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -13,6 +13,7 @@
 - [JSON Output](json.md)
 - [Tests](tests/index.md)
 - [Platform Support](platform-support.md)
+    - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
 - [Target Tier Policy](target-tier-policy.md)
 - [Targets](targets/index.md)
     - [Built-in Targets](targets/built-in.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index f9a7599c497..321d3c5c44e 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -144,7 +144,7 @@ target | std | notes
 `mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL
 `mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL
 `mipsel-unknown-linux-musl` | ✓ | MIPS (LE) Linux with MUSL
-`nvptx64-nvidia-cuda` | ✓ | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
+`nvptx64-nvidia-cuda` | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs]
 `riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA)
 `riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA)
 `riscv32imc-unknown-none-elf` | * | Bare RISC-V (RV32IMC ISA)
@@ -196,7 +196,7 @@ host tools.
 target | std | host | notes
 -------|:---:|:----:|-------
 `aarch64-apple-ios-macabi` | ? |  | Apple Catalyst on ARM64
-`aarch64-apple-ios-sim` | ? |  | Apple iOS Simulator on ARM64
+[`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ |  | Apple iOS Simulator on ARM64
 `aarch64-apple-tvos` | * |  | ARM64 tvOS
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 `aarch64-unknown-hermit` | ? |  |
diff --git a/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md b/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md
new file mode 100644
index 00000000000..9aa5db26f91
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md
@@ -0,0 +1,56 @@
+# aarch64-apple-ios-sim
+
+**Tier: 3**
+
+Apple iOS Simulator on ARM64.
+
+## Designated Developers
+
+* [@badboy](https://github.com/badboy)
+* [@deg4uss3r](https://github.com/deg4uss3r)
+
+## Requirements
+
+This target is cross-compiled.
+To build this target Xcode 12 or higher on macOS is required.
+
+## Building
+
+The target can be built by enabling it for a `rustc` build:
+
+```toml
+[build]
+build-stage = 1
+target = ["aarch64-apple-ios-sim"]
+```
+
+## Cross-compilation
+
+This target can be cross-compiled from `x86_64` or `aarch64` macOS hosts.
+
+Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK.
+
+## Testing
+
+Currently there is no support to run the rustc test suite for this target.
+
+
+## Building Rust programs
+
+*Note: Building for this target requires the corresponding iOS SDK, as provided by Xcode 12+.*
+
+If `rustc` has support for that target and the library artifacts are available,
+then Rust programs can be built for that target:
+
+```text
+rustc --target aarch64-apple-ios-sim your-code.rs
+```
+
+On Rust Nightly it is possible to build without the target artifacts available:
+
+```text
+cargo build -Z build-std --target aarch64-apple-ios-sim
+```
+
+There is no easy way to run simple programs in the iOS simulator.
+Static library builds can be embedded into iOS applications.
diff --git a/src/doc/rustdoc/README.md b/src/doc/rustdoc/README.md
new file mode 100644
index 00000000000..7d97d5e4ab5
--- /dev/null
+++ b/src/doc/rustdoc/README.md
@@ -0,0 +1,5 @@
+# Rustdoc
+
+This is documentation for rustdoc itself, written in mdbook format.
+To build the book, use `x.py doc src/doc/rustdoc`.
+To run doctests, use `x.py test src/doc/rustdoc`.
diff --git a/src/doc/rustdoc/src/how-to-write-documentation.md b/src/doc/rustdoc/src/how-to-write-documentation.md
index 688be7aedea..f89495cca3a 100644
--- a/src/doc/rustdoc/src/how-to-write-documentation.md
+++ b/src/doc/rustdoc/src/how-to-write-documentation.md
@@ -229,15 +229,13 @@ Example:
 
 ```md
 - [x] Complete task
-- [ ] IncComplete task
+- [ ] Incomplete task
 ```
 
-This will render as
+This will render as:
 
-<ul>
-    <li><input type="checkbox"></li>
-    <li><input type="checkbox" checked></li>
-</ul>
+> - [x] Complete task
+> - [ ] Incomplete task
 
 See the specification for the [task list extension] for more details.
 
diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md
index a6626679a7d..16b091eb255 100644
--- a/src/doc/rustdoc/src/lints.md
+++ b/src/doc/rustdoc/src/lints.md
@@ -294,6 +294,50 @@ warning: unclosed HTML tag `h1`
 warning: 2 warnings emitted
 ```
 
+## invalid_rust_codeblocks
+
+This lint **warns by default**. It detects Rust code blocks in documentation
+examples that are invalid (e.g. empty, not parsable as Rust). For example:
+
+```rust
+/// Empty code blocks (with and without the `rust` marker):
+///
+/// ```rust
+/// ```
+///
+/// Invalid syntax in code blocks:
+///
+/// ```rust
+/// '<
+/// ```
+pub fn foo() {}
+```
+
+Which will give:
+
+```text
+warning: Rust code block is empty
+ --> lint.rs:3:5
+  |
+3 |   /// ```rust
+  |  _____^
+4 | | /// ```
+  | |_______^
+  |
+  = note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default
+
+warning: could not parse code block as Rust code
+  --> lint.rs:8:5
+   |
+8  |   /// ```rust
+   |  _____^
+9  | | /// '<
+10 | | /// ```
+   | |_______^
+   |
+   = note: error from rustc: unterminated character literal
+```
+
 ## bare_urls
 
 This lint is **warn-by-default**. It detects URLs which are not links.
diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md
index 52f2a3728fa..d192f7d5ce9 100644
--- a/src/doc/rustdoc/src/the-doc-attribute.md
+++ b/src/doc/rustdoc/src/the-doc-attribute.md
@@ -35,6 +35,13 @@ Which can feel more flexible. Note that this would generate this:
 
 but given that docs are rendered via Markdown, it will remove these newlines.
 
+Another use case is for including external files as documentation:
+
+```rust,no_run
+#[doc = include_str!("../README.md")]
+# fn f() {}
+```
+
 The `doc` attribute has more options though! These don't involve the text of
 the output, but instead, various aspects of the presentation of the output.
 We've split them into two kinds below: attributes that are useful at the
diff --git a/src/doc/unstable-book/src/compiler-flags/force-warns.md b/src/doc/unstable-book/src/compiler-flags/force-warns.md
new file mode 100644
index 00000000000..0a205be096c
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/force-warns.md
@@ -0,0 +1,21 @@
+# `force-warns`
+
+The tracking issue for this feature is: [#85512](https://github.com/rust-lang/rust/issues/85512).
+
+------------------------
+
+This feature allows you to cause any lint to produce a warning even if the lint has a different level by default or another level is set somewhere else. For instance, the `force-warns` option can be used to make a lint (e.g., `dead_code`) produce a warning even if that lint is allowed in code with `#![allow(dead_code)]`.
+
+## Example
+
+```rust,ignore (partial-example)
+#![allow(dead_code)]
+
+fn dead_function() {}
+// This would normally not produce a warning even though the
+// function is not used, because dead code is being allowed
+
+fn main() {}
+```
+
+We can force a warning to be produced by providing `--force-warns dead_code` to rustc.
diff --git a/src/doc/unstable-book/src/language-features/member-constraints.md b/src/doc/unstable-book/src/language-features/member-constraints.md
deleted file mode 100644
index 3ba4a3e6b1f..00000000000
--- a/src/doc/unstable-book/src/language-features/member-constraints.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# `member_constraints`
-
-The tracking issue for this feature is: [#61997]
-
-[#61997]: https://github.com/rust-lang/rust/issues/61997
-
-------------------------
-
-The `member_constraints` feature gate lets you use `impl Trait` syntax with
-multiple unrelated lifetime parameters.
-
-A simple example is:
-
-```rust
-#![feature(member_constraints)]
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T {}
-
-fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
-  (x, y)
-}
-
-fn main() { }
-```
-
-Without the `member_constraints` feature gate, the above example is an
-error because both `'a` and `'b` appear in the impl Trait bounds, but
-neither outlives the other.
diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis
index 030892a432b..89280149a03 100644
--- a/src/etc/natvis/intrinsic.natvis
+++ b/src/etc/natvis/intrinsic.natvis
@@ -149,4 +149,57 @@
       <Synthetic Name="[...]"><DisplayString>...</DisplayString></Synthetic>
     </Expand>
   </Type>
+  <Type Name="enum$&lt;*&gt;">
+    <Intrinsic Name="tag" Expression="variant0.variant$" />
+    <DisplayString Condition="tag() == 0">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 1" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 2" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 3" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 4" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 5" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 6" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 7" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 8" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 9" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 10" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 11" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 12" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 13" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 14" Optional="true">{tag(),en}</DisplayString>
+    <DisplayString Condition="tag() == 15" Optional="true">{tag(),en}</DisplayString>
+
+    <Expand>
+      <ExpandedItem Condition="tag() == 0">variant0</ExpandedItem>
+      <ExpandedItem Condition="tag() == 1" Optional="true">variant1</ExpandedItem>
+      <ExpandedItem Condition="tag() == 2" Optional="true">variant2</ExpandedItem>
+      <ExpandedItem Condition="tag() == 3" Optional="true">variant3</ExpandedItem>
+      <ExpandedItem Condition="tag() == 4" Optional="true">variant4</ExpandedItem>
+      <ExpandedItem Condition="tag() == 5" Optional="true">variant5</ExpandedItem>
+      <ExpandedItem Condition="tag() == 6" Optional="true">variant6</ExpandedItem>
+      <ExpandedItem Condition="tag() == 7" Optional="true">variant7</ExpandedItem>
+      <ExpandedItem Condition="tag() == 8" Optional="true">variant8</ExpandedItem>
+      <ExpandedItem Condition="tag() == 9" Optional="true">variant9</ExpandedItem>
+      <ExpandedItem Condition="tag() == 10" Optional="true">variant10</ExpandedItem>
+      <ExpandedItem Condition="tag() == 11" Optional="true">variant11</ExpandedItem>
+      <ExpandedItem Condition="tag() == 12" Optional="true">variant12</ExpandedItem>
+      <ExpandedItem Condition="tag() == 13" Optional="true">variant13</ExpandedItem>
+      <ExpandedItem Condition="tag() == 14" Optional="true">variant14</ExpandedItem>
+      <ExpandedItem Condition="tag() == 15" Optional="true">variant15</ExpandedItem>
+    </Expand>
+  </Type>
+
+  <!-- $T1 is the name of the enum, $T2 is the low value of the dataful variant tag,
+       $T3 is the high value of the dataful variant tag, $T4 is the name of the dataful variant -->
+  <Type Name="enum$&lt;*, *, *, *&gt;">
+    <Intrinsic Name="tag" Expression="discriminant" />
+    <Intrinsic Name="is_dataful" Expression="tag() &gt;= $T2 &amp;&amp; tag() &lt;= $T3" />
+    <DisplayString Condition="is_dataful()">{"$T4",sb}({dataful_variant})</DisplayString>
+    <DisplayString Condition="!is_dataful()">{discriminant,en}</DisplayString>
+    <Expand>
+      <ExpandedItem Condition="is_dataful()">dataful_variant</ExpandedItem>
+      <Synthetic Condition="is_dataful()" Name="[variant]">
+        <DisplayString>{"$T4",sb}</DisplayString>
+      </Synthetic>
+    </Expand>
+  </Type>
 </AutoVisualizer>
diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis
index 9c3c26f5978..17667770520 100644
--- a/src/etc/natvis/libcore.natvis
+++ b/src/etc/natvis/libcore.natvis
@@ -14,14 +14,6 @@
     </Expand>
   </Type>
 
-  <Type Name="core::option::Option&lt;*&gt;">
-    <DisplayString Condition="RUST$ENUM$DISR == 0x0">None</DisplayString>
-    <DisplayString Condition="RUST$ENUM$DISR == 0x1">Some({__0})</DisplayString>
-    <Expand>
-      <Item Name="[value]" ExcludeView="simple" Condition="RUST$ENUM$DISR == 1">__0</Item>
-    </Expand>
-  </Type>
-
   <Type Name="core::option::Option&lt;*&gt;" Priority="MediumLow">
     <DisplayString Condition="*(void**)this == nullptr">None</DisplayString>
     <DisplayString>Some({($T1 *)this})</DisplayString>
@@ -30,15 +22,6 @@
     </Expand>
   </Type>
 
-  <Type Name="core::result::Result&lt;*&gt;">
-    <DisplayString Condition="RUST$ENUM$DISR == 0x0">Ok({__0})</DisplayString>
-    <DisplayString Condition="RUST$ENUM$DISR == 0x1">Err({(*($T2*) &amp;__0)})</DisplayString>
-    <Expand>
-      <Item Name="[value]" Condition="RUST$ENUM$DISR == 0x0">__0</Item>
-      <Item Name="[value]" Condition="RUST$ENUM$DISR == 0x1">(*($T2*) &amp;__0)</Item>
-    </Expand>
-  </Type>
-
   <Type Name="core::ptr::non_null::NonNull&lt;*&gt;">
     <DisplayString>{(void*) pointer}</DisplayString>
     <Expand>
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index b816b9d7188..5ce75949457 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -10,7 +10,7 @@ path = "lib.rs"
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
 pulldown-cmark = { version = "0.8", default-features = false }
-minifier = "0.0.39"
+minifier = "0.0.41"
 rayon = { version = "0.3.0", package = "rustc-rayon" }
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 3bfc9fea62e..35ff57f85a5 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -561,7 +561,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                 }
                 WherePredicate::EqPredicate { lhs, rhs } => {
                     match lhs {
-                        Type::QPath { name: left_name, ref self_type, ref trait_ } => {
+                        Type::QPath { name: left_name, ref self_type, ref trait_, .. } => {
                             let ty = &*self_type;
                             match **trait_ {
                                 Type::ResolvedPath {
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 6d05ac073cc..111827aacdf 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -527,7 +527,7 @@ fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::St
 }
 
 fn build_macro(cx: &mut DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemKind {
-    let imported_from = cx.tcx.original_crate_name(did.krate);
+    let imported_from = cx.tcx.crate_name(did.krate);
     match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) {
         LoadedMacro::MacroDef(def, _) => {
             let matchers: Vec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.kind {
@@ -588,6 +588,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
                     self_type: box clean::Generic(ref s),
                     trait_: box clean::ResolvedPath { did, .. },
                     name: ref _name,
+                    ..
                 },
             ref bounds,
         } => !(bounds.is_empty() || *s == kw::SelfUpper && did == trait_did),
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index feeb03b1b67..231f13adeb6 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -418,9 +418,11 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
             GenericBound::TraitBound(t, _) => t.trait_,
             GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"),
         };
+        let self_type = self.self_ty().clean(cx);
         Type::QPath {
             name: cx.tcx.associated_item(self.item_def_id).ident.name,
-            self_type: box self.self_ty().clean(cx),
+            self_def_id: self_type.def_id(),
+            self_type: box self_type,
             trait_: box trait_,
         }
     }
@@ -1104,7 +1106,7 @@ impl Clean<Item> for ty::AssocItem {
                         .filter_map(|pred| {
                             let (name, self_type, trait_, bounds) = match *pred {
                                 WherePredicate::BoundPredicate {
-                                    ty: QPath { ref name, ref self_type, ref trait_ },
+                                    ty: QPath { ref name, ref self_type, ref trait_, .. },
                                     ref bounds,
                                 } => (name, self_type, trait_, bounds),
                                 _ => return None,
@@ -1282,16 +1284,15 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
 
             let segments = if p.is_global() { &p.segments[1..] } else { &p.segments };
             let trait_segments = &segments[..segments.len() - 1];
+            let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id();
             let trait_path = self::Path {
                 global: p.is_global(),
-                res: Res::Def(
-                    DefKind::Trait,
-                    cx.tcx.associated_item(p.res.def_id()).container.id(),
-                ),
+                res: Res::Def(DefKind::Trait, trait_def),
                 segments: trait_segments.clean(cx),
             };
             Type::QPath {
                 name: p.segments.last().expect("segments were empty").ident.name,
+                self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)),
                 self_type: box qself.clean(cx),
                 trait_: box resolve_type(cx, trait_path, hir_id),
             }
@@ -1306,6 +1307,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
             let trait_path = hir::Path { span, res, segments: &[] }.clean(cx);
             Type::QPath {
                 name: segment.ident.name,
+                self_def_id: res.opt_def_id(),
                 self_type: box qself.clean(cx),
                 trait_: box resolve_type(cx, trait_path, hir_id),
             }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 859e525627a..ac2d58903c1 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -526,7 +526,6 @@ impl Item {
     crate fn is_crate(&self) -> bool {
         self.is_mod() && self.def_id.as_real().map_or(false, |did| did.index == CRATE_DEF_INDEX)
     }
-
     crate fn is_mod(&self) -> bool {
         self.type_() == ItemType::Module
     }
@@ -1519,6 +1518,7 @@ crate enum Type {
     QPath {
         name: Symbol,
         self_type: Box<Type>,
+        self_def_id: Option<DefId>,
         trait_: Box<Type>,
     },
 
@@ -1665,7 +1665,7 @@ impl Type {
 
     crate fn projection(&self) -> Option<(&Type, DefId, Symbol)> {
         let (self_, trait_, name) = match self {
-            QPath { self_type, trait_, name } => (self_type, trait_, name),
+            QPath { self_type, trait_, name, .. } => (self_type, trait_, name),
             _ => return None,
         };
         let trait_did = match **trait_ {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 51a011cf197..2c31a502565 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -175,8 +175,9 @@ crate fn strip_type(ty: Type) -> Type {
         Type::BorrowedRef { lifetime, mutability, type_ } => {
             Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) }
         }
-        Type::QPath { name, self_type, trait_ } => Type::QPath {
+        Type::QPath { name, self_type, trait_, self_def_id } => Type::QPath {
             name,
+            self_def_id,
             self_type: Box::new(strip_type(*self_type)),
             trait_: Box::new(strip_type(*trait_)),
         },
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index b75e98ae16c..1b5a00dde59 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -6,8 +6,10 @@ use std::path::PathBuf;
 use std::str::FromStr;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_session::config::{self, parse_crate_types_from_list, parse_externs, CrateType};
-use rustc_session::config::{get_cmd_lint_options, host_triple, nightly_options};
+use rustc_session::config::{
+    self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType,
+};
+use rustc_session::config::{get_cmd_lint_options, nightly_options};
 use rustc_session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
 use rustc_session::getopts;
 use rustc_session::lint::Level;
@@ -347,13 +349,6 @@ impl Options {
             return Err(0);
         }
 
-        if matches.opt_strs("print").iter().any(|opt| opt == "unversioned-files") {
-            for file in crate::html::render::FILES_UNVERSIONED.keys() {
-                println!("{}", file);
-            }
-            return Err(0);
-        }
-
         let color = config::parse_color(&matches);
         let config::JsonConfig { json_rendered, json_unused_externs, .. } =
             config::parse_json(&matches);
@@ -562,14 +557,7 @@ impl Options {
             }
         }
 
-        let target =
-            matches.opt_str("target").map_or(TargetTriple::from_triple(host_triple()), |target| {
-                if target.ends_with(".json") {
-                    TargetTriple::TargetPath(PathBuf::from(target))
-                } else {
-                    TargetTriple::TargetTriple(target)
-                }
-            });
+        let target = parse_target_triple(matches, error_format);
 
         let show_coverage = matches.opt_present("show-coverage");
 
@@ -640,7 +628,8 @@ impl Options {
         let generate_redirect_map = matches.opt_present("generate-redirect-map");
         let show_type_layout = matches.opt_present("show-type-layout");
 
-        let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+        let (lint_opts, describe_lints, lint_cap, _) =
+            get_cmd_lint_options(matches, error_format, &debugging_opts);
 
         Ok(Options {
             input,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 8448b07d0be..d5213fd7711 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -18,7 +18,7 @@ use rustc_span::def_id::CRATE_DEF_INDEX;
 use rustc_target::spec::abi::Abi;
 
 use crate::clean::{
-    self, utils::find_nearest_parent_module, ExternalCrate, FakeDefId, PrimitiveType,
+    self, utils::find_nearest_parent_module, ExternalCrate, FakeDefId, GetDefId, PrimitiveType,
 };
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
@@ -836,10 +836,13 @@ fn fmt_type<'cx>(
                 write!(f, "impl {}", print_generic_bounds(bounds, cx))
             }
         }
-        clean::QPath { ref name, ref self_type, ref trait_ } => {
+        clean::QPath { ref name, ref self_type, ref trait_, ref self_def_id } => {
             let should_show_cast = match *trait_ {
                 box clean::ResolvedPath { ref path, .. } => {
-                    !path.segments.is_empty() && !self_type.is_self_type()
+                    !path.segments.is_empty()
+                        && self_def_id
+                            .zip(trait_.def_id())
+                            .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_)
                 }
                 _ => true,
             };
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index ec04c94dc11..429863f3635 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -119,7 +119,7 @@ crate fn render<T: Print, S: Print>(
     {after_content}\
     <div id=\"rustdoc-vars\" data-root-path=\"{root_path}\" data-current-crate=\"{krate}\" \
        data-search-index-js=\"{root_path}search-index{suffix}.js\" \
-       data-search-js=\"{static_root_path}search{suffix}.js\"></div>
+       data-search-js=\"{static_root_path}search{suffix}.js\"></div>\
     <script src=\"{static_root_path}main{suffix}.js\"></script>\
     {extra_scripts}\
 </body>\
@@ -235,6 +235,7 @@ crate fn redirect(url: &str) -> String {
 <html lang="en">
 <head>
     <meta http-equiv="refresh" content="0;URL={url}">
+    <title>Redirection</title>
 </head>
 <body>
     <p>Redirecting to <a href="{url}">{url}</a>...</p>
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 8676efd9fa8..d80b2db00ac 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -200,8 +200,15 @@ impl<'tcx> Context<'tcx> {
             )
         };
         let keywords = make_item_keywords(it);
+        let name;
+        let tyname_s = if it.is_crate() {
+            name = format!("{} crate", tyname);
+            name.as_str()
+        } else {
+            tyname.as_str()
+        };
         let page = layout::Page {
-            css_class: tyname.as_str(),
+            css_class: tyname_s,
             root_path: &self.root_path(),
             static_root_path: self.shared.static_root_path.as_deref(),
             title: &title,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index b807c5ccc47..10f5184e39a 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -33,7 +33,6 @@ mod print_item;
 mod write_shared;
 
 crate use context::*;
-crate use write_shared::FILES_UNVERSIONED;
 
 use std::collections::VecDeque;
 use std::default::Default;
@@ -509,7 +508,11 @@ fn document(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, parent: Option
         info!("Documenting {}", name);
     }
     document_item_info(w, cx, item, parent);
-    document_full_collapsible(w, item, cx);
+    if parent.is_none() {
+        document_full_collapsible(w, item, cx);
+    } else {
+        document_full(w, item, cx);
+    }
 }
 
 /// Render md_text as markdown.
@@ -1348,8 +1351,11 @@ fn render_impl(
         }
         let w = if short_documented && trait_.is_some() { interesting } else { boring };
 
-        if !doc_buffer.is_empty() {
-            w.write_str("<details class=\"rustdoc-toggle\" open><summary>");
+        let toggled = !doc_buffer.is_empty();
+        if toggled {
+            let method_toggle_class =
+                if item_type == ItemType::Method { " method-toggle" } else { "" };
+            write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
         }
         match *item.kind {
             clean::MethodItem(..) | clean::TyMethodItem(_) => {
@@ -1363,7 +1369,11 @@ fn render_impl(
                             })
                         })
                         .map(|item| format!("{}.{}", item.type_(), name));
-                    write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
+                    write!(
+                        w,
+                        "<div id=\"{}\" class=\"{}{} has-srclink\">",
+                        id, item_type, in_trait_class,
+                    );
                     w.write_str("<code>");
                     render_assoc_item(
                         w,
@@ -1382,13 +1392,17 @@ fn render_impl(
                     );
                     write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
                     write_srclink(cx, item, w);
-                    w.write_str("</h4>");
+                    w.write_str("</div>");
                 }
             }
             clean::TypedefItem(ref tydef, _) => {
                 let source_id = format!("{}.{}", ItemType::AssocType, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
+                write!(
+                    w,
+                    "<div id=\"{}\" class=\"{}{} has-srclink\"><code>",
+                    id, item_type, in_trait_class
+                );
                 assoc_type(
                     w,
                     item,
@@ -1400,12 +1414,16 @@ fn render_impl(
                 );
                 w.write_str("</code>");
                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
-                w.write_str("</h4>");
+                w.write_str("</div>");
             }
             clean::AssocConstItem(ref ty, ref default) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
+                write!(
+                    w,
+                    "<div id=\"{}\" class=\"{}{} has-srclink\"><code>",
+                    id, item_type, in_trait_class
+                );
                 assoc_const(
                     w,
                     item,
@@ -1425,12 +1443,12 @@ fn render_impl(
                 );
                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
                 write_srclink(cx, item, w);
-                w.write_str("</h4>");
+                w.write_str("</div>");
             }
             clean::AssocTypeItem(ref bounds, ref default) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class);
+                write!(w, "<div id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class,);
                 assoc_type(
                     w,
                     item,
@@ -1442,14 +1460,14 @@ fn render_impl(
                 );
                 w.write_str("</code>");
                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
-                w.write_str("</h4>");
+                w.write_str("</div>");
             }
             clean::StrippedItem(..) => return,
             _ => panic!("can't make docs for trait item with name {:?}", item.name),
         }
 
         w.push_buffer(info_buffer);
-        if !doc_buffer.is_empty() {
+        if toggled {
             w.write_str("</summary>");
             w.push_buffer(doc_buffer);
             w.push_str("</details>");
@@ -1535,24 +1553,33 @@ fn render_impl(
         }
     }
     let toggled = !impl_items.is_empty() || !default_impl_items.is_empty();
-    let open_details = |close_tags: &mut String| {
+    let open_details = |close_tags: &mut String, is_collapsed: bool| {
         if toggled {
             close_tags.insert_str(0, "</details>");
-            "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+            if is_collapsed {
+                "<details class=\"rustdoc-toggle implementors-toggle\"><summary>"
+            } else {
+                "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>"
+            }
         } else {
             ""
         }
     };
     if render_mode == RenderMode::Normal {
+        let is_implementing_trait;
         let id = cx.derive_id(match i.inner_impl().trait_ {
             Some(ref t) => {
+                is_implementing_trait = true;
                 if is_on_foreign_type {
                     get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
                 } else {
                     format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
                 }
             }
-            None => "impl".to_string(),
+            None => {
+                is_implementing_trait = false;
+                "impl".to_string()
+            }
         });
         let aliases = if aliases.is_empty() {
             String::new()
@@ -1562,8 +1589,9 @@ fn render_impl(
         if let Some(use_absolute) = use_absolute {
             write!(
                 w,
-                "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">",
-                open_details(&mut close_tags),
+                "{}<div id=\"{}\" class=\"impl has-srclink\"{}>\
+                     <code class=\"in-band\">",
+                open_details(&mut close_tags, is_implementing_trait),
                 id,
                 aliases
             );
@@ -1589,8 +1617,9 @@ fn render_impl(
         } else {
             write!(
                 w,
-                "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
-                open_details(&mut close_tags),
+                "{}<div id=\"{}\" class=\"impl has-srclink\"{}>\
+                     <code class=\"in-band\">{}</code>",
+                open_details(&mut close_tags, is_implementing_trait),
                 id,
                 aliases,
                 i.inner_impl().print(false, cx)
@@ -1606,9 +1635,9 @@ fn render_impl(
         );
         write_srclink(cx, &i.impl_item, w);
         if !toggled {
-            w.write_str("</h3>");
+            w.write_str("</div>");
         } else {
-            w.write_str("</h3></summary>");
+            w.write_str("</div></summary>");
         }
 
         if trait_.is_some() {
@@ -1634,13 +1663,9 @@ fn render_impl(
             );
         }
     }
-    if toggled {
+    if !default_impl_items.is_empty() || !impl_items.is_empty() {
         w.write_str("<div class=\"impl-items\">");
         w.push_buffer(default_impl_items);
-        if trait_.is_some() && !impl_items.is_empty() {
-            w.write_str("<details class=\"undocumented\"><summary></summary>");
-            close_tags.insert_str(0, "</details>");
-        }
         w.push_buffer(impl_items);
         close_tags.insert_str(0, "</div>");
     }
@@ -1688,7 +1713,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
                 "<div class=\"block version\">\
                      <p>Version {}</p>\
                  </div>",
-                Escape(version)
+                Escape(version),
             );
         }
     }
@@ -1698,9 +1723,10 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
         write!(
             buffer,
             "<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>",
-            it.name.as_ref().expect("crates always have a name")
+            it.name.as_ref().expect("crates always have a name"),
         );
     }
+
     match *it.kind {
         clean::StructItem(ref s) => sidebar_struct(cx, buffer, it, s),
         clean::TraitItem(ref t) => sidebar_trait(cx, buffer, it, t),
@@ -1710,7 +1736,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
         clean::TypedefItem(_, _) => sidebar_typedef(cx, buffer, it),
         clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
         clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it),
-        _ => (),
+        _ => {}
     }
 
     // The sidebar is designed to display sibling functions, modules and
@@ -1721,22 +1747,24 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
     // as much HTML as possible in order to allow non-JS-enabled browsers
     // to navigate the documentation (though slightly inefficiently).
 
-    buffer.write_str("<p class=\"location\">");
-    for (i, name) in cx.current.iter().take(parentlen).enumerate() {
-        if i > 0 {
-            buffer.write_str("::<wbr>");
+    if !it.is_mod() {
+        buffer.write_str("<p class=\"location\">Other items in<br>");
+        for (i, name) in cx.current.iter().take(parentlen).enumerate() {
+            if i > 0 {
+                buffer.write_str("::<wbr>");
+            }
+            write!(
+                buffer,
+                "<a href=\"{}index.html\">{}</a>",
+                &cx.root_path()[..(cx.current.len() - i - 1) * 3],
+                *name
+            );
         }
-        write!(
-            buffer,
-            "<a href=\"{}index.html\">{}</a>",
-            &cx.root_path()[..(cx.current.len() - i - 1) * 3],
-            *name
-        );
+        buffer.write_str("</p>");
     }
-    buffer.write_str("</p>");
 
     // Sidebar refers to the enclosing module, not this module.
-    let relpath = if it.is_mod() { "../" } else { "" };
+    let relpath = if it.is_mod() && parentlen != 0 { "./" } else { "" };
     write!(
         buffer,
         "<div id=\"sidebar-vars\" data-name=\"{name}\" data-ty=\"{ty}\" data-relpath=\"{path}\">\
@@ -1745,17 +1773,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
         ty = it.type_(),
         path = relpath
     );
-
-    if parentlen == 0 {
-        write!(
-            buffer,
-            "<script defer src=\"{}sidebar-items{}.js\"></script>",
-            relpath, cx.shared.resource_suffix
-        );
-    } else {
-        write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
-    }
-
+    write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
     // Closes sidebar-elems div.
     buffer.write_str("</div>");
 }
@@ -2263,8 +2281,8 @@ fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean:
     }
 }
 
-fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
-    match *ty {
+fn item_ty_to_strs(ty: ItemType) -> (&'static str, &'static str) {
+    match ty {
         ItemType::ExternCrate | ItemType::Import => ("reexports", "Re-exports"),
         ItemType::Module => ("modules", "Modules"),
         ItemType::Struct => ("structs", "Structs"),
@@ -2296,10 +2314,14 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) {
 fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
     let mut sidebar = String::new();
 
+    // Re-exports are handled a bit differently because they can be extern crates or imports.
     if items.iter().any(|it| {
-        it.type_() == ItemType::ExternCrate || (it.type_() == ItemType::Import && !it.is_stripped())
+        it.name.is_some()
+            && (it.type_() == ItemType::ExternCrate
+                || (it.type_() == ItemType::Import && !it.is_stripped()))
     }) {
-        sidebar.push_str("<li><a href=\"#reexports\">Re-exports</a></li>");
+        let (id, name) = item_ty_to_strs(ItemType::Import);
+        sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
     }
 
     // ordering taken from item_module, reorder, where it prioritized elements in a certain order
@@ -2326,13 +2348,9 @@ fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
         ItemType::ForeignType,
         ItemType::Keyword,
     ] {
-        if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) {
-            let (short, name) = item_ty_to_strs(&myty);
-            sidebar.push_str(&format!(
-                "<li><a href=\"#{id}\">{name}</a></li>",
-                id = short,
-                name = name
-            ));
+        if items.iter().any(|it| !it.is_stripped() && it.type_() == myty && it.name.is_some()) {
+            let (id, name) = item_ty_to_strs(myty);
+            sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
         }
     }
 
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index ff639cb2924..1c5d9a26441 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -75,13 +75,14 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer,
             );
         }
     }
-    write!(buf, "<a class=\"{}\" href=\"\">{}</a>", item.type_(), item.name.as_ref().unwrap());
+    write!(buf, "<a class=\"{}\" href=\"#\">{}</a>", item.type_(), item.name.as_ref().unwrap());
     write!(
         buf,
         "<button id=\"copy-path\" onclick=\"copy_path(this)\">\
             <img src=\"{static_root_path}clipboard{suffix}.svg\" \
                 width=\"19\" height=\"18\" \
-                alt=\"Copy item import\">\
+                alt=\"Copy item import\" \
+                title=\"Copy item import to clipboard\">\
          </button>",
         static_root_path = page.get_static_root_path(),
         suffix = page.resource_suffix,
@@ -262,7 +263,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                 w.write_str("</table>");
             }
             curty = myty;
-            let (short, name) = item_ty_to_strs(&myty.unwrap());
+            let (short, name) = item_ty_to_strs(myty.unwrap());
             write!(
                 w,
                 "<h2 id=\"{id}\" class=\"section-header\">\
@@ -578,13 +579,23 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         info!("Documenting {} on {:?}", name, t.name);
         let item_type = m.type_();
         let id = cx.derive_id(format!("{}.{}", item_type, name));
-        write!(w, "<h3 id=\"{id}\" class=\"method\"><code>", id = id,);
+        let mut content = Buffer::empty_from(w);
+        document(&mut content, cx, m, Some(t));
+        let toggled = !content.is_empty();
+        if toggled {
+            write!(w, "<details class=\"rustdoc-toggle\" open><summary>");
+        }
+        write!(w, "<div id=\"{}\" class=\"method has-srclink\"><code>", id);
         render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl, cx);
         w.write_str("</code>");
         render_stability_since(w, m, t, cx.tcx());
         write_srclink(cx, m, w);
-        w.write_str("</h3>");
-        document(w, cx, m, Some(t));
+        w.write_str("</div>");
+        if toggled {
+            write!(w, "</summary>");
+            w.push_buffer(content);
+            write!(w, "</details>");
+        }
     }
 
     if !types.is_empty() {
@@ -1501,7 +1512,7 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
             w.write_str(
                 "Non-exhaustive structs could have additional fields added in future. \
                  Therefore, non-exhaustive structs cannot be constructed in external crates \
-                 using the traditional <code>Struct {{ .. }}</code> syntax; cannot be \
+                 using the traditional <code>Struct { .. }</code> syntax; cannot be \
                  matched against without a wildcard <code>..</code>; and \
                  struct update syntax will not work.",
             );
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index bd781e7b741..a4188e6b203 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -18,7 +18,7 @@ use crate::docfs::PathError;
 use crate::error::Error;
 use crate::html::{layout, static_files};
 
-crate static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
+static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
     map! {
         "FiraSans-Regular.woff2" => static_files::fira_sans::REGULAR2,
         "FiraSans-Medium.woff2" => static_files::fira_sans::MEDIUM2,
@@ -33,6 +33,8 @@ crate static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
         "SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD,
         "SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC,
         "SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE,
+        "noto-sans-kr-v13-korean-regular.woff" => static_files::noto_sans_kr::REGULAR,
+        "noto-sans-kr-v13-korean-regular-LICENSE.txt" => static_files::noto_sans_kr::LICENSE,
         "LICENSE-MIT.txt" => static_files::LICENSE_MIT,
         "LICENSE-APACHE.txt" => static_files::LICENSE_APACHE,
         "COPYRIGHT.txt" => static_files::COPYRIGHT,
@@ -225,7 +227,6 @@ pub(super) fn write_shared(
     )?;
     write_minify("search.js", static_files::SEARCH_JS)?;
     write_minify("settings.js", static_files::SETTINGS_JS)?;
-    write_minify("sidebar-items.js", static_files::sidebar::ITEMS)?;
 
     if cx.shared.include_sources {
         write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT)?;
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index be30871ea4c..1a15a444a70 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -161,7 +161,7 @@ function hideThemeButtonState() {
         outputElement: function() {
             return document.getElementById("search");
         },
-        title: null,
+        title: document.title,
         titleBeforeSearch: document.title,
         timeout: null,
         // On the search screen, so you remain on the last tab you opened.
@@ -170,7 +170,8 @@ function hideThemeButtonState() {
         // 1 for "In Parameters"
         // 2 for "In Return Types"
         currentTab: 0,
-        mouseMovedAfterSearch: true,
+        // tab and back preserves the element that was focused.
+        focusedByTab: [null, null, null],
         clearInputTimeout: function() {
             if (searchState.timeout !== null) {
                 clearTimeout(searchState.timeout);
@@ -262,10 +263,6 @@ function hideThemeButtonState() {
                 search_input.placeholder = searchState.input.origPlaceholder;
             });
 
-            document.addEventListener("mousemove", function() {
-                searchState.mouseMovedAfterSearch = true;
-            });
-
             search_input.removeAttribute('disabled');
 
             // `crates{version}.js` should always be loaded before this script, so we can use it
@@ -428,9 +425,9 @@ function hideThemeButtonState() {
     function handleEscape(ev) {
         var help = getHelpElement(false);
         var search = searchState.outputElement();
-        if (!hasClass(help, "hidden")) {
+        if (help && !hasClass(help, "hidden")) {
             displayHelp(false, ev, help);
-        } else if (!hasClass(search, "hidden")) {
+        } else if (search && !hasClass(search, "hidden")) {
             searchState.clearInputTimeout();
             ev.preventDefault();
             searchState.hideResults(search);
@@ -564,41 +561,40 @@ function hideThemeButtonState() {
         }
     }());
 
-    function addSidebarCrates(crates) {
-        // Draw a convenient sidebar of known crates if we have a listing
-        if (window.rootPath === "../" || window.rootPath === "./") {
-            var sidebar = document.getElementsByClassName("sidebar-elems")[0];
-            if (sidebar) {
-                var div = document.createElement("div");
-                div.className = "block crate";
-                div.innerHTML = "<h3>Crates</h3>";
-                var ul = document.createElement("ul");
-                div.appendChild(ul);
-
-                for (var i = 0; i < crates.length; ++i) {
-                    var klass = "crate";
-                    if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
-                        klass += " current";
-                    }
-                    var link = document.createElement("a");
-                    link.href = window.rootPath + crates[i] + "/index.html";
-                    link.className = klass;
-                    link.textContent = crates[i];
-
-                    var li = document.createElement("li");
-                    li.appendChild(link);
-                    ul.appendChild(li);
-                }
-                sidebar.appendChild(div);
-            }
-        }
-    }
-
     // delayed sidebar rendering.
     window.initSidebarItems = function(items) {
         var sidebar = document.getElementsByClassName("sidebar-elems")[0];
         var current = window.sidebarCurrent;
 
+        function addSidebarCrates(crates) {
+            if (!hasClass(document.body, "crate")) {
+                // We only want to list crates on the crate page.
+                return;
+            }
+            // Draw a convenient sidebar of known crates if we have a listing
+            var div = document.createElement("div");
+            div.className = "block crate";
+            div.innerHTML = "<h3>Crates</h3>";
+            var ul = document.createElement("ul");
+            div.appendChild(ul);
+
+            for (var i = 0; i < crates.length; ++i) {
+                var klass = "crate";
+                if (window.rootPath !== "./" && crates[i] === window.currentCrate) {
+                    klass += " current";
+                }
+                var link = document.createElement("a");
+                link.href = window.rootPath + crates[i] + "/index.html";
+                link.className = klass;
+                link.textContent = crates[i];
+
+                var li = document.createElement("li");
+                li.appendChild(link);
+                ul.appendChild(li);
+            }
+            sidebar.appendChild(div);
+        }
+
         function block(shortty, longty) {
             var filtered = items[shortty];
             if (!filtered) {
@@ -637,28 +633,32 @@ function hideThemeButtonState() {
                 ul.appendChild(li);
             }
             div.appendChild(ul);
-            if (sidebar) {
-                sidebar.appendChild(div);
-            }
+            sidebar.appendChild(div);
         }
 
-        block("primitive", "Primitive Types");
-        block("mod", "Modules");
-        block("macro", "Macros");
-        block("struct", "Structs");
-        block("enum", "Enums");
-        block("union", "Unions");
-        block("constant", "Constants");
-        block("static", "Statics");
-        block("trait", "Traits");
-        block("fn", "Functions");
-        block("type", "Type Definitions");
-        block("foreigntype", "Foreign Types");
-        block("keyword", "Keywords");
-        block("traitalias", "Trait Aliases");
-
-        // `crates{version}.js` should always be loaded before this script, so we can use it safely.
-        addSidebarCrates(window.ALL_CRATES);
+        if (sidebar) {
+            var isModule = hasClass(document.body, "mod");
+            if (!isModule) {
+                block("primitive", "Primitive Types");
+                block("mod", "Modules");
+                block("macro", "Macros");
+                block("struct", "Structs");
+                block("enum", "Enums");
+                block("union", "Unions");
+                block("constant", "Constants");
+                block("static", "Statics");
+                block("trait", "Traits");
+                block("fn", "Functions");
+                block("type", "Type Definitions");
+                block("foreigntype", "Foreign Types");
+                block("keyword", "Keywords");
+                block("traitalias", "Trait Aliases");
+            }
+
+            // `crates{version}.js` should always be loaded before this script, so we can use
+            // it safely.
+            addSidebarCrates(window.ALL_CRATES);
+        }
     };
 
     window.register_implementors = function(imp) {
@@ -767,138 +767,6 @@ function hideThemeButtonState() {
         innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed);
     }
 
-    function collapseDocs(toggle, mode) {
-        if (!toggle || !toggle.parentNode) {
-            return;
-        }
-
-        function adjustToggle(arg) {
-            return function(e) {
-                if (hasClass(e, "toggle-label")) {
-                    if (arg) {
-                        e.style.display = "inline-block";
-                    } else {
-                        e.style.display = "none";
-                    }
-                }
-                if (hasClass(e, "inner")) {
-                    e.innerHTML = labelForToggleButton(arg);
-                }
-            };
-        }
-
-        function implHider(addOrRemove, fullHide) {
-            return function(n) {
-                var shouldHide =
-                    fullHide ||
-                    hasClass(n, "method") ||
-                    hasClass(n, "associatedconstant");
-                if (shouldHide || hasClass(n, "type")) {
-                    if (shouldHide) {
-                        if (addOrRemove) {
-                            addClass(n, "hidden-by-impl-hider");
-                        } else {
-                            removeClass(n, "hidden-by-impl-hider");
-                        }
-                    }
-                    var ns = n.nextElementSibling;
-                    while (ns && (hasClass(ns, "docblock") || hasClass(ns, "item-info"))) {
-                        if (addOrRemove) {
-                            addClass(ns, "hidden-by-impl-hider");
-                        } else {
-                            removeClass(ns, "hidden-by-impl-hider");
-                        }
-                        ns = ns.nextElementSibling;
-                    }
-                }
-            };
-        }
-
-        var relatedDoc;
-        var action = mode;
-        if (!hasClass(toggle.parentNode, "impl")) {
-            relatedDoc = toggle.parentNode.nextElementSibling;
-            if (hasClass(relatedDoc, "item-info")) {
-                relatedDoc = relatedDoc.nextElementSibling;
-            }
-            if (hasClass(relatedDoc, "docblock")) {
-                if (mode === "toggle") {
-                    if (hasClass(relatedDoc, "hidden-by-usual-hider")) {
-                        action = "show";
-                    } else {
-                        action = "hide";
-                    }
-                }
-                if (action === "hide") {
-                    addClass(relatedDoc, "hidden-by-usual-hider");
-                    onEachLazy(toggle.childNodes, adjustToggle(true));
-                    addClass(toggle.parentNode, "collapsed");
-                } else if (action === "show") {
-                    removeClass(relatedDoc, "hidden-by-usual-hider");
-                    removeClass(toggle.parentNode, "collapsed");
-                    onEachLazy(toggle.childNodes, adjustToggle(false));
-                }
-            }
-        } else {
-            // we are collapsing the impl block(s).
-
-            var parentElem = toggle.parentNode;
-            relatedDoc = parentElem;
-            var docblock = relatedDoc.nextElementSibling;
-
-            while (!hasClass(relatedDoc, "impl-items")) {
-                relatedDoc = relatedDoc.nextElementSibling;
-            }
-
-            if (!relatedDoc && !hasClass(docblock, "docblock")) {
-                return;
-            }
-
-            // Hide all functions, but not associated types/consts.
-
-            if (mode === "toggle") {
-                if (hasClass(relatedDoc, "fns-now-collapsed") ||
-                    hasClass(docblock, "hidden-by-impl-hider")) {
-                    action = "show";
-                } else {
-                    action = "hide";
-                }
-            }
-
-            var dontApplyBlockRule = toggle.parentNode.parentNode.id !== "main";
-            if (action === "show") {
-                removeClass(relatedDoc, "fns-now-collapsed");
-                // Stability/deprecation/portability information is never hidden.
-                if (!hasClass(docblock, "item-info")) {
-                    removeClass(docblock, "hidden-by-usual-hider");
-                }
-                onEachLazy(toggle.childNodes, adjustToggle(false, dontApplyBlockRule));
-                onEachLazy(relatedDoc.childNodes, implHider(false, dontApplyBlockRule));
-            } else if (action === "hide") {
-                addClass(relatedDoc, "fns-now-collapsed");
-                // Stability/deprecation/portability information should be shown even when detailed
-                // info is hidden.
-                if (!hasClass(docblock, "item-info")) {
-                    addClass(docblock, "hidden-by-usual-hider");
-                }
-                onEachLazy(toggle.childNodes, adjustToggle(true, dontApplyBlockRule));
-                onEachLazy(relatedDoc.childNodes, implHider(true, dontApplyBlockRule));
-            }
-        }
-    }
-
-    function collapseNonInherent(e) {
-        // inherent impl ids are like "impl" or impl-<number>'.
-        // they will never be hidden by default.
-        var n = e.parentElement;
-        if (n.id.match(/^impl(?:-\d+)?$/) === null) {
-            // Automatically minimize all non-inherent impls
-            if (hasClass(n, "impl")) {
-                collapseDocs(e, "hide");
-            }
-        }
-    }
-
     function insertAfter(newNode, referenceNode) {
         referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
     }
@@ -911,53 +779,36 @@ function hideThemeButtonState() {
 
         var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true";
         var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false";
+        var hideImplementations = getSettingValue("auto-hide-trait-implementations") !== "false";
         var hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
 
-        var impl_list = document.getElementById("trait-implementations-list");
-        if (impl_list !== null) {
-            onEachLazy(impl_list.getElementsByClassName("rustdoc-toggle"), function(e) {
-                collapseNonInherent(e);
-            });
+        function openImplementors(id) {
+            var list = document.getElementById(id);
+            if (list !== null) {
+                onEachLazy(list.getElementsByClassName("implementors-toggle"), function(e) {
+                    e.open = true;
+                });
+            }
         }
 
-        var blanket_list = document.getElementById("blanket-implementations-list");
-        if (blanket_list !== null) {
-            onEachLazy(blanket_list.getElementsByClassName("rustdoc-toggle"), function(e) {
-                collapseNonInherent(e);
-            });
+        if (!hideImplementations) {
+            openImplementors("trait-implementations-list");
+            openImplementors("blanket-implementations-list");
         }
 
-        if (hideMethodDocs) {
-            onEachLazy(document.getElementsByClassName("method"), function(e) {
-                var toggle = e.parentNode;
-                if (toggle) {
-                    toggle = toggle.parentNode;
-                }
-                if (toggle && toggle.tagName === "DETAILS") {
-                    toggle.open = false;
-                }
-            });
+        if (!hideImplementors) {
+            openImplementors("implementors-list");
         }
 
-        onEachLazy(document.getElementsByTagName("details"), function (e) {
-            var showLargeItem = !hideLargeItemContents && hasClass(e, "type-contents-toggle");
-            var showImplementor = !hideImplementors && hasClass(e, "implementors-toggle");
-            if (showLargeItem || showImplementor) {
+        onEachLazy(document.getElementsByClassName("rustdoc-toggle"), function (e) {
+            if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) {
                 e.open = true;
             }
-        });
-
-        var currentType = document.getElementsByClassName("type-decl")[0];
-        if (currentType) {
-            currentType = currentType.getElementsByClassName("rust")[0];
-            if (currentType) {
-                onEachLazy(currentType.classList, function(item) {
-                    if (item !== "main") {
-                        return true;
-                    }
-                });
+            if (hideMethodDocs && hasClass(e, "method-toggle")) {
+                e.open = false;
             }
-        }
+
+        });
 
         var pageId = getPageId();
         if (pageId !== null) {
@@ -1064,7 +915,7 @@ function hideThemeButtonState() {
             ["T", "Focus the theme picker menu"],
             ["↑", "Move up in search results"],
             ["↓", "Move down in search results"],
-            ["ctrl + ↑ / ↓", "Switch result tab"],
+            ["← / →", "Switch result tab (when results focused)"],
             ["&#9166;", "Go to active search result"],
             ["+", "Expand all sections"],
             ["-", "Collapse all sections"],
diff --git a/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt
new file mode 100644
index 00000000000..922d5fdc18d
--- /dev/null
+++ b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt
@@ -0,0 +1,93 @@
+Copyright 2014, 2015 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+
+This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff
new file mode 100644
index 00000000000..01d6b6b5466
--- /dev/null
+++ b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff
Binary files differdiff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index e2e1aefa4a8..d3f8a7aa67d 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -66,6 +66,14 @@
 	font-display: swap;
 }
 
+/* Avoid using legacy CJK serif fonts in Windows like Batang */
+@font-face {
+	font-family: 'Noto Sans KR';
+	src: url("noto-sans-kr-v13-korean-regular.woff") format("woff");
+	font-display: swap;
+	unicode-range: U+A960-A97F, U+AC00-D7AF, U+D7B0-D7FF;
+}
+
 * {
 	-webkit-box-sizing: border-box;
 	-moz-box-sizing: border-box;
@@ -90,7 +98,7 @@ html {
 /* General structure and fonts */
 
 body {
-	font: 16px/1.4 "Source Serif 4", serif;
+	font: 16px/1.4 "Source Serif 4", "Noto Sans KR", serif;
 	margin: 0;
 	position: relative;
 	padding: 10px 15px 20px 15px;
@@ -109,8 +117,7 @@ h2 {
 h3 {
 	font-size: 1.3em;
 }
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.notable),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
+h1, h2, h3, h4 {
 	font-weight: 500;
 	margin: 20px 0 15px 0;
 	padding-bottom: 6px;
@@ -127,29 +134,38 @@ h1.fqn {
 h1.fqn > .in-band > a:hover {
 	text-decoration: underline;
 }
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) {
+h2, h3, h4 {
 	border-bottom: 1px solid;
 }
-h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant, h4.associatedtype {
+.impl, .method,
+.type, .associatedconstant,
+.associatedtype {
 	flex-basis: 100%;
 	font-weight: 600;
 	margin-top: 16px;
 	margin-bottom: 10px;
 	position: relative;
 }
-h3.impl, h3.method, h4.method.trait-impl, h3.type,
-h4.type.trait-impl, h4.associatedconstant.trait-impl, h4.associatedtype.trait-impl {
+.impl, .method.trait-impl,
+.type.trait-impl,
+.associatedconstant.trait-impl,
+.associatedtype.trait-impl {
 	padding-left: 15px;
 }
 
+div.impl-items > div {
+	padding-left: 0;
+}
+
 h1, h2, h3, h4,
-.sidebar, a.source, .search-input, .content table td:first-child > a,
-div.item-list .out-of-band,
+.sidebar, a.source, .search-input, .search-results .result-name,
+.content table td:first-child > a,
+div.item-list .out-of-band, span.since,
 #source-sidebar, #sidebar-toggle,
 details.rustdoc-toggle > summary::before,
 details.undocumented > summary::before,
-.content ul.crate a.crate,
+div.impl-items > div:not(.docblock):not(.item-info),
+.content ul.crate a.crate, a.srclink,
 /* This selector is for the items listed in the "all items" page. */
 #main > ul.docblock > li > a {
 	font-family: "Fira Sans", Arial, sans-serif;
@@ -295,17 +311,18 @@ nav.sub {
 	border: none;
 }
 
-.location a:first-child {
+.location a:first-of-type {
 	font-weight: 500;
 }
+.location a:hover {
+	text-decoration: underline;
+}
 
 .block {
 	padding: 0;
 	margin-bottom: 14px;
 }
 .block h2, .block h3 {
-	margin-top: 0;
-	margin-bottom: 8px;
 	text-align: center;
 }
 .block ul, .block li {
@@ -427,9 +444,13 @@ nav.sub {
 	border-bottom: 1px solid;
 }
 
-#main > .docblock h1 { font-size: 1.3em; }
-#main > .docblock h2 { font-size: 1.15em; }
-#main > .docblock h3, #main > .docblock h4, #main > .docblock h5 { font-size: 1em; }
+.top-doc .docblock h1 { font-size: 1.3em; }
+.top-doc .docblock h2 { font-size: 1.15em; }
+.top-doc .docblock h3,
+.top-doc .docblock h4,
+.top-doc .docblock h5 {
+	font-size: 1em;
+}
 
 .docblock h1 { font-size: 1em; }
 .docblock h2 { font-size: 0.95em; }
@@ -449,15 +470,7 @@ nav.sub {
 	font-weight: normal;
 }
 
-h3.impl > .out-of-band {
-	font-size: 21px;
-}
-
-h4.method > .out-of-band {
-	font-size: 19px;
-}
-
-h4 > code, h3 > code, .invisible > code {
+.method > code, .trait-impl > code, .invisible > code {
 	max-width: calc(100% - 41px);
 	display: block;
 }
@@ -530,7 +543,7 @@ h4 > code, h3 > code, .invisible > code {
 }
 .content .multi-column li { width: 100%; display: inline-block; }
 
-.content .method {
+.content > .methods > .method {
 	font-size: 1em;
 	position: relative;
 }
@@ -542,7 +555,7 @@ h4 > code, h3 > code, .invisible > code {
 	font-size: 0.8em;
 }
 
-.content .methods > div:not(.notable-traits):not(.methods) {
+.content .methods > div:not(.notable-traits):not(.method) {
 	margin-left: 40px;
 	margin-bottom: 15px;
 }
@@ -551,9 +564,6 @@ h4 > code, h3 > code, .invisible > code {
 	margin-left: 20px;
 	margin-top: -34px;
 }
-.content .docblock > .impl-items > h4 {
-	border-bottom: 0;
-}
 .content .docblock >.impl-items .table-display {
 	margin: 0;
 }
@@ -675,7 +685,8 @@ a {
 	text-decoration: underline;
 }
 
-.invisible > .srclink, h4 > code + .srclink, h3 > code + .srclink {
+.invisible > .srclink,
+.method > code + .srclink {
 	position: absolute;
 	top: 0;
 	right: 0;
@@ -748,41 +759,47 @@ a {
 	outline: 0;
 }
 
-.search-results .desc {
+.search-results {
+	display: none;
+	padding-bottom: 2em;
+}
+
+.search-results.active {
+	display: block;
+	/* prevent overhanging tabs from moving the first result */
+	clear: both;
+}
+
+.search-results .desc > span {
 	white-space: nowrap;
 	text-overflow: ellipsis;
 	overflow: hidden;
 	display: block;
 }
 
-.search-results a {
+.search-results > a {
 	display: block;
+	width: 100%;
+	/* A little margin ensures the browser's outlining of focused links has room to display. */
+	margin-left: 2px;
+	margin-right: 2px;
+	border-bottom: 1px solid #aaa3;
 }
 
-.content .search-results td:first-child {
-	padding-right: 0;
-	width: 50%;
-}
-.content .search-results td:first-child a {
-	padding-right: 10px;
-}
-.content .search-results td:first-child a:after {
-	clear: both;
-	content: "";
-	display: block;
-}
-.content .search-results td:first-child a span {
-	float: left;
+.search-results > a > div {
+	display: flex;
+	flex-flow: row wrap;
 }
 
-tr.result span.primitive::after {
-	content: ' (primitive type)';
-	font-style: italic;
+.search-results .result-name, .search-results div.desc, .search-results .result-description {
+	width: 50%;
+}
+.search-results .result-name {
+	padding-right: 1em;
 }
 
-tr.result span.keyword::after {
-	content: ' (keyword)';
-	font-style: italic;
+.search-results .result-name > span {
+	display: inline-block;
 }
 
 body.blur > :not(#help) {
@@ -904,7 +921,7 @@ body.blur > :not(#help) {
 	flex-grow: 1;
 }
 
-.impl-items h4, h4.impl, h3.impl, .methods h3 {
+.has-srclink {
 	display: flex;
 	flex-basis: 100%;
 	font-size: 16px;
@@ -1115,6 +1132,13 @@ a.test-arrow:hover{
 	margin: 0;
 }
 
+.notable-traits .notable {
+	margin: 0;
+	margin-bottom: 13px;
+	font-size: 19px;
+	font-weight: 600;
+}
+
 .notable-traits .docblock code.content{
 	margin: 0;
 	padding: 0;
@@ -1134,6 +1158,11 @@ pre.rust {
 .search-failed {
 	text-align: center;
 	margin-top: 20px;
+	display: none;
+}
+
+.search-failed.active {
+	display: block;
 }
 
 .search-failed > ul {
@@ -1173,12 +1202,6 @@ pre.rust {
 	margin-left: 5px;
 }
 
-h4 > .notable-traits {
-	position: absolute;
-	left: -44px;
-	top: 2px;
-}
-
 #all-types {
 	text-align: center;
 	border: 1px solid;
@@ -1262,12 +1285,11 @@ h4 > .notable-traits {
 }
 
 #copy-path {
+	background: initial;
 	margin-left: 10px;
 	padding: 0;
 	padding-left: 2px;
-}
-#copy-path> img {
-	margin-bottom: 2px;
+	border: 0;
 }
 
 #theme-choices {
@@ -1293,14 +1315,6 @@ h4 > .notable-traits {
 	border-top: 1px solid;
 }
 
-
-
-h3.notable {
-	margin: 0;
-	margin-bottom: 13px;
-	font-size: 19px;
-}
-
 kbd {
 	display: inline-block;
 	padding: 3px 5px;
@@ -1445,13 +1459,12 @@ details.rustdoc-toggle > summary.hideme::before {
 details.rustdoc-toggle > summary:not(.hideme)::before {
 	position: absolute;
 	left: -23px;
-	top: initial;
+	top: 3px;
 }
 
 .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
 .undocumented > details.rustdoc-toggle > summary:not(.hideme)::before {
 	position: absolute;
-	top: 3px;
 	left: -2px;
 }
 
@@ -1593,10 +1606,6 @@ details.undocumented[open] > summary::before {
 		padding: 0;
 	}
 
-	.content h4 > .out-of-band {
-		position: inherit;
-	}
-
 	#search {
 		margin-left: 0;
 	}
@@ -1616,7 +1625,7 @@ details.undocumented[open] > summary::before {
 		z-index: 1;
 	}
 
-	h4 > .notable-traits {
+	.notable-traits {
 		position: absolute;
 		left: -22px;
 		top: 24px;
@@ -1724,6 +1733,18 @@ details.undocumented[open] > summary::before {
 	.search-container > div {
 		width: calc(100% - 32px);
 	}
+
+	/* Display an alternating layout on tablets and phones */
+	.search-results > a {
+		border-bottom: 1px solid #aaa9;
+		padding: 5px 0px;
+	}
+	.search-results .result-name, .search-results div.desc, .search-results .result-description {
+		width: 100%;
+	}
+	.search-results div.desc, .search-results .result-description {
+		padding-left: 2em;
+	}
 }
 
 @media print {
diff --git a/src/librustdoc/html/static/search.js b/src/librustdoc/html/static/search.js
index c53b3d5f14b..b3242bf4df9 100644
--- a/src/librustdoc/html/static/search.js
+++ b/src/librustdoc/html/static/search.js
@@ -51,9 +51,9 @@ function printTab(nb) {
     });
     onEachLazy(document.getElementById("results").childNodes, function(elem) {
         if (nb === 0) {
-            elem.style.display = "";
+            addClass(elem, "active");
         } else {
-            elem.style.display = "none";
+            removeClass(elem, "active");
         }
         nb -= 1;
     });
@@ -878,106 +878,22 @@ window.initSearch = function(rawSearchIndex) {
         };
     }
 
-    function initSearchNav() {
-        var hoverTimeout;
-
-        var click_func = function(e) {
-            var el = e.target;
-            // to retrieve the real "owner" of the event.
-            while (el.tagName !== "TR") {
-                el = el.parentNode;
-            }
-            var dst = e.target.getElementsByTagName("a");
-            if (dst.length < 1) {
-                return;
-            }
-            dst = dst[0];
-            if (window.location.pathname === dst.pathname) {
-                searchState.hideResults();
-                document.location.href = dst.href;
-            }
-        };
-        var mouseover_func = function(e) {
-            if (searchState.mouseMovedAfterSearch) {
-                var el = e.target;
-                // to retrieve the real "owner" of the event.
-                while (el.tagName !== "TR") {
-                    el = el.parentNode;
-                }
-                clearTimeout(hoverTimeout);
-                hoverTimeout = setTimeout(function() {
-                    onEachLazy(document.getElementsByClassName("search-results"), function(e) {
-                        onEachLazy(e.getElementsByClassName("result"), function(i_e) {
-                            removeClass(i_e, "highlighted");
-                        });
-                    });
-                    addClass(el, "highlighted");
-                }, 20);
-            }
-        };
-        onEachLazy(document.getElementsByClassName("search-results"), function(e) {
-            onEachLazy(e.getElementsByClassName("result"), function(i_e) {
-                i_e.onclick = click_func;
-                i_e.onmouseover = mouseover_func;
-            });
-        });
-
-        searchState.input.onkeydown = function(e) {
-            // "actives" references the currently highlighted item in each search tab.
-            // Each array in "actives" represents a tab.
-            var actives = [[], [], []];
-            // "current" is used to know which tab we're looking into.
-            var current = 0;
-            onEachLazy(document.getElementById("results").childNodes, function(e) {
-                onEachLazy(e.getElementsByClassName("highlighted"), function(h_e) {
-                    actives[current].push(h_e);
-                });
-                current += 1;
-            });
-            var SHIFT = 16;
-            var CTRL = 17;
-            var ALT = 18;
+    function nextTab(direction) {
+        var next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
+        searchState.focusedByTab[searchState.currentTab] = document.activeElement;
+        printTab(next);
+        focusSearchResult();
+    }
 
-            var currentTab = searchState.currentTab;
-            if (e.which === 38) { // up
-                if (e.ctrlKey) { // Going through result tabs.
-                    printTab(currentTab > 0 ? currentTab - 1 : 2);
-                } else {
-                    if (!actives[currentTab].length ||
-                        !actives[currentTab][0].previousElementSibling) {
-                        return;
-                    }
-                    addClass(actives[currentTab][0].previousElementSibling, "highlighted");
-                    removeClass(actives[currentTab][0], "highlighted");
-                }
-                e.preventDefault();
-            } else if (e.which === 40) { // down
-                if (e.ctrlKey) { // Going through result tabs.
-                    printTab(currentTab > 1 ? 0 : currentTab + 1);
-                } else if (!actives[currentTab].length) {
-                    var results = document.getElementById("results").childNodes;
-                    if (results.length > 0) {
-                        var res = results[currentTab].getElementsByClassName("result");
-                        if (res.length > 0) {
-                            addClass(res[0], "highlighted");
-                        }
-                    }
-                } else if (actives[currentTab][0].nextElementSibling) {
-                    addClass(actives[currentTab][0].nextElementSibling, "highlighted");
-                    removeClass(actives[currentTab][0], "highlighted");
-                }
-                e.preventDefault();
-            } else if (e.which === 13) { // return
-                if (actives[currentTab].length) {
-                    var elem = actives[currentTab][0].getElementsByTagName("a")[0];
-                    document.location.href = elem.href;
-                }
-            } else if ([SHIFT, CTRL, ALT].indexOf(e.which) !== -1) {
-                // Does nothing, it's just to avoid losing "focus" on the highlighted element.
-            } else if (actives[currentTab].length > 0) {
-                removeClass(actives[currentTab][0], "highlighted");
-            }
-        };
+    // Focus the first search result on the active tab, or the result that
+    // was focused last time this tab was active.
+    function focusSearchResult() {
+        var target = searchState.focusedByTab[searchState.currentTab] ||
+            document.querySelectorAll(".search-results.active a").item(0) ||
+            document.querySelectorAll("#titles > button").item(searchState.currentTab);
+        if (target) {
+            target.focus();
+        }
     }
 
     function buildHrefAndPath(item) {
@@ -1047,45 +963,77 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     function addTab(array, query, display) {
-        var extraStyle = "";
-        if (display === false) {
-            extraStyle = " style=\"display: none;\"";
+        var extraClass = "";
+        if (display === true) {
+            extraClass = " active";
         }
 
-        var output = "";
+        var output = document.createElement("div");
         var duplicates = {};
         var length = 0;
         if (array.length > 0) {
-            output = "<table class=\"search-results\"" + extraStyle + ">";
+            output.className = "search-results " + extraClass;
 
             array.forEach(function(item) {
-                var name, type;
-
-                name = item.name;
-                type = itemTypes[item.ty];
-
                 if (item.is_alias !== true) {
                     if (duplicates[item.fullPath]) {
                         return;
                     }
                     duplicates[item.fullPath] = true;
                 }
+
+                var name = item.name;
+                var type = itemTypes[item.ty];
+
                 length += 1;
 
-                output += "<tr class=\"" + type + " result\"><td>" +
-                          "<a href=\"" + item.href + "\">" +
-                          (item.is_alias === true ?
-                           ("<span class=\"alias\"><b>" + item.alias + " </b></span><span " +
-                              "class=\"grey\"><i>&nbsp;- see&nbsp;</i></span>") : "") +
-                          item.displayPath + "<span class=\"" + type + "\">" +
-                          name + "</span></a></td><td>" +
-                          "<a href=\"" + item.href + "\">" +
-                          "<span class=\"desc\">" + item.desc +
-                          "&nbsp;</span></a></td></tr>";
+                var extra = "";
+                if (type === "primitive") {
+                    extra = " <i>(primitive type)</i>";
+                } else if (type === "keyword") {
+                    extra = " <i>(keyword)</i>";
+                }
+
+                var link = document.createElement("a");
+                link.className = "result-" + type;
+                link.href = item.href;
+
+                var wrapper = document.createElement("div");
+                var resultName = document.createElement("div");
+                resultName.className = "result-name";
+
+                if (item.is_alias) {
+                    var alias = document.createElement("span");
+                    alias.className = "alias";
+
+                    var bold = document.createElement("b");
+                    bold.innerText = item.alias;
+                    alias.appendChild(bold);
+
+                    alias.insertAdjacentHTML(
+                        "beforeend",
+                        "<span class=\"grey\"><i>&nbsp;- see&nbsp;</i></span>");
+
+                    resultName.appendChild(alias);
+                }
+                resultName.insertAdjacentHTML(
+                    "beforeend",
+                    item.displayPath + "<span class=\"" + type + "\">" + name + extra + "</span>");
+                wrapper.appendChild(resultName);
+
+                var description = document.createElement("div");
+                description.className = "desc";
+                var spanDesc = document.createElement("span");
+                spanDesc.innerText = item.desc + "\u00A0";
+
+                description.appendChild(spanDesc);
+                wrapper.appendChild(description);
+                link.appendChild(wrapper);
+                output.appendChild(link);
             });
-            output += "</table>";
         } else {
-            output = "<div class=\"search-failed\"" + extraStyle + ">No results :(<br/>" +
+            output.className = "search-failed" + extraClass;
+            output.innerHTML = "No results :(<br/>" +
                 "Try on <a href=\"https://duckduckgo.com/?q=" +
                 encodeURIComponent("rust " + query.query) +
                 "\">DuckDuckGo</a>?<br/><br/>" +
@@ -1097,7 +1045,7 @@ window.initSearch = function(rawSearchIndex) {
                 "href=\"https://doc.rust-lang.org/book/index.html\">Rust Book</a> for " +
                 "introductions to language features and the language itself.</li><li><a " +
                 "href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
-                " <a href=\"https://crates.io/\">crates.io</a>.</li></ul></div>";
+                " <a href=\"https://crates.io/\">crates.io</a>.</li></ul>";
         }
         return [output, length];
     }
@@ -1121,7 +1069,7 @@ window.initSearch = function(rawSearchIndex) {
         {
             var elem = document.createElement("a");
             elem.href = results.others[0].href;
-            elem.style.display = "none";
+            removeClass(elem, "active");
             // For firefox, we need the element to be in the DOM so it can be clicked.
             document.body.appendChild(elem);
             elem.click();
@@ -1157,12 +1105,19 @@ window.initSearch = function(rawSearchIndex) {
             makeTabHeader(0, "In Names", ret_others[1]) +
             makeTabHeader(1, "In Parameters", ret_in_args[1]) +
             makeTabHeader(2, "In Return Types", ret_returned[1]) +
-            "</div><div id=\"results\">" +
-            ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>";
+            "</div>";
+
+        var resultsElem = document.createElement("div");
+        resultsElem.id = "results";
+        resultsElem.appendChild(ret_others[0]);
+        resultsElem.appendChild(ret_in_args[0]);
+        resultsElem.appendChild(ret_returned[0]);
 
         search.innerHTML = output;
+        search.appendChild(resultsElem);
+        // Reset focused elements.
+        searchState.focusedByTab = [null, null, null];
         searchState.showResults(search);
-        initSearchNav();
         var elems = document.getElementById("titles").childNodes;
         elems[0].onclick = function() { printTab(0); };
         elems[1].onclick = function() { printTab(1); };
@@ -1440,6 +1395,49 @@ window.initSearch = function(rawSearchIndex) {
         };
         searchState.input.onpaste = searchState.input.onchange;
 
+        searchState.outputElement().addEventListener("keydown", function(e) {
+            // We only handle unmodified keystrokes here. We don't want to interfere with,
+            // for instance, alt-left and alt-right for history navigation.
+            if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
+                return;
+            }
+            // up and down arrow select next/previous search result, or the
+            // search box if we're already at the top.
+            if (e.which === 38) { // up
+                var previous = document.activeElement.previousElementSibling;
+                if (previous) {
+                    previous.focus();
+                } else {
+                    searchState.focus();
+                }
+                e.preventDefault();
+            } else if (e.which === 40) { // down
+                var next = document.activeElement.nextElementSibling;
+                if (next) {
+                    next.focus();
+                }
+                var rect = document.activeElement.getBoundingClientRect();
+                if (window.innerHeight - rect.bottom < rect.height) {
+                    window.scrollBy(0, rect.height);
+                }
+                e.preventDefault();
+            } else if (e.which === 37) { // left
+                nextTab(-1);
+                e.preventDefault();
+            } else if (e.which === 39) { // right
+                nextTab(1);
+                e.preventDefault();
+            }
+        });
+
+        searchState.input.addEventListener("keydown", function(e) {
+            if (e.which === 40) { // down
+                focusSearchResult();
+                e.preventDefault();
+            }
+        });
+
+
         var selectCrate = document.getElementById("crate-search");
         if (selectCrate) {
             selectCrate.onchange = function() {
diff --git a/src/librustdoc/html/static/sidebar-items.js b/src/librustdoc/html/static/sidebar-items.js
deleted file mode 100644
index 81172ba0d92..00000000000
--- a/src/librustdoc/html/static/sidebar-items.js
+++ /dev/null
@@ -1 +0,0 @@
-initSidebarItems({});
diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css
index 16f40ec14d5..d220d8708a1 100644
--- a/src/librustdoc/html/static/themes/ayu.css
+++ b/src/librustdoc/html/static/themes/ayu.css
@@ -10,8 +10,7 @@ body {
 	color: #c5c5c5;
 }
 
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3, h4 {
 	color: white;
 }
 h1.fqn {
@@ -20,10 +19,10 @@ h1.fqn {
 h1.fqn  a {
 	color: #fff;
 }
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod) {
+h2, h3, h4 {
 	border-bottom-color: #5c6773;
 }
-h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
+h4 {
 	border: none;
 }
 
@@ -151,12 +150,12 @@ pre, .rustdoc.source .example-wrap {
 	color: #c5c5c5;
 }
 
-.content .highlighted {
-	color: #000 !important;
-	background-color: #c6afb3;
+.search-results a:hover {
+	background-color: #777;
 }
-.content .highlighted a, .content .highlighted span { color: #000 !important; }
-.content .highlighted {
+
+.search-results a:focus {
+	color: #000 !important;
 	background-color: #c6afb3;
 }
 .search-results a {
@@ -407,6 +406,10 @@ pre.ignore:hover, .information:hover + pre.ignore {
 	border-color: #5c6773;
 }
 
+.notable-traits-tooltiptext .notable {
+	border-bottom-color: #5c6773;
+}
+
 #titles > button.selected {
 	background-color: #141920 !important;
 	border-bottom: 1px solid #ffb44c !important;
@@ -432,31 +435,21 @@ individually rather than as a group) */
 /* FIXME: these rules should be at the bottom of the file but currently must be
 above the `@media (max-width: 700px)` rules due to a bug in the css checker */
 /* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */
-.content .highlighted.mod, .content .highlighted.externcrate {}
 .search-input:focus {}
 .content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,
 .block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro {}
-.content .highlighted.trait {}
 .content span.struct,.content a.struct,.block a.current.struct {}
 #titles>button:hover,#titles>button.selected {}
-.content .highlighted.traitalias {}
 .content span.type,.content a.type,.block a.current.type {}
 .content span.union,.content a.union,.block a.current.union {}
-.content .highlighted.foreigntype {}
 pre.rust .lifetime {}
-.content .highlighted.primitive {}
-.content .highlighted.constant,.content .highlighted.static {}
 .stab.unstable {}
-.content .highlighted.fn,.content .highlighted.method,.content .highlighted.tymethod {}
 h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod) {}
 .content span.enum,.content a.enum,.block a.current.enum {}
 .content span.constant,.content a.constant,.block a.current.constant,.content span.static,
-.content a.static,.block a.current.static {}
+.content a.static, .block a.current.static {}
 .content span.keyword,.content a.keyword,.block a.current.keyword {}
 pre.rust .comment {}
-.content .highlighted.enum {}
-.content .highlighted.struct {}
-.content .highlighted.keyword {}
 .content span.traitalias,.content a.traitalias,.block a.current.traitalias {}
 .content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method,
 .block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,
@@ -467,15 +460,36 @@ pre.rust .attribute .ident {}
 .content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype {}
 pre.rust .doccomment {}
 .stab.deprecated {}
-.content .highlighted.attr,.content .highlighted.derive,.content .highlighted.macro {}
+.content a.attr,.content a.derive,.content a.macro {}
 .stab.portability {}
-.content .highlighted.union {}
 .content span.primitive,.content a.primitive,.block a.current.primitive {}
 .content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod {}
-.content .highlighted.type {}
 pre.rust .kw-2,pre.rust .prelude-ty {}
 .content span.trait,.content a.trait,.block a.current.trait {}
 
+.search-results a:focus span {}
+a.result-trait:focus {}
+a.result-traitalias:focus {}
+a.result-mod:focus,
+a.result-externcrate:focus {}
+a.result-mod:focus {}
+a.result-externcrate:focus {}
+a.result-enum:focus {}
+a.result-struct:focus {}
+a.result-union:focus {}
+a.result-fn:focus,
+a.result-method:focus,
+a.result-tymethod:focus {}
+a.result-type:focus {}
+a.result-foreigntype:focus {}
+a.result-attr:focus,
+a.result-derive:focus,
+a.result-macro:focus {}
+a.result-constant:focus,
+a.result-static:focus {}
+a.result-primitive:focus {}
+a.result-keyword:focus {}
+
 @media (max-width: 700px) {
 	.sidebar-menu {
 		background-color: #14191f;
@@ -502,20 +516,29 @@ kbd {
 	box-shadow-color: #c6cbd1;
 }
 
-#theme-picker, #settings-menu, #help-button, #copy-path {
+#theme-picker, #settings-menu, #help-button {
 	border-color: #5c6773;
 	background-color: #0f1419;
 	color: #fff;
 }
 
-#theme-picker > img, #settings-menu > img, #copy-path > img {
+#theme-picker > img, #settings-menu > img {
 	filter: invert(100);
 }
 
+#copy-path {
+	color: #fff;
+}
+#copy-path > img {
+	filter: invert(70%);
+}
+#copy-path:hover > img {
+	filter: invert(100%);
+}
+
 #theme-picker:hover, #theme-picker:focus,
 #settings-menu:hover, #settings-menu:focus,
-#help-button:hover, #help-button:focus,
-#copy-path:hover, #copy-path:focus {
+#help-button:hover, #help-button:focus {
 	border-color: #e0e0e0;
 }
 
@@ -545,10 +568,10 @@ kbd {
 	background-color: rgba(70, 70, 70, 0.33);
 }
 
-.search-results td span.alias {
+.search-results .result-name span.alias {
 	color: #c5c5c5;
 }
-.search-results td span.grey {
+.search-results .result-name span.grey {
 	color: #999;
 }
 
diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css
index fe05a462e81..6385a763f2e 100644
--- a/src/librustdoc/html/static/themes/dark.css
+++ b/src/librustdoc/html/static/themes/dark.css
@@ -3,15 +3,13 @@ body {
 	color: #ddd;
 }
 
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3, h4 {
 	color: #ddd;
 }
 h1.fqn {
 	border-bottom-color: #d2d2d2;
 }
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h2, h3, h4 {
 	border-bottom-color: #d2d2d2;
 }
 
@@ -109,32 +107,36 @@ pre, .rustdoc.source .example-wrap {
 	color: #ddd;
 }
 
-.content .highlighted {
+.search-results a:hover {
+	background-color: #777;
+}
+
+.search-results a:focus {
 	color: #eee !important;
 	background-color: #616161;
 }
-.content .highlighted a, .content .highlighted span { color: #eee !important; }
-.content .highlighted.trait { background-color: #013191; }
-.content .highlighted.traitalias { background-color: #013191; }
-.content .highlighted.mod,
-.content .highlighted.externcrate { background-color: #afc6e4; }
-.content .highlighted.mod { background-color: #803a1b; }
-.content .highlighted.externcrate { background-color: #396bac; }
-.content .highlighted.enum { background-color: #5b4e68; }
-.content .highlighted.struct { background-color: #194e9f; }
-.content .highlighted.union { background-color: #b7bd49; }
-.content .highlighted.fn,
-.content .highlighted.method,
-.content .highlighted.tymethod { background-color: #4950ed; }
-.content .highlighted.type { background-color: #38902c; }
-.content .highlighted.foreigntype { background-color: #b200d6; }
-.content .highlighted.attr,
-.content .highlighted.derive,
-.content .highlighted.macro { background-color: #217d1c; }
-.content .highlighted.constant,
-.content .highlighted.static { background-color: #0063cc; }
-.content .highlighted.primitive { background-color: #00708a; }
-.content .highlighted.keyword { background-color: #884719; }
+.search-results a:focus span { color: #eee !important; }
+a.result-trait:focus { background-color: #013191; }
+a.result-traitalias:focus { background-color: #013191; }
+a.result-mod:focus,
+a.result-externcrate:focus { background-color: #afc6e4; }
+a.result-mod:focus { background-color: #803a1b; }
+a.result-externcrate:focus { background-color: #396bac; }
+a.result-enum:focus { background-color: #5b4e68; }
+a.result-struct:focus { background-color: #194e9f; }
+a.result-union:focus { background-color: #b7bd49; }
+a.result-fn:focus,
+a.result-method:focus,
+a.result-tymethod:focus { background-color: #4950ed; }
+a.result-type:focus { background-color: #38902c; }
+a.result-foreigntype:focus { background-color: #b200d6; }
+a.result-attr:focus,
+a.result-derive:focus,
+a.result-macro:focus { background-color: #217d1c; }
+a.result-constant:focus,
+a.result-static:focus { background-color: #0063cc; }
+a.result-primitive:focus { background-color: #00708a; }
+a.result-keyword:focus { background-color: #884719; }
 
 .content .item-info::before { color: #ccc; }
 
@@ -352,6 +354,10 @@ pre.ignore:hover, .information:hover + pre.ignore {
 	border-color: #777;
 }
 
+.notable-traits-tooltiptext .notable {
+	border-bottom-color: #d2d2d2;
+}
+
 #titles > button:not(.selected) {
 	background-color: #252525;
 	border-top-color: #252525;
@@ -392,7 +398,7 @@ kbd {
 	box-shadow-color: #c6cbd1;
 }
 
-#theme-picker, #settings-menu, #help-button, #copy-path {
+#theme-picker, #settings-menu, #help-button {
 	border-color: #e0e0e0;
 	background: #f0f0f0;
 	color: #000;
@@ -400,11 +406,20 @@ kbd {
 
 #theme-picker:hover, #theme-picker:focus,
 #settings-menu:hover, #settings-menu:focus,
-#help-button:hover, #help-button:focus,
-#copy-path:hover, #copy-path:focus {
+#help-button:hover, #help-button:focus {
 	border-color: #ffb900;
 }
 
+#copy-path {
+	color: #999;
+}
+#copy-path > img {
+	filter: invert(50%);
+}
+#copy-path:hover > img {
+	filter: invert(65%);
+}
+
 #theme-choices {
 	border-color: #e0e0e0;
 	background-color: #353535;
@@ -431,10 +446,10 @@ kbd {
 	background-color: #606060;
 }
 
-.search-results td span.alias {
+.search-results .result-name span.alias {
 	color: #fff;
 }
-.search-results td span.grey {
+.search-results .result-name span.grey {
 	color: #ccc;
 }
 
diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css
index 2253fac1c09..c19d5bfc317 100644
--- a/src/librustdoc/html/static/themes/light.css
+++ b/src/librustdoc/html/static/themes/light.css
@@ -5,15 +5,13 @@ body {
 	color: black;
 }
 
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h1, h2, h3, h4 {
 	color: black;
 }
 h1.fqn {
 	border-bottom-color: #D5D5D5;
 }
-h2, h3:not(.impl):not(.method):not(.type):not(.tymethod),
-h4:not(.method):not(.type):not(.tymethod) {
+h2, h3, h4 {
 	border-bottom-color: #DDDDDD;
 }
 
@@ -109,30 +107,34 @@ pre, .rustdoc.source .example-wrap {
 	color: #4E4C4C;
 }
 
-.content .highlighted {
+.search-results a:hover {
+	background-color: #ddd;
+}
+
+.search-results a:focus {
 	color: #000 !important;
 	background-color: #ccc;
 }
-.content .highlighted a, .content .highlighted span { color: #000 !important; }
-.content .highlighted.trait { background-color: #c7b6ff; }
-.content .highlighted.traitalias { background-color: #c7b6ff; }
-.content .highlighted.mod,
-.content .highlighted.externcrate { background-color: #afc6e4; }
-.content .highlighted.enum { background-color: #b4d1b9; }
-.content .highlighted.struct { background-color: #e7b1a0; }
-.content .highlighted.union { background-color: #b7bd49; }
-.content .highlighted.fn,
-.content .highlighted.method,
-.content .highlighted.tymethod { background-color: #c6afb3; }
-.content .highlighted.type { background-color: #ffc891; }
-.content .highlighted.foreigntype { background-color: #f5c4ff; }
-.content .highlighted.attr,
-.content .highlighted.derive,
-.content .highlighted.macro { background-color: #8ce488; }
-.content .highlighted.constant,
-.content .highlighted.static { background-color: #c3e0ff; }
-.content .highlighted.primitive { background-color: #9aecff; }
-.content .highlighted.keyword { background-color: #f99650; }
+.search-results a:focus span { color: #000 !important; }
+a.result-trait:focus { background-color: #c7b6ff; }
+a.result-traitalias:focus { background-color: #c7b6ff; }
+a.result-mod:focus,
+a.result-externcrate:focus { background-color: #afc6e4; }
+a.result-enum:focus { background-color: #b4d1b9; }
+a.result-struct:focus { background-color: #e7b1a0; }
+a.result-union:focus { background-color: #b7bd49; }
+a.result-fn:focus,
+a.result-method:focus,
+a.result-tymethod:focus { background-color: #c6afb3; }
+a.result-type:focus { background-color: #ffc891; }
+a.result-foreigntype:focus { background-color: #f5c4ff; }
+a.result-attr:focus,
+a.result-derive:focus,
+a.result-macro:focus { background-color: #8ce488; }
+a.result-constant:focus,
+a.result-static:focus { background-color: #c3e0ff; }
+a.result-primitive:focus { background-color: #9aecff; }
+a.result-keyword:focus { background-color: #f99650; }
 
 .content .item-info::before { color: #ccc; }
 
@@ -344,6 +346,10 @@ pre.ignore:hover, .information:hover + pre.ignore {
 	border-color: #999;
 }
 
+.notable-traits-tooltiptext .notable {
+	border-bottom-color: #DDDDDD;
+}
+
 #titles > button:not(.selected) {
 	background-color: #e6e6e6;
 	border-top-color: #e6e6e6;
@@ -384,18 +390,27 @@ kbd {
 	box-shadow-color: #c6cbd1;
 }
 
-#theme-picker, #settings-menu, #help-button, #copy-path {
+#theme-picker, #settings-menu, #help-button {
 	border-color: #e0e0e0;
 	background-color: #fff;
 }
 
 #theme-picker:hover, #theme-picker:focus,
 #settings-menu:hover, #settings-menu:focus,
-#help-button:hover, #help-button:focus,
-#copy-path:hover, #copy-path:focus {
+#help-button:hover, #help-button:focus {
 	border-color: #717171;
 }
 
+#copy-path {
+	color: #999;
+}
+#copy-path > img {
+	filter: invert(50%);
+}
+#copy-path:hover > img {
+	filter: invert(35%);
+}
+
 #theme-choices {
 	border-color: #ccc;
 	background-color: #fff;
@@ -422,10 +437,10 @@ kbd {
 	background-color: #f9f9f9;
 }
 
-.search-results td span.alias {
+.search-results .result-name span.alias {
 	color: #000;
 }
-.search-results td span.grey {
+.search-results .result-name span.grey {
 	color: #999;
 }
 
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 4e3d5ff0a4a..ca7e5ef8150 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -126,11 +126,19 @@ crate mod source_code_pro {
     crate static LICENSE: &[u8] = include_bytes!("static/SourceCodePro-LICENSE.txt");
 }
 
+crate mod noto_sans_kr {
+    /// The file `noto-sans-kr-v13-korean-regular.woff`, the Regular variant of the Noto Sans KR
+    /// font.
+    crate static REGULAR: &[u8] = include_bytes!("static/noto-sans-kr-v13-korean-regular.woff");
+
+    /// The file `noto-sans-kr-v13-korean-regular-LICENSE.txt`, the license text of the Noto Sans KR
+    /// font.
+    crate static LICENSE: &[u8] =
+        include_bytes!("static/noto-sans-kr-v13-korean-regular-LICENSE.txt");
+}
+
 /// Files related to the sidebar in rustdoc sources.
 crate mod sidebar {
     /// File script to handle sidebar.
     crate static SOURCE_SCRIPT: &str = include_str!("static/source-script.js");
-
-    /// Top Level sidebar items script which will load a sidebar without items.
-    crate static ITEMS: &str = include_str!("static/sidebar-items.js");
 }
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index e0c0e241497..bee62915ea9 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -396,7 +396,7 @@ impl FromWithTcx<clean::Type> for Type {
                 mutable: mutability == ast::Mutability::Mut,
                 type_: Box::new((*type_).into_tcx(tcx)),
             },
-            QPath { name, self_type, trait_ } => Type::QualifiedPath {
+            QPath { name, self_type, trait_, .. } => Type::QualifiedPath {
                 name: name.to_string(),
                 self_type: Box::new((*self_type).into_tcx(tcx)),
                 trait_: Box::new((*trait_).into_tcx(tcx)),
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 5ede3780e87..7c93a094807 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -8,7 +8,6 @@
 #![feature(box_syntax)]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(test)]
 #![feature(crate_visibility_modifier)]
 #![feature(never_type)]
@@ -511,6 +510,14 @@ fn opts() -> Vec<RustcOptGroup> {
                 "LEVEL",
             )
         }),
+        unstable("force-warns", |o| {
+            o.optopt(
+                "",
+                "force-warns",
+                "Lints that will warn even if allowed somewhere else",
+                "LINTS",
+            )
+        }),
         unstable("index-page", |o| {
             o.optopt("", "index-page", "Markdown file to be used as index page", "PATH")
         }),
@@ -582,9 +589,6 @@ fn opts() -> Vec<RustcOptGroup> {
                 "Generate JSON file at the top level instead of generating HTML redirection files",
             )
         }),
-        unstable("print", |o| {
-            o.optmulti("", "print", "Rustdoc information to print on stdout", "[unversioned-files]")
-        }),
         unstable("emit", |o| {
             o.optmulti(
                 "",
diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs
index 1b79811d4b0..376c83b1a6e 100644
--- a/src/librustdoc/lint.rs
+++ b/src/librustdoc/lint.rs
@@ -157,6 +157,18 @@ declare_rustdoc_lint! {
     "detects URLs that are not hyperlinks"
 }
 
+declare_rustdoc_lint! {
+   /// The `invalid_rust_codeblocks` lint detects Rust code blocks in
+   /// documentation examples that are invalid (e.g. empty, not parsable as
+   /// Rust code). This is a `rustdoc` only lint, see the documentation in the
+   /// [rustdoc book].
+   ///
+   /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_rust_codeblocks
+   INVALID_RUST_CODEBLOCKS,
+   Warn,
+   "codeblock could not be parsed as valid Rust or is empty"
+}
+
 crate static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
     vec![
         BROKEN_INTRA_DOC_LINKS,
@@ -164,6 +176,7 @@ crate static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| {
         MISSING_DOC_CODE_EXAMPLES,
         PRIVATE_DOC_TESTS,
         INVALID_CODEBLOCK_ATTRIBUTES,
+        INVALID_RUST_CODEBLOCKS,
         INVALID_HTML_TAGS,
         BARE_URLS,
         MISSING_CRATE_LEVEL_DOCS,
diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs
index 8d07cde5188..7ccfdf29041 100644
--- a/src/librustdoc/passes/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/check_code_block_syntax.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler};
+use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_parse::parse_stream_from_source_str;
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
@@ -47,55 +48,68 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
         .unwrap_or(false);
         let buffer = buffer.borrow();
 
-        if buffer.has_errors || is_empty {
-            let mut diag = if let Some(sp) = super::source_span_for_markdown_range(
-                self.cx.tcx,
-                &dox,
-                &code_block.range,
-                &item.attrs,
-            ) {
-                let (warning_message, suggest_using_text) = if buffer.has_errors {
-                    ("could not parse code block as Rust code", true)
-                } else {
-                    ("Rust code block is empty", false)
-                };
-
-                let mut diag = self.cx.sess().struct_span_warn(sp, warning_message);
-
-                if code_block.syntax.is_none() && code_block.is_fenced {
-                    let sp = sp.from_inner(InnerSpan::new(0, 3));
-                    diag.span_suggestion(
-                        sp,
-                        "mark blocks that do not contain Rust code as text",
-                        String::from("```text"),
-                        Applicability::MachineApplicable,
+        if !buffer.has_errors && !is_empty {
+            // No errors in a non-empty program.
+            return;
+        }
+
+        let local_id = match item.def_id.as_real().and_then(|x| x.as_local()) {
+            Some(id) => id,
+            // We don't need to check the syntax for other crates so returning
+            // without doing anything should not be a problem.
+            None => return,
+        };
+
+        let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id);
+        let empty_block = code_block.syntax.is_none() && code_block.is_fenced;
+        let is_ignore = code_block.is_ignore;
+
+        // The span and whether it is precise or not.
+        let (sp, precise_span) = match super::source_span_for_markdown_range(
+            self.cx.tcx,
+            &dox,
+            &code_block.range,
+            &item.attrs,
+        ) {
+            Some(sp) => (sp, true),
+            None => (item.attr_span(self.cx.tcx), false),
+        };
+
+        // lambda that will use the lint to start a new diagnostic and add
+        // a suggestion to it when needed.
+        let diag_builder = |lint: LintDiagnosticBuilder<'_>| {
+            let explanation = if is_ignore {
+                "`ignore` code blocks require valid Rust code for syntax highlighting; \
+                    mark blocks that do not contain Rust code as text"
+            } else {
+                "mark blocks that do not contain Rust code as text"
+            };
+            let msg = if buffer.has_errors {
+                "could not parse code block as Rust code"
+            } else {
+                "Rust code block is empty"
+            };
+            let mut diag = lint.build(msg);
+
+            if precise_span {
+                if is_ignore {
+                    // giving an accurate suggestion is hard because `ignore` might not have come first in the list.
+                    // just give a `help` instead.
+                    diag.span_help(
+                        sp.from_inner(InnerSpan::new(0, 3)),
+                        &format!("{}: ```text", explanation),
                     );
-                } else if suggest_using_text && code_block.is_ignore {
-                    let sp = sp.from_inner(InnerSpan::new(0, 3));
+                } else if empty_block {
                     diag.span_suggestion(
-                        sp,
-                        "`ignore` code blocks require valid Rust code for syntax highlighting. \
-                         Mark blocks that do not contain Rust code as text",
-                        String::from("```text,"),
+                        sp.from_inner(InnerSpan::new(0, 3)),
+                        explanation,
+                        String::from("```text"),
                         Applicability::MachineApplicable,
                     );
                 }
-
-                diag
-            } else {
-                // We couldn't calculate the span of the markdown block that had the error, so our
-                // diagnostics are going to be a bit lacking.
-                let mut diag = self.cx.sess().struct_span_warn(
-                    item.attr_span(self.cx.tcx),
-                    "doc comment contains an invalid Rust code block",
-                );
-
-                if code_block.syntax.is_none() && code_block.is_fenced {
-                    diag.help("mark blocks that do not contain Rust code as text: ```text");
-                }
-
-                diag
-            };
+            } else if empty_block || is_ignore {
+                diag.help(&format!("{}: ```text", explanation));
+            }
 
             // FIXME(#67563): Provide more context for these errors by displaying the spans inline.
             for message in buffer.messages.iter() {
@@ -103,7 +117,17 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
             }
 
             diag.emit();
-        }
+        };
+
+        // Finally build and emit the completed diagnostic.
+        // All points of divergence have been handled earlier so this can be
+        // done the same way whether the span is precise or not.
+        self.cx.tcx.struct_span_lint_hir(
+            crate::lint::INVALID_RUST_CODEBLOCKS,
+            hir_id,
+            sp,
+            diag_builder,
+        );
     }
 }
 
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 191d8d5a2ea..b563c4f4799 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -9,6 +9,7 @@ use rustc_hir::Node;
 use rustc_middle::middle::privacy::AccessLevel;
 use rustc_middle::ty::TyCtxt;
 use rustc_span;
+use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Symbol};
 
@@ -76,7 +77,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             &Spanned { span, node: hir::VisibilityKind::Public },
             hir::CRATE_HIR_ID,
             &krate.item,
-            self.cx.tcx.crate_name,
+            self.cx.tcx.crate_name(LOCAL_CRATE),
         );
         // Attach the crate's exported macros to the top-level module.
         // In the case of macros 2.0 (`pub macro`), and for built-in `derive`s or attributes as
diff --git a/src/stage0.txt b/src/stage0.txt
index 6ad0f6db42b..1027057f385 100644
--- a/src/stage0.txt
+++ b/src/stage0.txt
@@ -12,7 +12,7 @@
 # stable release's version number. `date` is the date where the release we're
 # bootstrapping off was released.
 
-date: 2021-04-07
+date: 2021-05-23
 rustc: beta
 
 # We use a nightly rustfmt to format the source because it solves some
diff --git a/src/test/assembly/static-relocation-model.rs b/src/test/assembly/static-relocation-model.rs
index 0463045c156..2cd74a01c84 100644
--- a/src/test/assembly/static-relocation-model.rs
+++ b/src/test/assembly/static-relocation-model.rs
@@ -1,9 +1,10 @@
 // min-llvm-version: 12.0.0
-// needs-llvm-components: aarch64 x86
-// revisions:X64 A64
+// needs-llvm-components: aarch64 x86 powerpc
+// revisions: x64 A64 ppc64le
 // assembly-output: emit-asm
-// [X64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static
+// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static
 // [A64] compile-flags: --target aarch64-unknown-linux-gnu -Crelocation-model=static
+// [ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -Crelocation-model=static
 
 #![feature(no_core, lang_items)]
 #![no_core]
@@ -15,14 +16,26 @@ trait Sized {}
 #[lang="copy"]
 trait Copy {}
 
+#[lang="sync"]
+trait Sync {}
+
+#[lang = "drop_in_place"]
+fn drop_in_place<T>(_: *mut T) {}
+
 impl Copy for u8 {}
+impl Sync for u8 {}
+
+#[no_mangle]
+pub static PIERIS: u8 = 42;
 
 extern "C" {
+    static EXOCHORDA: *mut u8;
+
     fn chaenomeles();
 }
 
 // CHECK-LABEL: banana:
-// x64: movb    chaenomeles, %{{[a,z]+}}
+// x64: movb   chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}}
 // A64:      adrp    [[REG:[a-z0-9]+]], chaenomeles
 // A64-NEXT: ldrb    {{[a-z0-9]+}}, {{\[}}[[REG]], :lo12:chaenomeles]
 #[no_mangle]
@@ -33,7 +46,7 @@ pub fn banana() -> u8 {
 }
 
 // CHECK-LABEL: peach:
-// x64: movb    banana, %{{[a,z]+}}
+// x64: movb    banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}}
 // A64:      adrp    [[REG2:[a-z0-9]+]], banana
 // A64-NEXT: ldrb    {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:banana]
 #[no_mangle]
@@ -42,3 +55,30 @@ pub fn peach() -> u8 {
         *(banana as *mut u8)
     }
 }
+
+// CHECK-LABEL: mango:
+// x64:      movq    EXOCHORDA{{(\(%[a-z0-9]+\))?}}, %[[REG:[a-z0-9]+]]
+// x64-NEXT: movb    (%[[REG]]), %{{[a-z0-9]+}}
+// A64:      adrp    [[REG2:[a-z0-9]+]], EXOCHORDA
+// A64-NEXT: ldr     {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:EXOCHORDA]
+#[no_mangle]
+pub fn mango() -> u8 {
+    unsafe {
+        *EXOCHORDA
+    }
+}
+
+// CHECK-LABEL: orange:
+// x64: mov{{l|absq}}    $PIERIS, %{{[a-z0-9]+}}
+// A64:      adrp    [[REG2:[a-z0-9]+]], PIERIS
+// A64-NEXT: add     {{[a-z0-9]+}}, [[REG2]], :lo12:PIERIS
+#[no_mangle]
+pub fn orange() -> &'static u8 {
+    &PIERIS
+}
+
+// For ppc64 we need to make sure to generate TOC entries even with the static relocation model
+// ppc64le: .tc chaenomeles[TC],chaenomeles
+// ppc64le: .tc banana[TC],banana
+// ppc64le: .tc EXOCHORDA[TC],EXOCHORDA
+// ppc64le: .tc PIERIS[TC],PIERIS
diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs
index f2641404aae..e410180bfff 100644
--- a/src/test/codegen/async-fn-debug-msvc.rs
+++ b/src/test/codegen/async-fn-debug-msvc.rs
@@ -17,33 +17,33 @@ async fn async_fn_test() {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]]
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0"
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
 // For brevity, we only check the struct name and members of the last variant.
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 15,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 15,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 12,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 14,
 // CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]],
+// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]],
 // CHECK-SAME: flags: DIFlagArtificial
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
 // CHECK-NOT:  flags: DIFlagArtificial
diff --git a/src/test/codegen/auxiliary/thread_local_aux.rs b/src/test/codegen/auxiliary/thread_local_aux.rs
new file mode 100644
index 00000000000..29b5e3ca244
--- /dev/null
+++ b/src/test/codegen/auxiliary/thread_local_aux.rs
@@ -0,0 +1,6 @@
+#![crate_type = "lib"]
+#![feature(thread_local_const_init)]
+
+use std::cell::Cell;
+
+thread_local!(pub static A: Cell<u64> = const { Cell::new(0) });
diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs
index 44be71f3b9b..7edb07d224c 100644
--- a/src/test/codegen/generator-debug-msvc.rs
+++ b/src/test/codegen/generator-debug-msvc.rs
@@ -21,33 +21,33 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[GEN_FN:!.*]] = !DINamespace(name: "generator_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]]
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0"
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
 // For brevity, we only check the struct name and members of the last variant.
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 18,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 18,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 15,
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]],
 // CHECK-SAME: file: [[FILE]], line: 17,
 // CHECK-SAME: baseType: [[VARIANT:![0-9]*]]
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]],
+// CHECK:      [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]],
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: )
-// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]],
+// CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]],
 // CHECK-SAME: flags: DIFlagArtificial
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]]
 // CHECK-NOT:  flags: DIFlagArtificial
diff --git a/src/test/codegen/thread-local.rs b/src/test/codegen/thread-local.rs
new file mode 100644
index 00000000000..f14368e3990
--- /dev/null
+++ b/src/test/codegen/thread-local.rs
@@ -0,0 +1,50 @@
+// compile-flags: -O
+// aux-build:thread_local_aux.rs
+// ignore-windows FIXME(#84933)
+// ignore-wasm globals are used instead of thread locals
+// ignore-emscripten globals are used instead of thread locals
+// ignore-android does not use #[thread_local]
+
+#![crate_type = "lib"]
+#![feature(thread_local_const_init)]
+
+extern crate thread_local_aux as aux;
+
+use std::cell::Cell;
+
+thread_local!(static A: Cell<u32> = const { Cell::new(1) });
+
+// CHECK: [[TLS_AUX:@.+]] = external thread_local local_unnamed_addr global i64
+// CHECK: [[TLS:@.+]] = internal thread_local unnamed_addr global
+
+// CHECK-LABEL: @get
+#[no_mangle]
+fn get() -> u32 {
+    // CHECK: %0 = load i32, i32* bitcast ({{.*}} [[TLS]] to i32*)
+    // CHECK-NEXT: ret i32 %0
+    A.with(|a| a.get())
+}
+
+// CHECK-LABEL: @set
+#[no_mangle]
+fn set(v: u32) {
+    // CHECK: store i32 %0, i32* bitcast ({{.*}} [[TLS]] to i32*)
+    // CHECK-NEXT: ret void
+    A.with(|a| a.set(v))
+}
+
+// CHECK-LABEL: @get_aux
+#[no_mangle]
+fn get_aux() -> u64 {
+    // CHECK: %0 = load i64, i64* [[TLS_AUX]]
+    // CHECK-NEXT: ret i64 %0
+    aux::A.with(|a| a.get())
+}
+
+// CHECK-LABEL: @set_aux
+#[no_mangle]
+fn set_aux(v: u64) {
+    // CHECK: store i64 %0, i64* [[TLS_AUX]]
+    // CHECK-NEXT: ret void
+    aux::A.with(|a| a.set(v))
+}
diff --git a/src/test/codegen/try_identity.rs b/src/test/codegen/try_identity.rs
index 81e2435e5b8..3ff77163b9f 100644
--- a/src/test/codegen/try_identity.rs
+++ b/src/test/codegen/try_identity.rs
@@ -7,11 +7,28 @@
 
 type R = Result<u64, i32>;
 
+// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure,
+// so the relevant desugar is copied inline in order to keep the test testing the same thing.
+// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR
+// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not.
 #[no_mangle]
-fn try_identity(x: R) -> R {
+pub fn try_identity(x: R) -> R {
 // CHECK: start:
 // CHECK-NOT: br {{.*}}
 // CHECK ret void
-    let y = x?;
+    let y = match into_result(x) {
+        Err(e) => return from_error(From::from(e)),
+        Ok(v) => v,
+    };
     Ok(y)
 }
+
+#[inline]
+fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> {
+    r
+}
+
+#[inline]
+fn from_error<T, E>(e: E) -> Result<T, E> {
+    Err(e)
+}
diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs
new file mode 100644
index 00000000000..550cc66f389
--- /dev/null
+++ b/src/test/debuginfo/msvc-pretty-enums.rs
@@ -0,0 +1,97 @@
+// only-cdb
+// ignore-tidy-linelength
+// compile-flags:-g
+
+// cdb-command: g
+
+// Note: The natvis used to visualize niche-layout enums don't work correctly in cdb
+//       so the best we can do is to make sure we are generating the right debuginfo
+
+// cdb-command: dx -r2 a,!
+// cdb-check:a,!              [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Some]
+// cdb-check:        [+0x000] __0              : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check:    [+0x000] discriminant     : 0x2 [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Discriminant$]
+
+// cdb-command: dx -r2 b,!
+// cdb-check:b,!              [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Some]
+// cdb-check:        [+0x000] __0              : 0x11 [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check:    [+0x000] discriminant     : None (0x11) [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Discriminant$]
+
+// cdb-command: dx -r2 c,!
+// cdb-check:c,!              [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
+// cdb-check:        [+0x000] my_data          : 0x11 [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check:    [+0x000] discriminant     : Tag1 (0x11) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
+
+// cdb-command: dx -r2 d,!
+// cdb-check:d,!              [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
+// cdb-check:        [+0x000] my_data          : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check:    [+0x000] discriminant     : 0x10 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
+
+// cdb-command: dx -r2 e,!
+// cdb-check:e,!              [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data]
+// cdb-check:        [+0x000] my_data          : 0x13 [Type: msvc_pretty_enums::CStyleEnum]
+// cdb-check:    [+0x000] discriminant     : Tag2 (0x13) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$]
+
+// cdb-command: dx -r2 f,!
+// cdb-check:f,!              [Type: enum$<core::option::Option<u32*>, 1, [...], Some>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Some]
+// cdb-check:        [+0x000] __0              : 0x[...] : 0x1 [Type: unsigned int *]
+// cdb-check:    [+0x000] discriminant     : 0x[...] [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Discriminant$]
+
+// cdb-command: dx -r2 g,!
+// cdb-check:g,!              [Type: enum$<core::option::Option<u32*>, 1, [...], Some>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Some]
+// cdb-check:        [+0x000] __0              : 0x0 [Type: unsigned int *]
+// cdb-check:    [+0x000] discriminant     : None (0x0) [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Discriminant$]
+
+// cdb-command: dx h
+// cdb-check:h                : Some [Type: enum$<core::option::Option<u32>>]
+// cdb-check:    [+0x000] variant$         : Some (0x1) [Type: core::option::Option]
+// cdb-check:    [+0x004] __0              : 0xc [Type: unsigned int]
+
+// cdb-command: dx i
+// cdb-check:i                : None [Type: enum$<core::option::Option<u32>>]
+// cdb-check:    [+0x000] variant$         : None (0x0) [Type: core::option::Option]
+
+// cdb-command: dx j
+// cdb-check:j                : High (0x10) [Type: msvc_pretty_enums::CStyleEnum]
+
+// cdb-command: dx -r2 k,!
+// cdb-check:k,!              [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
+// cdb-check:    [+0x000] dataful_variant  [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Some]
+// cdb-check:        [+0x000] __0              [Type: alloc::string::String]
+// cdb-check:    [+0x000] discriminant     : 0x[...] [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Discriminant$]
+
+pub enum CStyleEnum {
+    Low = 2,
+    High = 16,
+}
+
+pub enum NicheLayoutEnum {
+    Tag1,
+    Data { my_data: CStyleEnum },
+    Tag2,
+}
+
+fn main() {
+    let a = Some(CStyleEnum::Low);
+    let b = Option::<CStyleEnum>::None;
+    let c = NicheLayoutEnum::Tag1;
+    let d = NicheLayoutEnum::Data { my_data: CStyleEnum::High };
+    let e = NicheLayoutEnum::Tag2;
+    let f = Some(&1u32);
+    let g = Option::<&'static u32>::None;
+    let h = Some(12u32);
+    let i = Option::<u32>::None;
+    let j = CStyleEnum::High;
+    let k = Some("IAMA optional string!".to_string());
+
+    zzz(); // #break
+}
+
+fn zzz() { () }
diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs
index 1a99f841250..68e73b5f38d 100644
--- a/src/test/debuginfo/pretty-std.rs
+++ b/src/test/debuginfo/pretty-std.rs
@@ -1,6 +1,7 @@
 // ignore-freebsd: gdb package too new
 // only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155
 // ignore-android: FIXME(#10381)
+// ignore-tidy-linelength
 // compile-flags:-g
 // min-gdb-version: 7.7
 // min-lldb-version: 310
@@ -111,11 +112,11 @@
 // NOTE: OsString doesn't have a .natvis entry yet.
 
 // cdb-command: dx some
-// cdb-check:some             : Some(8) [Type: [...]::Option<i16>]
+// cdb-check:some             : Some [Type: enum$<core::option::Option<i16>>]
 // cdb-command: dx none
-// cdb-check:none             : None [Type: [...]::Option<i64>]
+// cdb-check:none             : None [Type: enum$<core::option::Option<i64>>]
 // cdb-command: dx some_string
-// cdb-check:some_string      : Some("IAMA optional string!") [[...]::Option<[...]::String>]
+// cdb-check:some_string      [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>]
 
 #![allow(unused_variables)]
 use std::ffi::OsString;
diff --git a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs
index f698f8835a2..ea1ea1943e9 100644
--- a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs
+++ b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs
@@ -24,7 +24,7 @@ extern crate point;
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -35,7 +35,7 @@ pub mod fn_calls_methods_in_same_impl {
 pub mod fn_calls_free_fn {
     use point::{self, Point};
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         point::distance_squared(&x);
@@ -46,7 +46,7 @@ pub mod fn_calls_free_fn {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -56,7 +56,7 @@ pub mod fn_make_struct {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -66,7 +66,7 @@ pub mod fn_read_field {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
diff --git a/src/test/incremental/callee_caller_cross_crate/b.rs b/src/test/incremental/callee_caller_cross_crate/b.rs
index 02453740079..084ed232a55 100644
--- a/src/test/incremental/callee_caller_cross_crate/b.rs
+++ b/src/test/incremental/callee_caller_cross_crate/b.rs
@@ -6,12 +6,12 @@
 
 extern crate a;
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn call_function0() {
     a::function0(77);
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn call_function1() {
     a::function1(77);
 }
diff --git a/src/test/incremental/change_add_field/struct_point.rs b/src/test/incremental/change_add_field/struct_point.rs
index 8d98cfac8a4..3308ea56222 100644
--- a/src/test/incremental/change_add_field/struct_point.rs
+++ b/src/test/incremental/change_add_field/struct_point.rs
@@ -70,7 +70,7 @@ pub mod point {
 pub mod fn_with_type_in_sig {
     use point::Point;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
     pub fn boop(p: Option<&Point>) -> f32 {
         p.map(|p| p.total()).unwrap_or(0.0)
     }
@@ -86,7 +86,7 @@ pub mod fn_with_type_in_sig {
 pub mod call_fn_with_type_in_sig {
     use fn_with_type_in_sig;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")]
     pub fn bip() -> f32 {
         fn_with_type_in_sig::boop(None)
     }
@@ -102,7 +102,7 @@ pub mod call_fn_with_type_in_sig {
 pub mod fn_with_type_in_body {
     use point::Point;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")]
     pub fn boop() -> f32 {
         Point::origin().total()
     }
@@ -115,7 +115,7 @@ pub mod fn_with_type_in_body {
 pub mod call_fn_with_type_in_body {
     use fn_with_type_in_body;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn bip() -> f32 {
         fn_with_type_in_body::boop()
     }
@@ -125,7 +125,7 @@ pub mod call_fn_with_type_in_body {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
     pub fn make_origin(p: Point) -> Point {
         Point { ..p }
     }
@@ -135,7 +135,7 @@ pub mod fn_make_struct {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -145,7 +145,7 @@ pub mod fn_read_field {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
diff --git a/src/test/incremental/change_private_fn/struct_point.rs b/src/test/incremental/change_private_fn/struct_point.rs
index ba4bf4e7b7d..1791c089cfa 100644
--- a/src/test/incremental/change_private_fn/struct_point.rs
+++ b/src/test/incremental/change_private_fn/struct_point.rs
@@ -51,7 +51,7 @@ pub mod point {
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -62,7 +62,7 @@ pub mod fn_calls_methods_in_same_impl {
 pub mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
@@ -73,7 +73,7 @@ pub mod fn_calls_methods_in_another_impl {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -83,7 +83,7 @@ pub mod fn_make_struct {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -93,7 +93,7 @@ pub mod fn_read_field {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
diff --git a/src/test/incremental/change_private_fn_cc/struct_point.rs b/src/test/incremental/change_private_fn_cc/struct_point.rs
index 5072ef609e2..1c27ec3a3f7 100644
--- a/src/test/incremental/change_private_fn_cc/struct_point.rs
+++ b/src/test/incremental/change_private_fn_cc/struct_point.rs
@@ -23,7 +23,7 @@ extern crate point;
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -34,7 +34,7 @@ pub mod fn_calls_methods_in_same_impl {
 pub mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
@@ -45,7 +45,7 @@ pub mod fn_calls_methods_in_another_impl {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -55,7 +55,7 @@ pub mod fn_make_struct {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -65,7 +65,7 @@ pub mod fn_read_field {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs
index 11ba96a8c8d..cf43e4757cb 100644
--- a/src/test/incremental/change_private_impl_method/struct_point.rs
+++ b/src/test/incremental/change_private_impl_method/struct_point.rs
@@ -51,7 +51,7 @@ pub mod point {
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -62,7 +62,7 @@ pub mod fn_calls_methods_in_same_impl {
 pub mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
@@ -73,7 +73,7 @@ pub mod fn_calls_methods_in_another_impl {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -83,7 +83,7 @@ pub mod fn_make_struct {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -93,7 +93,7 @@ pub mod fn_read_field {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs
index 2aeecfc89d5..9fe8b5df93a 100644
--- a/src/test/incremental/change_private_impl_method_cc/struct_point.rs
+++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs
@@ -24,7 +24,7 @@ extern crate point;
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
@@ -35,7 +35,7 @@ pub mod fn_calls_methods_in_same_impl {
 pub mod fn_calls_methods_in_another_impl {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn dirty() {
         let mut x = Point { x: 2.0, y: 2.0 };
         x.translate(3.0, 3.0);
@@ -46,7 +46,7 @@ pub mod fn_calls_methods_in_another_impl {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -56,7 +56,7 @@ pub mod fn_make_struct {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -66,7 +66,7 @@ pub mod fn_read_field {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
diff --git a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs
index a192dff19e9..1b87b18fcd4 100644
--- a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs
+++ b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs
@@ -42,7 +42,7 @@ pub mod point {
 pub mod fn_calls_changed_method {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.distance_from_origin();
@@ -53,7 +53,7 @@ pub mod fn_calls_changed_method {
 pub mod fn_calls_another_method {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.x();
@@ -64,7 +64,7 @@ pub mod fn_calls_another_method {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -74,7 +74,7 @@ pub mod fn_make_struct {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -84,7 +84,7 @@ pub mod fn_read_field {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
diff --git a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs
index b0476168555..0a672956768 100644
--- a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs
+++ b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs
@@ -52,7 +52,7 @@ pub mod point {
 pub mod fn_calls_changed_method {
     use point::Point;
 
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.distance_from_point(None);
@@ -63,7 +63,7 @@ pub mod fn_calls_changed_method {
 pub mod fn_calls_another_method {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn check() {
         let p = Point { x: 2.0, y: 2.0 };
         p.x();
@@ -74,7 +74,7 @@ pub mod fn_calls_another_method {
 pub mod fn_make_struct {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn make_origin() -> Point {
         Point { x: 2.0, y: 2.0 }
     }
@@ -84,7 +84,7 @@ pub mod fn_make_struct {
 pub mod fn_read_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn get_x(p: Point) -> f32 {
         p.x
     }
@@ -94,7 +94,7 @@ pub mod fn_read_field {
 pub mod fn_write_field {
     use point::Point;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn inc_x(p: &mut Point) {
         p.x += 1.0;
     }
diff --git a/src/test/incremental/crate_hash_reorder.rs b/src/test/incremental/crate_hash_reorder.rs
index 6e06e67b668..ca476b4d2db 100644
--- a/src/test/incremental/crate_hash_reorder.rs
+++ b/src/test/incremental/crate_hash_reorder.rs
@@ -7,9 +7,9 @@
 
 // Check that reordering otherwise identical items is not considered a
 // change at all.
-#[rustc_clean(label = "hir_crate", cfg = "rpass2")]
+#[rustc_clean(cfg = "rpass2")]
 // But removing an item, naturally, is.
-#[rustc_dirty(label = "hir_crate", cfg = "rpass3")]
+#[rustc_clean(except="hir_crate", cfg = "rpass3")]
 #[cfg(rpass1)]
 pub struct X {
     pub x: u32,
diff --git a/src/test/incremental/dirty_clean.rs b/src/test/incremental/dirty_clean.rs
index 02c9a0c5798..11d999ab328 100644
--- a/src/test/incremental/dirty_clean.rs
+++ b/src/test/incremental/dirty_clean.rs
@@ -25,15 +25,24 @@ mod x {
 mod y {
     use x;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
+    #[rustc_clean(
+        except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig",
+        cfg="cfail2",
+    )]
     pub fn y() {
-        //[cfail2]~^ ERROR `typeck(y)` should be clean but is not
+        //[cfail2]~^ ERROR `hir_owner(y)` should be dirty but is not
+        //[cfail2]~| ERROR `hir_owner_nodes(y)` should be dirty but is not
+        //[cfail2]~| ERROR `generics_of(y)` should be dirty but is not
+        //[cfail2]~| ERROR `predicates_of(y)` should be dirty but is not
+        //[cfail2]~| ERROR `type_of(y)` should be dirty but is not
+        //[cfail2]~| ERROR `fn_sig(y)` should be dirty but is not
+        //[cfail2]~| ERROR `typeck(y)` should be clean but is not
         x::x();
     }
 }
 
 mod z {
-    #[rustc_dirty(label="typeck", cfg="cfail2")]
+    #[rustc_clean(except="typeck", cfg="cfail2")]
     pub fn z() {
         //[cfail2]~^ ERROR `typeck(z)` should be dirty but is not
     }
diff --git a/src/test/incremental/hashes/call_expressions.rs b/src/test/incremental/hashes/call_expressions.rs
index d4511cee75b..d4201400f0f 100644
--- a/src/test/incremental/hashes/call_expressions.rs
+++ b/src/test/incremental/hashes/call_expressions.rs
@@ -55,12 +55,8 @@ mod change_callee_indirectly_function {
     #[cfg(not(cfail1))]
     use super::callee2 as callee;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-
-
+    #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     pub fn change_callee_indirectly_function() {
         callee(1, 2)
     }
diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs
index c73c03ca14e..76bff3cad38 100644
--- a/src/test/incremental/hashes/enum_defs.rs
+++ b/src/test/incremental/hashes/enum_defs.rs
@@ -370,7 +370,7 @@ enum EnumChangeNameOfTypeParameter<S> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumChangeNameOfTypeParameter<T> {
     Variant1(T),
@@ -386,7 +386,7 @@ enum EnumAddTypeParameter<S> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddTypeParameter<S, T> {
     Variant1(S),
@@ -402,7 +402,7 @@ enum EnumChangeNameOfLifetimeParameter<'a> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="predicates_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumChangeNameOfLifetimeParameter<'b> {
     Variant1(&'b u32),
@@ -418,7 +418,7 @@ enum EnumAddLifetimeParameter<'a> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="predicates_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddLifetimeParameter<'a, 'b> {
     Variant1(&'a u32),
@@ -435,7 +435,7 @@ enum EnumAddLifetimeParameterBound<'a, 'b> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="generics_of,type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddLifetimeParameterBound<'a, 'b: 'a> {
     Variant1(&'a u32),
@@ -450,7 +450,7 @@ enum EnumAddLifetimeBoundToParameter<'a, T> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddLifetimeBoundToParameter<'a, T: 'a> {
     Variant1(T),
@@ -466,7 +466,7 @@ enum EnumAddTraitBound<S> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddTraitBound<T: Sync> {
     Variant1(T),
@@ -482,7 +482,7 @@ enum EnumAddLifetimeParameterBoundWhere<'a, 'b> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="generics_of,type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a {
     Variant1(&'a u32),
@@ -499,7 +499,7 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2", except="type_of")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a {
     Variant1(T),
@@ -515,7 +515,7 @@ enum EnumAddTraitBoundWhere<S> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg="cfail2")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")]
 #[rustc_clean(cfg="cfail3")]
 enum EnumAddTraitBoundWhere<T> where T: Sync {
     Variant1(T),
diff --git a/src/test/incremental/hashes/extern_mods.rs b/src/test/incremental/hashes/extern_mods.rs
index 93e70d3792c..1160bc376c4 100644
--- a/src/test/incremental/hashes/extern_mods.rs
+++ b/src/test/incremental/hashes/extern_mods.rs
@@ -21,7 +21,7 @@ extern "C" {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn change_function_name2(c: i64) -> i32;
@@ -34,7 +34,7 @@ extern "C" {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn change_parameter_name(d: i64) -> i32;
@@ -47,7 +47,7 @@ extern "C" {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn change_parameter_type(c: i32) -> i32;
@@ -60,7 +60,7 @@ extern "C" {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn change_return_type(c: i32) -> i8;
@@ -73,7 +73,7 @@ extern "C" {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn add_parameter(c: i32, d: i32) -> i32;
@@ -86,7 +86,7 @@ extern "C" {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn add_return_type(c: i32) -> i32;
@@ -99,7 +99,7 @@ extern "C" {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn make_function_variadic(c: i32, ...);
@@ -112,7 +112,7 @@ extern "C" {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
 #[rustc_clean(cfg = "cfail3")]
 extern "rust-call" {
     pub fn change_calling_convention(c: i32);
@@ -125,7 +125,7 @@ extern "C" {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn make_function_public(c: i32);
@@ -138,7 +138,7 @@ extern "C" {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
 #[rustc_clean(cfg = "cfail3")]
 extern "C" {
     pub fn add_function1(c: i32);
@@ -153,7 +153,7 @@ extern "C" {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+#[rustc_clean(cfg = "cfail2")]
 #[rustc_clean(cfg = "cfail3")]
 #[link(name = "bar")]
 extern "C" {
@@ -170,7 +170,7 @@ mod indirectly_change_parameter_type {
     #[cfg(not(cfail1))]
     use super::c_i64 as c_int;
 
-    #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+    #[rustc_clean(cfg = "cfail2")]
     #[rustc_clean(cfg = "cfail3")]
     extern "C" {
         pub fn indirectly_change_parameter_type(c: c_int);
@@ -184,7 +184,7 @@ mod indirectly_change_return_type {
     #[cfg(not(cfail1))]
     use super::c_i64 as c_int;
 
-    #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
+    #[rustc_clean(cfg = "cfail2")]
     #[rustc_clean(cfg = "cfail3")]
     extern "C" {
         pub fn indirectly_change_return_type() -> c_int;
diff --git a/src/test/incremental/hashes/indexing_expressions.rs b/src/test/incremental/hashes/indexing_expressions.rs
index 7a8cbc3566e..49ee7a9cac0 100644
--- a/src/test/incremental/hashes/indexing_expressions.rs
+++ b/src/test/incremental/hashes/indexing_expressions.rs
@@ -20,10 +20,8 @@ fn change_simple_index(slice: &[u32]) -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn change_simple_index(slice: &[u32]) -> u32 {
     slice[4]
 }
@@ -37,10 +35,8 @@ fn change_lower_bound(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn change_lower_bound(slice: &[u32]) -> &[u32] {
     &slice[2..5]
 }
@@ -54,10 +50,8 @@ fn change_upper_bound(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn change_upper_bound(slice: &[u32]) -> &[u32] {
     &slice[3..7]
 }
@@ -71,10 +65,8 @@ fn add_lower_bound(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn add_lower_bound(slice: &[u32]) -> &[u32] {
     &slice[3..4]
 }
@@ -88,10 +80,8 @@ fn add_upper_bound(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn add_upper_bound(slice: &[u32]) -> &[u32] {
     &slice[3..7]
 }
@@ -105,10 +95,8 @@ fn change_mutability(slice: &mut [u32]) -> u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn change_mutability(slice: &mut [u32]) -> u32 {
     (&slice[3..5])[0]
 }
@@ -122,10 +110,8 @@ fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] {
     &slice[3..=7]
 }
diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs
index 70ce81bd473..284a95f1a68 100644
--- a/src/test/incremental/hashes/inherent_impls.rs
+++ b/src/test/incremental/hashes/inherent_impls.rs
@@ -103,7 +103,10 @@ impl Foo {
 #[rustc_clean(cfg="cfail2", except="hir_owner")]
 #[rustc_clean(cfg="cfail3")]
 impl Foo {
-    #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of,promoted_mir")]
+    #[rustc_clean(
+        cfg="cfail2",
+        except="hir_owner,hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir",
+    )]
     #[rustc_clean(cfg="cfail3")]
     pub fn method_selfness(&self) { }
 }
diff --git a/src/test/incremental/hashes/struct_defs.rs b/src/test/incremental/hashes/struct_defs.rs
index 1339a1e5bf2..0ce5aeaaf50 100644
--- a/src/test/incremental/hashes/struct_defs.rs
+++ b/src/test/incremental/hashes/struct_defs.rs
@@ -24,16 +24,8 @@
 pub struct LayoutPacked;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[repr(packed)]
 pub struct LayoutPacked;
 
@@ -41,16 +33,8 @@ pub struct LayoutPacked;
 struct LayoutC;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 #[repr(C)]
 struct LayoutC;
 
@@ -61,16 +45,8 @@ struct LayoutC;
 struct TupleStructFieldType(i32);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 // Note that changing the type of a field does not change the type of the struct or enum, but
 // adding/removing fields or changing a fields name or visibility does.
 struct TupleStructFieldType(
@@ -84,16 +60,8 @@ struct TupleStructFieldType(
 struct TupleStructAddField(i32);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct TupleStructAddField(
     i32,
     u32
@@ -106,16 +74,8 @@ struct TupleStructAddField(
 struct TupleStructFieldVisibility(char);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct TupleStructFieldVisibility(pub char);
 
 
@@ -125,16 +85,8 @@ struct TupleStructFieldVisibility(pub char);
 struct RecordStructFieldType { x: f32 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 // Note that changing the type of a field does not change the type of the struct or enum, but
 // adding/removing fields or changing a fields name or visibility does.
 struct RecordStructFieldType {
@@ -148,16 +100,8 @@ struct RecordStructFieldType {
 struct RecordStructFieldName { x: f32 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct RecordStructFieldName { y: f32 }
 
 
@@ -167,16 +111,8 @@ struct RecordStructFieldName { y: f32 }
 struct RecordStructAddField { x: f32 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct RecordStructAddField {
     x: f32,
     y: () }
@@ -188,16 +124,8 @@ struct RecordStructAddField {
 struct RecordStructFieldVisibility { x: f32 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct RecordStructFieldVisibility {
     pub x: f32
 }
@@ -209,16 +137,8 @@ struct RecordStructFieldVisibility {
 struct AddLifetimeParameter<'a>(&'a f32, &'a f64);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_dirty(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64);
 
 
@@ -228,16 +148,8 @@ struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64);
 struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct AddLifetimeParameterBound<'a, 'b: 'a>(
     &'a f32,
     &'b f64
@@ -247,16 +159,8 @@ struct AddLifetimeParameterBound<'a, 'b: 'a>(
 struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct AddLifetimeParameterBoundWhereClause<'a, 'b>(
     &'a f32,
     &'b f64)
@@ -269,16 +173,8 @@ struct AddLifetimeParameterBoundWhereClause<'a, 'b>(
 struct AddTypeParameter<T1>(T1, T1);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_dirty(label="type_of", cfg="cfail2")]
-#[rustc_dirty(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct AddTypeParameter<T1, T2>(
      // The field contains the parent's Generics, so it's dirty even though its
      // type hasn't changed.
@@ -293,16 +189,8 @@ struct AddTypeParameter<T1, T2>(
 struct AddTypeParameterBound<T>(T);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct AddTypeParameterBound<T: Send>(
     T
 );
@@ -312,16 +200,8 @@ struct AddTypeParameterBound<T: Send>(
 struct AddTypeParameterBoundWhereClause<T>(T);
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_dirty(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 struct AddTypeParameterBoundWhereClause<T>(
     T
 ) where T: Sync;
@@ -332,16 +212,8 @@ struct AddTypeParameterBoundWhereClause<T>(
 // fingerprint is stable (i.e., that there are no random influences like memory
 // addresses taken into account by the hashing algorithm).
 // Note: there is no #[cfg(...)], so this is ALWAYS compiled
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 pub struct EmptyStruct;
 
 
@@ -351,16 +223,8 @@ pub struct EmptyStruct;
 struct Visibility;
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-#[rustc_clean(label="type_of", cfg="cfail2")]
-#[rustc_clean(label="generics_of", cfg="cfail2")]
-#[rustc_clean(label="predicates_of", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
-#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-#[rustc_clean(label="type_of", cfg="cfail3")]
-#[rustc_clean(label="generics_of", cfg="cfail3")]
-#[rustc_clean(label="predicates_of", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 pub struct Visibility;
 
 struct ReferencedType1;
@@ -373,16 +237,8 @@ mod tuple_struct_change_field_type_indirectly {
     #[cfg(not(cfail1))]
     use super::ReferencedType2 as FieldType;
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="type_of", cfg="cfail2")]
-    #[rustc_clean(label="generics_of", cfg="cfail2")]
-    #[rustc_clean(label="predicates_of", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-    #[rustc_clean(label="type_of", cfg="cfail3")]
-    #[rustc_clean(label="generics_of", cfg="cfail3")]
-    #[rustc_clean(label="predicates_of", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     struct TupleStruct(
         FieldType
     );
@@ -396,16 +252,8 @@ mod record_struct_change_field_type_indirectly {
     #[cfg(not(cfail1))]
     use super::ReferencedType2 as FieldType;
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="type_of", cfg="cfail2")]
-    #[rustc_clean(label="generics_of", cfg="cfail2")]
-    #[rustc_clean(label="predicates_of", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-    #[rustc_clean(label="type_of", cfg="cfail3")]
-    #[rustc_clean(label="generics_of", cfg="cfail3")]
-    #[rustc_clean(label="predicates_of", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     struct RecordStruct {
         _x: FieldType
     }
@@ -424,16 +272,8 @@ mod change_trait_bound_indirectly {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait2 as Trait;
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="type_of", cfg="cfail2")]
-    #[rustc_clean(label="generics_of", cfg="cfail2")]
-    #[rustc_dirty(label="predicates_of", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-    #[rustc_clean(label="type_of", cfg="cfail3")]
-    #[rustc_clean(label="generics_of", cfg="cfail3")]
-    #[rustc_clean(label="predicates_of", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     struct Struct<T: Trait>(T);
 }
 
@@ -444,15 +284,7 @@ mod change_trait_bound_indirectly_in_where_clause {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait2 as Trait;
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="type_of", cfg="cfail2")]
-    #[rustc_clean(label="generics_of", cfg="cfail2")]
-    #[rustc_dirty(label="predicates_of", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
-    #[rustc_clean(label="type_of", cfg="cfail3")]
-    #[rustc_clean(label="generics_of", cfg="cfail3")]
-    #[rustc_clean(label="predicates_of", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     struct Struct<T>(T) where T : Trait;
 }
diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs
index 4dab032e47f..a604ca5ca82 100644
--- a/src/test/incremental/hashes/trait_defs.rs
+++ b/src/test/incremental/hashes/trait_defs.rs
@@ -25,8 +25,8 @@
 trait TraitVisibility { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 pub trait TraitVisibility { }
 
 
@@ -36,8 +36,8 @@ pub trait TraitVisibility { }
 trait TraitUnsafety { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 unsafe trait TraitUnsafety { }
 
 
@@ -48,8 +48,8 @@ trait TraitAddMethod {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 pub trait TraitAddMethod {
     fn method();
 }
@@ -63,8 +63,8 @@ trait TraitChangeMethodName {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeMethodName {
     fn methodChanged();
 }
@@ -78,11 +78,11 @@ trait TraitAddReturnType {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddReturnType {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method() -> u32;
 }
 
@@ -95,11 +95,11 @@ trait TraitChangeReturnType {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeReturnType {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method() -> u64;
 }
 
@@ -112,11 +112,11 @@ trait TraitAddParameterToMethod {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddParameterToMethod {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(a: u32);
 }
 
@@ -130,18 +130,16 @@ trait TraitChangeMethodParameterName {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterName {
     // FIXME(#38501) This should preferably always be clean.
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(b: u32);
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn with_default(y: i32) {}
 }
 
@@ -154,11 +152,11 @@ trait TraitChangeMethodParameterType {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterType {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(a: i64);
 }
 
@@ -171,11 +169,11 @@ trait TraitChangeMethodParameterTypeRef {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeMethodParameterTypeRef {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(a: &mut i32);
 }
 
@@ -188,11 +186,11 @@ trait TraitChangeMethodParametersOrder {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeMethodParametersOrder {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(b: i64, a: i32);
 }
 
@@ -205,11 +203,11 @@ trait TraitAddMethodAutoImplementation {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddMethodAutoImplementation {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method() { }
 }
 
@@ -223,8 +221,8 @@ trait TraitChangeOrderOfMethods {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeOrderOfMethods {
     fn method1();
     fn method0();
@@ -239,11 +237,11 @@ trait TraitChangeModeSelfRefToMut {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeModeSelfRefToMut {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(&mut self);
 }
 
@@ -255,13 +253,11 @@ trait TraitChangeModeSelfOwnToMut: Sized {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeModeSelfOwnToMut: Sized {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(mut self) {}
 }
 
@@ -273,11 +269,11 @@ trait TraitChangeModeSelfOwnToRef {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeModeSelfOwnToRef {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method(&self);
 }
 
@@ -290,11 +286,11 @@ trait TraitAddUnsafeModifier {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddUnsafeModifier {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     unsafe fn method();
 }
 
@@ -307,11 +303,11 @@ trait TraitAddExternModifier {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddExternModifier {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     extern "C" fn method();
 }
 
@@ -324,11 +320,11 @@ trait TraitChangeExternCToRustIntrinsic {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeExternCToRustIntrinsic {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     extern "stdcall" fn method();
 }
 
@@ -341,11 +337,11 @@ trait TraitAddTypeParameterToMethod {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTypeParameterToMethod {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,generics_of,predicates_of,type_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method<T>();
 }
 
@@ -358,11 +354,11 @@ trait TraitAddLifetimeParameterToMethod {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeParameterToMethod {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method<'a>();
 }
 
@@ -379,11 +375,11 @@ trait TraitAddTraitBoundToMethodTypeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTraitBoundToMethodTypeParameter {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method<T: ReferencedTrait0>();
 }
 
@@ -396,11 +392,11 @@ trait TraitAddBuiltinBoundToMethodTypeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddBuiltinBoundToMethodTypeParameter {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method<T: Sized>();
 }
 
@@ -413,11 +409,14 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToMethodLifetimeParameter {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(
+        except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of",
+        cfg="cfail2",
+    )]
+    #[rustc_clean(cfg="cfail3")]
     fn method<'a, 'b: 'a>(a: &'a u32, b: &'b u32);
 }
 
@@ -430,11 +429,11 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondTraitBoundToMethodTypeParameter {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method<T: ReferencedTrait0 + ReferencedTrait1>();
 }
 
@@ -447,11 +446,11 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondBuiltinBoundToMethodTypeParameter {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method<T: Sized + Sync>();
 }
 
@@ -464,11 +463,14 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(
+        except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of",
+        cfg="cfail2",
+    )]
+    #[rustc_clean(cfg="cfail3")]
     fn method<'a, 'b, 'c: 'a + 'b>(a: &'a u32, b: &'b u32, c: &'c u32);
 }
 
@@ -478,14 +480,14 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
 #[cfg(cfail1)]
 trait TraitAddAssociatedType {
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method();
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddAssociatedType {
     type Associated;
 
@@ -506,11 +508,11 @@ trait TraitAddTraitBoundToAssociatedType {
 // Apparently the type bound contributes to the predicates of the trait, but
 // does not change the associated item itself.
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTraitBoundToAssociatedType {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     type Associated: ReferencedTrait0;
 
     fn method();
@@ -527,11 +529,11 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToAssociatedType<'a> {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     type Associated: 'a;
 
     fn method();
@@ -548,11 +550,11 @@ trait TraitAddDefaultToAssociatedType {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddDefaultToAssociatedType {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     type Associated = ReferenceType0;
 
     fn method();
@@ -567,8 +569,8 @@ trait TraitAddAssociatedConstant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddAssociatedConstant {
     const Value: u32;
 
@@ -586,15 +588,15 @@ trait TraitAddInitializerToAssociatedConstant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddInitializerToAssociatedConstant {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     const Value: u32 = 1;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method();
 }
 
@@ -609,15 +611,15 @@ trait TraitChangeTypeOfAssociatedConstant {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitChangeTypeOfAssociatedConstant {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,type_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     const Value: f64;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method();
 }
 
@@ -628,8 +630,8 @@ trait TraitChangeTypeOfAssociatedConstant {
 trait TraitAddSuperTrait { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSuperTrait : ReferencedTrait0 { }
 
 
@@ -639,8 +641,8 @@ trait TraitAddSuperTrait : ReferencedTrait0 { }
 trait TraitAddBuiltiBound { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddBuiltiBound : Send { }
 
 
@@ -650,8 +652,8 @@ trait TraitAddBuiltiBound : Send { }
 trait TraitAddStaticLifetimeBound { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddStaticLifetimeBound : 'static { }
 
 
@@ -661,16 +663,16 @@ trait TraitAddStaticLifetimeBound : 'static { }
 trait TraitAddTraitAsSecondBound : ReferencedTrait0 { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { }
 
 #[cfg(cfail1)]
 trait TraitAddTraitAsSecondBoundFromBuiltin : Send { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { }
 
 
@@ -680,16 +682,16 @@ trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { }
 trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { }
 
 #[cfg(cfail1)]
 trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin : Send { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { }
 
 
@@ -699,16 +701,16 @@ trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { }
 trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { }
 
 #[cfg(cfail1)]
 trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { }
 
 
@@ -718,8 +720,8 @@ trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { }
 trait TraitAddTypeParameterToTrait { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTypeParameterToTrait<T> { }
 
 
@@ -729,8 +731,8 @@ trait TraitAddTypeParameterToTrait<T> { }
 trait TraitAddLifetimeParameterToTrait { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeParameterToTrait<'a> { }
 
 
@@ -740,8 +742,8 @@ trait TraitAddLifetimeParameterToTrait<'a> { }
 trait TraitAddTraitBoundToTypeParameterOfTrait<T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
 
 
@@ -751,8 +753,8 @@ trait TraitAddTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
 trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { }
 
 
@@ -762,8 +764,8 @@ trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { }
 trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a, 'b> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { }
 
 
@@ -773,8 +775,8 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { }
 trait TraitAddBuiltinBoundToTypeParameterOfTrait<T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddBuiltinBoundToTypeParameterOfTrait<T: Send> { }
 
 
@@ -784,8 +786,8 @@ trait TraitAddBuiltinBoundToTypeParameterOfTrait<T: Send> { }
 trait TraitAddSecondTypeParameterToTrait<T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondTypeParameterToTrait<T, S> { }
 
 
@@ -795,8 +797,8 @@ trait TraitAddSecondTypeParameterToTrait<T, S> { }
 trait TraitAddSecondLifetimeParameterToTrait<'a> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { }
 
 
@@ -806,8 +808,8 @@ trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { }
 trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0 + ReferencedTrait1> { }
 
 
@@ -817,8 +819,8 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0 + Refer
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { }
 
 
@@ -828,8 +830,8 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { }
 trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b, 'c> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> { }
 
 
@@ -839,8 +841,8 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c>
 trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait<T: Send> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait<T: Send + Sync> { }
 
 
@@ -855,8 +857,8 @@ struct ReferenceType1 {}
 trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0 { }
 
 
@@ -866,8 +868,8 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0
 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { }
 
 
@@ -877,8 +879,8 @@ trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { }
 trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b { }
 
 
@@ -888,8 +890,8 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b
 trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { }
 
 
@@ -899,8 +901,8 @@ trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { }
 trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0 { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T>
     where T: ReferencedTrait0 + ReferencedTrait1 { }
 
@@ -911,8 +913,8 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T>
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { }
 
 
@@ -922,8 +924,8 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T:
 trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b + 'c { }
 
 
@@ -933,8 +935,8 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> whe
 trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send + Sync { }
 
 
@@ -945,11 +947,11 @@ mod change_return_type_of_method_indirectly_use {
     #[cfg(not(cfail1))]
     use super::ReferenceType1 as ReturnType;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     trait TraitChangeReturnType {
-        #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-        #[rustc_clean(label="hir_owner", cfg="cfail3")]
+        #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
+        #[rustc_clean(cfg="cfail3")]
         fn method() -> ReturnType;
     }
 }
@@ -963,11 +965,11 @@ mod change_method_parameter_type_indirectly_by_use {
     #[cfg(not(cfail1))]
     use super::ReferenceType1 as ArgType;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     trait TraitChangeArgType {
-        #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-        #[rustc_clean(label="hir_owner", cfg="cfail3")]
+        #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+        #[rustc_clean(cfg="cfail3")]
         fn method(a: ArgType);
     }
 }
@@ -981,11 +983,11 @@ mod change_method_parameter_type_bound_indirectly_by_use {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait1 as Bound;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     trait TraitChangeBoundOfMethodTypeParameter {
-        #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-        #[rustc_clean(label="hir_owner", cfg="cfail3")]
+        #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+        #[rustc_clean(cfg="cfail3")]
         fn method<T: Bound>(a: T);
     }
 }
@@ -1000,11 +1002,11 @@ mod change_method_parameter_type_bound_indirectly_by_use_where {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait1 as Bound;
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     trait TraitChangeBoundOfMethodTypeParameterWhere {
-        #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-        #[rustc_clean(label="hir_owner", cfg="cfail3")]
+        #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+        #[rustc_clean(cfg="cfail3")]
         fn method<T>(a: T) where T: Bound;
     }
 }
@@ -1018,8 +1020,8 @@ mod change_method_type_parameter_bound_indirectly {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait1 as Bound;
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     trait TraitChangeTraitBound<T: Bound> {
         fn method(a: T);
     }
@@ -1035,8 +1037,8 @@ mod change_method_type_parameter_bound_indirectly_where {
     #[cfg(not(cfail1))]
     use super::ReferencedTrait1 as Bound;
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     trait TraitChangeTraitBoundWhere<T> where T: Bound {
         fn method(a: T);
     }
diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs
index e9118da5a61..c9a3de1f6ae 100644
--- a/src/test/incremental/hashes/trait_impls.rs
+++ b/src/test/incremental/hashes/trait_impls.rs
@@ -30,18 +30,18 @@ impl ChangeMethodNameTrait for Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 pub trait ChangeMethodNameTrait {
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name2();
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeMethodNameTrait for Foo {
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name2() { }
 }
 
@@ -59,13 +59,11 @@ impl ChangeMethodBodyTrait for Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeMethodBodyTrait for Foo {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name() {
         ()
     }
@@ -86,13 +84,11 @@ impl ChangeMethodBodyTraitInlined for Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeMethodBodyTraitInlined for Foo {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     #[inline]
     fn method_name() {
         panic!()
@@ -117,11 +113,14 @@ pub trait ChangeMethodSelfnessTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeMethodSelfnessTrait for Foo {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(
+        except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir",
+        cfg="cfail2",
+    )]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name(&self) {
         ()
     }
@@ -145,11 +144,14 @@ pub trait RemoveMethodSelfnessTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl RemoveMethodSelfnessTrait for Foo {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(
+        except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir",
+        cfg="cfail2",
+    )]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name() {}
 }
 
@@ -171,11 +173,11 @@ pub trait ChangeMethodSelfmutnessTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeMethodSelfmutnessTrait for Foo {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name(&mut self) {}
 }
 
@@ -197,8 +199,8 @@ pub trait ChangeItemKindTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeItemKindTrait for Foo {
     type name = ();
 }
@@ -223,8 +225,8 @@ pub trait RemoveItemTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl RemoveItemTrait for Foo {
     type TypeName = ();
 }
@@ -248,8 +250,8 @@ pub trait AddItemTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl AddItemTrait for Foo {
     type TypeName = ();
     fn method_name() { }
@@ -268,17 +270,17 @@ impl ChangeHasValueTrait for Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 pub trait ChangeHasValueTrait {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name() { }
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeHasValueTrait for Foo {
     fn method_name() { }
 }
@@ -295,11 +297,11 @@ impl AddDefaultTrait for Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl AddDefaultTrait for Foo {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     default fn method_name() { }
 }
 
@@ -321,11 +323,11 @@ pub trait AddArgumentTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl AddArgumentTrait for Foo {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name(&self, _x: u32) { }
 }
 
@@ -347,11 +349,11 @@ pub trait ChangeArgumentTypeTrait {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeArgumentTypeTrait for Foo {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn method_name(&self, _x: char) { }
 }
 
@@ -370,11 +372,14 @@ impl AddTypeParameterToImpl<u32> for Bar<u32> {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,generics_of,impl_trait_ref", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl<T> AddTypeParameterToImpl<T> for Bar<T> {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(
+        except="hir_owner,hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir",
+        cfg="cfail2",
+    )]
+    #[rustc_clean(cfg="cfail3")]
     fn id(t: T) -> T { t }
 }
 
@@ -391,11 +396,11 @@ impl ChangeSelfTypeOfImpl for u32 {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,impl_trait_ref", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl ChangeSelfTypeOfImpl for u64 {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(except="fn_sig,typeck,optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn id(self) -> Self { self }
 }
 
@@ -412,11 +417,11 @@ impl<T> AddLifetimeBoundToImplParameter for T {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl<T: 'static> AddLifetimeBoundToImplParameter for T {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn id(self) -> Self { self }
 }
 
@@ -433,11 +438,11 @@ impl<T> AddTraitBoundToImplParameter for T {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_dirty(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl<T: Clone> AddTraitBoundToImplParameter for T {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     fn id(self) -> Self { self }
 }
 
@@ -454,11 +459,11 @@ impl AddNoMangleToMethod for Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl AddNoMangleToMethod for Foo {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     #[no_mangle]
     fn add_no_mangle_to_method(&self) { }
 }
@@ -475,11 +480,11 @@ impl MakeMethodInline for Foo {
 }
 
 #[cfg(not(cfail1))]
-#[rustc_clean(label="hir_owner", cfg="cfail2")]
-#[rustc_clean(label="hir_owner", cfg="cfail3")]
+#[rustc_clean(cfg="cfail2")]
+#[rustc_clean(cfg="cfail3")]
 impl MakeMethodInline for Foo {
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    #[rustc_clean(label="hir_owner", cfg="cfail3")]
+    #[rustc_clean(cfg="cfail2")]
+    #[rustc_clean(cfg="cfail3")]
     #[inline]
     fn make_method_inline(&self) -> u8 { 0 }
 }
diff --git a/src/test/incremental/hello_world.rs b/src/test/incremental/hello_world.rs
index 4c60d7bd9d5..d5ec6e92bc0 100644
--- a/src/test/incremental/hello_world.rs
+++ b/src/test/incremental/hello_world.rs
@@ -21,7 +21,7 @@ mod x {
 mod y {
     use x;
 
-    #[rustc_clean(label="typeck", cfg="rpass2")]
+    #[rustc_clean(cfg="rpass2")]
     pub fn yyyy() {
         x::xxxx();
     }
@@ -30,7 +30,7 @@ mod y {
 mod z {
     use y;
 
-    #[rustc_clean(label="typeck", cfg="rpass2")]
+    #[rustc_clean(cfg="rpass2")]
     pub fn z() {
         y::yyyy();
     }
diff --git a/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs b/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs
index 91a9f63d39b..b31f60e972b 100644
--- a/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs
+++ b/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs
@@ -13,7 +13,7 @@ macro_rules! first_macro {
     }
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir,promoted_mir", cfg="rpass2")]
 #[inline(always)]
 pub fn changed_fn() {
     // This will cause additional hygiene to be generate,
diff --git a/src/test/incremental/ich_method_call_trait_scope.rs b/src/test/incremental/ich_method_call_trait_scope.rs
index 6d7d446cb7c..5566506c039 100644
--- a/src/test/incremental/ich_method_call_trait_scope.rs
+++ b/src/test/incremental/ich_method_call_trait_scope.rs
@@ -26,16 +26,12 @@ mod mod3 {
     #[cfg(rpass2)]
     use Trait2;
 
-    #[rustc_clean(label="hir_owner", cfg="rpass2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
-    #[rustc_dirty(label="typeck", cfg="rpass2")]
+    #[rustc_clean(except="typeck", cfg="rpass2")]
     fn bar() {
         ().method();
     }
 
-    #[rustc_clean(label="hir_owner", cfg="rpass2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
-    #[rustc_clean(label="typeck", cfg="rpass2")]
+    #[rustc_clean(cfg="rpass2")]
     fn baz() {
         22; // no method call, traits in scope don't matter
     }
diff --git a/src/test/incremental/ich_nested_items.rs b/src/test/incremental/ich_nested_items.rs
index 8df54467e5e..379c09575ed 100644
--- a/src/test/incremental/ich_nested_items.rs
+++ b/src/test/incremental/ich_nested_items.rs
@@ -8,14 +8,12 @@
 #![crate_type = "rlib"]
 #![feature(rustc_attrs)]
 
-#[rustc_clean(label = "hir_owner", cfg = "cfail2")]
-#[rustc_dirty(label = "hir_owner_nodes", cfg = "cfail2")]
+#[rustc_clean(except = "hir_owner_nodes", cfg = "cfail2")]
 pub fn foo() {
     #[cfg(cfail1)]
     pub fn baz() {} // order is different...
 
-    #[rustc_clean(label = "hir_owner", cfg = "cfail2")]
-    #[rustc_clean(label = "hir_owner_nodes", cfg = "cfail2")]
+    #[rustc_clean(cfg = "cfail2")]
     pub fn bar() {} // but that doesn't matter.
 
     #[cfg(cfail2)]
diff --git a/src/test/incremental/ich_resolve_results.rs b/src/test/incremental/ich_resolve_results.rs
index 1fb0f8aa84d..e6ab6bcebae 100644
--- a/src/test/incremental/ich_resolve_results.rs
+++ b/src/test/incremental/ich_resolve_results.rs
@@ -29,18 +29,14 @@ mod mod3 {
     #[cfg(rpass3)]
     use mod2::Foo;
 
-    #[rustc_clean(label="hir_owner", cfg="rpass2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
-    #[rustc_clean(label="hir_owner", cfg="rpass3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="rpass3")]
+    #[rustc_clean(cfg="rpass2")]
+    #[rustc_clean(except="hir_owner_nodes,typeck", cfg="rpass3")]
     fn in_expr() {
         Foo(0);
     }
 
-    #[rustc_clean(label="hir_owner", cfg="rpass2")]
-    #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
-    #[rustc_clean(label="hir_owner", cfg="rpass3")]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="rpass3")]
+    #[rustc_clean(cfg="rpass2")]
+    #[rustc_clean(except="hir_owner_nodes,typeck", cfg="rpass3")]
     fn in_type() {
         test::<Foo>();
     }
diff --git a/src/test/incremental/link_order/auxiliary/my_lib.rs b/src/test/incremental/link_order/auxiliary/my_lib.rs
new file mode 100644
index 00000000000..57cde5f7c6e
--- /dev/null
+++ b/src/test/incremental/link_order/auxiliary/my_lib.rs
@@ -0,0 +1,3 @@
+// no-prefer-dynamic
+//[cfail1] compile-flags: -lbar -lfoo --crate-type lib
+//[cfail2] compile-flags: -lfoo -lbar --crate-type lib
diff --git a/src/test/incremental/link_order/main.rs b/src/test/incremental/link_order/main.rs
new file mode 100644
index 00000000000..d211c295bc4
--- /dev/null
+++ b/src/test/incremental/link_order/main.rs
@@ -0,0 +1,12 @@
+// aux-build:my_lib.rs
+// error-pattern: error: linking with
+// revisions:cfail1 cfail2
+// compile-flags:-Z query-dep-graph
+
+// Tests that re-ordering the `-l` arguments used
+// when compiling an external dependency does not lead to
+// an 'unstable fingerprint' error.
+
+extern crate my_lib;
+
+fn main() {}
diff --git a/src/test/incremental/rlib_cross_crate/b.rs b/src/test/incremental/rlib_cross_crate/b.rs
index 73846712b59..639cfc918cb 100644
--- a/src/test/incremental/rlib_cross_crate/b.rs
+++ b/src/test/incremental/rlib_cross_crate/b.rs
@@ -12,15 +12,15 @@
 
 extern crate a;
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(except="typeck,optimized_mir", cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
 pub fn use_X() -> u32 {
     let x: a::X = 22;
     x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
 pub fn use_Y() {
     let x: a::Y = 'c';
 }
diff --git a/src/test/incremental/source_loc_macros.rs b/src/test/incremental/source_loc_macros.rs
index f18d2fdaf0a..e5f04e5dc58 100644
--- a/src/test/incremental/source_loc_macros.rs
+++ b/src/test/incremental/source_loc_macros.rs
@@ -7,26 +7,22 @@
 
 #![feature(rustc_attrs)]
 
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 fn line_same() {
     let _ = line!();
 }
 
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 fn col_same() {
     let _ = column!();
 }
 
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 fn file_same() {
     let _ = file!();
 }
 
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="rpass2")]
 fn line_different() {
     #[cfg(rpass1)]
     {
@@ -38,8 +34,7 @@ fn line_different() {
     }
 }
 
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="rpass2")]
 fn col_different() {
     #[cfg(rpass1)]
     {
diff --git a/src/test/incremental/span_hash_stable/auxiliary/sub1.rs b/src/test/incremental/span_hash_stable/auxiliary/sub1.rs
index 2927ddec4e5..70e2ea06b7e 100644
--- a/src/test/incremental/span_hash_stable/auxiliary/sub1.rs
+++ b/src/test/incremental/span_hash_stable/auxiliary/sub1.rs
@@ -1,4 +1,4 @@
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub struct SomeType {
     pub x: u32,
     pub y: i64,
diff --git a/src/test/incremental/span_hash_stable/auxiliary/sub2.rs b/src/test/incremental/span_hash_stable/auxiliary/sub2.rs
index aa635077db8..1167cdb0a82 100644
--- a/src/test/incremental/span_hash_stable/auxiliary/sub2.rs
+++ b/src/test/incremental/span_hash_stable/auxiliary/sub2.rs
@@ -1,4 +1,4 @@
-#[rustc_clean(label="hir_owner", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub struct SomeOtherType {
     pub a: i32,
     pub b: u64,
diff --git a/src/test/incremental/spans_significant_w_debuginfo.rs b/src/test/incremental/spans_significant_w_debuginfo.rs
index aff2be830ff..8506636e22b 100644
--- a/src/test/incremental/spans_significant_w_debuginfo.rs
+++ b/src/test/incremental/spans_significant_w_debuginfo.rs
@@ -12,6 +12,5 @@
 pub fn main() {}
 
 #[cfg(rpass2)]
-#[rustc_dirty(label="hir_owner", cfg="rpass2")]
-#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir", cfg="rpass2")]
 pub fn main() {}
diff --git a/src/test/incremental/spans_significant_w_panic.rs b/src/test/incremental/spans_significant_w_panic.rs
index 37728af9516..a29b61ab153 100644
--- a/src/test/incremental/spans_significant_w_panic.rs
+++ b/src/test/incremental/spans_significant_w_panic.rs
@@ -13,7 +13,7 @@ pub fn main() {
 }
 
 #[cfg(rpass2)]
-#[rustc_dirty(label="optimized_mir", cfg="rpass2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir", cfg="rpass2")]
 pub fn main() {
     let _ = 0u8 + 1;
 }
diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs
index 2fc72529431..866f51d759e 100644
--- a/src/test/incremental/string_constant.rs
+++ b/src/test/incremental/string_constant.rs
@@ -18,8 +18,7 @@ pub mod x {
     }
 
     #[cfg(cfail2)]
-    #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")]
-    #[rustc_dirty(label="optimized_mir", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir,promoted_mir", cfg="cfail2")]
     pub fn x() {
         println!("{}", "2");
     }
@@ -28,8 +27,7 @@ pub mod x {
 pub mod y {
     use x;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
-    #[rustc_clean(label="optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn y() {
         x::x();
     }
@@ -38,8 +36,7 @@ pub mod y {
 pub mod z {
     use y;
 
-    #[rustc_clean(label="typeck", cfg="cfail2")]
-    #[rustc_clean(label="optimized_mir", cfg="cfail2")]
+    #[rustc_clean(cfg="cfail2")]
     pub fn z() {
         y::y();
     }
diff --git a/src/test/incremental/struct_add_field.rs b/src/test/incremental/struct_add_field.rs
index 4c29f196f67..720854f1605 100644
--- a/src/test/incremental/struct_add_field.rs
+++ b/src/test/incremental/struct_add_field.rs
@@ -21,17 +21,17 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="fn_sig,typeck", cfg="rpass2")]
 pub fn use_X(x: X) -> u32 {
     x.x as u32
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn use_EmbedX(embed: EmbedX) -> u32 {
     embed.x.x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs
index ee88fbdf592..7498d0305e0 100644
--- a/src/test/incremental/struct_change_field_name.rs
+++ b/src/test/incremental/struct_change_field_name.rs
@@ -24,7 +24,7 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_dirty(label="typeck", cfg="cfail2")]
+#[rustc_clean(except="typeck", cfg="cfail2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
     //[cfail2]~^ ERROR struct `X` has no field named `x`
@@ -32,13 +32,13 @@ pub fn use_X() -> u32 {
     //[cfail2]~^ ERROR no field `x` on type `X`
 }
 
-#[rustc_dirty(label="typeck", cfg="cfail2")]
+#[rustc_clean(except="typeck", cfg="cfail2")]
 pub fn use_EmbedX(embed: EmbedX) -> u32 {
     embed.x.x as u32
     //[cfail2]~^ ERROR no field `x` on type `X`
 }
 
-#[rustc_clean(label="typeck", cfg="cfail2")]
+#[rustc_clean(cfg="cfail2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
diff --git a/src/test/incremental/struct_change_field_type.rs b/src/test/incremental/struct_change_field_type.rs
index b60b4b311ee..37d2fba9901 100644
--- a/src/test/incremental/struct_change_field_type.rs
+++ b/src/test/incremental/struct_change_field_type.rs
@@ -24,19 +24,19 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn use_EmbedX(x: EmbedX) -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
diff --git a/src/test/incremental/struct_change_field_type_cross_crate/b.rs b/src/test/incremental/struct_change_field_type_cross_crate/b.rs
index 0221d510eab..c78207bcb1a 100644
--- a/src/test/incremental/struct_change_field_type_cross_crate/b.rs
+++ b/src/test/incremental/struct_change_field_type_cross_crate/b.rs
@@ -8,18 +8,18 @@ extern crate a;
 
 use a::*;
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn use_EmbedX(embed: EmbedX) -> u32 {
     embed.x.x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
diff --git a/src/test/incremental/struct_change_nothing.rs b/src/test/incremental/struct_change_nothing.rs
index 3ab90e966fb..de30c818cfe 100644
--- a/src/test/incremental/struct_change_nothing.rs
+++ b/src/test/incremental/struct_change_nothing.rs
@@ -24,19 +24,19 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_EmbedX(x: EmbedX) -> u32 {
     let x: X = X { x: 22 };
     x.x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
diff --git a/src/test/incremental/struct_remove_field.rs b/src/test/incremental/struct_remove_field.rs
index f6017b1b1c3..b97a87e0962 100644
--- a/src/test/incremental/struct_remove_field.rs
+++ b/src/test/incremental/struct_remove_field.rs
@@ -25,17 +25,17 @@ pub struct Y {
     pub y: char
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck,fn_sig", cfg="rpass2")]
 pub fn use_X(x: X) -> u32 {
     x.x as u32
 }
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
 pub fn use_EmbedX(embed: EmbedX) -> u32 {
     embed.x.x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass2")]
 pub fn use_Y() {
     let x: Y = Y { y: 'c' };
 }
diff --git a/src/test/incremental/type_alias_cross_crate/b.rs b/src/test/incremental/type_alias_cross_crate/b.rs
index 05c926fdded..f6c2526841c 100644
--- a/src/test/incremental/type_alias_cross_crate/b.rs
+++ b/src/test/incremental/type_alias_cross_crate/b.rs
@@ -6,15 +6,15 @@
 
 extern crate a;
 
-#[rustc_dirty(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(except="typeck", cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
 pub fn use_X() -> u32 {
     let x: a::X = 22;
     x as u32
 }
 
-#[rustc_clean(label="typeck", cfg="rpass2")]
-#[rustc_clean(label="typeck", cfg="rpass3")]
+#[rustc_clean(cfg="rpass2")]
+#[rustc_clean(cfg="rpass3")]
 pub fn use_Y() {
     let x: a::Y = 'c';
 }
diff --git a/src/test/incremental/unchecked_dirty_clean.rs b/src/test/incremental/unchecked_dirty_clean.rs
index 3bc8818aa6f..3c8692a302d 100644
--- a/src/test/incremental/unchecked_dirty_clean.rs
+++ b/src/test/incremental/unchecked_dirty_clean.rs
@@ -4,31 +4,31 @@
 #![allow(warnings)]
 #![feature(rustc_attrs)]
 
-// Sanity check for the dirty-clean system. We add #[rustc_dirty]/#[rustc_clean]
+// Sanity check for the dirty-clean system. We add #[rustc_clean]
 // attributes in places that are not checked and make sure that this causes an
 // error.
 
 fn main() {
 
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
     {
         // empty block
     }
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+    #[rustc_clean(cfg="cfail2")]
+    //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
     {
         // empty block
     }
 }
 
 struct _Struct {
-    #[rustc_dirty(label="hir_owner", cfg="cfail2")]
-    //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
     _field1: i32,
 
-    #[rustc_clean(label="hir_owner", cfg="cfail2")]
-    //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute
+    #[rustc_clean(cfg="cfail2")]
+    //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute
     _field2: i32,
 }
diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
index 2566d745ecd..8bb5dbc48fe 100644
--- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
+++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
@@ -30,7 +30,7 @@
 -         _3 = [move _4];                  // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
 -         _2 = &_3;                        // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
 +                                          // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:35
-+                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
++                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[55e6]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
 +         _2 = &(*_6);                     // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
           _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
 -         StorageDead(_4);                 // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35
diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
index 093e228a0ce..54f1200a21f 100644
--- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
+++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
@@ -32,7 +32,7 @@
 -         _3 = [move _4];                  // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 -         _2 = &_3;                        // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 +                                          // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:46
-+                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
++                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[55e6]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
 +         _2 = &(*_6);                     // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
           _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 -         StorageDead(_4);                 // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
index 0517e7fac40..db6e1369161 100644
--- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
@@ -31,7 +31,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
-                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _3 = _9;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
index 0517e7fac40..db6e1369161 100644
--- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
@@ -31,7 +31,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
-                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _3 = _9;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
index 28c80b346e7..d7bc035e667 100644
--- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
@@ -22,7 +22,7 @@
                                            // + val: Unevaluated(FOO, [], None)
                                            // mir::Constant
                                            // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main::FOO), const_param_did: None }, substs: [], promoted: None }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[2706]::main::FOO), const_param_did: None }, substs: [], promoted: None }) }
           _2 = &raw const (*_3);           // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
           _1 = move _2 as usize (Misc);    // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
           StorageDead(_2);                 // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39
diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
index ae77443e019..4e19465189c 100644
--- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
@@ -17,7 +17,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/ref_deref.rs:5:6: 5:10
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _2 = _4;                         // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
 -         _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
 +         _1 = const 4_i32;                // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
diff --git a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff
index 402a28f3f9f..a58dabdaa41 100644
--- a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff
+++ b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff
@@ -20,7 +20,7 @@
 +                                          // + val: Unevaluated(main, [], Some(promoted[0]))
 +                                          // mir::Constant
 +                                          // + span: $DIR/ref_deref.rs:5:6: 5:10
-+                                          // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
++                                          // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
 +         _2 = &(*_4);                     // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
 -         StorageDead(_3);                 // scope 0 at $DIR/ref_deref.rs:5:10: 5:11
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
index b97d7d1be15..bb265b2af7d 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
@@ -17,7 +17,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/ref_deref_project.rs:5:6: 5:17
-                                           // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
           StorageDead(_2);                 // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
index 48ede27112c..bb7570fabbb 100644
--- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
+++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
@@ -20,7 +20,7 @@
 +                                          // + val: Unevaluated(main, [], Some(promoted[0]))
 +                                          // mir::Constant
 +                                          // + span: $DIR/ref_deref_project.rs:5:6: 5:17
-+                                          // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
++                                          // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
 +         _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
 -         StorageDead(_3);                 // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
index 27791852d6d..d5a36182e35 100644
--- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
+++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
@@ -24,7 +24,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/slice_len.rs:5:6: 5:19
-                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
index 27791852d6d..d5a36182e35 100644
--- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
+++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
@@ -24,7 +24,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/slice_len.rs:5:6: 5:19
-                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19
diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
index 1aabee83be6..5ceefce6114 100644
--- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
+++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
@@ -38,7 +38,7 @@ fn bar() -> bool {
                                          // + val: Unevaluated(bar, [], Some(promoted[1]))
                                          // mir::Constant
                                          // + span: $DIR/inline-retag.rs:12:7: 12:9
-                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) }
         Retag(_10);                      // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
         _4 = &(*_10);                    // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
         Retag(_4);                       // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
@@ -52,7 +52,7 @@ fn bar() -> bool {
                                          // + val: Unevaluated(bar, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $DIR/inline-retag.rs:12:11: 12:14
-                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
         Retag(_9);                       // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
         _7 = &(*_9);                     // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
         Retag(_7);                       // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir
index c1421f20a0b..ba17a45f984 100644
--- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir
+++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir
@@ -4,21 +4,20 @@ fn test() -> Option<Box<u32>> {
     let mut _0: std::option::Option<std::boxed::Box<u32>>; // return place in scope 0 at $DIR/issue-62289.rs:8:14: 8:30
     let mut _1: std::boxed::Box<u32>;    // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
     let mut _2: std::boxed::Box<u32>;    // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
-    let mut _3: std::result::Result<u32, std::option::NoneError>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+    let mut _3: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
     let mut _4: std::option::Option<u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19
     let mut _5: isize;                   // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-    let _6: std::option::NoneError;      // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+    let _6: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
     let mut _7: !;                       // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-    let mut _8: std::option::NoneError;  // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-    let mut _9: std::option::NoneError;  // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-    let _10: u32;                        // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+    let mut _8: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+    let _9: u32;                         // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
     scope 1 {
-        debug err => _6;                 // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20
+        debug residual => _6;            // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20
         scope 2 {
         }
     }
     scope 3 {
-        debug val => _10;                // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20
+        debug val => _9;                 // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20
         scope 4 {
         }
     }
@@ -30,10 +29,10 @@ fn test() -> Option<Box<u32>> {
         StorageLive(_3);                 // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
         StorageLive(_4);                 // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
         _4 = Option::<u32>::None;        // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
-        _3 = <Option<u32> as Try>::into_result(move _4) -> [return: bb1, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+        _3 = <Option<u32> as Try>::branch(move _4) -> [return: bb1, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
                                          // mir::Constant
                                          // + span: $DIR/issue-62289.rs:9:15: 9:20
-                                         // + literal: Const { ty: fn(std::option::Option<u32>) -> std::result::Result<<std::option::Option<u32> as std::ops::Try>::Ok, <std::option::Option<u32> as std::ops::Try>::Error> {<std::option::Option<u32> as std::ops::Try>::into_result}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(std::option::Option<u32>) -> std::ops::ControlFlow<<std::option::Option<u32> as std::ops::Try>::Residual, <std::option::Option<u32> as std::ops::Try>::Output> {<std::option::Option<u32> as std::ops::Try>::branch}, val: Value(Scalar(<ZST>)) }
     }
 
     bb1: {
@@ -43,12 +42,12 @@ fn test() -> Option<Box<u32>> {
     }
 
     bb2: {
-        StorageLive(_10);                // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
-        _10 = ((_3 as Ok).0: u32);       // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
-        (*_2) = _10;                     // scope 4 at $DIR/issue-62289.rs:9:15: 9:20
-        StorageDead(_10);                // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+        StorageLive(_9);                 // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+        _9 = ((_3 as Continue).0: u32);  // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+        (*_2) = _9;                      // scope 4 at $DIR/issue-62289.rs:9:15: 9:20
+        StorageDead(_9);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
         _1 = move _2;                    // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
-        drop(_2) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+        drop(_2) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
     }
 
     bb3: {
@@ -57,62 +56,53 @@ fn test() -> Option<Box<u32>> {
 
     bb4: {
         StorageLive(_6);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-        _6 = ((_3 as Err).0: std::option::NoneError); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+        _6 = ((_3 as Break).0: std::option::Option<std::convert::Infallible>); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
         StorageLive(_8);                 // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
-        StorageLive(_9);                 // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
-        _9 = _6;                         // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
-        _8 = <NoneError as From<NoneError>>::from(move _9) -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
+        _8 = _6;                         // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
+        _0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _8) -> [return: bb5, unwind: bb11]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20
                                          // mir::Constant
                                          // + span: $DIR/issue-62289.rs:9:19: 9:20
-                                         // + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {<std::option::NoneError as std::convert::From<std::option::NoneError>>::from}, val: Value(Scalar(<ZST>)) }
+                                         // + literal: Const { ty: fn(std::option::Option<std::convert::Infallible>) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::FromResidual<std::option::Option<std::convert::Infallible>>>::from_residual}, val: Value(Scalar(<ZST>)) }
     }
 
     bb5: {
-        StorageDead(_9);                 // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
-        _0 = <Option<Box<u32>> as Try>::from_error(move _8) -> [return: bb6, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20
-                                         // mir::Constant
-                                         // + span: $DIR/issue-62289.rs:9:15: 9:20
-                                         // + literal: Const { ty: fn(<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::Error) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::from_error}, val: Value(Scalar(<ZST>)) }
-    }
-
-    bb6: {
         StorageDead(_8);                 // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
         StorageDead(_6);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-        drop(_2) -> bb9;                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+        drop(_2) -> bb8;                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
     }
 
-    bb7: {
+    bb6: {
         StorageDead(_2);                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
         _0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22
-        drop(_1) -> bb8;                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
+        drop(_1) -> bb7;                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
     }
 
-    bb8: {
+    bb7: {
         StorageDead(_1);                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
         StorageDead(_3);                 // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
-        goto -> bb10;                    // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
+        goto -> bb9;                     // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
     }
 
-    bb9: {
+    bb8: {
         StorageDead(_2);                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
         StorageDead(_1);                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
         StorageDead(_3);                 // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
-        goto -> bb10;                    // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
+        goto -> bb9;                     // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
     }
 
-    bb10: {
+    bb9: {
         return;                          // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
     }
 
-    bb11 (cleanup): {
-        drop(_1) -> bb13;                // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
+    bb10 (cleanup): {
+        drop(_1) -> bb12;                // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
     }
 
-    bb12 (cleanup): {
-        drop(_2) -> bb13;                // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+    bb11 (cleanup): {
+        drop(_2) -> bb12;                // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
     }
 
-    bb13 (cleanup): {
+    bb12 (cleanup): {
         resume;                          // scope 0 at $DIR/issue-62289.rs:8:1: 10:2
     }
 }
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
index 95a8ef997fa..e955feb7d1f 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
@@ -66,7 +66,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _8 = _20;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_6.0: &i32) = move _7;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_6.1: &i32) = move _8;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
index 95a8ef997fa..e955feb7d1f 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
@@ -66,7 +66,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _8 = _20;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_6.0: &i32) = move _7;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_6.1: &i32) = move _8;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
index 261eb3b27ea..ff8c410a726 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
@@ -87,7 +87,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _11 = _28;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_9.0: &i32) = move _10;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_9.1: &i32) = move _11;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
index 261eb3b27ea..ff8c410a726 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
@@ -87,7 +87,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _11 = _28;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_9.0: &i32) = move _10;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_9.1: &i32) = move _11;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
index a37df4da9ae..acb8aca7590 100644
--- a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
@@ -50,7 +50,7 @@
                                            // + val: Unevaluated(discriminant, [T], Some(promoted[2]))
                                            // mir::Constant
                                            // + span: $DIR/lower_intrinsics.rs:70:42: 70:44
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) }
           _7 = &(*_19);                    // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44
           _6 = &(*_7);                     // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44
 -         _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45
@@ -74,7 +74,7 @@
                                            // + val: Unevaluated(discriminant, [T], Some(promoted[1]))
                                            // mir::Constant
                                            // + span: $DIR/lower_intrinsics.rs:71:42: 71:45
-                                           // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) }
+                                           // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) }
           _11 = &(*_18);                   // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45
           _10 = &(*_11);                   // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45
 -         _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46
@@ -98,7 +98,7 @@
                                            // + val: Unevaluated(discriminant, [T], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/lower_intrinsics.rs:72:42: 72:47
-                                           // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) }
           _15 = &(*_17);                   // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47
           _14 = &(*_15);                   // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47
 -         _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48
diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
index 5af242376c9..c27ee528b80 100644
--- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
+++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
@@ -57,7 +57,7 @@ fn full_tested_match() -> () {
                                          // + val: Unevaluated(full_tested_match, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $DIR/match_false_edges.rs:16:14: 16:15
-                                         // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                         // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[4011]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
         _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
         _4 = &shallow _2;                // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
         StorageLive(_7);                 // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
index dd8a9251042..80024124dc5 100644
--- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
+++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
@@ -32,6 +32,10 @@
                   scope 5 {
                       debug i => _15;      // in scope 5 at $DIR/remove_storage_markers.rs:8:9: 8:10
                   }
+                  scope 7 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
+                      debug self => _9;    // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+                      let mut _18: &mut std::ops::Range<i32>; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+                  }
               }
           }
           scope 6 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
@@ -61,19 +65,15 @@
 -         StorageLive(_10);                // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
           _10 = &mut _4;                   // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
           _9 = &mut (*_10);                // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
-          _8 = <std::ops::Range<i32> as Iterator>::next(move _9) -> bb2; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19
+-         StorageLive(_18);                // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+          _18 = &mut (*_9);                // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+          _8 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _18) -> bb4; // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
                                            // mir::Constant
                                            // + span: $DIR/remove_storage_markers.rs:8:14: 8:19
-                                           // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::Iterator>::Item> {<std::ops::Range<i32> as std::iter::Iterator>::next}, val: Value(Scalar(<ZST>)) }
+                                           // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::spec_next}, val: Value(Scalar(<ZST>)) }
       }
   
       bb2: {
--         StorageDead(_9);                 // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
-          _11 = discriminant(_8);          // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
-          switchInt(move _11) -> [0_isize: bb3, otherwise: bb4]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
-      }
-  
-      bb3: {
           _0 = const ();                   // scope 3 at $DIR/remove_storage_markers.rs:8:5: 10:6
 -         StorageDead(_10);                // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
 -         StorageDead(_8);                 // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
@@ -85,7 +85,7 @@
           return;                          // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2
       }
   
-      bb4: {
+      bb3: {
 -         StorageLive(_12);                // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
           _12 = ((_8 as Some).0: i32);     // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
 -         StorageLive(_13);                // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10
@@ -111,5 +111,12 @@
 -         StorageDead(_6);                 // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6
           goto -> bb1;                     // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6
       }
+  
+      bb4: {
+-         StorageDead(_18);                // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19
+-         StorageDead(_9);                 // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19
+          _11 = discriminant(_8);          // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
+          switchInt(move _11) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10
+      }
   }
   
diff --git a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
index c6ef403c3c1..787310d072a 100644
--- a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
@@ -127,7 +127,7 @@ fn array_casts() -> () {
                                          // + val: Unevaluated(array_casts, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                         // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[317d]::array_casts), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                         // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[13e7]::array_casts), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
         Retag(_35);                      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _18 = &(*_35);                   // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         Retag(_18);                      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
index 4bab5a97488..8abc6a3e4b5 100644
--- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
@@ -113,7 +113,7 @@ fn main() -> () {
         StorageLive(_14);                // scope 1 at $DIR/retag.rs:40:31: 43:6
         _14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:40:31: 43:6
                                          // closure
-                                         // + def_id: DefId(0:14 ~ retag[317d]::main::{closure#0})
+                                         // + def_id: DefId(0:14 ~ retag[13e7]::main::{closure#0})
                                          // + substs: [
                                          //     i8,
                                          //     for<'r> extern "rust-call" fn((&'r i32,)) -> &'r i32,
@@ -153,7 +153,7 @@ fn main() -> () {
                                          // + val: Unevaluated(main, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:47:21: 47:23
-                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[13e7]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
         Retag(_28);                      // scope 7 at $DIR/retag.rs:47:21: 47:23
         _23 = &(*_28);                   // scope 7 at $DIR/retag.rs:47:21: 47:23
         Retag(_23);                      // scope 7 at $DIR/retag.rs:47:21: 47:23
diff --git a/src/test/mir-opt/simplify-arm.rs b/src/test/mir-opt/simplify-arm.rs
index 50b5147e0cf..f7dcaa13449 100644
--- a/src/test/mir-opt/simplify-arm.rs
+++ b/src/test/mir-opt/simplify-arm.rs
@@ -20,8 +20,23 @@ fn id_result(r: Result<u8, i32>) -> Result<u8, i32> {
     }
 }
 
+fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> {
+    r
+}
+
+fn from_error<T, E>(e: E) -> Result<T, E> {
+    Err(e)
+}
+
+// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure,
+// so the relevant desugar is copied inline in order to keep the test testing the same thing.
+// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR
+// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not.
 fn id_try(r: Result<u8, i32>) -> Result<u8, i32> {
-    let x = r?;
+    let x = match into_result(r) {
+        Err(e) => return from_error(From::from(e)),
+        Ok(v) => v,
+    };
     Ok(x)
 }
 
diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
index ccb3b71817f..a3bad4f0c62 100644
--- a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff
@@ -2,101 +2,93 @@
 + // MIR for `id_try` after SimplifyArmIdentity
   
   fn id_try(_1: Result<u8, i32>) -> Result<u8, i32> {
-      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:23:11: 23:12
-      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:23:34: 23:49
-      let _2: u8;                          // in scope 0 at $DIR/simplify-arm.rs:24:9: 24:10
-      let mut _3: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
-      let mut _4: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
-      let mut _5: isize;                   // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-      let _6: i32;                         // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-      let mut _7: !;                       // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-      let mut _8: i32;                     // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-      let mut _9: i32;                     // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-      let _10: u8;                         // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
-      let mut _11: u8;                     // in scope 0 at $DIR/simplify-arm.rs:25:8: 25:9
+      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:35:11: 35:12
+      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:35:34: 35:49
+      let _2: u8;                          // in scope 0 at $DIR/simplify-arm.rs:36:9: 36:10
+      let mut _3: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:36:19: 36:33
+      let mut _4: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:36:31: 36:32
+      let mut _5: isize;                   // in scope 0 at $DIR/simplify-arm.rs:37:9: 37:15
+      let _6: i32;                         // in scope 0 at $DIR/simplify-arm.rs:37:13: 37:14
+      let mut _7: !;                       // in scope 0 at $DIR/simplify-arm.rs:37:19: 37:51
+      let mut _8: i32;                     // in scope 0 at $DIR/simplify-arm.rs:37:37: 37:50
+      let mut _9: i32;                     // in scope 0 at $DIR/simplify-arm.rs:37:48: 37:49
+      let _10: u8;                         // in scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
+      let mut _11: u8;                     // in scope 0 at $DIR/simplify-arm.rs:40:8: 40:9
       scope 1 {
--         debug x => _2;                   // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10
-+         debug x => ((_0 as Ok).0: u8);   // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10
+-         debug x => _2;                   // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10
++         debug x => ((_0 as Ok).0: u8);   // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10
       }
       scope 2 {
--         debug err => _6;                 // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15
-+         debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15
-          scope 3 {
-              scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:24:14: 24:15
--                 debug t => _9;           // in scope 7 at $DIR/simplify-arm.rs:24:14: 24:15
-+                 debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify-arm.rs:24:14: 24:15
-              }
-              scope 8 (inlined <Result<u8, i32> as Try>::from_error) { // at $DIR/simplify-arm.rs:24:13: 24:15
--                 debug v => _8;           // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
-+                 debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
-                  let mut _12: i32;        // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
-              }
+-         debug e => _6;                   // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14
++         debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14
+          scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:37:37: 37:50
+-             debug t => _9;               // in scope 5 at $DIR/simplify-arm.rs:37:37: 37:50
++             debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify-arm.rs:37:37: 37:50
           }
-      }
-      scope 4 {
--         debug val => _10;                // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15
-+         debug val => ((_0 as Ok).0: u8); // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15
-          scope 5 {
+          scope 6 (inlined from_error::<u8, i32>) { // at $DIR/simplify-arm.rs:37:26: 37:51
+-             debug e => _8;               // in scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
++             debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
           }
       }
-      scope 6 (inlined <Result<u8, i32> as Try>::into_result) { // at $DIR/simplify-arm.rs:24:13: 24:15
-          debug self => _4;                // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15
+      scope 3 {
+-         debug v => _10;                  // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13
++         debug v => ((_0 as Ok).0: u8);   // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13
+      }
+      scope 4 (inlined into_result::<u8, i32>) { // at $DIR/simplify-arm.rs:36:19: 36:33
+          debug r => _4;                   // in scope 4 at $DIR/simplify-arm.rs:36:19: 36:33
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/simplify-arm.rs:24:9: 24:10
-          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
-          StorageLive(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
-          _4 = _1;                         // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
-          _3 = move _4;                    // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15
-          StorageDead(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-          _5 = discriminant(_3);           // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-          switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageLive(_2);                 // scope 0 at $DIR/simplify-arm.rs:36:9: 36:10
+          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33
+          StorageLive(_4);                 // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32
+          _4 = _1;                         // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32
+          _3 = move _4;                    // scope 4 at $DIR/simplify-arm.rs:36:19: 36:33
+          StorageDead(_4);                 // scope 0 at $DIR/simplify-arm.rs:36:32: 36:33
+          _5 = discriminant(_3);           // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15
+          switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15
       }
   
       bb1: {
--         StorageLive(_10);                // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
--         _10 = ((_3 as Ok).0: u8);        // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
--         _2 = _10;                        // scope 5 at $DIR/simplify-arm.rs:24:13: 24:15
--         StorageDead(_10);                // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-+         _0 = move _3;                    // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10
-          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
--         StorageLive(_11);                // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9
--         _11 = _2;                        // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9
--         ((_0 as Ok).0: u8) = move _11;   // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10
--         discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10
--         StorageDead(_11);                // scope 1 at $DIR/simplify-arm.rs:25:9: 25:10
-          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
-          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+-         StorageLive(_10);                // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
+-         _10 = ((_3 as Ok).0: u8);        // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
+-         _2 = _10;                        // scope 3 at $DIR/simplify-arm.rs:38:18: 38:19
+-         StorageDead(_10);                // scope 0 at $DIR/simplify-arm.rs:38:18: 38:19
++         _0 = move _3;                    // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
+-         StorageLive(_11);                // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9
+-         _11 = _2;                        // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9
+-         ((_0 as Ok).0: u8) = move _11;   // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
+-         discriminant(_0) = 0;            // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
+-         StorageDead(_11);                // scope 1 at $DIR/simplify-arm.rs:40:9: 40:10
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
       }
   
       bb2: {
-          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+          unreachable;                     // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33
       }
   
       bb3: {
--         StorageLive(_6);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
--         _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
--         StorageLive(_8);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
--         StorageLive(_9);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
--         _9 = _6;                         // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
--         _8 = move _9;                    // scope 7 at $DIR/simplify-arm.rs:24:14: 24:15
--         StorageDead(_9);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
--         StorageLive(_12);                // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
--         _12 = move _8;                   // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
--         ((_0 as Err).0: i32) = move _12; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
--         discriminant(_0) = 1;            // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
--         StorageDead(_12);                // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
--         StorageDead(_8);                 // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15
--         StorageDead(_6);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-+         _0 = move _3;                    // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
-          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
-          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
-          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+-         StorageLive(_6);                 // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14
+-         _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14
+-         StorageLive(_8);                 // scope 2 at $DIR/simplify-arm.rs:37:37: 37:50
+-         StorageLive(_9);                 // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49
+-         _9 = _6;                         // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49
+-         _8 = move _9;                    // scope 5 at $DIR/simplify-arm.rs:37:37: 37:50
+-         StorageDead(_9);                 // scope 2 at $DIR/simplify-arm.rs:37:49: 37:50
+-         ((_0 as Err).0: i32) = move _8;  // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
+-         discriminant(_0) = 1;            // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
+-         StorageDead(_8);                 // scope 2 at $DIR/simplify-arm.rs:37:50: 37:51
+-         StorageDead(_6);                 // scope 0 at $DIR/simplify-arm.rs:37:50: 37:51
++         _0 = move _3;                    // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
+          goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
       }
   
       bb4: {
-          return;                          // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+          return;                          // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
       }
   }
   
diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
index ec8ac30228e..b6b7511b3f5 100644
--- a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
+++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff
@@ -2,75 +2,70 @@
 + // MIR for `id_try` after SimplifyBranchSame
   
   fn id_try(_1: Result<u8, i32>) -> Result<u8, i32> {
-      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:23:11: 23:12
-      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:23:34: 23:49
-      let _2: u8;                          // in scope 0 at $DIR/simplify-arm.rs:24:9: 24:10
-      let mut _3: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
-      let mut _4: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
-      let mut _5: isize;                   // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-      let _6: i32;                         // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-      let mut _7: !;                       // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-      let mut _8: i32;                     // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-      let mut _9: i32;                     // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-      let _10: u8;                         // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
-      let mut _11: u8;                     // in scope 0 at $DIR/simplify-arm.rs:25:8: 25:9
+      debug r => _1;                       // in scope 0 at $DIR/simplify-arm.rs:35:11: 35:12
+      let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:35:34: 35:49
+      let _2: u8;                          // in scope 0 at $DIR/simplify-arm.rs:36:9: 36:10
+      let mut _3: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:36:19: 36:33
+      let mut _4: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:36:31: 36:32
+      let mut _5: isize;                   // in scope 0 at $DIR/simplify-arm.rs:37:9: 37:15
+      let _6: i32;                         // in scope 0 at $DIR/simplify-arm.rs:37:13: 37:14
+      let mut _7: !;                       // in scope 0 at $DIR/simplify-arm.rs:37:19: 37:51
+      let mut _8: i32;                     // in scope 0 at $DIR/simplify-arm.rs:37:37: 37:50
+      let mut _9: i32;                     // in scope 0 at $DIR/simplify-arm.rs:37:48: 37:49
+      let _10: u8;                         // in scope 0 at $DIR/simplify-arm.rs:38:12: 38:13
+      let mut _11: u8;                     // in scope 0 at $DIR/simplify-arm.rs:40:8: 40:9
       scope 1 {
-          debug x => ((_0 as Ok).0: u8);   // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10
+          debug x => ((_0 as Ok).0: u8);   // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10
       }
       scope 2 {
-          debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15
-          scope 3 {
-              scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:24:14: 24:15
-                  debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify-arm.rs:24:14: 24:15
-              }
-              scope 8 (inlined <Result<u8, i32> as Try>::from_error) { // at $DIR/simplify-arm.rs:24:13: 24:15
-                  debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
-                  let mut _12: i32;        // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
-              }
+          debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14
+          scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:37:37: 37:50
+              debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify-arm.rs:37:37: 37:50
           }
-      }
-      scope 4 {
-          debug val => ((_0 as Ok).0: u8); // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15
-          scope 5 {
+          scope 6 (inlined from_error::<u8, i32>) { // at $DIR/simplify-arm.rs:37:26: 37:51
+              debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
           }
       }
-      scope 6 (inlined <Result<u8, i32> as Try>::into_result) { // at $DIR/simplify-arm.rs:24:13: 24:15
-          debug self => _4;                // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15
+      scope 3 {
+          debug v => ((_0 as Ok).0: u8);   // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13
+      }
+      scope 4 (inlined into_result::<u8, i32>) { // at $DIR/simplify-arm.rs:36:19: 36:33
+          debug r => _4;                   // in scope 4 at $DIR/simplify-arm.rs:36:19: 36:33
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/simplify-arm.rs:24:9: 24:10
-          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
-          StorageLive(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
-          _4 = _1;                         // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14
-          _3 = move _4;                    // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15
-          StorageDead(_4);                 // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-          _5 = discriminant(_3);           // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
--         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
-+         goto -> bb1;                     // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15
+          StorageLive(_2);                 // scope 0 at $DIR/simplify-arm.rs:36:9: 36:10
+          StorageLive(_3);                 // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33
+          StorageLive(_4);                 // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32
+          _4 = _1;                         // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32
+          _3 = move _4;                    // scope 4 at $DIR/simplify-arm.rs:36:19: 36:33
+          StorageDead(_4);                 // scope 0 at $DIR/simplify-arm.rs:36:32: 36:33
+          _5 = discriminant(_3);           // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15
+-         switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15
++         goto -> bb1;                     // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15
       }
   
       bb1: {
-          _0 = move _3;                    // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10
-          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
-          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
--         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
-+         goto -> bb2;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+          _0 = move _3;                    // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
+-         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
++         goto -> bb2;                     // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
       }
   
       bb2: {
--         unreachable;                     // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15
+-         unreachable;                     // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33
 -     }
 - 
 -     bb3: {
--         _0 = move _3;                    // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15
--         StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16
--         StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2
--         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+-         _0 = move _3;                    // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51
+-         StorageDead(_3);                 // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7
+-         StorageDead(_2);                 // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2
+-         goto -> bb4;                     // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
 -     }
 - 
 -     bb4: {
-          return;                          // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2
+          return;                          // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2
       }
   }
   
diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs
index eb307de2074..15e351e7d50 100644
--- a/src/test/mir-opt/simplify_try.rs
+++ b/src/test/mir-opt/simplify_try.rs
@@ -4,8 +4,24 @@
 // EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir
 // EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff
 
+
+fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> {
+    r
+}
+
+fn from_error<T, E>(e: E) -> Result<T, E> {
+    Err(e)
+}
+
+// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure,
+// so the relevant desugar is copied inline in order to keep the test testing the same thing.
+// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR
+// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not.
 fn try_identity(x: Result<u32, i32>) -> Result<u32, i32> {
-    let y = x?;
+    let y = match into_result(x) {
+        Err(e) => return from_error(From::from(e)),
+        Ok(v) => v,
+    };
     Ok(y)
 }
 
diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff
index b1bae447f9c..e09b8cb39bd 100644
--- a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff
+++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff
@@ -2,67 +2,62 @@
 + // MIR for `try_identity` after DestinationPropagation
   
   fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> {
-      debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18
-      let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57
-      let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10
-      let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15
-      let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14
-      let mut _5: isize;                   // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-      let _6: i32;                         // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-      let mut _7: !;                       // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-      let mut _8: i32;                     // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-      let mut _9: i32;                     // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-      let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15
-      let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9
+      debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18
+      let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57
+      let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:21:9: 21:10
+      let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33
+      let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+      let mut _5: isize;                   // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15
+      let _6: i32;                         // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14
+      let mut _7: !;                       // in scope 0 at $DIR/simplify_try.rs:22:19: 22:51
+      let mut _8: i32;                     // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50
+      let mut _9: i32;                     // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49
+      let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13
+      let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9
       scope 1 {
-          debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10
+          debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
       }
       scope 2 {
-          debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15
-          scope 3 {
-              scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:8:14: 8:15
-                  debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15
-              }
-              scope 8 (inlined <Result<u32, i32> as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15
-                  debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
-                  let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
-              }
+          debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
+          scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
+              debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50
           }
-      }
-      scope 4 {
-          debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15
-          scope 5 {
+          scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
+              debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51
           }
       }
-      scope 6 (inlined <Result<u32, i32> as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15
--         debug self => _4;                // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15
-+         debug self => _0;                // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15
+      scope 3 {
+          debug v => ((_0 as Ok).0: u32);  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
+      }
+      scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
+-         debug r => _4;                   // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33
++         debug r => _0;                   // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:8:9: 8:10
--         StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
--         StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
--         _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
--         _3 = move _4;                    // scope 6 at $DIR/simplify_try.rs:8:13: 8:15
--         StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
--         _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-+         nop;                             // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
-+         nop;                             // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
-+         _0 = _1;                         // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
-+         nop;                             // scope 6 at $DIR/simplify_try.rs:8:13: 8:15
-+         nop;                             // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-+         _5 = discriminant(_0);           // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-          goto -> bb1;                     // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+          StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:21:9: 21:10
+-         StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
+-         StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+-         _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+-         _3 = move _4;                    // scope 4 at $DIR/simplify_try.rs:21:19: 21:33
+-         StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:21:32: 21:33
+-         _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
++         nop;                             // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
++         nop;                             // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
++         _0 = _1;                         // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
++         nop;                             // scope 4 at $DIR/simplify_try.rs:21:19: 21:33
++         nop;                             // scope 0 at $DIR/simplify_try.rs:21:32: 21:33
++         _5 = discriminant(_0);           // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
+          goto -> bb1;                     // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
       }
   
       bb1: {
--         _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:9:5: 9:10
--         StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:8:15: 8:16
-+         nop;                             // scope 1 at $DIR/simplify_try.rs:9:5: 9:10
-+         nop;                             // scope 0 at $DIR/simplify_try.rs:8:15: 8:16
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:10:1: 10:2
-          return;                          // scope 0 at $DIR/simplify_try.rs:10:2: 10:2
+-         _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+-         StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
++         nop;                             // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
++         nop;                             // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
+          return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
       }
   }
   
diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff
index df274852f68..488ad33f80a 100644
--- a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff
+++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff
@@ -2,93 +2,85 @@
 + // MIR for `try_identity` after SimplifyArmIdentity
   
   fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> {
-      debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18
-      let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57
-      let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10
-      let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15
-      let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14
-      let mut _5: isize;                   // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-      let _6: i32;                         // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-      let mut _7: !;                       // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-      let mut _8: i32;                     // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-      let mut _9: i32;                     // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-      let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15
-      let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9
+      debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18
+      let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57
+      let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:21:9: 21:10
+      let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33
+      let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+      let mut _5: isize;                   // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15
+      let _6: i32;                         // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14
+      let mut _7: !;                       // in scope 0 at $DIR/simplify_try.rs:22:19: 22:51
+      let mut _8: i32;                     // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50
+      let mut _9: i32;                     // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49
+      let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13
+      let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9
       scope 1 {
--         debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10
-+         debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10
+-         debug y => _2;                   // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
++         debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
       }
       scope 2 {
--         debug err => _6;                 // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15
-+         debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15
-          scope 3 {
-              scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:8:14: 8:15
--                 debug t => _9;           // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15
-+                 debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15
-              }
-              scope 8 (inlined <Result<u32, i32> as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15
--                 debug v => _8;           // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
-+                 debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
-                  let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
-              }
+-         debug e => _6;                   // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
++         debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
+          scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
+-             debug t => _9;               // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50
++             debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50
           }
-      }
-      scope 4 {
--         debug val => _10;                // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15
-+         debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15
-          scope 5 {
+          scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
+-             debug e => _8;               // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51
++             debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51
           }
       }
-      scope 6 (inlined <Result<u32, i32> as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15
-          debug self => _4;                // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15
+      scope 3 {
+-         debug v => _10;                  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
++         debug v => ((_0 as Ok).0: u32);  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
+      }
+      scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
+          debug r => _4;                   // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33
       }
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:8:9: 8:10
-          StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
-          StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
-          _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
-          _3 = move _4;                    // scope 6 at $DIR/simplify_try.rs:8:13: 8:15
-          StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-          _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-          switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+          StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:21:9: 21:10
+          StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
+          StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+          _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+          _3 = move _4;                    // scope 4 at $DIR/simplify_try.rs:21:19: 21:33
+          StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:21:32: 21:33
+          _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
+          switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
       }
   
       bb1: {
--         StorageLive(_10);                // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
--         _10 = ((_3 as Ok).0: u32);       // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
--         _2 = _10;                        // scope 5 at $DIR/simplify_try.rs:8:13: 8:15
--         StorageDead(_10);                // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-+         _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:9:5: 9:10
-          StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:8:15: 8:16
--         StorageLive(_11);                // scope 1 at $DIR/simplify_try.rs:9:8: 9:9
--         _11 = _2;                        // scope 1 at $DIR/simplify_try.rs:9:8: 9:9
--         ((_0 as Ok).0: u32) = move _11;  // scope 1 at $DIR/simplify_try.rs:9:5: 9:10
--         discriminant(_0) = 0;            // scope 1 at $DIR/simplify_try.rs:9:5: 9:10
--         StorageDead(_11);                // scope 1 at $DIR/simplify_try.rs:9:9: 9:10
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:10:1: 10:2
-          return;                          // scope 0 at $DIR/simplify_try.rs:10:2: 10:2
+-         StorageLive(_10);                // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
+-         _10 = ((_3 as Ok).0: u32);       // scope 0 at $DIR/simplify_try.rs:23:12: 23:13
+-         _2 = _10;                        // scope 3 at $DIR/simplify_try.rs:23:18: 23:19
+-         StorageDead(_10);                // scope 0 at $DIR/simplify_try.rs:23:18: 23:19
++         _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+          StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
+-         StorageLive(_11);                // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
+-         _11 = _2;                        // scope 1 at $DIR/simplify_try.rs:25:8: 25:9
+-         ((_0 as Ok).0: u32) = move _11;  // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+-         discriminant(_0) = 0;            // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+-         StorageDead(_11);                // scope 1 at $DIR/simplify_try.rs:25:9: 25:10
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
+          return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
       }
   
       bb2: {
--         StorageLive(_6);                 // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
--         _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
--         StorageLive(_8);                 // scope 3 at $DIR/simplify_try.rs:8:14: 8:15
--         StorageLive(_9);                 // scope 3 at $DIR/simplify_try.rs:8:14: 8:15
--         _9 = _6;                         // scope 3 at $DIR/simplify_try.rs:8:14: 8:15
--         _8 = move _9;                    // scope 7 at $DIR/simplify_try.rs:8:14: 8:15
--         StorageDead(_9);                 // scope 3 at $DIR/simplify_try.rs:8:14: 8:15
--         StorageLive(_12);                // scope 8 at $DIR/simplify_try.rs:8:13: 8:15
--         _12 = move _8;                   // scope 8 at $DIR/simplify_try.rs:8:13: 8:15
--         ((_0 as Err).0: i32) = move _12; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15
--         discriminant(_0) = 1;            // scope 8 at $DIR/simplify_try.rs:8:13: 8:15
--         StorageDead(_12);                // scope 8 at $DIR/simplify_try.rs:8:13: 8:15
--         StorageDead(_8);                 // scope 3 at $DIR/simplify_try.rs:8:14: 8:15
--         StorageDead(_6);                 // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-+         _0 = move _3;                    // scope 8 at $DIR/simplify_try.rs:8:13: 8:15
-          StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:8:15: 8:16
-          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:10:1: 10:2
-          return;                          // scope 0 at $DIR/simplify_try.rs:10:2: 10:2
+-         StorageLive(_6);                 // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
+-         _6 = ((_3 as Err).0: i32);       // scope 0 at $DIR/simplify_try.rs:22:13: 22:14
+-         StorageLive(_8);                 // scope 2 at $DIR/simplify_try.rs:22:37: 22:50
+-         StorageLive(_9);                 // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
+-         _9 = _6;                         // scope 2 at $DIR/simplify_try.rs:22:48: 22:49
+-         _8 = move _9;                    // scope 5 at $DIR/simplify_try.rs:22:37: 22:50
+-         StorageDead(_9);                 // scope 2 at $DIR/simplify_try.rs:22:49: 22:50
+-         ((_0 as Err).0: i32) = move _8;  // scope 6 at $DIR/simplify_try.rs:22:26: 22:51
+-         discriminant(_0) = 1;            // scope 6 at $DIR/simplify_try.rs:22:26: 22:51
+-         StorageDead(_8);                 // scope 2 at $DIR/simplify_try.rs:22:50: 22:51
+-         StorageDead(_6);                 // scope 0 at $DIR/simplify_try.rs:22:50: 22:51
++         _0 = move _3;                    // scope 6 at $DIR/simplify_try.rs:22:26: 22:51
+          StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
+          StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
+          return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
       }
   }
   
diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir
index 37274691fb4..5d829f859e9 100644
--- a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir
+++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir
@@ -1,57 +1,52 @@
 // MIR for `try_identity` after SimplifyBranchSame
 
 fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> {
-    debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18
-    let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57
-    let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10
-    let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15
-    let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14
-    let mut _5: isize;                   // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-    let _6: i32;                         // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-    let mut _7: !;                       // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-    let mut _8: i32;                     // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-    let mut _9: i32;                     // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-    let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15
-    let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9
+    debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18
+    let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57
+    let _2: u32;                         // in scope 0 at $DIR/simplify_try.rs:21:9: 21:10
+    let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33
+    let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+    let mut _5: isize;                   // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15
+    let _6: i32;                         // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14
+    let mut _7: !;                       // in scope 0 at $DIR/simplify_try.rs:22:19: 22:51
+    let mut _8: i32;                     // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50
+    let mut _9: i32;                     // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49
+    let _10: u32;                        // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13
+    let mut _11: u32;                    // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9
     scope 1 {
-        debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10
+        debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
     }
     scope 2 {
-        debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15
-        scope 3 {
-            scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:8:14: 8:15
-                debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15
-            }
-            scope 8 (inlined <Result<u32, i32> as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15
-                debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
-                let mut _12: i32;        // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
-            }
+        debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
+        scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
+            debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50
         }
-    }
-    scope 4 {
-        debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15
-        scope 5 {
+        scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
+            debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51
         }
     }
-    scope 6 (inlined <Result<u32, i32> as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15
-        debug self => _4;                // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15
+    scope 3 {
+        debug v => ((_0 as Ok).0: u32);  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
+    }
+    scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
+        debug r => _4;                   // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33
     }
 
     bb0: {
-        StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:8:9: 8:10
-        StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
-        StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
-        _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
-        _3 = move _4;                    // scope 6 at $DIR/simplify_try.rs:8:13: 8:15
-        StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-        _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
-        goto -> bb1;                     // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
+        StorageLive(_2);                 // scope 0 at $DIR/simplify_try.rs:21:9: 21:10
+        StorageLive(_3);                 // scope 0 at $DIR/simplify_try.rs:21:19: 21:33
+        StorageLive(_4);                 // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+        _4 = _1;                         // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+        _3 = move _4;                    // scope 4 at $DIR/simplify_try.rs:21:19: 21:33
+        StorageDead(_4);                 // scope 0 at $DIR/simplify_try.rs:21:32: 21:33
+        _5 = discriminant(_3);           // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
+        goto -> bb1;                     // scope 0 at $DIR/simplify_try.rs:22:9: 22:15
     }
 
     bb1: {
-        _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:9:5: 9:10
-        StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:8:15: 8:16
-        StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:10:1: 10:2
-        return;                          // scope 0 at $DIR/simplify_try.rs:10:2: 10:2
+        _0 = move _3;                    // scope 1 at $DIR/simplify_try.rs:25:5: 25:10
+        StorageDead(_3);                 // scope 0 at $DIR/simplify_try.rs:24:6: 24:7
+        StorageDead(_2);                 // scope 0 at $DIR/simplify_try.rs:26:1: 26:2
+        return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
     }
 }
diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir
index f8adcced4b3..1b5232422b6 100644
--- a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir
+++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir
@@ -1,33 +1,29 @@
 // MIR for `try_identity` after SimplifyLocals
 
 fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> {
-    debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18
-    let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57
+    debug x => _1;                       // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18
+    let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57
     scope 1 {
-        debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10
+        debug y => ((_0 as Ok).0: u32);  // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10
     }
     scope 2 {
-        debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15
-        scope 3 {
-            scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:8:14: 8:15
-                debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15
-            }
-            scope 8 (inlined <Result<u32, i32> as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15
-                debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15
-            }
+        debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14
+        scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
+            debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50
         }
-    }
-    scope 4 {
-        debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15
-        scope 5 {
+        scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
+            debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51
         }
     }
-    scope 6 (inlined <Result<u32, i32> as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15
-        debug self => _0;                // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15
+    scope 3 {
+        debug v => ((_0 as Ok).0: u32);  // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13
+    }
+    scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
+        debug r => _0;                   // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33
     }
 
     bb0: {
-        _0 = _1;                         // scope 0 at $DIR/simplify_try.rs:8:13: 8:14
-        return;                          // scope 0 at $DIR/simplify_try.rs:10:2: 10:2
+        _0 = _1;                         // scope 0 at $DIR/simplify_try.rs:21:31: 21:32
+        return;                          // scope 0 at $DIR/simplify_try.rs:26:2: 26:2
     }
 }
diff --git a/src/test/pretty/anonymous-types.rs b/src/test/pretty/anonymous-types.rs
new file mode 100644
index 00000000000..5ff452e8e43
--- /dev/null
+++ b/src/test/pretty/anonymous-types.rs
@@ -0,0 +1,24 @@
+// Test for issue 85480
+// Pretty print anonymous struct and union types
+
+// pp-exact
+// pretty-compare-only
+
+struct Foo {
+    _: union {
+           _: struct {
+                  a: u8,
+                  b: u16,
+              },
+           c: u32,
+       },
+    d: u64,
+    e: f32,
+}
+
+type A =
+ struct {
+     field: u8,
+ };
+
+fn main() { }
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt
index 322f5681b3f..dc06a485a8f 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt
@@ -12,6 +12,7 @@
    12|      1|    if b {
    13|      1|        println!("non_async_func println in block");
    14|      1|    }
+                   ^0
    15|      1|}
    16|       |
    17|       |
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt
index 656a2659775..2d8a98a5d0c 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt
@@ -5,6 +5,7 @@
     5|      1|    if true {
     6|      1|        countdown = 10;
     7|      1|    }
+                   ^0
     8|       |
     9|       |    const B: u32 = 100;
    10|      1|    let x = if countdown > 7 {
@@ -24,6 +25,7 @@
    24|      1|    if true {
    25|      1|        countdown = 10;
    26|      1|    }
+                   ^0
    27|       |
    28|      1|    if countdown > 7 {
    29|      1|        countdown -= 4;
@@ -42,6 +44,7 @@
    41|      1|        if true {
    42|      1|            countdown = 10;
    43|      1|        }
+                       ^0
    44|       |
    45|      1|        if countdown > 7 {
    46|      1|            countdown -= 4;
@@ -54,13 +57,14 @@
    53|       |        } else {
    54|      0|            return;
    55|       |        }
-   56|       |    } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal
-   57|       |      // `true` was const-evaluated. The compiler knows the `if` block will be executed.
+   56|      0|    }
+   57|       |
    58|       |
    59|      1|    let mut countdown = 0;
    60|      1|    if true {
    61|      1|        countdown = 1;
    62|      1|    }
+                   ^0
    63|       |
    64|      1|    let z = if countdown > 7 {
                       ^0
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt
index 1b6bb9ff889..7ae0e978808 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt
@@ -9,7 +9,7 @@
     8|      1|//!     assert_eq!(1, 1);
     9|       |//! } else {
    10|       |//!     // this is not!
-   11|       |//!     assert_eq!(1, 2);
+   11|      0|//!     assert_eq!(1, 2);
    12|       |//! }
    13|      1|//! ```
    14|       |//!
@@ -84,7 +84,7 @@
    74|      1|    if true {
    75|      1|        assert_eq!(1, 1);
    76|       |    } else {
-   77|       |        assert_eq!(1, 2);
+   77|      0|        assert_eq!(1, 2);
    78|       |    }
    79|      1|}
    80|       |
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt
index fab5be41901..fe6a9e93cbf 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt
@@ -19,11 +19,11 @@
    19|      1|    if true {
    20|      1|        println!("Exiting with error...");
    21|      1|        return Err(1);
-   22|       |    }
-   23|       |
-   24|       |    let _ = Firework { strength: 1000 };
-   25|       |
-   26|       |    Ok(())
+   22|      0|    }
+   23|      0|
+   24|      0|    let _ = Firework { strength: 1000 };
+   25|      0|
+   26|      0|    Ok(())
    27|      1|}
    28|       |
    29|       |// Expected program output:
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt
new file mode 100644
index 00000000000..0fb3808ff2e
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt
@@ -0,0 +1,32 @@
+    1|       |#![feature(generators, generator_trait)]
+    2|       |
+    3|       |use std::ops::{Generator, GeneratorState};
+    4|       |use std::pin::Pin;
+    5|       |
+    6|       |// The following implementation of a function called from a `yield` statement
+    7|       |// (apparently requiring the Result and the `String` type or constructor)
+    8|       |// creates conditions where the `generator::StateTransform` MIR transform will
+    9|       |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic
+   10|       |// to handle this condition, and still report dead block coverage.
+   11|      1|fn get_u32(val: bool) -> Result<u32, String> {
+   12|      1|    if val { Ok(1) } else { Err(String::from("some error")) }
+                                          ^0
+   13|      1|}
+   14|       |
+   15|      1|fn main() {
+   16|      1|    let is_true = std::env::args().len() == 1;
+   17|      1|    let mut generator = || {
+   18|      1|        yield get_u32(is_true);
+   19|      1|        return "foo";
+   20|      1|    };
+   21|       |
+   22|      1|    match Pin::new(&mut generator).resume(()) {
+   23|      1|        GeneratorState::Yielded(Ok(1)) => {}
+   24|      0|        _ => panic!("unexpected return from resume"),
+   25|       |    }
+   26|      1|    match Pin::new(&mut generator).resume(()) {
+   27|      1|        GeneratorState::Complete("foo") => {}
+   28|      0|        _ => panic!("unexpected return from resume"),
+   29|       |    }
+   30|      1|}
+
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt
index 7b38ffb87cb..8569513e842 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt
@@ -11,16 +11,16 @@
    11|      3|        self.strength = new_strength;
    12|      3|    }
   ------------------
-  | <generics::Firework<f64>>::set_strength:
-  |   10|      2|    fn set_strength(&mut self, new_strength: T) {
-  |   11|      2|        self.strength = new_strength;
-  |   12|      2|    }
-  ------------------
   | <generics::Firework<i32>>::set_strength:
   |   10|      1|    fn set_strength(&mut self, new_strength: T) {
   |   11|      1|        self.strength = new_strength;
   |   12|      1|    }
   ------------------
+  | <generics::Firework<f64>>::set_strength:
+  |   10|      2|    fn set_strength(&mut self, new_strength: T) {
+  |   11|      2|        self.strength = new_strength;
+  |   12|      2|    }
+  ------------------
    13|       |}
    14|       |
    15|       |impl<T> Drop for Firework<T> where T: Copy + std::fmt::Display {
@@ -52,15 +52,15 @@
    30|      1|    if true {
    31|      1|        println!("Exiting with error...");
    32|      1|        return Err(1);
-   33|       |    } // The remaining lines below have no coverage because `if true` (with the constant literal
-   34|       |      // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`.
-   35|       |      // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown
-   36|       |      // in other tests, the lines below would have coverage (which would show they had `0`
-   37|       |      // executions, assuming the condition still evaluated to `true`).
-   38|       |
-   39|       |    let _ = Firework { strength: 1000 };
-   40|       |
-   41|       |    Ok(())
+   33|      0|    }
+   34|      0|
+   35|      0|
+   36|      0|
+   37|      0|
+   38|      0|
+   39|      0|    let _ = Firework { strength: 1000 };
+   40|      0|
+   41|      0|    Ok(())
    42|      1|}
    43|       |
    44|       |// Expected program output:
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt
index 81d5c7d9034..5d572db7cc6 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt
@@ -9,23 +9,23 @@
     9|      1|    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    10|      1|        if true {
    11|      1|            if false {
-   12|       |                while true {
-   13|       |                }
+   12|      0|                while true {
+   13|      0|                }
    14|      1|            }
-   15|      1|            write!(f, "error")?;
-                                            ^0
-   16|       |        } else {
-   17|       |        }
+   15|      1|            write!(f, "cool")?;
+                                           ^0
+   16|      0|        } else {
+   17|      0|        }
    18|       |
    19|     10|        for i in 0..10 {
    20|     10|            if true {
    21|     10|                if false {
-   22|       |                    while true {}
+   22|      0|                    while true {}
    23|     10|                }
-   24|     10|                write!(f, "error")?;
-                                                ^0
-   25|       |            } else {
-   26|       |            }
+   24|     10|                write!(f, "cool")?;
+                                               ^0
+   25|      0|            } else {
+   26|      0|            }
    27|       |        }
    28|      1|        Ok(())
    29|      1|    }
@@ -36,21 +36,21 @@
    34|       |impl std::fmt::Display for DisplayTest {
    35|      1|    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
    36|      1|        if false {
-   37|       |        } else {
+   37|      0|        } else {
    38|      1|            if false {
-   39|       |                while true {}
+   39|      0|                while true {}
    40|      1|            }
-   41|      1|            write!(f, "error")?;
-                                            ^0
+   41|      1|            write!(f, "cool")?;
+                                           ^0
    42|       |        }
    43|     10|        for i in 0..10 {
    44|     10|            if false {
-   45|       |            } else {
+   45|      0|            } else {
    46|     10|                if false {
-   47|       |                    while true {}
+   47|      0|                    while true {}
    48|     10|                }
-   49|     10|                write!(f, "error")?;
-                                                ^0
+   49|     10|                write!(f, "cool")?;
+                                               ^0
    50|       |            }
    51|       |        }
    52|      1|        Ok(())
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt
index 5adeef7d085..2d4c57f451a 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt
@@ -1,6 +1,6 @@
     1|      1|fn main() {
     2|      1|    if false {
-    3|       |        loop {}
+    3|      0|        loop {}
     4|      1|    }
     5|      1|}
 
diff --git a/src/test/run-make-fulldeps/coverage/conditions.rs b/src/test/run-make-fulldeps/coverage/conditions.rs
index 8a2a0b53e58..057599d1b47 100644
--- a/src/test/run-make-fulldeps/coverage/conditions.rs
+++ b/src/test/run-make-fulldeps/coverage/conditions.rs
@@ -53,8 +53,8 @@ fn main() {
         } else {
             return;
         }
-    } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal
-      // `true` was const-evaluated. The compiler knows the `if` block will be executed.
+    }
+
 
     let mut countdown = 0;
     if true {
diff --git a/src/test/run-make-fulldeps/coverage/generator.rs b/src/test/run-make-fulldeps/coverage/generator.rs
new file mode 100644
index 00000000000..4319991021e
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/generator.rs
@@ -0,0 +1,30 @@
+#![feature(generators, generator_trait)]
+
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+// The following implementation of a function called from a `yield` statement
+// (apparently requiring the Result and the `String` type or constructor)
+// creates conditions where the `generator::StateTransform` MIR transform will
+// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic
+// to handle this condition, and still report dead block coverage.
+fn get_u32(val: bool) -> Result<u32, String> {
+    if val { Ok(1) } else { Err(String::from("some error")) }
+}
+
+fn main() {
+    let is_true = std::env::args().len() == 1;
+    let mut generator = || {
+        yield get_u32(is_true);
+        return "foo";
+    };
+
+    match Pin::new(&mut generator).resume(()) {
+        GeneratorState::Yielded(Ok(1)) => {}
+        _ => panic!("unexpected return from resume"),
+    }
+    match Pin::new(&mut generator).resume(()) {
+        GeneratorState::Complete("foo") => {}
+        _ => panic!("unexpected return from resume"),
+    }
+}
diff --git a/src/test/run-make-fulldeps/coverage/generics.rs b/src/test/run-make-fulldeps/coverage/generics.rs
index cbeda35d3b8..18b38868496 100644
--- a/src/test/run-make-fulldeps/coverage/generics.rs
+++ b/src/test/run-make-fulldeps/coverage/generics.rs
@@ -30,11 +30,11 @@ fn main() -> Result<(),u8> {
     if true {
         println!("Exiting with error...");
         return Err(1);
-    } // The remaining lines below have no coverage because `if true` (with the constant literal
-      // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`.
-      // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown
-      // in other tests, the lines below would have coverage (which would show they had `0`
-      // executions, assuming the condition still evaluated to `true`).
+    }
+
+
+
+
 
     let _ = Firework { strength: 1000 };
 
diff --git a/src/test/run-make-fulldeps/coverage/loops_branches.rs b/src/test/run-make-fulldeps/coverage/loops_branches.rs
index 4d9bbad3367..7116ce47f4b 100644
--- a/src/test/run-make-fulldeps/coverage/loops_branches.rs
+++ b/src/test/run-make-fulldeps/coverage/loops_branches.rs
@@ -12,7 +12,7 @@ impl std::fmt::Debug for DebugTest {
                 while true {
                 }
             }
-            write!(f, "error")?;
+            write!(f, "cool")?;
         } else {
         }
 
@@ -21,7 +21,7 @@ impl std::fmt::Debug for DebugTest {
                 if false {
                     while true {}
                 }
-                write!(f, "error")?;
+                write!(f, "cool")?;
             } else {
             }
         }
@@ -38,7 +38,7 @@ impl std::fmt::Display for DisplayTest {
             if false {
                 while true {}
             }
-            write!(f, "error")?;
+            write!(f, "cool")?;
         }
         for i in 0..10 {
             if false {
@@ -46,7 +46,7 @@ impl std::fmt::Display for DisplayTest {
                 if false {
                     while true {}
                 }
-                write!(f, "error")?;
+                write!(f, "cool")?;
             }
         }
         Ok(())
diff --git a/src/test/run-make-fulldeps/issue-47551/Makefile b/src/test/run-make-fulldeps/issue-47551/Makefile
new file mode 100644
index 00000000000..f4495e6b671
--- /dev/null
+++ b/src/test/run-make-fulldeps/issue-47551/Makefile
@@ -0,0 +1,9 @@
+# only-linux
+# ignore-32bit
+
+-include ../tools.mk
+
+all:
+	$(RUSTC) eh_frame-terminator.rs
+	$(call RUN,eh_frame-terminator) | $(CGREP) '1122334455667788'
+	objdump --dwarf=frames $(TMPDIR)/eh_frame-terminator | $(CGREP) 'ZERO terminator'
diff --git a/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs b/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs
new file mode 100644
index 00000000000..2f740dc4fac
--- /dev/null
+++ b/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs
@@ -0,0 +1,23 @@
+// run-pass
+
+#![feature(backtrace)]
+#[derive(Clone, Copy)]
+struct Foo {
+    array: [u64; 10240],
+}
+
+impl Foo {
+    const fn new() -> Self {
+        Self {
+            array: [0x1122_3344_5566_7788; 10240]
+        }
+    }
+}
+
+static BAR: [Foo; 10240] = [Foo::new(); 10240];
+
+fn main() {
+    let bt = std::backtrace::Backtrace::force_capture();
+    println!("Hello, world! {:?}", bt);
+    println!("{:x}", BAR[0].array[0]);
+}
diff --git a/src/test/run-make-fulldeps/link-dedup/Makefile b/src/test/run-make-fulldeps/link-dedup/Makefile
new file mode 100644
index 00000000000..4e7ce0f02d4
--- /dev/null
+++ b/src/test/run-make-fulldeps/link-dedup/Makefile
@@ -0,0 +1,12 @@
+# ignore-msvc
+
+-include ../tools.mk
+
+all:
+	$(RUSTC) depa.rs
+	$(RUSTC) depb.rs
+	$(RUSTC) depc.rs
+	$(RUSTC) empty.rs --cfg bar 2>&1 | $(CGREP) '"-ltesta" "-ltestb" "-ltesta"'
+	$(RUSTC) empty.rs 2>&1 | $(CGREP) '"-ltesta"'
+	$(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltestb"'
+	$(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltesta" "-ltesta"'
diff --git a/src/test/run-make-fulldeps/link-dedup/depa.rs b/src/test/run-make-fulldeps/link-dedup/depa.rs
new file mode 100644
index 00000000000..e48ffd6413c
--- /dev/null
+++ b/src/test/run-make-fulldeps/link-dedup/depa.rs
@@ -0,0 +1,7 @@
+#![crate_type = "rlib"]
+
+#[link(name = "testa")]
+extern "C" {}
+
+#[link(name = "testa")]
+extern "C" {}
diff --git a/src/test/run-make-fulldeps/link-dedup/depb.rs b/src/test/run-make-fulldeps/link-dedup/depb.rs
new file mode 100644
index 00000000000..b1be21fe005
--- /dev/null
+++ b/src/test/run-make-fulldeps/link-dedup/depb.rs
@@ -0,0 +1,8 @@
+#![feature(link_cfg)]
+#![crate_type = "rlib"]
+
+#[link(name = "testb", cfg(foo))]
+extern "C" {}
+
+#[link(name = "testb", cfg(bar))]
+extern "C" {}
diff --git a/src/test/run-make-fulldeps/link-dedup/depc.rs b/src/test/run-make-fulldeps/link-dedup/depc.rs
new file mode 100644
index 00000000000..8dcb3dee5a2
--- /dev/null
+++ b/src/test/run-make-fulldeps/link-dedup/depc.rs
@@ -0,0 +1,4 @@
+#![crate_type = "rlib"]
+
+#[link(name = "testa")]
+extern "C" {}
diff --git a/src/test/run-make-fulldeps/link-dedup/empty.rs b/src/test/run-make-fulldeps/link-dedup/empty.rs
new file mode 100644
index 00000000000..e00ae18f4af
--- /dev/null
+++ b/src/test/run-make-fulldeps/link-dedup/empty.rs
@@ -0,0 +1,5 @@
+extern crate depa;
+extern crate depb;
+extern crate depc;
+
+fn main() {}
diff --git a/src/test/run-make-fulldeps/print-unversioned-files/Makefile b/src/test/run-make-fulldeps/print-unversioned-files/Makefile
deleted file mode 100644
index e368f61cddf..00000000000
--- a/src/test/run-make-fulldeps/print-unversioned-files/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
--include ../tools.mk
-
-all:
-	$(RUSTDOC) -Z unstable-options --print unversioned-files | sort | diff - unversioned-files.txt
diff --git a/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt b/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt
deleted file mode 100644
index 4b20cd5d745..00000000000
--- a/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-COPYRIGHT.txt
-FiraSans-LICENSE.txt
-FiraSans-Medium.woff
-FiraSans-Medium.woff2
-FiraSans-Regular.woff
-FiraSans-Regular.woff2
-LICENSE-APACHE.txt
-LICENSE-MIT.txt
-SourceCodePro-It.ttf.woff
-SourceCodePro-LICENSE.txt
-SourceCodePro-Regular.ttf.woff
-SourceCodePro-Semibold.ttf.woff
-SourceSerif4-Bold.ttf.woff
-SourceSerif4-It.ttf.woff
-SourceSerif4-LICENSE.md
-SourceSerif4-Regular.ttf.woff
diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile
new file mode 100644
index 00000000000..6d0bc4186f2
--- /dev/null
+++ b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile
@@ -0,0 +1,9 @@
+include ../tools.mk
+
+# Test that rustdoc will properly canonicalize the target spec json path just like rustc
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc-target-spec-json-path"
+
+all:
+	$(RUSTC) --crate-type lib dummy_core.rs --target target.json
+	$(RUSTDOC) -o $(OUTPUT_DIR) -L $(TMPDIR) my_crate.rs --target target.json
diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs
new file mode 100644
index 00000000000..da27b7f3463
--- /dev/null
+++ b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs
@@ -0,0 +1,2 @@
+#![feature(no_core)]
+#![no_core]
diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs
new file mode 100644
index 00000000000..12aa0822084
--- /dev/null
+++ b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs
@@ -0,0 +1,3 @@
+#![feature(no_core)]
+#![no_core]
+extern crate dummy_core;
diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json
new file mode 100644
index 00000000000..58e924a9895
--- /dev/null
+++ b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json
@@ -0,0 +1,39 @@
+{
+  "arch": "x86_64",
+  "cpu": "x86-64",
+  "crt-static-respected": true,
+  "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
+  "dynamic-linking": true,
+  "env": "gnu",
+  "executables": true,
+  "has-elf-tls": true,
+  "has-rpath": true,
+  "is-builtin": true,
+  "linker-is-gnu": true,
+  "llvm-target": "x86_64-unknown-linux-gnu",
+  "max-atomic-width": 64,
+  "os": "linux",
+  "position-independent-executables": true,
+  "pre-link-args": {
+    "gcc": [
+      "-m64"
+    ]
+  },
+  "relro-level": "full",
+  "stack-probes": {
+    "kind": "inline-or-call",
+    "min-llvm-version-for-inline": [
+      11,
+      0,
+      1
+    ]
+  },
+  "supported-sanitizers": [
+    "address",
+    "leak",
+    "memory",
+    "thread"
+  ],
+  "target-family": "unix",
+  "target-pointer-width": "64"
+}
diff --git a/src/test/run-make/emit-named-files/Makefile b/src/test/run-make/emit-named-files/Makefile
new file mode 100644
index 00000000000..03eb83b97e3
--- /dev/null
+++ b/src/test/run-make/emit-named-files/Makefile
@@ -0,0 +1,33 @@
+-include ../../run-make-fulldeps/tools.mk
+
+OUT=$(TMPDIR)/emit
+
+all: asm llvm-bc llvm-ir obj metadata link dep-info mir
+
+asm: $(OUT)
+	$(RUSTC) --emit asm=$(OUT)/libfoo.s foo.rs
+	test -f $(OUT)/libfoo.s
+llvm-bc: $(OUT)
+	$(RUSTC) --emit llvm-bc=$(OUT)/libfoo.bc foo.rs
+	test -f $(OUT)/libfoo.bc
+llvm-ir: $(OUT)
+	$(RUSTC) --emit llvm-ir=$(OUT)/libfoo.ll foo.rs
+	test -f $(OUT)/libfoo.ll
+obj: $(OUT)
+	$(RUSTC) --emit obj=$(OUT)/libfoo.o foo.rs
+	test -f $(OUT)/libfoo.o
+metadata: $(OUT)
+	$(RUSTC) --emit metadata=$(OUT)/libfoo.rmeta foo.rs
+	test -f $(OUT)/libfoo.rmeta
+link: $(OUT)
+	$(RUSTC) --emit link=$(OUT)/libfoo.rlib foo.rs
+	test -f $(OUT)/libfoo.rlib
+dep-info: $(OUT)
+	$(RUSTC) --emit dep-info=$(OUT)/libfoo.d foo.rs
+	test -f $(OUT)/libfoo.d
+mir: $(OUT)
+	$(RUSTC) --emit mir=$(OUT)/libfoo.mir foo.rs
+	test -f $(OUT)/libfoo.mir
+
+$(OUT):
+	mkdir -p $(OUT)
diff --git a/src/test/run-make/emit-named-files/foo.rs b/src/test/run-make/emit-named-files/foo.rs
new file mode 100644
index 00000000000..c1bfaa6cab5
--- /dev/null
+++ b/src/test/run-make/emit-named-files/foo.rs
@@ -0,0 +1 @@
+#![crate_type = "rlib"]
diff --git a/src/test/run-make/incremental-session-fail/Makefile b/src/test/run-make/incremental-session-fail/Makefile
new file mode 100644
index 00000000000..0461bb926e7
--- /dev/null
+++ b/src/test/run-make/incremental-session-fail/Makefile
@@ -0,0 +1,14 @@
+include ../../run-make-fulldeps/tools.mk
+
+SESSION_DIR := $(TMPDIR)/session
+OUTPUT_FILE := $(TMPDIR)/build-output
+
+all:
+	echo $(TMPDIR)
+	# Make it so that rustc will fail to create a session directory.
+	touch $(SESSION_DIR)
+	# Check exit code is 1 for an error, and not 101 for ICE.
+	$(RUSTC) foo.rs --crate-type=rlib -C incremental=$(SESSION_DIR) > $(OUTPUT_FILE) 2>&1; [ $$? -eq 1 ]
+	$(CGREP) "Could not create incremental compilation crate directory" < $(OUTPUT_FILE)
+	# -v tests are fragile, hopefully this text won't change
+	$(CGREP) -v "internal compiler error" < $(OUTPUT_FILE)
diff --git a/src/test/run-make/incremental-session-fail/foo.rs b/src/test/run-make/incremental-session-fail/foo.rs
new file mode 100644
index 00000000000..d11c69f812a
--- /dev/null
+++ b/src/test/run-make/incremental-session-fail/foo.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/run-make/unstable-flag-required/Makefile b/src/test/run-make/unstable-flag-required/Makefile
index b8769d5f690..aa20d6aa4bf 100644
--- a/src/test/run-make/unstable-flag-required/Makefile
+++ b/src/test/run-make/unstable-flag-required/Makefile
@@ -2,3 +2,4 @@
 
 all:
 	$(RUSTDOC) --output-format=json x.html 2>&1 | diff - output-format-json.stderr
+	$(RUSTC) --force-warns dead_code x.rs 2>&1 | diff - force-warns.stderr
diff --git a/src/test/run-make/unstable-flag-required/force-warns.stderr b/src/test/run-make/unstable-flag-required/force-warns.stderr
new file mode 100644
index 00000000000..e0936196a11
--- /dev/null
+++ b/src/test/run-make/unstable-flag-required/force-warns.stderr
@@ -0,0 +1,2 @@
+error: the `-Z unstable-options` flag must also be passed to enable the flag `--force-warns=lints`
+
diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml
new file mode 100644
index 00000000000..ec034f52c97
--- /dev/null
+++ b/src/test/rustdoc-gui/escape-key.goml
@@ -0,0 +1,34 @@
+goto: file://|DOC_PATH|/test_docs/index.html
+// First, we check that the search results are hidden when the Escape key is pressed.
+write: (".search-input", "test")
+wait-for: "#search > h1" // The search element is empty before the first search 
+assert: ("#search", "class", "content")
+assert: ("#main", "class", "content hidden")
+press-key: "Escape"
+assert: ("#search", "class", "content hidden")
+assert: ("#main", "class", "content")
+
+// Check that focusing the search input brings back the search results
+focus: ".search-input"
+assert: ("#search", "class", "content")
+assert: ("#main", "class", "content hidden")
+
+// Now let's check that when the help popup is displayed and we press Escape, it doesn't
+// hide the search results too.
+click: "#help-button"
+assert: ("#help", "class", "")
+press-key: "Escape"
+assert: ("#help", "class", "hidden")
+assert: ("#search", "class", "content")
+assert: ("#main", "class", "content hidden")
+
+// Check that Escape hides the search results when a search result is focused.
+focus: ".search-input"
+assert: ".search-input:focus"
+press-key: "ArrowDown"
+assert-false: ".search-input:focus"
+assert: "#results a:focus"
+press-key: "Escape"
+assert: ("#help", "class", "hidden")
+assert: ("#search", "class", "content hidden")
+assert: ("#main", "class", "content")
diff --git a/src/test/rustdoc-gui/search-result-colors.goml b/src/test/rustdoc-gui/search-result-colors.goml
new file mode 100644
index 00000000000..25a01512159
--- /dev/null
+++ b/src/test/rustdoc-gui/search-result-colors.goml
@@ -0,0 +1,14 @@
+goto: file://|DOC_PATH|/test_docs/index.html
+// We set the theme so we're sure that the corect values will be used, whatever the computer
+// this test is running on.
+local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
+// If the text isn't displayed, the browser doesn't compute color style correctly...
+show-text: true
+// We reload the page so the local storage settings are being used.
+reload:
+write: (".search-input", "thisisanalias")
+// Waiting for the search results to appear...
+wait-for: "#titles"
+// Checking that the colors for the alias element are the ones expected.
+assert: (".result-name > .alias", {"color": "rgb(255, 255, 255)"})
+assert: (".result-name > .alias > .grey", {"color": "rgb(204, 204, 204)"})
diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml
new file mode 100644
index 00000000000..96d15c624f1
--- /dev/null
+++ b/src/test/rustdoc-gui/search-result-display.goml
@@ -0,0 +1,12 @@
+goto: file://|DOC_PATH|/test_docs/index.html
+size: (900, 1000)
+write: (".search-input", "test")
+// Waiting for the search results to appear...
+wait-for: "#titles"
+// The width is returned by "getComputedStyle" which returns the exact number instead of the
+// CSS rule which is "50%"...
+assert: (".search-results div.desc", {"width": "320px"})
+size: (600, 100)
+// As counter-intuitive as it may seem, in this width, the width is "100%", which is why
+// when computed it's larger.
+assert: (".search-results div.desc", {"width": "570px"})
diff --git a/src/test/rustdoc-gui/search-result-keyword.goml b/src/test/rustdoc-gui/search-result-keyword.goml
new file mode 100644
index 00000000000..e7612d66371
--- /dev/null
+++ b/src/test/rustdoc-gui/search-result-keyword.goml
@@ -0,0 +1,10 @@
+goto: file://|DOC_PATH|/test_docs/index.html
+write: (".search-input", "CookieMonster")
+// Waiting for the search results to appear...
+wait-for: "#titles"
+// Note: The two next assert commands could be merged as one but readability would be
+// less good.
+//
+// Checking that the CSS is displaying " (keyword)" in italic.
+assert: (".result-name span.keyword > i", "(keyword)")
+assert: (".result-name span.keyword", "CookieMonster (keyword)")
diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml
new file mode 100644
index 00000000000..388ca120d77
--- /dev/null
+++ b/src/test/rustdoc-gui/sidebar.goml
@@ -0,0 +1,56 @@
+goto: file://|DOC_PATH|/test_docs/index.html
+assert: (".sidebar > .location", "Crate test_docs")
+// In modules, we only have one "location" element.
+assert: (".sidebar .location", 1)
+assert: (".sidebar-elems > #all-types", "See all test_docs's items")
+// We check that we have the crates list and that the "current" on is "test_docs".
+assert: (".sidebar-elems > .crate > ul > li > a.current", "test_docs")
+// And we're also supposed to have the list of items in the current module.
+assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
+assert: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
+assert: (".sidebar-elems > .items > ul > li:nth-child(3)", "Enums")
+assert: (".sidebar-elems > .items > ul > li:nth-child(4)", "Traits")
+assert: (".sidebar-elems > .items > ul > li:nth-child(5)", "Functions")
+assert: (".sidebar-elems > .items > ul > li:nth-child(6)", "Keywords")
+assert: ("#structs + table td > a", "Foo")
+click: "#structs + table td > a"
+
+// PAGE: struct.Foo.html
+assert: (".sidebar .location", 2)
+// We check that there is no crate listed outside of the top level.
+assert-false: ".sidebar-elems > .crate"
+// We now go back to the crate page to click on the "lib2" crate link.
+goto: file://|DOC_PATH|/test_docs/index.html
+click: ".sidebar-elems > .crate > ul > li:first-child > a"
+
+// PAGE: lib2/index.html
+goto: file://|DOC_PATH|/lib2/index.html
+assert: (".sidebar > .location", "Crate lib2")
+// We check that we have the crates list and that the "current" on is now "lib2".
+assert: (".sidebar-elems > .crate > ul > li > a.current", "lib2")
+// We now go to the "foobar" function page.
+assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
+assert: (".sidebar-elems > .items > ul > li:nth-child(2)", "Functions")
+assert:	("#functions + table td > a", "foobar")
+click: "#functions + table td > a"
+
+// PAGE: fn.foobar.html
+// In items containing no items (like functions or constants) and in modules, we have one
+// "location" elements.
+assert: (".sidebar .location", 1)
+// There is a "<br>" tag between "in" and "lib2", but it doesn't count as a space.
+assert: (".sidebar .sidebar-elems .location", "Other items inlib2")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+
+goto: ./module/index.html
+assert: (".sidebar > .location", "Module module")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+
+goto: ./sub_module/sub_sub_module/index.html
+assert: (".sidebar > .location", "Module sub_sub_module")
+// We check that we don't have the crate list.
+assert-false: ".sidebar-elems > .crate"
+assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Functions")
+assert: ("#functions + table td > a", "foo")
diff --git a/src/test/rustdoc-gui/src/lib.rs b/src/test/rustdoc-gui/src/lib.rs
index eeba3e3f907..272b1d05452 100644
--- a/src/test/rustdoc-gui/src/lib.rs
+++ b/src/test/rustdoc-gui/src/lib.rs
@@ -2,6 +2,7 @@
 //! documentation generated so we can test each different features.
 
 #![crate_name = "test_docs"]
+#![feature(doc_keyword)]
 
 use std::fmt;
 
@@ -35,6 +36,7 @@ impl Foo {
 }
 
 /// Just a normal enum.
+#[doc(alias = "ThisIsAnAlias")]
 pub enum WhoLetTheDogOut {
     /// Woof!
     Woof,
@@ -91,3 +93,6 @@ pub fn check_list_code_block() {}
 pub enum AnEnum {
     WithVariants { and: usize, sub: usize, variants: usize },
 }
+
+#[doc(keyword = "CookieMonster")]
+pub mod keyword {}
diff --git a/src/test/rustdoc-gui/src/lib2.rs b/src/test/rustdoc-gui/src/lib2.rs
new file mode 100644
index 00000000000..73384cbf906
--- /dev/null
+++ b/src/test/rustdoc-gui/src/lib2.rs
@@ -0,0 +1,11 @@
+pub mod module {
+    pub mod sub_module {
+        pub mod sub_sub_module {
+            pub fn foo() {}
+        }
+        pub fn bar() {}
+    }
+    pub fn whatever() {}
+}
+
+pub fn foobar() {}
diff --git a/src/test/rustdoc-ui/ignore-block-help.rs b/src/test/rustdoc-ui/ignore-block-help.rs
index c22dddd11df..86f6a2868fb 100644
--- a/src/test/rustdoc-ui/ignore-block-help.rs
+++ b/src/test/rustdoc-ui/ignore-block-help.rs
@@ -3,5 +3,8 @@
 /// ```ignore (to-prevent-tidy-error)
 /// let heart = '❤️';
 /// ```
-//~^^^ WARN
+//~^^^ WARNING could not parse code block
+//~| NOTE on by default
+//~| NOTE character literal may only contain one codepoint
+//~| HELP `ignore` code blocks require valid Rust code
 pub struct X;
diff --git a/src/test/rustdoc-ui/ignore-block-help.stderr b/src/test/rustdoc-ui/ignore-block-help.stderr
index d45cd92d2d1..9c02ff11d19 100644
--- a/src/test/rustdoc-ui/ignore-block-help.stderr
+++ b/src/test/rustdoc-ui/ignore-block-help.stderr
@@ -7,11 +7,13 @@ LL | | /// let heart = '❤️';
 LL | | /// ```
    | |_______^
    |
-   = note: error from rustc: character literal may only contain one codepoint
-help: `ignore` code blocks require valid Rust code for syntax highlighting. Mark blocks that do not contain Rust code as text
+   = note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default
+help: `ignore` code blocks require valid Rust code for syntax highlighting; mark blocks that do not contain Rust code as text: ```text
+  --> $DIR/ignore-block-help.rs:3:5
    |
-LL | /// ```text,ignore (to-prevent-tidy-error)
-   |     ^^^^^^^^
+LL | /// ```ignore (to-prevent-tidy-error)
+   |     ^^^
+   = note: error from rustc: character literal may only contain one codepoint
 
 warning: 1 warning emitted
 
diff --git a/src/test/rustdoc-ui/invalid-syntax.rs b/src/test/rustdoc-ui/invalid-syntax.rs
index c395a8ef3d4..b503d1093fd 100644
--- a/src/test/rustdoc-ui/invalid-syntax.rs
+++ b/src/test/rustdoc-ui/invalid-syntax.rs
@@ -71,7 +71,7 @@ pub fn blargh() {}
 /// \_
 #[doc = "```"]
 pub fn crazy_attrs() {}
-//~^^^^ WARNING doc comment contains an invalid Rust code block
+//~^^^^ WARNING could not parse code block
 
 /// ```rust
 /// ```
diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr
index 75acdc5ab5f..82eac9bd68b 100644
--- a/src/test/rustdoc-ui/invalid-syntax.stderr
+++ b/src/test/rustdoc-ui/invalid-syntax.stderr
@@ -7,6 +7,7 @@ LL | | /// \__________pkt->size___________/          \_result->size_/ \__pkt->si
 LL | | /// ```
    | |_______^
    |
+   = note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default
    = note: error from rustc: unknown start of token: \
    = note: error from rustc: unknown start of token: \
    = note: error from rustc: unknown start of token: \
@@ -90,7 +91,7 @@ LL | | /// ```
    |
    = note: error from rustc: unknown start of token: \
 
-warning: doc comment contains an invalid Rust code block
+warning: could not parse code block as Rust code
   --> $DIR/invalid-syntax.rs:70:1
    |
 LL | / #[doc = "```"]
diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs
index 7bfa922185b..a3dd166e651 100644
--- a/src/test/rustdoc/assoc-consts.rs
+++ b/src/test/rustdoc/assoc-consts.rs
@@ -88,14 +88,12 @@ impl Qux for Bar {
     /// Docs for QUX1 in impl.
     const QUX1: i8 = 5;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16'
-    // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
-    // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
+    // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait."
     const QUX_DEFAULT0: u16 = 6;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16'
     // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl."
     /// Docs for QUX_DEFAULT1 in impl.
     const QUX_DEFAULT1: i16 = 7;
     // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32'
-    // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
-    // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
+    // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait."
 }
diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs
index 4b66b5271c5..9f95d9a994b 100644
--- a/src/test/rustdoc/async-fn.rs
+++ b/src/test/rustdoc/async-fn.rs
@@ -77,12 +77,12 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T }
 
 impl Foo {
     // @has async_fn/struct.Foo.html
-    // @has - '//h4[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+    // @has - '//div[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
     pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
     // taken from `tokio` as an example of a method that was particularly bad before
-    // @has - '//h4[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
+    // @has - '//div[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
     pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
-    // @has - '//h4[@class="method"]' "pub async fn mut_self(&mut self)"
+    // @has - '//div[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
     pub async fn mut_self(&mut self) {}
 }
 
diff --git a/src/test/rustdoc/auto_aliases.rs b/src/test/rustdoc/auto_aliases.rs
index 56e0770ab5c..01ea09a9461 100644
--- a/src/test/rustdoc/auto_aliases.rs
+++ b/src/test/rustdoc/auto_aliases.rs
@@ -1,6 +1,6 @@
 #![feature(auto_traits)]
 
-// @has auto_aliases/trait.Bar.html '//h3[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
+// @has auto_aliases/trait.Bar.html '//div[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
 pub struct Foo;
 
 pub auto trait Bar {}
diff --git a/src/test/rustdoc/blanket-reexport-item.rs b/src/test/rustdoc/blanket-reexport-item.rs
index f247ee637b9..6f0c15cb5ac 100644
--- a/src/test/rustdoc/blanket-reexport-item.rs
+++ b/src/test/rustdoc/blanket-reexport-item.rs
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-// @has foo/struct.S.html '//h3[@id="impl-Into%3CU%3E"]//code' 'impl<T, U> Into<U> for T'
+// @has foo/struct.S.html '//div[@id="impl-Into%3CU%3E"]//code' 'impl<T, U> Into<U> for T'
 pub struct S2 {}
 mod m {
     pub struct S {}
diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs
index fb5c8517f6c..2761f92ef57 100644
--- a/src/test/rustdoc/const-display.rs
+++ b/src/test/rustdoc/const-display.rs
@@ -38,12 +38,12 @@ pub const unsafe fn bar_not_gated() -> u32 { 42 }
 pub struct Foo;
 
 impl Foo {
-    // @has 'foo/struct.Foo.html' '//h4[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32'
+    // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32'
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature="foo", issue = "none")]
     pub const unsafe fn gated() -> u32 { 42 }
 
-    // @has 'foo/struct.Foo.html' '//h4[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32'
+    // @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32'
     // @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)'
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "rust1", since = "1.2.0")]
diff --git a/src/test/rustdoc/const-fn.rs b/src/test/rustdoc/const-fn.rs
index 9ea7343e075..28eba849ace 100644
--- a/src/test/rustdoc/const-fn.rs
+++ b/src/test/rustdoc/const-fn.rs
@@ -8,7 +8,7 @@ pub const fn bar() -> usize {
 }
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="method"]' 'const fn new()'
+// @has - '//*[@class="method has-srclink"]' 'const fn new()'
 pub struct Foo(usize);
 
 impl Foo {
diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs
index 77432ba1539..8f412aa8c40 100644
--- a/src/test/rustdoc/const-generics/add-impl.rs
+++ b/src/test/rustdoc/const-generics/add-impl.rs
@@ -8,7 +8,7 @@ pub struct Simd<T, const WIDTH: usize> {
     inner: T,
 }
 
-// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
+// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//div/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
 impl Add for Simd<u8, 16> {
     type Output = Self;
 
diff --git a/src/test/rustdoc/const-generics/const-generic-slice.rs b/src/test/rustdoc/const-generics/const-generic-slice.rs
index 60d96770f7e..626a9e2b210 100644
--- a/src/test/rustdoc/const-generics/const-generic-slice.rs
+++ b/src/test/rustdoc/const-generics/const-generic-slice.rs
@@ -6,7 +6,7 @@ pub trait Array {
 }
 
 // @has foo/trait.Array.html
-// @has - '//h3[@class="impl"]' 'impl<T, const N: usize> Array for [T; N]'
+// @has - '//div[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]'
 impl <T, const N: usize> Array for [T; N] {
     type Item = T;
 }
diff --git a/src/test/rustdoc/const-generics/const-generics-docs.rs b/src/test/rustdoc/const-generics/const-generics-docs.rs
index 21bf216c304..7c4c70432c7 100644
--- a/src/test/rustdoc/const-generics/const-generics-docs.rs
+++ b/src/test/rustdoc/const-generics/const-generics-docs.rs
@@ -36,7 +36,7 @@ pub struct Foo<const N: usize> where u8: Trait<N>;
 // @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
 pub struct Bar<T, const N: usize>([T; N]);
 
-// @has foo/struct.Foo.html '//h3[@id="impl"]/code' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
+// @has foo/struct.Foo.html '//div[@id="impl"]/code' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
 impl<const M: usize> Foo<M> where u8: Trait<M> {
     // @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
     pub const FOO_ASSOC: usize = M + 13;
@@ -47,7 +47,7 @@ impl<const M: usize> Foo<M> where u8: Trait<M> {
     }
 }
 
-// @has foo/struct.Bar.html '//h3[@id="impl"]/code' 'impl<const M: usize> Bar<u8, M>'
+// @has foo/struct.Bar.html '//div[@id="impl"]/code' 'impl<const M: usize> Bar<u8, M>'
 impl<const M: usize> Bar<u8, M> {
     // @has - '//*[@id="method.hey"]' \
     //      'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>'
diff --git a/src/test/rustdoc/const-generics/const-impl.rs b/src/test/rustdoc/const-generics/const-impl.rs
index 04fb3395333..e4e504dd83b 100644
--- a/src/test/rustdoc/const-generics/const-impl.rs
+++ b/src/test/rustdoc/const-generics/const-impl.rs
@@ -9,20 +9,20 @@ pub enum Order {
 }
 
 // @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
-// @has foo/struct.VSet.html '//h3[@id="impl-Send"]/code' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
-// @has foo/struct.VSet.html '//h3[@id="impl-Sync"]/code' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//div[@id="impl-Send"]/code' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//div[@id="impl-Sync"]/code' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
 pub struct VSet<T, const ORDER: Order> {
     inner: Vec<T>,
 }
 
-// @has foo/struct.VSet.html '//h3[@id="impl"]/code' 'impl<T> VSet<T, {Order::Sorted}>'
+// @has foo/struct.VSet.html '//div[@id="impl"]/code' 'impl<T> VSet<T, {Order::Sorted}>'
 impl <T> VSet<T, {Order::Sorted}> {
     pub fn new() -> Self {
         Self { inner: Vec::new() }
     }
 }
 
-// @has foo/struct.VSet.html '//h3[@id="impl-1"]/code' 'impl<T> VSet<T, {Order::Unsorted}>'
+// @has foo/struct.VSet.html '//div[@id="impl-1"]/code' 'impl<T> VSet<T, {Order::Unsorted}>'
 impl <T> VSet<T, {Order::Unsorted}> {
     pub fn new() -> Self {
         Self { inner: Vec::new() }
@@ -31,7 +31,7 @@ impl <T> VSet<T, {Order::Unsorted}> {
 
 pub struct Escape<const S: &'static str>;
 
-// @has foo/struct.Escape.html '//h3[@id="impl"]/code' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>'
+// @has foo/struct.Escape.html '//div[@id="impl"]/code' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>'
 impl Escape<{ r#"<script>alert("Escape");</script>"# }> {
     pub fn f() {}
 }
diff --git a/src/test/rustdoc/doc-assoc-item.rs b/src/test/rustdoc/doc-assoc-item.rs
index 4d5c9f83e1e..4f15418650c 100644
--- a/src/test/rustdoc/doc-assoc-item.rs
+++ b/src/test/rustdoc/doc-assoc-item.rs
@@ -8,7 +8,7 @@ pub trait Bar {
     fn foo(foo: Self::Fuu);
 }
 
-// @has doc_assoc_item/struct.Foo.html '//*[@class="impl"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
+// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl<T: Bar<Fuu = u32>> Foo<T>'
 impl<T: Bar<Fuu = u32>> Foo<T> {
     pub fn new(t: T) -> Foo<T> {
         Foo {
diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs
index 1e644bb9739..15c3444606c 100644
--- a/src/test/rustdoc/duplicate_impls/issue-33054.rs
+++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs
@@ -1,8 +1,8 @@
 // @has issue_33054/impls/struct.Foo.html
 // @has - '//code' 'impl Foo'
 // @has - '//code' 'impl Bar for Foo'
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @count - '//*[@id="main"]/details/summary/*[@class="impl"]' 1
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="main"]/details/summary/*[@class="impl has-srclink"]' 1
 // @has issue_33054/impls/bar/trait.Bar.html
 // @has - '//code' 'impl Bar for Foo'
 // @count - '//*[@class="struct"]' 1
diff --git a/src/test/rustdoc/empty-impls.rs b/src/test/rustdoc/empty-impls.rs
index 86dec32e625..2eed1cc9d74 100644
--- a/src/test/rustdoc/empty-impls.rs
+++ b/src/test/rustdoc/empty-impls.rs
@@ -1,19 +1,19 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Foo.html
-// @has - '//div[@id="synthetic-implementations-list"]/h3[@id="impl-Send"]' 'impl Send for Foo'
+// @has - '//div[@id="synthetic-implementations-list"]/div[@id="impl-Send"]' 'impl Send for Foo'
 pub struct Foo;
 
 pub trait EmptyTrait {}
 
-// @has - '//div[@id="trait-implementations-list"]/h3[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
+// @has - '//div[@id="trait-implementations-list"]/div[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
 impl EmptyTrait for Foo {}
 
 pub trait NotEmpty {
     fn foo(&self);
 }
 
-// @has - '//div[@id="trait-implementations-list"]/details/summary/h3[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
+// @has - '//div[@id="trait-implementations-list"]/details/summary/div[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
 impl NotEmpty for Foo {
     fn foo(&self) {}
 }
diff --git a/src/test/rustdoc/ensure-src-link.rs b/src/test/rustdoc/ensure-src-link.rs
index b7e7b11d27a..4b6270b26da 100644
--- a/src/test/rustdoc/ensure-src-link.rs
+++ b/src/test/rustdoc/ensure-src-link.rs
@@ -2,5 +2,5 @@
 
 // This test ensures that the [src] link is present on traits items.
 
-// @has foo/trait.Iterator.html '//h3[@id="method.zip"]/a[@class="srclink"]' "[src]"
+// @has foo/trait.Iterator.html '//div[@id="method.zip"]/a[@class="srclink"]' "[src]"
 pub use std::iter::Iterator;
diff --git a/src/test/rustdoc/external-doc.rs b/src/test/rustdoc/external-doc.rs
index befd31a5492..0dadca551a9 100644
--- a/src/test/rustdoc/external-doc.rs
+++ b/src/test/rustdoc/external-doc.rs
@@ -1,5 +1,4 @@
 #![feature(external_doc)]
-#![feature(extended_key_value_attributes)]
 
 // @has external_doc/struct.CanHasDocs.html
 // @has - '//h1' 'External Docs'
diff --git a/src/test/rustdoc/generic-impl.rs b/src/test/rustdoc/generic-impl.rs
index 03a4d197499..96ced021041 100644
--- a/src/test/rustdoc/generic-impl.rs
+++ b/src/test/rustdoc/generic-impl.rs
@@ -2,10 +2,10 @@
 
 use std::fmt;
 
-// @!has foo/struct.Bar.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @!has foo/struct.Bar.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
 pub struct Bar;
 
-// @has foo/struct.Foo.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @has foo/struct.Foo.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
 pub struct Foo;
 // @has foo/struct.Foo.html '//div[@class="sidebar-links"]/a[@href="#impl-ToString"]' 'ToString'
 
diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs
index 90110babea7..e4039eecb71 100644
--- a/src/test/rustdoc/impl-parts.rs
+++ b/src/test/rustdoc/impl-parts.rs
@@ -5,7 +5,7 @@ pub auto trait AnAutoTrait {}
 
 pub struct Foo<T> { field: T }
 
-// @has impl_parts/struct.Foo.html '//*[@class="impl"]//code' \
+// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//code' \
 //     "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
 // @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//code' \
 //     "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync,"
diff --git a/src/test/rustdoc/inline_cross/assoc-items.rs b/src/test/rustdoc/inline_cross/assoc-items.rs
index 8fc01c3f04c..231805a52b9 100644
--- a/src/test/rustdoc/inline_cross/assoc-items.rs
+++ b/src/test/rustdoc/inline_cross/assoc-items.rs
@@ -16,18 +16,15 @@ extern crate assoc_items;
 // @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16'
 // @has - '//*[@class="docblock"]' 'dox for ConstNoDefault'
 // @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for ConstWithDefault'
-// @has - '//details/details/div[@class="docblock"]' 'docs for ConstWithDefault'
+// @has - '//div[@class="docblock"]' 'docs for ConstWithDefault'
 // @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32'
 // @has - '//*[@class="docblock"]' 'dox for TypeNoDefault'
 // @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for TypeWithDefault'
-// @has - '//details/details/div[@class="docblock"]' 'docs for TypeWithDefault'
+// @has - '//div[@class="docblock"]' 'docs for TypeWithDefault'
 // @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()'
 // @has - '//*[@class="docblock"]' 'dox for method_no_default'
 // @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for method_with_default'
-// @has - '//details/details/div[@class="docblock"]' 'docs for method_with_default'
+// @has - '//div[@class="docblock"]' 'docs for method_with_default'
 pub use assoc_items::MyStruct;
 
 // @has foo/trait.MyTrait.html
diff --git a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs
index cc0596c70ce..9b67022fd4b 100644
--- a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs
+++ b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs
@@ -8,6 +8,5 @@ extern crate impl_inline_without_trait;
 
 // @has 'foo/struct.MyStruct.html'
 // @has - '//*[@id="method.my_trait_method"]' 'fn my_trait_method()'
-// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for my_trait_method'
-// @has - '//details/details/div[@class="docblock"]' 'docs for my_trait_method'
+// @has - '//div[@class="docblock"]' 'docs for my_trait_method'
 pub use impl_inline_without_trait::MyStruct;
diff --git a/src/test/rustdoc/inline_cross/issue-31948-1.rs b/src/test/rustdoc/inline_cross/issue-31948-1.rs
index f47056223fe..390f0b845e0 100644
--- a/src/test/rustdoc/inline_cross/issue-31948-1.rs
+++ b/src/test/rustdoc/inline_cross/issue-31948-1.rs
@@ -5,8 +5,8 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948_1/struct.Wobble.html
-// @has - '//*[@class="impl"]//code' 'Bark for'
-// @has - '//*[@class="impl"]//code' 'Woof for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
 // @!has - '//*[@class="impl"]//code' 'Bar for'
 // @!has - '//*[@class="impl"]//code' 'Qux for'
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
diff --git a/src/test/rustdoc/inline_cross/issue-31948-2.rs b/src/test/rustdoc/inline_cross/issue-31948-2.rs
index 282f0679e98..013e777440f 100644
--- a/src/test/rustdoc/inline_cross/issue-31948-2.rs
+++ b/src/test/rustdoc/inline_cross/issue-31948-2.rs
@@ -5,9 +5,9 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948_2/struct.Wobble.html
-// @has - '//*[@class="impl"]//code' 'Qux for'
-// @has - '//*[@class="impl"]//code' 'Bark for'
-// @has - '//*[@class="impl"]//code' 'Woof for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Qux for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
 // @!has - '//*[@class="impl"]//code' 'Bar for'
 pub use rustdoc_nonreachable_impls::hidden::Wobble;
 
diff --git a/src/test/rustdoc/inline_cross/issue-31948.rs b/src/test/rustdoc/inline_cross/issue-31948.rs
index d5725175e3f..82dcc2d2cc3 100644
--- a/src/test/rustdoc/inline_cross/issue-31948.rs
+++ b/src/test/rustdoc/inline_cross/issue-31948.rs
@@ -5,9 +5,9 @@
 extern crate rustdoc_nonreachable_impls;
 
 // @has issue_31948/struct.Foo.html
-// @has - '//*[@class="impl"]//code' 'Bark for'
-// @has - '//*[@class="impl"]//code' 'Woof for'
-// @!has - '//*[@class="impl"]//code' 'Bar for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Bark for'
+// @has - '//*[@class="impl has-srclink"]//code' 'Woof for'
+// @!has - '//*[@class="impl has-srclink"]//code' 'Bar for'
 // @!has - '//*[@class="impl"]//code' 'Qux for'
 pub use rustdoc_nonreachable_impls::Foo;
 
diff --git a/src/test/rustdoc/issue-21474.rs b/src/test/rustdoc/issue-21474.rs
index 5de26abace6..43ce13fd9b1 100644
--- a/src/test/rustdoc/issue-21474.rs
+++ b/src/test/rustdoc/issue-21474.rs
@@ -7,5 +7,5 @@ mod inner {
 pub trait Blah { }
 
 // @count issue_21474/struct.What.html \
-//        '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
+//        '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
 pub struct What;
diff --git a/src/test/rustdoc/issue-29503.rs b/src/test/rustdoc/issue-29503.rs
index 2b25da77d7e..23d9e73b567 100644
--- a/src/test/rustdoc/issue-29503.rs
+++ b/src/test/rustdoc/issue-29503.rs
@@ -5,7 +5,7 @@ pub trait MyTrait {
     fn my_string(&self) -> String;
 }
 
-// @has - "//div[@id='implementors-list']//h3[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug"
+// @has - "//div[@id='implementors-list']//div[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug"
 impl<T> MyTrait for T where T: fmt::Debug {
     fn my_string(&self) -> String {
         format!("{:?}", self)
diff --git a/src/test/rustdoc/issue-33302.rs b/src/test/rustdoc/issue-33302.rs
index 21356b513ee..1777744c0fc 100644
--- a/src/test/rustdoc/issue-33302.rs
+++ b/src/test/rustdoc/issue-33302.rs
@@ -23,7 +23,7 @@ macro_rules! make {
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//h3[@class="impl"]' 'impl T<[i32; 16]> for S'
+        //        '//div[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
         // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]'
         // @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
         impl T<[i32; ($n * $n)]> for S {
@@ -31,7 +31,7 @@ macro_rules! make {
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//h3[@class="impl"]' 'impl T<[i32; 16]> for S'
+        //        '//div[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
         // @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)'
         // @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32'
         impl T<(i32,)> for S {
@@ -39,7 +39,7 @@ macro_rules! make {
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//h3[@class="impl"]' 'impl T<(i32, i32)> for S'
+        //        '//div[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S'
         // @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)'
         // @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32'
         impl T<(i32, i32)> for S {
diff --git a/src/test/rustdoc/issue-45584.rs b/src/test/rustdoc/issue-45584.rs
index 8a5f0413826..86479e6fb2e 100644
--- a/src/test/rustdoc/issue-45584.rs
+++ b/src/test/rustdoc/issue-45584.rs
@@ -4,12 +4,12 @@ pub trait Bar<T, U> {}
 
 // @has 'foo/struct.Foo1.html'
 pub struct Foo1;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @has - '//*[@class="impl has-srclink"]' "impl Bar<Foo1, &'static Foo1> for Foo1"
 impl Bar<Foo1, &'static Foo1> for Foo1 {}
 
 // @has 'foo/struct.Foo2.html'
 pub struct Foo2;
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8"
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8"
 impl Bar<&'static Foo2, Foo2> for u8 {}
diff --git a/src/test/rustdoc/issue-50159.rs b/src/test/rustdoc/issue-50159.rs
index 0820512e521..69774aa351f 100644
--- a/src/test/rustdoc/issue-50159.rs
+++ b/src/test/rustdoc/issue-50159.rs
@@ -14,7 +14,7 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> {
 // @has - '//code' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send'
 // @has - '//code' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync'
 // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
 pub struct Switch<B: Signal> {
     pub inner: <B as Signal2>::Item2,
 }
diff --git a/src/test/rustdoc/issue-51236.rs b/src/test/rustdoc/issue-51236.rs
index d018c948162..e01dae6c7f1 100644
--- a/src/test/rustdoc/issue-51236.rs
+++ b/src/test/rustdoc/issue-51236.rs
@@ -7,8 +7,8 @@ pub mod traits {
 }
 
 // @has issue_51236/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
-// Owned<T> where <T as Owned<'static>>::Reader: Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> Send for Owned<T> where <T as Owned<'static>>::Reader: Send"
 pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> {
     marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>,
 }
diff --git a/src/test/rustdoc/issue-53812.rs b/src/test/rustdoc/issue-53812.rs
index ddc14e68675..0b1f2f2c93f 100644
--- a/src/test/rustdoc/issue-53812.rs
+++ b/src/test/rustdoc/issue-53812.rs
@@ -12,9 +12,10 @@ macro_rules! array_impls {
     }
 }
 
-// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/h3[1]' 'MyStruct<[T; 0]>'
-// @has - '//*[@id="implementors-list"]/h3[2]' 'MyStruct<[T; 1]>'
-// @has - '//*[@id="implementors-list"]/h3[3]' 'MyStruct<[T; 2]>'
-// @has - '//*[@id="implementors-list"]/h3[4]' 'MyStruct<[T; 3]>'
-// @has - '//*[@id="implementors-list"]/h3[5]' 'MyStruct<[T; 10]>'
+// @has issue_53812/trait.MyIterator.html
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>'
 array_impls! { 10 3 2 1 0 }
diff --git a/src/test/rustdoc/issue-54705.rs b/src/test/rustdoc/issue-54705.rs
index 47da94a4ccf..5a94d36ed70 100644
--- a/src/test/rustdoc/issue-54705.rs
+++ b/src/test/rustdoc/issue-54705.rs
@@ -3,11 +3,11 @@ pub trait ScopeHandle<'scope> {}
 
 
 // @has issue_54705/struct.ScopeFutureContents.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \
-// Send for ScopeFutureContents<'scope, S> where S: Sync"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'scope, S> Send for ScopeFutureContents<'scope, S> where S: Sync"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \
-// Sync for ScopeFutureContents<'scope, S> where S: Sync"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S> where S: Sync"
 pub struct ScopeFutureContents<'scope, S>
     where S: ScopeHandle<'scope>,
 {
diff --git a/src/test/rustdoc/issue-55321.rs b/src/test/rustdoc/issue-55321.rs
index d1877f39ba7..b664733487b 100644
--- a/src/test/rustdoc/issue-55321.rs
+++ b/src/test/rustdoc/issue-55321.rs
@@ -1,16 +1,18 @@
 #![feature(negative_impls)]
 
 // @has issue_55321/struct.A.html
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Send for A"
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Sync for A"
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl !Send for A"
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl !Sync for A"
 pub struct A();
 
 impl !Send for A {}
 impl !Sync for A {}
 
 // @has issue_55321/struct.B.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
-// B<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \
-// B<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Send for B<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Sync for B<T>"
 pub struct B<T: ?Sized>(A, Box<T>);
diff --git a/src/test/rustdoc/issue-56822.rs b/src/test/rustdoc/issue-56822.rs
index b932a3d3474..977596e0b90 100644
--- a/src/test/rustdoc/issue-56822.rs
+++ b/src/test/rustdoc/issue-56822.rs
@@ -17,8 +17,8 @@ impl<'a, T> MyTrait for Inner<'a, T> {
 }
 
 // @has issue_56822/struct.Parser.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a> Send for \
-// Parser<'a>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'a> Send for Parser<'a>"
 pub struct Parser<'a> {
     field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output
 }
diff --git a/src/test/rustdoc/issue-60726.rs b/src/test/rustdoc/issue-60726.rs
index 79b8b70c545..e0417f1a4f4 100644
--- a/src/test/rustdoc/issue-60726.rs
+++ b/src/test/rustdoc/issue-60726.rs
@@ -26,10 +26,10 @@ where
 {}
 
 // @has issue_60726/struct.IntoIter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
-// IntoIter<T>"
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \
-// IntoIter<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Send for IntoIter<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Sync for IntoIter<T>"
 pub struct IntoIter<T>{
     hello:DynTrait<FooInterface<T>>,
 }
diff --git a/src/test/rustdoc/issue-76501.rs b/src/test/rustdoc/issue-76501.rs
index d468f35e280..a90e0fea092 100644
--- a/src/test/rustdoc/issue-76501.rs
+++ b/src/test/rustdoc/issue-76501.rs
@@ -8,7 +8,8 @@ pub const fn bloop() -> i32 {
 pub struct Struct {}
 
 impl Struct {
-    // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' 'pub const fn blurp() -> i32'
+    // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \
+    // 'pub const fn blurp() -> i32'
     /// A useless function that always returns 1.
     pub const fn blurp() -> i32 {
         1
diff --git a/src/test/rustdoc/issue-78673.rs b/src/test/rustdoc/issue-78673.rs
index d09141c3204..2e4bec2544c 100644
--- a/src/test/rustdoc/issue-78673.rs
+++ b/src/test/rustdoc/issue-78673.rs
@@ -7,8 +7,8 @@ pub trait AnAmazingTrait {}
 impl<T: Something> AnAmazingTrait for T {}
 
 // @has 'issue_78673/struct.MyStruct.html'
-// @has  - '//*[@class="impl"]' 'AnAmazingTrait for MyStruct'
-// @!has - '//*[@class="impl"]' 'AnAmazingTrait for T'
+// @has  - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct'
+// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
 pub struct MyStruct;
 
 impl AnAmazingTrait for MyStruct {}
@@ -16,8 +16,8 @@ impl AnAmazingTrait for MyStruct {}
 // generic structs may have _both_ specific and blanket impls that apply
 
 // @has 'issue_78673/struct.AnotherStruct.html'
-// @has - '//*[@class="impl"]' 'AnAmazingTrait for AnotherStruct<()>'
-// @has - '//*[@class="impl"]' 'AnAmazingTrait for T'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>'
+// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T'
 pub struct AnotherStruct<T>(T);
 
 impl<T: Something> Something for AnotherStruct<T> {}
diff --git a/src/test/rustdoc/issue-85454.rs b/src/test/rustdoc/issue-85454.rs
new file mode 100644
index 00000000000..45664dfc382
--- /dev/null
+++ b/src/test/rustdoc/issue-85454.rs
@@ -0,0 +1,17 @@
+// @has issue_85454/trait.FromResidual.html
+// @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }'
+pub trait FromResidual<R = <Self as Try>::Residual> {
+    fn from_residual(residual: R) -> Self;
+}
+
+pub trait Try: FromResidual {
+    type Output;
+    type Residual;
+    fn from_output(output: Self::Output) -> Self;
+    fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
+}
+
+pub enum ControlFlow<B, C = ()> {
+    Continue(C),
+    Break(B),
+}
diff --git a/src/test/rustdoc/keyword.rs b/src/test/rustdoc/keyword.rs
index 25e8b7912e7..652517c5c90 100644
--- a/src/test/rustdoc/keyword.rs
+++ b/src/test/rustdoc/keyword.rs
@@ -4,7 +4,8 @@
 
 // @has foo/index.html '//h2[@id="keywords"]' 'Keywords'
 // @has foo/index.html '//a[@href="keyword.match.html"]' 'match'
-// @has foo/index.html '//div[@class="block items"]//a/@href' '#keywords'
+// @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords'
+// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords'
 // @has foo/keyword.match.html '//a[@class="keyword"]' 'match'
 // @has foo/keyword.match.html '//span[@class="in-band"]' 'Keyword match'
 // @has foo/keyword.match.html '//section[@id="main"]//div[@class="docblock"]//p' 'this is a test!'
diff --git a/src/test/rustdoc/manual_impl.rs b/src/test/rustdoc/manual_impl.rs
index 776a191ceef..b2ee077bc6b 100644
--- a/src/test/rustdoc/manual_impl.rs
+++ b/src/test/rustdoc/manual_impl.rs
@@ -24,13 +24,10 @@ pub trait T {
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S1 trait implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.'
 // @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
 // @!has - '//*[@class="docblock"]' 'There is another line'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Read more'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Read more'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Read more'
 pub struct S1(usize);
 
 /// Docs associated with the S1 trait implementation.
@@ -45,10 +42,7 @@ impl T for S1 {
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S2 trait implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S2 trait a_method implementation.'
 // @has  - '//*[@class="docblock"]' 'Docs associated with the S2 trait c_method implementation.'
-// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait c_method definition.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.'
 pub struct S2(usize);
 
 /// Docs associated with the S2 trait implementation.
@@ -65,10 +59,9 @@ impl T for S2 {
 }
 
 // @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T'
-// @has  - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
-// @has  - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
-// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
-// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
+// @has  - '//div[@class="docblock"]' 'Docs associated with the S3 trait implementation.'
+// @has  - '//div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.'
+// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.'
 pub struct S3(usize);
 
 /// Docs associated with the S3 trait implementation.
diff --git a/src/test/rustdoc/mut-params.rs b/src/test/rustdoc/mut-params.rs
index 1ef7e304fa2..f3ea6995839 100644
--- a/src/test/rustdoc/mut-params.rs
+++ b/src/test/rustdoc/mut-params.rs
@@ -5,7 +5,7 @@
 
 pub struct Foo;
 
-// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method"]' 2
+// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2
 // @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut'
 impl Foo {
     pub fn foo(mut self) {}
diff --git a/src/test/rustdoc/negative-impl.rs b/src/test/rustdoc/negative-impl.rs
index d76aac6906c..ee65a7d5f39 100644
--- a/src/test/rustdoc/negative-impl.rs
+++ b/src/test/rustdoc/negative-impl.rs
@@ -5,8 +5,10 @@ pub struct Alpha;
 // @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>"
 pub struct Bravo<B>(B);
 
-// @matches negative_impl/struct.Alpha.html '//*[@class="impl"]//code' "impl !Send for Alpha"
+// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//code' \
+// "impl !Send for Alpha"
 impl !Send for Alpha {}
 
-// @matches negative_impl/struct.Bravo.html '//*[@class="impl"]//code' "impl<B> !Send for Bravo<B>"
+// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//code' "\
+// impl<B> !Send for Bravo<B>"
 impl<B> !Send for Bravo<B> {}
diff --git a/src/test/rustdoc/primitive-generic-impl.rs b/src/test/rustdoc/primitive-generic-impl.rs
index 5794322ba1d..2951f5128e0 100644
--- a/src/test/rustdoc/primitive-generic-impl.rs
+++ b/src/test/rustdoc/primitive-generic-impl.rs
@@ -2,4 +2,4 @@
 
 include!("primitive/primitive-generic-impl.rs");
 
-// @has foo/primitive.i32.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
+// @has foo/primitive.i32.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T'
diff --git a/src/test/rustdoc/pub-method.rs b/src/test/rustdoc/pub-method.rs
index 8e88b2b5901..fa7de0aff6a 100644
--- a/src/test/rustdoc/pub-method.rs
+++ b/src/test/rustdoc/pub-method.rs
@@ -10,8 +10,8 @@ pub fn bar() -> usize {
 }
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="method"]' 'pub fn new()'
-// @has - '//*[@class="method"]' 'fn not_pub()'
+// @has - '//*[@class="method has-srclink"]' 'pub fn new()'
+// @has - '//*[@class="method has-srclink"]' 'fn not_pub()'
 pub struct Foo(usize);
 
 impl Foo {
diff --git a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
index 6219a2c3b90..d256fbe8de0 100644
--- a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
+++ b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs
@@ -6,9 +6,9 @@
 // @has - '//*[@class="sidebar-title"][@href="#foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-u32"]' 'u32'
-// @has - '//h3[@id="impl-Foo-for-u32"]//code' 'impl Foo for u32'
+// @has - '//div[@id="impl-Foo-for-u32"]//code' 'impl Foo for u32'
 // @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str"
-// @has - '//h3[@id="impl-Foo-for-%26%27a%20str"]//code' "impl<'a> Foo for &'a str"
+// @has - '//div[@id="impl-Foo-for-%26%27a%20str"]//code' "impl<'a> Foo for &'a str"
 pub trait Foo {}
 
 impl Foo for u32 {}
diff --git a/src/test/rustdoc/sized_trait.rs b/src/test/rustdoc/sized_trait.rs
index 26d12817afc..6730c71e90f 100644
--- a/src/test/rustdoc/sized_trait.rs
+++ b/src/test/rustdoc/sized_trait.rs
@@ -1,17 +1,17 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Bar.html
-// @!has - '//h3[@id="impl-Sized"]'
+// @!has - '//div[@id="impl-Sized"]'
 pub struct Bar {
     a: u16,
 }
 
 // @has foo/struct.Foo.html
-// @!has - '//h3[@id="impl-Sized"]'
+// @!has - '//div[@id="impl-Sized"]'
 pub struct Foo<T: ?Sized>(T);
 
 // @has foo/struct.Unsized.html
-// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
+// @has - '//div[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
 pub struct Unsized {
     data: [u8],
 }
diff --git a/src/test/rustdoc/spotlight-from-dependency.rs b/src/test/rustdoc/spotlight-from-dependency.rs
index ed42c435945..864cb0c400b 100644
--- a/src/test/rustdoc/spotlight-from-dependency.rs
+++ b/src/test/rustdoc/spotlight-from-dependency.rs
@@ -3,7 +3,7 @@
 use std::iter::Iterator;
 
 // @has foo/struct.Odd.html
-// @has - '//h4[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
+// @has - '//div[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
 pub struct Odd {
     current: usize,
 }
diff --git a/src/test/rustdoc/src-links-auto-impls.rs b/src/test/rustdoc/src-links-auto-impls.rs
index a1d183df0f1..6f609e080d3 100644
--- a/src/test/rustdoc/src-links-auto-impls.rs
+++ b/src/test/rustdoc/src-links-auto-impls.rs
@@ -1,12 +1,12 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Unsized.html
-// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
-// @!has - '//h3[@id="impl-Sized"]/a[@class="srclink"]' '[src]'
-// @has - '//h3[@id="impl-Sync"]/code' 'impl Sync for Unsized'
-// @!has - '//h3[@id="impl-Sync"]/a[@class="srclink"]' '[src]'
-// @has - '//h3[@id="impl-Any"]/code' 'impl<T> Any for T'
-// @has - '//h3[@id="impl-Any"]/a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Sized"]/code' 'impl !Sized for Unsized'
+// @!has - '//div[@id="impl-Sized"]/a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Sync"]/code' 'impl Sync for Unsized'
+// @!has - '//div[@id="impl-Sync"]/a[@class="srclink"]' '[src]'
+// @has - '//div[@id="impl-Any"]/code' 'impl<T> Any for T'
+// @has - '//div[@id="impl-Any"]/a[@class="srclink"]' '[src]'
 pub struct Unsized {
     data: [u8],
 }
diff --git a/src/test/rustdoc/synthetic_auto/basic.rs b/src/test/rustdoc/synthetic_auto/basic.rs
index 0dd3a3f7a86..943596a0c85 100644
--- a/src/test/rustdoc/synthetic_auto/basic.rs
+++ b/src/test/rustdoc/synthetic_auto/basic.rs
@@ -1,8 +1,8 @@
 // @has basic/struct.Foo.html
 // @has - '//code' 'impl<T> Send for Foo<T> where T: Send'
 // @has - '//code' 'impl<T> Sync for Foo<T> where T: Sync'
-// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5
+// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5
 pub struct Foo<T> {
     field: T,
 }
diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs
index d951a20e2de..0213142266f 100644
--- a/src/test/rustdoc/synthetic_auto/complex.rs
+++ b/src/test/rustdoc/synthetic_auto/complex.rs
@@ -20,8 +20,8 @@ mod foo {
 }
 
 // @has complex/struct.NotOuter.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a, T, K: \
-// ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \
 // -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static"
 
 pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter};
diff --git a/src/test/rustdoc/synthetic_auto/lifetimes.rs b/src/test/rustdoc/synthetic_auto/lifetimes.rs
index 05c88f10822..c2e9b6f4046 100644
--- a/src/test/rustdoc/synthetic_auto/lifetimes.rs
+++ b/src/test/rustdoc/synthetic_auto/lifetimes.rs
@@ -9,11 +9,11 @@ where
 {}
 
 // @has lifetimes/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \
-// for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Send for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \
-// for Foo<'c, K> where K: Sync"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Sync for Foo<'c, K> where K: Sync"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
 }
diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs
index 88ddd57349a..91fe6c351c5 100644
--- a/src/test/rustdoc/synthetic_auto/manual.rs
+++ b/src/test/rustdoc/synthetic_auto/manual.rs
@@ -1,12 +1,12 @@
 // @has manual/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Sync for \
-// Foo<T> where T: Sync'
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// 'impl<T> Sync for Foo<T> where T: Sync'
 //
-// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' \
+// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \
 // 'impl<T> Send for Foo<T>'
 //
-// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1
-// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4
+// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1
+// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4
 pub struct Foo<T> {
     field: T,
 }
diff --git a/src/test/rustdoc/synthetic_auto/negative.rs b/src/test/rustdoc/synthetic_auto/negative.rs
index 53801542c95..16b36b56b68 100644
--- a/src/test/rustdoc/synthetic_auto/negative.rs
+++ b/src/test/rustdoc/synthetic_auto/negative.rs
@@ -3,11 +3,11 @@ pub struct Inner<T: Copy> {
 }
 
 // @has negative/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \
-// Outer<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Send for Outer<T>"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> \
-// !Sync for Outer<T>"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> !Sync for Outer<T>"
 pub struct Outer<T: Copy> {
     inner_field: Inner<T>,
 }
diff --git a/src/test/rustdoc/synthetic_auto/nested.rs b/src/test/rustdoc/synthetic_auto/nested.rs
index d4d93a87ffc..a6cf5890dca 100644
--- a/src/test/rustdoc/synthetic_auto/nested.rs
+++ b/src/test/rustdoc/synthetic_auto/nested.rs
@@ -9,10 +9,10 @@ where
 }
 
 // @has nested/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Send for \
-// Foo<T> where T: Copy'
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// 'impl<T> Send for Foo<T> where T: Copy'
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' \
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
 // 'impl<T> Sync for Foo<T> where T: Sync'
 pub struct Foo<T> {
     inner_field: Inner<T>,
diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
index 3a23dc2cf95..5c744e3eb3c 100644
--- a/src/test/rustdoc/synthetic_auto/no-redundancy.rs
+++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
@@ -9,8 +9,8 @@ where
 }
 
 // @has no_redundancy/struct.Outer.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
-// Outer<T> where T: Copy + Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> Send for Outer<T> where T: Copy + Send"
 pub struct Outer<T> {
     inner_field: Inner<T>,
 }
diff --git a/src/test/rustdoc/synthetic_auto/project.rs b/src/test/rustdoc/synthetic_auto/project.rs
index 060491e3cf1..baf9924b1ae 100644
--- a/src/test/rustdoc/synthetic_auto/project.rs
+++ b/src/test/rustdoc/synthetic_auto/project.rs
@@ -23,11 +23,12 @@ where
 }
 
 // @has project/struct.Foo.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \
-// for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Send for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static"
 //
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \
-// for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, 'c: 'static,"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<'c, K> Sync for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \
+// 'c: 'static,"
 pub struct Foo<'c, K: 'c> {
     inner_field: Inner<'c, K>,
 }
diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs
index ecdbdf41b20..e96187e2c96 100644
--- a/src/test/rustdoc/synthetic_auto/self-referential.rs
+++ b/src/test/rustdoc/synthetic_auto/self-referential.rs
@@ -23,7 +23,7 @@ impl<T> Pattern for Wrapper<T> {
 
 
 // @has self_referential/struct.WriteAndThen.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<P1> Send for \
-// WriteAndThen<P1>  where  <P1 as Pattern>::Value: Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<P1> Send for WriteAndThen<P1>  where  <P1 as Pattern>::Value: Send"
 pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value)
     where P1: Pattern;
diff --git a/src/test/rustdoc/synthetic_auto/static-region.rs b/src/test/rustdoc/synthetic_auto/static-region.rs
index a10e694c1b2..fc732a08ed4 100644
--- a/src/test/rustdoc/synthetic_auto/static-region.rs
+++ b/src/test/rustdoc/synthetic_auto/static-region.rs
@@ -3,8 +3,8 @@ pub trait OwnedTrait<'a> {
 }
 
 // @has static_region/struct.Owned.html
-// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \
-// Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
+// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \
+// "impl<T> Send for Owned<T> where <T as OwnedTrait<'static>>::Reader: Send"
 pub struct Owned<T> where T: OwnedTrait<'static> {
     marker: <T as OwnedTrait<'static>>::Reader,
 }
diff --git a/src/test/rustdoc/item-hide-threshold.rs b/src/test/rustdoc/toggle-item-contents.rs
index 8986f72636a..6e3c0b4c681 100644
--- a/src/test/rustdoc/item-hide-threshold.rs
+++ b/src/test/rustdoc/toggle-item-contents.rs
@@ -1,13 +1,13 @@
 #![allow(unused)]
 
-// @has 'item_hide_threshold/struct.PubStruct.html'
+// @has 'toggle_item_contents/struct.PubStruct.html'
 // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
 pub struct PubStruct {
     pub a: usize,
     pub b: usize,
 }
 
-// @has 'item_hide_threshold/struct.BigPubStruct.html'
+// @has 'toggle_item_contents/struct.BigPubStruct.html'
 // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
 pub struct BigPubStruct {
@@ -26,7 +26,7 @@ pub struct BigPubStruct {
     pub m: usize,
 }
 
-// @has 'item_hide_threshold/union.BigUnion.html'
+// @has 'toggle_item_contents/union.BigUnion.html'
 // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
 pub union BigUnion {
@@ -45,7 +45,7 @@ pub union BigUnion {
     pub m: usize,
 }
 
-// @has 'item_hide_threshold/union.Union.html'
+// @has 'toggle_item_contents/union.Union.html'
 // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
 pub union Union {
     pub a: usize,
@@ -53,7 +53,7 @@ pub union Union {
     pub c: usize,
 }
 
-// @has 'item_hide_threshold/struct.PrivStruct.html'
+// @has 'toggle_item_contents/struct.PrivStruct.html'
 // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
 // @has - '//div[@class="docblock type-decl"]' 'fields omitted'
 pub struct PrivStruct {
@@ -61,7 +61,7 @@ pub struct PrivStruct {
     b: usize,
 }
 
-// @has 'item_hide_threshold/enum.Enum.html'
+// @has 'toggle_item_contents/enum.Enum.html'
 // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields'
 pub enum Enum {
@@ -72,14 +72,14 @@ pub enum Enum {
     }
 }
 
-// @has 'item_hide_threshold/enum.LargeEnum.html'
+// @has 'toggle_item_contents/enum.LargeEnum.html'
 // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show variants'
 pub enum LargeEnum {
     A, B, C, D, E, F(u8), G, H, I, J, K, L, M
 }
 
-// @has 'item_hide_threshold/trait.Trait.html'
+// @has 'toggle_item_contents/trait.Trait.html'
 // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
 pub trait Trait {
     type A;
@@ -88,7 +88,7 @@ pub trait Trait {
     fn bar();
 }
 
-// @has 'item_hide_threshold/trait.GinormousTrait.html'
+// @has 'toggle_item_contents/trait.GinormousTrait.html'
 // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated items'
 pub trait GinormousTrait {
@@ -111,7 +111,7 @@ pub trait GinormousTrait {
     fn bar();
 }
 
-// @has 'item_hide_threshold/trait.HugeTrait.html'
+// @has 'toggle_item_contents/trait.HugeTrait.html'
 // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated constants and methods'
 pub trait HugeTrait {
@@ -133,7 +133,7 @@ pub trait HugeTrait {
     fn bar();
 }
 
-// @has 'item_hide_threshold/trait.BigTrait.html'
+// @has 'toggle_item_contents/trait.BigTrait.html'
 // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1
 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show methods'
 pub trait BigTrait {
diff --git a/src/test/rustdoc/toggle-method.rs b/src/test/rustdoc/toggle-method.rs
new file mode 100644
index 00000000000..f7f6086a4cb
--- /dev/null
+++ b/src/test/rustdoc/toggle-method.rs
@@ -0,0 +1,18 @@
+#![crate_name = "foo"]
+
+// Struct methods with documentation should be wrapped in a <details> toggle with an appropriate
+// summary. Struct methods with no documentation should not be wrapped.
+//
+// @has foo/struct.Foo.html
+// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//code' 'is_documented()'
+// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//code' 'not_documented()'
+pub struct Foo {
+}
+
+impl Foo {
+    pub fn not_documented() {}
+
+    /// is_documented is documented
+    pub fn is_documented() {}
+}
diff --git a/src/test/rustdoc/toggle-trait-fn.rs b/src/test/rustdoc/toggle-trait-fn.rs
new file mode 100644
index 00000000000..0bc5eba75a1
--- /dev/null
+++ b/src/test/rustdoc/toggle-trait-fn.rs
@@ -0,0 +1,23 @@
+#![crate_name = "foo"]
+
+// Trait methods with documentation should be wrapped in a <details> toggle with an appropriate
+// summary. Trait methods with no documentation should not be wrapped.
+//
+// @has foo/trait.Foo.html
+// @has -  '//details[@class="rustdoc-toggle"]//summary//code' 'is_documented()'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//code' 'not_documented()'
+// @has -  '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented is documented'
+// @has -  '//details[@class="rustdoc-toggle"]//summary//code' 'is_documented_optional()'
+// @!has - '//details[@class="rustdoc-toggle"]//summary//code' 'not_documented_optional()'
+// @has -  '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented'
+pub trait Foo {
+    fn not_documented();
+
+    /// is_documented is documented
+    fn is_documented();
+
+    fn not_documented_optional() {}
+
+    /// is_documented_optional is documented
+    fn is_documented_optional() {}
+}
diff --git a/src/test/rustdoc/trait-attributes.rs b/src/test/rustdoc/trait-attributes.rs
index 2bb24a82193..d0dfb8759e6 100644
--- a/src/test/rustdoc/trait-attributes.rs
+++ b/src/test/rustdoc/trait-attributes.rs
@@ -2,7 +2,7 @@
 
 
 pub trait Foo {
-    // @has foo/trait.Foo.html '//h3[@id="tymethod.foo"]//div[@class="code-attribute"]' '#[must_use]'
+    // @has foo/trait.Foo.html '//div[@id="tymethod.foo"]//div[@class="code-attribute"]' '#[must_use]'
     #[must_use]
     fn foo();
 }
@@ -11,11 +11,11 @@ pub trait Foo {
 pub struct Bar;
 
 impl Bar {
-    // @has foo/struct.Bar.html '//h4[@id="method.bar"]//div[@class="code-attribute"]' '#[must_use]'
+    // @has foo/struct.Bar.html '//div[@id="method.bar"]//div[@class="code-attribute"]' '#[must_use]'
     #[must_use]
     pub fn bar() {}
 
-    // @has foo/struct.Bar.html '//h4[@id="method.bar2"]//div[@class="code-attribute"]' '#[must_use]'
+    // @has foo/struct.Bar.html '//div[@id="method.bar2"]//div[@class="code-attribute"]' '#[must_use]'
     #[must_use]
     pub fn bar2() {}
 }
diff --git a/src/test/rustdoc/trait-impl-items-links-and-anchors.rs b/src/test/rustdoc/trait-impl-items-links-and-anchors.rs
index c6a9313e821..5b7c04c0d44 100644
--- a/src/test/rustdoc/trait-impl-items-links-and-anchors.rs
+++ b/src/test/rustdoc/trait-impl-items-links-and-anchors.rs
@@ -8,58 +8,58 @@ pub trait MyTrait {
 
 
 impl MyTrait for String {
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-1"]//a[@class="type"]/@href' #associatedtype.Assoc
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="type"]/@href' #associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1
     type Assoc = ();
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1
     const VALUE: u32 = 5;
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
     fn trait_function(&self) {}
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1
     fn defaulted_override(&self) {}
 }
 
 impl MyTrait for Vec<u8> {
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-2"]//a[@class="type"]/@href' #associatedtype.Assoc
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="type"]/@href' #associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2
     type Assoc = ();
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2
     const VALUE: u32 = 5;
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1
     fn trait_function(&self) {}
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2
     fn defaulted_override(&self) {}
 }
 
 impl MyTrait for MyStruct {
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="type"]/@href' trait.MyTrait.html#associatedtype.Assoc
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="type"]/@href' trait.MyTrait.html#associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
     type Assoc = bool;
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
     const VALUE: u32 = 20;
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
     fn trait_function(&self) {}
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
     fn defaulted_override(&self) {}
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
 }
 
 pub struct MyStruct;
diff --git a/src/test/rustdoc/typedef.rs b/src/test/rustdoc/typedef.rs
index 7f834d3d5a5..21a7fdda769 100644
--- a/src/test/rustdoc/typedef.rs
+++ b/src/test/rustdoc/typedef.rs
@@ -9,8 +9,8 @@ impl MyStruct {
 }
 
 // @has typedef/type.MyAlias.html
-// @has - '//*[@class="impl"]//code' 'impl MyAlias'
-// @has - '//*[@class="impl"]//code' 'impl MyTrait for MyAlias'
+// @has - '//*[@class="impl has-srclink"]//code' 'impl MyAlias'
+// @has - '//*[@class="impl has-srclink"]//code' 'impl MyTrait for MyAlias'
 // @has - 'Alias docstring'
 // @has - '//*[@class="sidebar"]//p[@class="location"]' 'Type Definition MyAlias'
 // @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs
index 992cddfe72a..f204a27d7d3 100644
--- a/src/test/rustdoc/where.rs
+++ b/src/test/rustdoc/where.rs
@@ -11,7 +11,7 @@ pub fn charlie<C>() where C: MyTrait {}
 
 pub struct Delta<D>(D);
 
-// @has foo/struct.Delta.html '//*[@class="impl"]//code' \
+// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//code' \
 //          "impl<D> Delta<D> where D: MyTrait"
 impl<D> Delta<D> where D: MyTrait {
     pub fn delta() {}
@@ -19,7 +19,7 @@ impl<D> Delta<D> where D: MyTrait {
 
 pub struct Echo<E>(E);
 
-// @has foo/struct.Echo.html '//*[@class="impl"]//code' \
+// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//code' \
 //          "impl<E> MyTrait for Echo<E> where E: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \
 //          "impl<E> MyTrait for Echo<E> where E: MyTrait"
@@ -27,7 +27,7 @@ impl<E> MyTrait for Echo<E> where E: MyTrait {}
 
 pub enum Foxtrot<F> { Foxtrot1(F) }
 
-// @has foo/enum.Foxtrot.html '//*[@class="impl"]//code' \
+// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//code' \
 //          "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
 // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \
 //          "impl<F> MyTrait for Foxtrot<F> where F: MyTrait"
diff --git a/src/test/ui/async-await/async-await.rs b/src/test/ui/async-await/async-await.rs
index 0207752afe0..3d22025bf28 100644
--- a/src/test/ui/async-await/async-await.rs
+++ b/src/test/ui/async-await/async-await.rs
@@ -1,7 +1,8 @@
 // run-pass
 
-// revisions: default nomiropt
+// revisions: default nomiropt thirunsafeck
 //[nomiropt]compile-flags: -Z mir-opt-level=0
+//[thirunsafeck]compile-flags: -Zthir-unsafeck
 
 #![allow(unused)]
 
diff --git a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs
index 2ed343b4a07..fc37822cb7b 100644
--- a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs
+++ b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs
@@ -16,6 +16,6 @@ async fn g() {
 }
 
 fn main() {
-    S::f(); //~ ERROR call to unsafe function is unsafe
-    f(); //~ ERROR call to unsafe function is unsafe
+    S::f(); //[mir]~ ERROR call to unsafe function is unsafe
+    f(); //[mir]~ ERROR call to unsafe function is unsafe
 }
diff --git a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr
index d22413beecb..21ba45d7f1e 100644
--- a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr
+++ b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr
@@ -14,22 +14,6 @@ LL |     f();
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/async-unsafe-fn-call-in-safe.rs:19:5
-   |
-LL |     S::f();
-   |     ^^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/async-unsafe-fn-call-in-safe.rs:20:5
-   |
-LL |     f();
-   |     ^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs
index 4a8e841b33d..9fe3313ee6c 100644
--- a/src/test/ui/async-await/issue-61076.rs
+++ b/src/test/ui/async-await/issue-61076.rs
@@ -42,7 +42,7 @@ async fn bar() -> Result<(), ()> {
     foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
     //~^ NOTE the `?` operator cannot be applied to type `impl Future`
     //~| HELP the trait `Try` is not implemented for `impl Future`
-    //~| NOTE required by `into_result`
+    //~| NOTE required by `branch`
     //~| HELP consider `await`ing on the `Future`
     //~| NOTE in this expansion of desugaring of operator `?`
     //~| NOTE in this expansion of desugaring of operator `?`
@@ -65,7 +65,7 @@ async fn baz() -> Result<(), ()> {
     t?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
     //~^ NOTE the `?` operator cannot be applied to type `T`
     //~| HELP the trait `Try` is not implemented for `T`
-    //~| NOTE required by `into_result`
+    //~| NOTE required by `branch`
     //~| HELP consider `await`ing on the `Future`
     //~| NOTE in this expansion of desugaring of operator `?`
     //~| NOTE in this expansion of desugaring of operator `?`
diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr
index fd00522fac7..ad661fb2833 100644
--- a/src/test/ui/async-await/issue-61076.stderr
+++ b/src/test/ui/async-await/issue-61076.stderr
@@ -5,7 +5,7 @@ LL |     foo()?;
    |     ^^^^^^ the `?` operator cannot be applied to type `impl Future`
    |
    = help: the trait `Try` is not implemented for `impl Future`
-   = note: required by `into_result`
+   = note: required by `branch`
 help: consider `await`ing on the `Future`
    |
 LL |     foo().await?;
@@ -18,7 +18,7 @@ LL |     t?;
    |     ^^ the `?` operator cannot be applied to type `T`
    |
    = help: the trait `Try` is not implemented for `T`
-   = note: required by `into_result`
+   = note: required by `branch`
 help: consider `await`ing on the `Future`
    |
 LL |     t.await?;
diff --git a/src/test/ui/async-await/issue-73741-type-err.rs b/src/test/ui/async-await/issue-73741-type-err.rs
new file mode 100644
index 00000000000..c5b9e34edf7
--- /dev/null
+++ b/src/test/ui/async-await/issue-73741-type-err.rs
@@ -0,0 +1,14 @@
+// edition:2018
+//
+// Regression test for issue #73741
+// Ensures that we don't emit spurious errors when
+// a type error ocurrs in an `async fn`
+
+async fn weird() {
+    1 = 2; //~ ERROR invalid left-hand side
+
+    let mut loop_count = 0;
+    async {}.await
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/issue-73741-type-err.stderr b/src/test/ui/async-await/issue-73741-type-err.stderr
new file mode 100644
index 00000000000..0b5343a98cf
--- /dev/null
+++ b/src/test/ui/async-await/issue-73741-type-err.stderr
@@ -0,0 +1,11 @@
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/issue-73741-type-err.rs:8:7
+   |
+LL |     1 = 2;
+   |     - ^
+   |     |
+   |     cannot assign to this expression
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0070`.
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs
index b901b61aa18..f1002947fb9 100644
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs
+++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs
@@ -1,10 +1,9 @@
 // edition:2018
 // run-pass
 
-// Test that a feature gate is needed to use `impl Trait` as the
-// return type of an async.
-
-#![feature(member_constraints)]
+// Test member constraints that appear in the `impl Trait`
+// return type of an async function.
+// (This used to require a feature gate.)
 
 trait Trait<'a, 'b> { }
 impl<T> Trait<'_, '_> for T { }
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs
deleted file mode 100644
index 05960c0c7f6..00000000000
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// edition:2018
-
-// Test that a feature gate is needed to use `impl Trait` as the
-// return type of an async.
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
-
-async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
-    //~^ ERROR ambiguous lifetime bound
-    //~| ERROR ambiguous lifetime bound
-    //~| ERROR ambiguous lifetime bound
-    //~| ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
-    //~| ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
-    (a, b)
-}
-
-fn main() {
-    let _ = async_ret_impl_trait(&22, &44);
-}
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr
deleted file mode 100644
index f65bbeaa31a..00000000000
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error: ambiguous lifetime bound in `impl Trait`
-  --> $DIR/ret-impl-trait-no-fg.rs:9:64
-   |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
-   |                                                                ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
-   |
-   = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: ambiguous lifetime bound in `impl Trait`
-  --> $DIR/ret-impl-trait-no-fg.rs:9:64
-   |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
-   |                                                                ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
-   |
-   = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: ambiguous lifetime bound in `impl Trait`
-  --> $DIR/ret-impl-trait-no-fg.rs:9:64
-   |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
-   |                                                                ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another
-   |
-   = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ret-impl-trait-no-fg.rs:9:1
-   |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: hidden type `(&u8, &u8)` captures lifetime '_#5r
-
-error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ret-impl-trait-no-fg.rs:9:1
-   |
-LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: hidden type `(&u8, &u8)` captures lifetime '_#6r
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0700`.
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr
index 53b0dd691b8..eed90772d29 100644
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr
+++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ret-impl-trait-one.rs:12:80
+  --> $DIR/ret-impl-trait-one.rs:10:80
    |
 LL |   async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
    |  ________________________________--__--__________________________________________^
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs
index babc90a5e96..7e084217c26 100644
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs
+++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs
@@ -3,8 +3,6 @@
 // Test that a feature gate is needed to use `impl Trait` as the
 // return type of an async.
 
-#![feature(member_constraints)]
-
 trait Trait<'a> { }
 impl<T> Trait<'_> for T { }
 
diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
index 5041b39a9e9..8e28605721c 100644
--- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
+++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
@@ -1,5 +1,5 @@
 error[E0623]: lifetime mismatch
-  --> $DIR/ret-impl-trait-one.rs:12:65
+  --> $DIR/ret-impl-trait-one.rs:10:65
    |
 LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> {
    |                                           ------                ^^^^^^^^^^^^^^
diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr
index 8e7823f3571..a3f122a4663 100644
--- a/src/test/ui/async-await/try-on-option-in-async.stderr
+++ b/src/test/ui/async-await/try-on-option-in-async.stderr
@@ -1,47 +1,47 @@
-error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-in-async.rs:8:9
+error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-in-async.rs:8:10
    |
 LL |       async {
    |  ___________-
 LL | |         let x: Option<u32> = None;
 LL | |         x?;
-   | |         ^^ cannot use the `?` operator in an async block that returns `{integer}`
+   | |          ^ cannot use the `?` operator in an async block that returns `{integer}`
 LL | |         22
 LL | |     }
    | |_____- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `{integer}`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}`
+   = note: required by `from_residual`
 
-error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-in-async.rs:17:9
+error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-in-async.rs:17:10
    |
 LL |       let async_closure = async || {
    |  __________________________________-
 LL | |         let x: Option<u32> = None;
 LL | |         x?;
-   | |         ^^ cannot use the `?` operator in an async closure that returns `u32`
+   | |          ^ cannot use the `?` operator in an async closure that returns `u32`
 LL | |         22_u32
 LL | |     };
    | |_____- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `u32`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
+   = note: required by `from_residual`
 
-error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-in-async.rs:26:5
+error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-in-async.rs:26:6
    |
 LL |   async fn an_async_function() -> u32 {
    |  _____________________________________-
 LL | |     let x: Option<u32> = None;
 LL | |     x?;
-   | |     ^^ cannot use the `?` operator in an async function that returns `u32`
+   | |      ^ cannot use the `?` operator in an async function that returns `u32`
 LL | |     22
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `u32`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
+   = note: required by `from_residual`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/attributes/key-value-expansion-on-mac.rs b/src/test/ui/attributes/key-value-expansion-on-mac.rs
index 1247ff2b230..95bc1c04961 100644
--- a/src/test/ui/attributes/key-value-expansion-on-mac.rs
+++ b/src/test/ui/attributes/key-value-expansion-on-mac.rs
@@ -1,4 +1,3 @@
-#![feature(extended_key_value_attributes)]
 #![feature(rustc_attrs)]
 
 #[rustc_dummy = stringify!(a)] // OK
diff --git a/src/test/ui/attributes/key-value-expansion-on-mac.stderr b/src/test/ui/attributes/key-value-expansion-on-mac.stderr
index b74f3518a7e..fa9ea543765 100644
--- a/src/test/ui/attributes/key-value-expansion-on-mac.stderr
+++ b/src/test/ui/attributes/key-value-expansion-on-mac.stderr
@@ -1,5 +1,5 @@
 error: unexpected token: `stringify!(b)`
-  --> $DIR/key-value-expansion-on-mac.rs:12:17
+  --> $DIR/key-value-expansion-on-mac.rs:11:17
    |
 LL | #[rustc_dummy = stringify!(b)]
    |                 ^^^^^^^^^^^^^
diff --git a/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr b/src/test/ui/cast/cast-ptr-to-int-const.mir.stderr
index 8282bc3db05..dcc9a243f0f 100644
--- a/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr
+++ b/src/test/ui/cast/cast-ptr-to-int-const.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
-  --> $DIR/cast-ptr-to-int-const.rs:16:9
+  --> $DIR/cast-ptr-to-int-const.rs:10:9
    |
 LL |         &Y as *const u32 as usize
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
@@ -7,7 +7,7 @@ LL |         &Y as *const u32 as usize
    = note: casting pointers to integers in constants
 
 error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
-  --> $DIR/cast-ptr-to-int-const.rs:23:5
+  --> $DIR/cast-ptr-to-int-const.rs:17:5
    |
 LL |     &0 as *const i32 as usize
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
diff --git a/src/test/ui/cast/cast-ptr-to-int-const.rs b/src/test/ui/cast/cast-ptr-to-int-const.rs
index aed099a53ea..01ea627679d 100644
--- a/src/test/ui/cast/cast-ptr-to-int-const.rs
+++ b/src/test/ui/cast/cast-ptr-to-int-const.rs
@@ -1,25 +1,19 @@
-// gate-test-const_raw_ptr_to_usize_cast
-// revisions: with_feature without_feature
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 
-#![cfg_attr(with_feature, feature(const_raw_ptr_to_usize_cast))]
+#![feature(const_raw_ptr_to_usize_cast)]
 
 fn main() {
-    const X: usize = unsafe {
-        main as usize //[without_feature]~ ERROR casting pointers to integers in constants is unstable
-    };
     const Y: u32 = 0;
-    const Z: usize = unsafe {
-        &Y as *const u32 as usize //[without_feature]~ ERROR is unstable
-    };
     // Cast in `const` without `unsafe` block
     const SAFE: usize = {
-        &Y as *const u32 as usize //[without_feature]~ ERROR is unstable
-        //[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe
+        &Y as *const u32 as usize
+        //~^ ERROR cast of pointer to int is unsafe and requires unsafe
     };
 }
 
 // Cast in `const fn` without `unsafe` block
 const fn test() -> usize {
-    &0 as *const i32 as usize //[without_feature]~ ERROR is unstable
-    //[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe
+    &0 as *const i32 as usize
+    //~^ ERROR cast of pointer to int is unsafe and requires unsafe
 }
diff --git a/src/test/ui/cast/cast-ptr-to-int-const.thir.stderr b/src/test/ui/cast/cast-ptr-to-int-const.thir.stderr
new file mode 100644
index 00000000000..dcc9a243f0f
--- /dev/null
+++ b/src/test/ui/cast/cast-ptr-to-int-const.thir.stderr
@@ -0,0 +1,19 @@
+error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
+  --> $DIR/cast-ptr-to-int-const.rs:10:9
+   |
+LL |         &Y as *const u32 as usize
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
+   |
+   = note: casting pointers to integers in constants
+
+error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block
+  --> $DIR/cast-ptr-to-int-const.rs:17:5
+   |
+LL |     &0 as *const i32 as usize
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int
+   |
+   = note: casting pointers to integers in constants
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs
new file mode 100644
index 00000000000..03e99eb7527
--- /dev/null
+++ b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs
@@ -0,0 +1,13 @@
+fn main() {
+    const X: usize = unsafe {
+        main as usize //~ ERROR casting pointers to integers in constants is unstable
+    };
+    const Y: u32 = 0;
+    const Z: usize = unsafe {
+        &Y as *const u32 as usize //~ ERROR is unstable
+    };
+}
+
+const fn test() -> usize {
+    &0 as *const i32 as usize //~ ERROR is unstable
+}
diff --git a/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.stderr
index c87fa1a14a4..4a0b424e181 100644
--- a/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr
+++ b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.stderr
@@ -1,5 +1,5 @@
 error[E0658]: casting pointers to integers in constants is unstable
-  --> $DIR/cast-ptr-to-int-const.rs:8:9
+  --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:3:9
    |
 LL |         main as usize
    |         ^^^^^^^^^^^^^
@@ -8,16 +8,7 @@ LL |         main as usize
    = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
 error[E0658]: casting pointers to integers in constants is unstable
-  --> $DIR/cast-ptr-to-int-const.rs:12:9
-   |
-LL |         &Y as *const u32 as usize
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
-   = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
-
-error[E0658]: casting pointers to integers in constants is unstable
-  --> $DIR/cast-ptr-to-int-const.rs:16:9
+  --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:7:9
    |
 LL |         &Y as *const u32 as usize
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -26,7 +17,7 @@ LL |         &Y as *const u32 as usize
    = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
 error[E0658]: casting pointers to integers in constant functions is unstable
-  --> $DIR/cast-ptr-to-int-const.rs:23:5
+  --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:12:5
    |
 LL |     &0 as *const i32 as usize
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -34,6 +25,6 @@ LL |     &0 as *const i32 as usize
    = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information
    = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/cast/issue-84213.stderr b/src/test/ui/cast/issue-84213.stderr
index 1b71d4db511..90cfa263c52 100644
--- a/src/test/ui/cast/issue-84213.stderr
+++ b/src/test/ui/cast/issue-84213.stderr
@@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `Something` as `*const Something`
 LL |     let _pointer_to_something = something as *const Something;
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
    |
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
    |
 LL |     let _pointer_to_something = &something as *const Something;
    |                                 ^
@@ -15,7 +15,7 @@ error[E0605]: non-primitive cast: `Something` as `*mut Something`
 LL |     let _mut_pointer_to_something = something as *mut Something;
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
    |
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
    |
 LL |     let _mut_pointer_to_something = &mut something as *mut Something;
    |                                     ^^^^
diff --git a/src/test/ui/command/command-pre-exec.rs b/src/test/ui/command/command-pre-exec.rs
index 819ed0b2dde..61914e22930 100644
--- a/src/test/ui/command/command-pre-exec.rs
+++ b/src/test/ui/command/command-pre-exec.rs
@@ -1,4 +1,6 @@
 // run-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 #![allow(stable_features)]
 // ignore-windows - this is a unix-specific test
diff --git a/src/test/ui/confuse-field-and-method/issue-18343.stderr b/src/test/ui/confuse-field-and-method/issue-18343.stderr
index d6b399acb73..fe6b12968c1 100644
--- a/src/test/ui/confuse-field-and-method/issue-18343.stderr
+++ b/src/test/ui/confuse-field-and-method/issue-18343.stderr
@@ -1,4 +1,4 @@
-error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-18343.rs:6:28: 6:33]>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
   --> $DIR/issue-18343.rs:7:7
    |
 LL | struct Obj<F> where F: FnMut() -> u32 {
diff --git a/src/test/ui/confuse-field-and-method/issue-2392.stderr b/src/test/ui/confuse-field-and-method/issue-2392.stderr
index 051940bbe96..0480958e99c 100644
--- a/src/test/ui/confuse-field-and-method/issue-2392.stderr
+++ b/src/test/ui/confuse-field-and-method/issue-2392.stderr
@@ -1,4 +1,4 @@
-error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
   --> $DIR/issue-2392.rs:36:15
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -12,7 +12,7 @@ help: to call the function stored in `closure`, surround the field access with p
 LL |     (o_closure.closure)();
    |     ^                 ^
 
-error[E0599]: no method named `not_closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope
+error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope
   --> $DIR/issue-2392.rs:38:15
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -23,7 +23,7 @@ LL |     o_closure.not_closure();
    |               |
    |               field, not a method
 
-error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
   --> $DIR/issue-2392.rs:42:12
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -65,7 +65,7 @@ help: to call the function stored in `boxed_closure`, surround the field access
 LL |     (boxed_closure.boxed_closure)();
    |     ^                           ^
 
-error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
   --> $DIR/issue-2392.rs:53:12
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -79,7 +79,7 @@ help: to call the function stored in `closure`, surround the field access with p
 LL |     (w.wrap.closure)();
    |     ^              ^
 
-error[E0599]: no method named `not_closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope
+error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope
   --> $DIR/issue-2392.rs:55:12
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
@@ -90,7 +90,7 @@ LL |     w.wrap.not_closure();
    |            |
    |            field, not a method
 
-error[E0599]: no method named `closure` found for struct `Obj<Box<(dyn FnOnce() -> u32 + 'static)>>` in the current scope
+error[E0599]: no method named `closure` found for struct `Obj` in the current scope
   --> $DIR/issue-2392.rs:58:24
    |
 LL | struct Obj<F> where F: FnOnce() -> u32 {
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs
index 05049d9c2a6..26c4295cd9b 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs
@@ -9,6 +9,7 @@ struct Foo<T>(PhantomData<T>);
 fn test<T>() -> [u8; size_of::<T>()] {
     [0; size_of::<Foo<T>>()]
     //~^ ERROR unconstrained generic constant
+    //~| ERROR mismatched types
 }
 
 fn main() {
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr
index 7c11a47b2f0..2aeb9b961ff 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr
@@ -1,3 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/different-fn.rs:10:5
+   |
+LL |     [0; size_of::<Foo<T>>()]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::<T>()`, found `size_of::<Foo<T>>()`
+   |
+   = note: expected type `size_of::<T>()`
+              found type `size_of::<Foo<T>>()`
+
 error: unconstrained generic constant
   --> $DIR/different-fn.rs:10:9
    |
@@ -6,5 +15,6 @@ LL |     [0; size_of::<Foo<T>>()]
    |
    = help: try adding a `where` bound using this expression: `where [(); size_of::<Foo<T>>()]:`
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs b/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs
new file mode 100644
index 00000000000..0f36ce383a8
--- /dev/null
+++ b/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+// We previously always returned ambiguity when equating generic consts, even if they
+// only contain generic parameters. This is incorrect as trying to unify `N > 1` with `M > 1`
+// should fail.
+#![allow(incomplete_features)]
+#![feature(const_generics, const_evaluatable_checked)]
+
+enum Assert<const COND: bool> {}
+trait IsTrue {}
+impl IsTrue for Assert<true> {}
+
+struct Foo<const N: usize, const M: usize>;
+trait Bar<const N: usize, const M: usize> {}
+impl<const N: usize, const M: usize> Bar<N, M> for Foo<N, M>
+where
+    Assert<{ N > 1 }>: IsTrue,
+    Assert<{ M > 1 }>: IsTrue,
+{
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs
index 3da4688702c..8167d785d7a 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs
@@ -2,7 +2,7 @@
 #![allow(incomplete_features)]
 
 fn test<const N: usize>() -> [u8; N - 1] {
-    //~^ ERROR evaluation of constant
+    //~^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed
     todo!()
 }
 
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr
index 25af18eb162..31ccf979694 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr
@@ -1,4 +1,4 @@
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed
   --> $DIR/from-sig-fail.rs:4:35
    |
 LL | fn test<const N: usize>() -> [u8; N - 1] {
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
index acf0a52ce5b..1f2313a6028 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr
@@ -1,10 +1,10 @@
-error[E0080]: evaluation of constant value failed
-  --> $DIR/simple_fail.rs:9:48
+error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed
+  --> $DIR/simple_fail.rs:10:48
    |
 LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
    |                                                ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
 
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `Arr::<0_usize>::{constant#0}` failed
   --> $DIR/simple_fail.rs:6:33
    |
 LL | type Arr<const N: usize> = [u8; N - 1];
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
index fe5463f8acc..1aa66f9a8ba 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr
@@ -8,7 +8,7 @@ LL | type Arr<const N: usize> = [u8; N - 1];
    = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
-  --> $DIR/simple_fail.rs:9:48
+  --> $DIR/simple_fail.rs:10:48
    |
 LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
    |                                                ^ cannot perform const operation using `N`
diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
index c9535d04244..f08d2495b4d 100644
--- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
+++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs
@@ -3,12 +3,13 @@
 #![cfg_attr(full, feature(const_evaluatable_checked))]
 #![allow(incomplete_features)]
 
-type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant
+type Arr<const N: usize> = [u8; N - 1];
 //[min]~^ ERROR generic parameters may not be used in const operations
+//[full]~^^ ERROR evaluation of `Arr::<0_usize>::{constant#0}` failed
 
 fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized {
 //[min]~^ ERROR generic parameters may not be used in const operations
-//[full]~^^ ERROR evaluation of constant
+//[full]~^^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed
     todo!()
 }
 
diff --git a/src/test/ui/const-generics/defaults/const-param-as-default-value.rs b/src/test/ui/const-generics/defaults/const-param-as-default-value.rs
index 59ac261f44f..9779835d315 100644
--- a/src/test/ui/const-generics/defaults/const-param-as-default-value.rs
+++ b/src/test/ui/const-generics/defaults/const-param-as-default-value.rs
@@ -1,6 +1,5 @@
 // run-pass
 #![feature(const_generics_defaults)]
-#![allow(incomplete_features)]
 struct Foo<const N: usize, const M: usize = N>([u8; N], [u8; M]);
 
 fn foo<const N: usize>() -> Foo<N> {
diff --git a/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs b/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs
index 3f534ca0308..dbcab77dcd2 100644
--- a/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs
+++ b/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs
@@ -1,6 +1,5 @@
 // run-pass
 #![feature(const_generics_defaults)]
-#![allow(incomplete_features)]
 struct Foo<const N: usize, T = [u8; N]>(T);
 
 impl<const N: usize> Foo<N> {
diff --git a/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs b/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs
index 4bb56c6a1c0..d4271adefd1 100644
--- a/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs
+++ b/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs
@@ -1,5 +1,4 @@
 #![feature(const_generics_defaults)]
-#![allow(incomplete_features)]
 struct Foo<const N: u8 = { 255 + 1 }>;
 //~^ ERROR evaluation of constant value failed
 fn main() {}
diff --git a/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr b/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr
index 8464ea98bf6..6fca9d31c0a 100644
--- a/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr
+++ b/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr
@@ -1,5 +1,5 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/default-param-wf-concrete.rs:3:28
+  --> $DIR/default-param-wf-concrete.rs:2:28
    |
 LL | struct Foo<const N: u8 = { 255 + 1 }>;
    |                            ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
diff --git a/src/test/ui/const-generics/defaults/forward-declared.rs b/src/test/ui/const-generics/defaults/forward-declared.rs
new file mode 100644
index 00000000000..09fc105320e
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/forward-declared.rs
@@ -0,0 +1,15 @@
+#![feature(const_generics_defaults)]
+
+struct Foo<const N: usize = M, const M: usize = 10>;
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+enum Bar<const N: usize = M, const M: usize = 10> {}
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+struct Foo2<const N: usize = N>;
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+enum Bar2<const N: usize = N> {}
+//~^ ERROR generic parameters with a default cannot use forward declared identifiers
+
+fn main() {}
diff --git a/src/test/ui/const-generics/defaults/forward-declared.stderr b/src/test/ui/const-generics/defaults/forward-declared.stderr
new file mode 100644
index 00000000000..a6c4a7ae4ef
--- /dev/null
+++ b/src/test/ui/const-generics/defaults/forward-declared.stderr
@@ -0,0 +1,27 @@
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+  --> $DIR/forward-declared.rs:3:29
+   |
+LL | struct Foo<const N: usize = M, const M: usize = 10>;
+   |                             ^ defaulted generic parameters cannot be forward declared
+
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+  --> $DIR/forward-declared.rs:6:27
+   |
+LL | enum Bar<const N: usize = M, const M: usize = 10> {}
+   |                           ^ defaulted generic parameters cannot be forward declared
+
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+  --> $DIR/forward-declared.rs:9:30
+   |
+LL | struct Foo2<const N: usize = N>;
+   |                              ^ defaulted generic parameters cannot be forward declared
+
+error[E0128]: generic parameters with a default cannot use forward declared identifiers
+  --> $DIR/forward-declared.rs:12:28
+   |
+LL | enum Bar2<const N: usize = N> {}
+   |                            ^ defaulted generic parameters cannot be forward declared
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0128`.
diff --git a/src/test/ui/const-generics/defaults/pretty-printing-ast.rs b/src/test/ui/const-generics/defaults/pretty-printing-ast.rs
index 7a57950dfc9..0487668cd2a 100644
--- a/src/test/ui/const-generics/defaults/pretty-printing-ast.rs
+++ b/src/test/ui/const-generics/defaults/pretty-printing-ast.rs
@@ -4,7 +4,6 @@
 
 #![crate_type = "lib"]
 #![feature(const_generics_defaults)]
-#![allow(incomplete_features)]
 
 trait Foo<const KIND: bool = true> {}
 
diff --git a/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout b/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout
index f549993c413..1bceb8cbb94 100644
--- a/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout
+++ b/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout
@@ -6,7 +6,6 @@
 
 #![crate_type = "lib"]
 #![feature(const_generics_defaults)]
-#![allow(incomplete_features)]
 #[prelude_import]
 use ::std::prelude::rust_2015::*;
 #[macro_use]
diff --git a/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs b/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs
index c64c2974c8f..ca29ee94206 100644
--- a/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs
+++ b/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs
@@ -3,7 +3,6 @@
 // run-pass
 
 #![feature(const_generics_defaults)]
-#![allow(incomplete_features)]
 
 #[repr(C)]
 pub struct Loaf<T: Sized, const N: usize = 1> {
diff --git a/src/test/ui/const-generics/issues/issue-62504.full.stderr b/src/test/ui/const-generics/issues/issue-62504.full.stderr
index f09af76325e..efbcdc3d2b7 100644
--- a/src/test/ui/const-generics/issues/issue-62504.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-62504.full.stderr
@@ -1,3 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-62504.rs:18:21
+   |
+LL |         ArrayHolder([0; Self::SIZE])
+   |                     ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE`
+   |
+   = note: expected type `X`
+              found type `Self::SIZE`
+
 error: constant expression depends on a generic parameter
   --> $DIR/issue-62504.rs:18:25
    |
@@ -6,5 +15,6 @@ LL |         ArrayHolder([0; Self::SIZE])
    |
    = note: this may fail depending on what value the parameter takes
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs
index 0b95754cab4..1b70cd1c376 100644
--- a/src/test/ui/const-generics/issues/issue-62504.rs
+++ b/src/test/ui/const-generics/issues/issue-62504.rs
@@ -17,7 +17,7 @@ impl<const X: usize> ArrayHolder<X> {
     pub const fn new() -> Self {
         ArrayHolder([0; Self::SIZE])
         //~^ ERROR constant expression depends on a generic parameter
-        //[min]~| ERROR mismatched types
+        //~| ERROR mismatched types
     }
 }
 
diff --git a/src/test/ui/const-generics/min_const_generics/default_function_param.rs b/src/test/ui/const-generics/min_const_generics/default_function_param.rs
index ebdb5a65bc3..b47dd2f618c 100644
--- a/src/test/ui/const-generics/min_const_generics/default_function_param.rs
+++ b/src/test/ui/const-generics/min_const_generics/default_function_param.rs
@@ -1,6 +1,5 @@
 #![crate_type = "lib"]
 #![feature(const_generics_defaults)]
-#![allow(incomplete_features)]
 
 fn foo<const SIZE: usize = 5usize>() {}
 //~^ ERROR defaults for const parameters are
diff --git a/src/test/ui/const-generics/min_const_generics/default_function_param.stderr b/src/test/ui/const-generics/min_const_generics/default_function_param.stderr
index 243ac0db5f5..11df8621faa 100644
--- a/src/test/ui/const-generics/min_const_generics/default_function_param.stderr
+++ b/src/test/ui/const-generics/min_const_generics/default_function_param.stderr
@@ -1,5 +1,5 @@
 error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
-  --> $DIR/default_function_param.rs:5:14
+  --> $DIR/default_function_param.rs:4:14
    |
 LL | fn foo<const SIZE: usize = 5usize>() {}
    |              ^^^^
diff --git a/src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs b/src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs
new file mode 100644
index 00000000000..bdeaa0cd360
--- /dev/null
+++ b/src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs
@@ -0,0 +1,20 @@
+// Auxiliary crate used for testing post-monomorphization errors cross-crate.
+// It duplicates the setup used in `stdarch` to validate its intrinsics' const arguments.
+
+struct ValidateConstImm<const IMM: i32, const MIN: i32, const MAX: i32>;
+impl<const IMM: i32, const MIN: i32, const MAX: i32> ValidateConstImm<IMM, MIN, MAX> {
+    pub(crate) const VALID: () = {
+        let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize);
+    };
+}
+
+macro_rules! static_assert_imm1 {
+    ($imm:ident) => {
+        let _ = $crate::ValidateConstImm::<$imm, 0, { (1 << 1) - 1 }>::VALID;
+    };
+}
+
+// This function triggers an error whenever the const argument does not fit in 1-bit.
+pub fn stdarch_intrinsic<const IMM1: i32>() {
+    static_assert_imm1!(IMM1);
+}
diff --git a/src/test/ui/consts/const-eval/const_panic.rs b/src/test/ui/consts/const-eval/const_panic.rs
index 8ae8376ae4a..b33b1475a22 100644
--- a/src/test/ui/consts/const-eval/const_panic.rs
+++ b/src/test/ui/consts/const-eval/const_panic.rs
@@ -6,40 +6,30 @@ const MSG: &str = "hello";
 
 const Z: () = std::panic!("cheese");
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const Z2: () = std::panic!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const Y: () = std::unreachable!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const X: () = std::unimplemented!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 //
 const W: () = std::panic!(MSG);
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const Z_CORE: () = core::panic!("cheese");
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const Z2_CORE: () = core::panic!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const Y_CORE: () = core::unreachable!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const X_CORE: () = core::unimplemented!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const W_CORE: () = core::panic!(MSG);
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
diff --git a/src/test/ui/consts/const-eval/const_panic.stderr b/src/test/ui/consts/const-eval/const_panic.stderr
index 5637de8b313..3c890f78af7 100644
--- a/src/test/ui/consts/const-eval/const_panic.stderr
+++ b/src/test/ui/consts/const-eval/const_panic.stderr
@@ -1,4 +1,4 @@
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
   --> $DIR/const_panic.rs:7:15
    |
 LL | const Z: () = std::panic!("cheese");
@@ -6,118 +6,98 @@ LL | const Z: () = std::panic!("cheese");
    |               |
    |               the evaluated program panicked at 'cheese', $DIR/const_panic.rs:7:15
    |
-   = note: `#[deny(const_err)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:11:16
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:10:16
    |
 LL | const Z2: () = std::panic!();
    | ---------------^^^^^^^^^^^^^-
    |                |
-   |                the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:11:16
+   |                the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:10:16
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:15:15
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:13:15
    |
 LL | const Y: () = std::unreachable!();
    | --------------^^^^^^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:15:15
+   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:13:15
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:19:15
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:16:15
    |
 LL | const X: () = std::unimplemented!();
    | --------------^^^^^^^^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:19:15
+   |               the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:16:15
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:23:15
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:19:15
    |
 LL | const W: () = std::panic!(MSG);
    | --------------^^^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'hello', $DIR/const_panic.rs:23:15
+   |               the evaluated program panicked at 'hello', $DIR/const_panic.rs:19:15
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:27:20
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:22:20
    |
 LL | const Z_CORE: () = core::panic!("cheese");
    | -------------------^^^^^^^^^^^^^^^^^^^^^^-
    |                    |
-   |                    the evaluated program panicked at 'cheese', $DIR/const_panic.rs:27:20
+   |                    the evaluated program panicked at 'cheese', $DIR/const_panic.rs:22:20
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:31:21
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:25:21
    |
 LL | const Z2_CORE: () = core::panic!();
    | --------------------^^^^^^^^^^^^^^-
    |                     |
-   |                     the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:31:21
+   |                     the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:25:21
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:35:20
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:28:20
    |
 LL | const Y_CORE: () = core::unreachable!();
    | -------------------^^^^^^^^^^^^^^^^^^^^-
    |                    |
-   |                    the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:35:20
+   |                    the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:28:20
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:39:20
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:31:20
    |
 LL | const X_CORE: () = core::unimplemented!();
    | -------------------^^^^^^^^^^^^^^^^^^^^^^-
    |                    |
-   |                    the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:39:20
+   |                    the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:31:20
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic.rs:43:20
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic.rs:34:20
    |
 LL | const W_CORE: () = core::panic!(MSG);
    | -------------------^^^^^^^^^^^^^^^^^-
    |                    |
-   |                    the evaluated program panicked at 'hello', $DIR/const_panic.rs:43:20
+   |                    the evaluated program panicked at 'hello', $DIR/const_panic.rs:34:20
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 10 previous errors
 
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs b/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs
index 0eb1e3eb94e..6b03e847def 100644
--- a/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs
+++ b/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs
@@ -8,15 +8,12 @@ use core::panic::PanicInfo;
 
 const Z: () = panic!("cheese");
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const Y: () = unreachable!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 const X: () = unimplemented!();
 //~^ ERROR any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
 
 #[lang = "eh_personality"]
 fn eh() {}
diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr b/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr
index 9971559e33b..2a3ad3ca180 100644
--- a/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr
+++ b/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr
@@ -1,4 +1,4 @@
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
   --> $DIR/const_panic_libcore_bin.rs:9:15
    |
 LL | const Z: () = panic!("cheese");
@@ -6,34 +6,28 @@ LL | const Z: () = panic!("cheese");
    |               |
    |               the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_bin.rs:9:15
    |
-   = note: `#[deny(const_err)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic_libcore_bin.rs:13:15
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic_libcore_bin.rs:12:15
    |
 LL | const Y: () = unreachable!();
    | --------------^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:13:15
+   |               the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:12:15
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: any use of this value will cause an error
-  --> $DIR/const_panic_libcore_bin.rs:17:15
+error[E0080]: any use of this value will cause an error
+  --> $DIR/const_panic_libcore_bin.rs:15:15
    |
 LL | const X: () = unimplemented!();
    | --------------^^^^^^^^^^^^^^^^-
    |               |
-   |               the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:17:15
+   |               the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:15:15
    |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/issue-50814-2.stderr b/src/test/ui/consts/const-eval/issue-50814-2.stderr
index 0c520165496..d34ac773da2 100644
--- a/src/test/ui/consts/const-eval/issue-50814-2.stderr
+++ b/src/test/ui/consts/const-eval/issue-50814-2.stderr
@@ -10,7 +10,7 @@ LL |     const BAR: usize = [5, 6, 7][T::BOO];
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `foo::<()>` failed
   --> $DIR/issue-50814-2.rs:19:6
    |
 LL |     &<A<T> as Foo<T>>::BAR
diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr
index cf82d1eef3e..dd8d6bf839a 100644
--- a/src/test/ui/consts/const-eval/issue-50814.stderr
+++ b/src/test/ui/consts/const-eval/issue-50814.stderr
@@ -10,7 +10,7 @@ LL |     const MAX: u8 = A::MAX + B::MAX;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `foo::<i32>` failed
   --> $DIR/issue-50814.rs:21:6
    |
 LL |     &Sum::<U8,U8>::MAX
diff --git a/src/test/ui/consts/const-eval/issue-85155.rs b/src/test/ui/consts/const-eval/issue-85155.rs
new file mode 100644
index 00000000000..c3216d53d05
--- /dev/null
+++ b/src/test/ui/consts/const-eval/issue-85155.rs
@@ -0,0 +1,21 @@
+// This is a test with a setup similar to issue 85155, which triggers a const eval error: a const
+// argument value is outside the range expected by the `stdarch` intrinsic.
+//
+// It's not the exact code mentioned in that issue because it depends both on `stdarch` intrinsics
+// only available on x64, and internal implementation details of `stdarch`. But mostly because these
+// are not important to trigger the diagnostics issue: it's specifically about the lack of context
+// in the diagnostics of post-monomorphization errors (PMEs) for consts, happening in a dependency.
+// Therefore, its setup is reproduced with an aux crate, which will similarly trigger a PME
+// depending on the const argument value, like the `stdarch` intrinsics would.
+//
+// aux-build: post_monomorphization_error.rs
+// build-fail: this is a post-monomorphization error, it passes check runs and requires building
+//             to actually fail.
+
+extern crate post_monomorphization_error;
+
+fn main() {
+    // This function triggers a PME whenever the const argument does not fit in 1-bit.
+    post_monomorphization_error::stdarch_intrinsic::<2>();
+    //~^ NOTE the above error was encountered while instantiating
+}
diff --git a/src/test/ui/consts/const-eval/issue-85155.stderr b/src/test/ui/consts/const-eval/issue-85155.stderr
new file mode 100644
index 00000000000..c36d7c17215
--- /dev/null
+++ b/src/test/ui/consts/const-eval/issue-85155.stderr
@@ -0,0 +1,15 @@
+error[E0080]: evaluation of `post_monomorphization_error::ValidateConstImm::<2_i32, 0_i32, 1_i32>::VALID` failed
+  --> $DIR/auxiliary/post_monomorphization_error.rs:7:17
+   |
+LL |         let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to divide `1_usize` by zero
+
+note: the above error was encountered while instantiating `fn post_monomorphization_error::stdarch_intrinsic::<2_i32>`
+  --> $DIR/issue-85155.rs:19:5
+   |
+LL |     post_monomorphization_error::stdarch_intrinsic::<2>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
index f76440298b3..dd18a98035b 100644
--- a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
+++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs
@@ -9,8 +9,7 @@ struct PrintName;
 
 impl PrintName {
     const VOID: ! = panic!();
-    //~^ WARN any use of this value will cause an error
-    //~| WARN this was previously accepted by the compiler but is being phased out
+    //~^ ERROR any use of this value will cause an error
 }
 
 fn main() {
diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
index d1f067df848..e186240f53a 100644
--- a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
+++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr
@@ -1,4 +1,4 @@
-warning: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
   --> $DIR/panic-assoc-never-type.rs:11:21
    |
 LL |     const VOID: ! = panic!();
@@ -6,21 +6,14 @@ LL |     const VOID: ! = panic!();
    |                     |
    |                     the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:11:21
    |
-note: the lint level is defined here
-  --> $DIR/panic-assoc-never-type.rs:4:9
-   |
-LL | #![warn(const_err)]
-   |         ^^^^^^^^^
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: erroneous constant used
-  --> $DIR/panic-assoc-never-type.rs:17:13
+  --> $DIR/panic-assoc-never-type.rs:16:13
    |
 LL |     let _ = PrintName::VOID;
    |             ^^^^^^^^^^^^^^^ referenced constant has errors
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/panic-never-type.rs b/src/test/ui/consts/const-eval/panic-never-type.rs
index c5139c575b1..71b489d828c 100644
--- a/src/test/ui/consts/const-eval/panic-never-type.rs
+++ b/src/test/ui/consts/const-eval/panic-never-type.rs
@@ -1,15 +1,11 @@
-// build-fail
-
 // Regression test for #66975
 #![warn(const_err)]
 #![feature(const_panic)]
 #![feature(never_type)]
 
 const VOID: ! = panic!();
-//~^ WARN any use of this value will cause an error
-//~| WARN this was previously accepted by the compiler but is being phased out
+//~^ ERROR any use of this value will cause an error
 
 fn main() {
     let _ = VOID;
-    //~^ ERROR erroneous constant used
 }
diff --git a/src/test/ui/consts/const-eval/panic-never-type.stderr b/src/test/ui/consts/const-eval/panic-never-type.stderr
index 2217bf1e05a..2254c3dcfdf 100644
--- a/src/test/ui/consts/const-eval/panic-never-type.stderr
+++ b/src/test/ui/consts/const-eval/panic-never-type.stderr
@@ -1,26 +1,13 @@
-warning: any use of this value will cause an error
-  --> $DIR/panic-never-type.rs:8:17
+error[E0080]: any use of this value will cause an error
+  --> $DIR/panic-never-type.rs:6:17
    |
 LL | const VOID: ! = panic!();
    | ----------------^^^^^^^^-
    |                 |
-   |                 the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:8:17
+   |                 the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:6:17
    |
-note: the lint level is defined here
-  --> $DIR/panic-never-type.rs:4:9
-   |
-LL | #![warn(const_err)]
-   |         ^^^^^^^^^
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
-   = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0080]: erroneous constant used
-  --> $DIR/panic-never-type.rs:13:13
-   |
-LL |     let _ = VOID;
-   |             ^^^^ referenced constant has errors
+   = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to previous error; 1 warning emitted
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/unwind-abort.rs b/src/test/ui/consts/const-eval/unwind-abort.rs
index 10820986fa7..9bc63d9328c 100644
--- a/src/test/ui/consts/const-eval/unwind-abort.rs
+++ b/src/test/ui/consts/const-eval/unwind-abort.rs
@@ -2,8 +2,7 @@
 
 #[unwind(aborts)]
 const fn foo() {
-    panic!() //~ ERROR any use of this value will cause an error [const_err]
-    //~| WARN this was previously accepted by the compiler but is being phased out
+    panic!() //~ ERROR any use of this value will cause an error
 }
 
 const _: () = foo();
diff --git a/src/test/ui/consts/const-eval/unwind-abort.stderr b/src/test/ui/consts/const-eval/unwind-abort.stderr
index 79fdd05be30..b41d786169b 100644
--- a/src/test/ui/consts/const-eval/unwind-abort.stderr
+++ b/src/test/ui/consts/const-eval/unwind-abort.stderr
@@ -1,4 +1,4 @@
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
   --> $DIR/unwind-abort.rs:5:5
    |
 LL |     panic!()
@@ -6,15 +6,13 @@ LL |     panic!()
    |     |
    |     the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5
    |     inside `foo` at $SRC_DIR/std/src/panic.rs:LL:COL
-   |     inside `_` at $DIR/unwind-abort.rs:9:15
+   |     inside `_` at $DIR/unwind-abort.rs:8:15
 ...
 LL | const _: () = foo();
    | --------------------
    |
-   = note: `#[deny(const_err)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs
index 1ce78147970..031e67a1e3c 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs
@@ -9,5 +9,5 @@ fn main() {
     let a: [u8; foo()];
     //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
     foo();
-    //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
+    //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
 }
diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
index b643ecc0ce8..c6077da768b 100644
--- a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
+++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr
@@ -1,12 +1,4 @@
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/const-extern-fn-requires-unsafe.rs:11:5
-   |
-LL |     foo();
-   |     ^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
   --> $DIR/const-extern-fn-requires-unsafe.rs:9:17
    |
 LL |     let a: [u8; foo()];
@@ -14,6 +6,6 @@ LL |     let a: [u8; foo()];
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/consts/const-unwrap.stderr b/src/test/ui/consts/const-unwrap.stderr
index 0100dce5a96..95f4711cb65 100644
--- a/src/test/ui/consts/const-unwrap.stderr
+++ b/src/test/ui/consts/const-unwrap.stderr
@@ -1,4 +1,4 @@
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
   --> $SRC_DIR/core/src/option.rs:LL:COL
    |
 LL |             None => panic!("called `Option::unwrap()` on a `None` value"),
@@ -13,10 +13,8 @@ LL |             None => panic!("called `Option::unwrap()` on a `None` value"),
 LL | const BAR: i32 = Option::<i32>::None.unwrap();
    | ----------------------------------------------
    |
-   = note: `#[deny(const_err)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const_fn_unsize.gated.stderr b/src/test/ui/consts/const_fn_unsize.gated.stderr
deleted file mode 100644
index 8a65c274ca9..00000000000
--- a/src/test/ui/consts/const_fn_unsize.gated.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: fatal error triggered by #[rustc_error]
-  --> $DIR/const_fn_unsize.rs:16:1
-   |
-LL | fn main() {}
-   | ^^^^^^^^^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/consts/const_fn_unsize.rs b/src/test/ui/consts/const_fn_unsize.rs
index 0cab3b0a031..01da57320c2 100644
--- a/src/test/ui/consts/const_fn_unsize.rs
+++ b/src/test/ui/consts/const_fn_unsize.rs
@@ -1,16 +1,21 @@
-// gate-test-const_fn_unsize
-
-// revisions: stock gated
-
-#![feature(rustc_attrs)]
-#![cfg_attr(gated, feature(const_fn_unsize))]
+// run-pass
+#![feature(slice_ptr_len)]
 
 use std::ptr::NonNull;
 
+#[allow(unused)]
 const fn test() {
     let _x = NonNull::<[i32; 0]>::dangling() as NonNull<[i32]>;
-    //[stock]~^ unsizing cast
 }
 
-#[rustc_error]
-fn main() {} //[gated]~ fatal error triggered by #[rustc_error]
+// Regression test for #75118.
+pub const fn dangling_slice<T>() -> NonNull<[T]> {
+    NonNull::<[T; 1]>::dangling()
+}
+
+const C: NonNull<[i32]> = dangling_slice();
+
+fn main() {
+    assert_eq!(C.as_ptr(), NonNull::<[i32; 1]>::dangling().as_ptr() as *mut _);
+    assert_eq!(C.as_ptr().len(), 1);
+}
diff --git a/src/test/ui/consts/const_fn_unsize.stock.stderr b/src/test/ui/consts/const_fn_unsize.stock.stderr
deleted file mode 100644
index cc746d4f175..00000000000
--- a/src/test/ui/consts/const_fn_unsize.stock.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: unsizing casts to types besides slices are not allowed in const fn
-  --> $DIR/const_fn_unsize.rs:11:14
-   |
-LL |     let _x = NonNull::<[i32; 0]>::dangling() as NonNull<[i32]>;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information
-   = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/consts/control-flow/assert.const_panic.stderr b/src/test/ui/consts/control-flow/assert.const_panic.stderr
index 665b4240011..8e1a2b5eb46 100644
--- a/src/test/ui/consts/control-flow/assert.const_panic.stderr
+++ b/src/test/ui/consts/control-flow/assert.const_panic.stderr
@@ -1,4 +1,4 @@
-error: any use of this value will cause an error
+error[E0080]: any use of this value will cause an error
   --> $DIR/assert.rs:10:15
    |
 LL | const _: () = assert!(false);
@@ -6,10 +6,8 @@ LL | const _: () = assert!(false);
    |               |
    |               the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:10:15
    |
-   = note: `#[deny(const_err)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
    = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/control-flow/assert.rs b/src/test/ui/consts/control-flow/assert.rs
index a21f28604bd..90017fee193 100644
--- a/src/test/ui/consts/control-flow/assert.rs
+++ b/src/test/ui/consts/control-flow/assert.rs
@@ -10,6 +10,5 @@ const _: () = assert!(true);
 const _: () = assert!(false);
 //[stock]~^ ERROR panicking in constants is unstable
 //[const_panic]~^^ ERROR any use of this value will cause an error
-//[const_panic]~| WARN this was previously accepted by the compiler but is being phased out
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs
index e46127c36bf..b7904e6841b 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs
@@ -133,13 +133,13 @@ const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
 //~^ ERROR trait bounds other than `Sized`
 const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
 //~^ ERROR trait bounds other than `Sized`
-//~| ERROR unsizing cast
-//~| ERROR unsizing cast
 
 const fn no_unsafe() { unsafe {} }
 
 const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-//~^ ERROR unsizing cast
+//~^ ERROR trait bounds other than `Sized`
+//~| ERROR trait bounds other than `Sized`
+//~| ERROR trait bounds other than `Sized`
 
 const fn no_fn_ptrs(_x: fn()) {}
 //~^ ERROR function pointer
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
index e6ce7e12520..d31d4121936 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr
@@ -288,32 +288,32 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: unsizing casts to types besides slices are not allowed in const fn
-  --> $DIR/min_const_fn.rs:134:63
+error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:139:41
    |
-LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-   |                                                               ^^^
+LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
+   |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information
-   = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: unsizing casts to types besides slices are not allowed in const fn
-  --> $DIR/min_const_fn.rs:134:63
+error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:139:42
    |
-LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
-   |                                                               ^^^
+LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information
-   = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: unsizing casts to types besides slices are not allowed in const fn
-  --> $DIR/min_const_fn.rs:141:42
+error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
+  --> $DIR/min_const_fn.rs:139:42
    |
 LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 }
-   |                                          ^^^
+   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information
-   = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: function pointers cannot appear in constant functions
   --> $DIR/min_const_fn.rs:144:21
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
index 4a22ef2dffd..6ca1e59b3af 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs
@@ -10,6 +10,6 @@ const fn no_inner_dyn_trait2(x: Hide) {
 //~^ ERROR trait bounds other than `Sized`
 }
 const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
-//~^ ERROR unsizing cast
+//~^ ERROR trait bounds other than `Sized`
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
index cf635d65699..ce844a2f071 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
@@ -7,14 +7,14 @@ LL |     x.0.field;
    = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
-error[E0658]: unsizing casts to types besides slices are not allowed in const fn
+error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
   --> $DIR/min_const_fn_dyn.rs:12:66
    |
 LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
    |                                                                  ^^
    |
-   = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information
-   = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable
+   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/miri_unleashed/tls.stderr b/src/test/ui/consts/miri_unleashed/tls.stderr
index 62e2dc71210..30309da499f 100644
--- a/src/test/ui/consts/miri_unleashed/tls.stderr
+++ b/src/test/ui/consts/miri_unleashed/tls.stderr
@@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/tls.rs:12:25
    |
 LL |     unsafe { let _val = A; }
-   |                         ^ cannot access thread local static (DefId(0:6 ~ tls[317d]::A))
+   |                         ^ cannot access thread local static (DefId(0:6 ~ tls[f423]::A))
 
 error[E0080]: could not evaluate static initializer
   --> $DIR/tls.rs:19:26
    |
 LL |     unsafe { let _val = &A; }
-   |                          ^ cannot access thread local static (DefId(0:6 ~ tls[317d]::A))
+   |                          ^ cannot access thread local static (DefId(0:6 ~ tls[f423]::A))
 
 warning: skipping const checks
    |
diff --git a/src/test/ui/consts/unsizing-cast-non-null.rs b/src/test/ui/consts/unsizing-cast-non-null.rs
deleted file mode 100644
index af6bc2d85fd..00000000000
--- a/src/test/ui/consts/unsizing-cast-non-null.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Regression test for #75118.
-
-use std::ptr::NonNull;
-
-pub const fn dangling_slice<T>() -> NonNull<[T]> {
-    NonNull::<[T; 0]>::dangling()
-    //~^ ERROR: unsizing casts to types besides slices
-}
-
-fn main() {}
diff --git a/src/test/ui/consts/unsizing-cast-non-null.stderr b/src/test/ui/consts/unsizing-cast-non-null.stderr
deleted file mode 100644
index 79691cddfb4..00000000000
--- a/src/test/ui/consts/unsizing-cast-non-null.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: unsizing casts to types besides slices are not allowed in const fn
-  --> $DIR/unsizing-cast-non-null.rs:6:5
-   |
-LL |     NonNull::<[T; 0]>::dangling()
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information
-   = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/dep-graph/dep-graph-check-attr.rs b/src/test/ui/dep-graph/dep-graph-check-attr.rs
index 1026efc1b1d..a45bf24f8c1 100644
--- a/src/test/ui/dep-graph/dep-graph-check-attr.rs
+++ b/src/test/ui/dep-graph/dep-graph-check-attr.rs
@@ -5,7 +5,7 @@
 #![allow(dead_code)]
 #![allow(unused_variables)]
 
-#[rustc_dirty(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph
+#[rustc_clean(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph
 fn main() {}
 
 #[rustc_if_this_changed(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph
diff --git a/src/test/ui/dep-graph/dep-graph-check-attr.stderr b/src/test/ui/dep-graph/dep-graph-check-attr.stderr
index 945a4237c12..46f4e4358cf 100644
--- a/src/test/ui/dep-graph/dep-graph-check-attr.stderr
+++ b/src/test/ui/dep-graph/dep-graph-check-attr.stderr
@@ -1,7 +1,7 @@
 error: attribute requires -Z query-dep-graph to be enabled
   --> $DIR/dep-graph-check-attr.rs:8:1
    |
-LL | #[rustc_dirty(hir_owner)]
+LL | #[rustc_clean(hir_owner)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: attribute requires -Z query-dep-graph to be enabled
diff --git a/src/test/ui/deprecation/deprecation-lint.stderr b/src/test/ui/deprecation/deprecation-lint.stderr
index 3699a939e27..20af4f62e65 100644
--- a/src/test/ui/deprecation/deprecation-lint.stderr
+++ b/src/test/ui/deprecation/deprecation-lint.stderr
@@ -11,16 +11,16 @@ LL | #![deny(deprecated)]
    |         ^^^^^^^^^^
 
 error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text
-  --> $DIR/deprecation-lint.rs:21:9
+  --> $DIR/deprecation-lint.rs:21:16
    |
 LL |         Trait::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text
-  --> $DIR/deprecation-lint.rs:23:9
+  --> $DIR/deprecation-lint.rs:23:25
    |
 LL |         <Foo as Trait>::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^
 
 error: use of deprecated function `deprecation_lint::deprecated_text`: text
   --> $DIR/deprecation-lint.rs:25:9
@@ -29,16 +29,16 @@ LL |         deprecated_text();
    |         ^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text
-  --> $DIR/deprecation-lint.rs:30:9
+  --> $DIR/deprecation-lint.rs:30:16
    |
 LL | ...   Trait::trait_deprecated_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text
-  --> $DIR/deprecation-lint.rs:32:9
+  --> $DIR/deprecation-lint.rs:32:25
    |
 LL | ...   <Foo as Trait>::trait_deprecated_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated struct `deprecation_lint::DeprecatedStruct`: text
   --> $DIR/deprecation-lint.rs:34:17
@@ -53,10 +53,10 @@ LL |         let _ = DeprecatedUnitStruct;
    |                 ^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated variant `deprecation_lint::Enum::DeprecatedVariant`: text
-  --> $DIR/deprecation-lint.rs:40:17
+  --> $DIR/deprecation-lint.rs:40:23
    |
 LL |         let _ = Enum::DeprecatedVariant;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^
 
 error: use of deprecated struct `deprecation_lint::DeprecatedTupleStruct`: text
   --> $DIR/deprecation-lint.rs:42:17
@@ -65,28 +65,28 @@ LL |         let _ = DeprecatedTupleStruct (1);
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated struct `deprecation_lint::nested::DeprecatedStruct`: text
-  --> $DIR/deprecation-lint.rs:44:17
+  --> $DIR/deprecation-lint.rs:44:25
    |
 LL |         let _ = nested::DeprecatedStruct {
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^
 
 error: use of deprecated struct `deprecation_lint::nested::DeprecatedUnitStruct`: text
-  --> $DIR/deprecation-lint.rs:48:17
+  --> $DIR/deprecation-lint.rs:48:25
    |
 LL |         let _ = nested::DeprecatedUnitStruct;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated variant `deprecation_lint::nested::Enum::DeprecatedVariant`: text
-  --> $DIR/deprecation-lint.rs:50:17
+  --> $DIR/deprecation-lint.rs:50:31
    |
 LL | ...   let _ = nested::Enum::DeprecatedVariant;
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^^^^^^^^^
 
 error: use of deprecated struct `deprecation_lint::nested::DeprecatedTupleStruct`: text
-  --> $DIR/deprecation-lint.rs:52:17
+  --> $DIR/deprecation-lint.rs:52:25
    |
 LL | ...   let _ = nested::DeprecatedTupleStruct (1);
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated function `deprecation_lint::deprecated_text`: text
   --> $DIR/deprecation-lint.rs:59:25
@@ -101,28 +101,28 @@ LL |         macro_test_arg!(macro_test_arg!(deprecated_text()));
    |                                         ^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text
-  --> $DIR/deprecation-lint.rs:65:9
+  --> $DIR/deprecation-lint.rs:65:16
    |
 LL |         Trait::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text
-  --> $DIR/deprecation-lint.rs:67:9
+  --> $DIR/deprecation-lint.rs:67:25
    |
 LL |         <Foo as Trait>::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text
-  --> $DIR/deprecation-lint.rs:69:9
+  --> $DIR/deprecation-lint.rs:69:16
    |
 LL | ...   Trait::trait_deprecated_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text
-  --> $DIR/deprecation-lint.rs:71:9
+  --> $DIR/deprecation-lint.rs:71:25
    |
 LL | ...   <Foo as Trait>::trait_deprecated_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated trait `deprecation_lint::DeprecatedTrait`: text
   --> $DIR/deprecation-lint.rs:81:10
@@ -173,10 +173,10 @@ LL |         let Deprecated2
    |             ^^^^^^^^^^^
 
 error: use of deprecated function `deprecation_lint::deprecated_mod::deprecated`: text
-  --> $DIR/deprecation-lint.rs:162:9
+  --> $DIR/deprecation-lint.rs:162:25
    |
 LL |         deprecated_mod::deprecated();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^
 
 error: use of deprecated function `this_crate::deprecated`: text
   --> $DIR/deprecation-lint.rs:245:9
@@ -185,16 +185,16 @@ LL |         deprecated();
    |         ^^^^^^^^^^
 
 error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
-  --> $DIR/deprecation-lint.rs:250:9
+  --> $DIR/deprecation-lint.rs:250:16
    |
 LL |         Trait::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
-  --> $DIR/deprecation-lint.rs:252:9
+  --> $DIR/deprecation-lint.rs:252:25
    |
 LL |         <Foo as Trait>::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^
 
 error: use of deprecated function `this_crate::deprecated_text`: text
   --> $DIR/deprecation-lint.rs:254:9
@@ -203,16 +203,16 @@ LL |         deprecated_text();
    |         ^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
-  --> $DIR/deprecation-lint.rs:259:9
+  --> $DIR/deprecation-lint.rs:259:16
    |
 LL |         Trait::trait_deprecated_text(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
-  --> $DIR/deprecation-lint.rs:261:9
+  --> $DIR/deprecation-lint.rs:261:25
    |
 LL | ...   <Foo as Trait>::trait_deprecated_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated function `this_crate::deprecated_future`: text
   --> $DIR/deprecation-lint.rs:264:9
@@ -239,10 +239,10 @@ LL |         let _ = DeprecatedUnitStruct;
    |                 ^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated unit variant `this_crate::Enum::DeprecatedVariant`: text
-  --> $DIR/deprecation-lint.rs:274:17
+  --> $DIR/deprecation-lint.rs:274:23
    |
 LL |         let _ = Enum::DeprecatedVariant;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^
 
 error: use of deprecated tuple struct `this_crate::DeprecatedTupleStruct`: text
   --> $DIR/deprecation-lint.rs:276:17
@@ -251,52 +251,52 @@ LL |         let _ = DeprecatedTupleStruct (1);
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated struct `this_crate::nested::DeprecatedStruct`: text
-  --> $DIR/deprecation-lint.rs:278:17
+  --> $DIR/deprecation-lint.rs:278:25
    |
 LL |         let _ = nested::DeprecatedStruct {
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^
 
 error: use of deprecated unit struct `this_crate::nested::DeprecatedUnitStruct`: text
-  --> $DIR/deprecation-lint.rs:283:17
+  --> $DIR/deprecation-lint.rs:283:25
    |
 LL |         let _ = nested::DeprecatedUnitStruct;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated unit variant `this_crate::nested::Enum::DeprecatedVariant`: text
-  --> $DIR/deprecation-lint.rs:285:17
+  --> $DIR/deprecation-lint.rs:285:31
    |
 LL | ...   let _ = nested::Enum::DeprecatedVariant;
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                             ^^^^^^^^^^^^^^^^^
 
 error: use of deprecated tuple struct `this_crate::nested::DeprecatedTupleStruct`: text
-  --> $DIR/deprecation-lint.rs:287:17
+  --> $DIR/deprecation-lint.rs:287:25
    |
 LL | ...   let _ = nested::DeprecatedTupleStruct (1);
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
-  --> $DIR/deprecation-lint.rs:292:9
+  --> $DIR/deprecation-lint.rs:292:16
    |
 LL |         Trait::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
-  --> $DIR/deprecation-lint.rs:294:9
+  --> $DIR/deprecation-lint.rs:294:25
    |
 LL |         <Foo as Trait>::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
-  --> $DIR/deprecation-lint.rs:296:9
+  --> $DIR/deprecation-lint.rs:296:16
    |
 LL |         Trait::trait_deprecated_text(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
-  --> $DIR/deprecation-lint.rs:298:9
+  --> $DIR/deprecation-lint.rs:298:25
    |
 LL | ...   <Foo as Trait>::trait_deprecated_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar`
   --> $DIR/deprecation-lint.rs:316:13
diff --git a/src/test/ui/deprecation/suggestion.fixed b/src/test/ui/deprecation/suggestion.fixed
index eba72f88a89..1ba1821e6c1 100644
--- a/src/test/ui/deprecation/suggestion.fixed
+++ b/src/test/ui/deprecation/suggestion.fixed
@@ -1,9 +1,7 @@
 // run-rustfix
 
 #![feature(staged_api)]
-
 #![stable(since = "1.0.0", feature = "test")]
-
 #![deny(deprecated)]
 #![allow(dead_code)]
 
@@ -21,8 +19,21 @@ impl Foo {
     fn replacement(&self) {}
 }
 
+mod bar {
+    #[rustc_deprecated(
+    since = "1.0.0",
+    reason = "replaced by `replacement`",
+    suggestion = "replacement",
+    )]
+    #[stable(since = "1.0.0", feature = "test")]
+    pub fn deprecated() {}
+
+    pub fn replacement() {}
+}
+
 fn main() {
     let foo = Foo;
-
     foo.replacement(); //~ ERROR use of deprecated
+
+    bar::replacement(); //~ ERROR use of deprecated
 }
diff --git a/src/test/ui/deprecation/suggestion.rs b/src/test/ui/deprecation/suggestion.rs
index 8f9791c13e8..e40737d1957 100644
--- a/src/test/ui/deprecation/suggestion.rs
+++ b/src/test/ui/deprecation/suggestion.rs
@@ -1,9 +1,7 @@
 // run-rustfix
 
 #![feature(staged_api)]
-
 #![stable(since = "1.0.0", feature = "test")]
-
 #![deny(deprecated)]
 #![allow(dead_code)]
 
@@ -21,8 +19,21 @@ impl Foo {
     fn replacement(&self) {}
 }
 
+mod bar {
+    #[rustc_deprecated(
+    since = "1.0.0",
+    reason = "replaced by `replacement`",
+    suggestion = "replacement",
+    )]
+    #[stable(since = "1.0.0", feature = "test")]
+    pub fn deprecated() {}
+
+    pub fn replacement() {}
+}
+
 fn main() {
     let foo = Foo;
-
     foo.deprecated(); //~ ERROR use of deprecated
+
+    bar::deprecated(); //~ ERROR use of deprecated
 }
diff --git a/src/test/ui/deprecation/suggestion.stderr b/src/test/ui/deprecation/suggestion.stderr
index 8a7cb1def90..b95ca3a75e4 100644
--- a/src/test/ui/deprecation/suggestion.stderr
+++ b/src/test/ui/deprecation/suggestion.stderr
@@ -1,14 +1,20 @@
-error: use of deprecated associated function `Foo::deprecated`: replaced by `replacement`
-  --> $DIR/suggestion.rs:27:9
+error: use of deprecated function `bar::deprecated`: replaced by `replacement`
+  --> $DIR/suggestion.rs:38:10
    |
-LL |     foo.deprecated();
-   |         ^^^^^^^^^^ help: replace the use of the deprecated associated function: `replacement`
+LL |     bar::deprecated();
+   |          ^^^^^^^^^^ help: replace the use of the deprecated function: `replacement`
    |
 note: the lint level is defined here
-  --> $DIR/suggestion.rs:7:9
+  --> $DIR/suggestion.rs:5:9
    |
 LL | #![deny(deprecated)]
    |         ^^^^^^^^^^
 
-error: aborting due to previous error
+error: use of deprecated associated function `Foo::deprecated`: replaced by `replacement`
+  --> $DIR/suggestion.rs:36:9
+   |
+LL |     foo.deprecated();
+   |         ^^^^^^^^^^ help: replace the use of the deprecated associated function: `replacement`
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/derives/derive-macro-const-default.rs b/src/test/ui/derives/derive-macro-const-default.rs
index a844f2d2023..7c4ebca8746 100644
--- a/src/test/ui/derives/derive-macro-const-default.rs
+++ b/src/test/ui/derives/derive-macro-const-default.rs
@@ -1,5 +1,4 @@
 // check-pass
-#![allow(incomplete_features)]
 #![feature(const_generics_defaults)]
 
 #[derive(Clone, PartialEq, Debug)]
diff --git a/src/test/ui/error-codes/E0107.rs b/src/test/ui/error-codes/E0107.rs
index f7f6afa860e..840700c9cc6 100644
--- a/src/test/ui/error-codes/E0107.rs
+++ b/src/test/ui/error-codes/E0107.rs
@@ -1,5 +1,7 @@
 struct Foo<'a>(&'a str);
 struct Buzz<'a, 'b>(&'a str, &'b str);
+struct Qux<'a, T>(&'a T);
+struct Quux<T>(T);
 
 enum Bar {
     A,
@@ -19,6 +21,30 @@ struct Baz<'a, 'b, 'c> {
     foo2: Foo<'a, 'b, 'c>,
     //~^ ERROR this struct takes 1 lifetime argument
     //~| HELP remove these lifetime arguments
+
+    qux1: Qux<'a, 'b, i32>,
+    //~^ ERROR this struct takes 1 lifetime argument
+    //~| HELP remove this lifetime argument
+
+    qux2: Qux<'a, i32, 'b>,
+    //~^ ERROR this struct takes 1 lifetime argument
+    //~| HELP remove this lifetime argument
+
+    qux3: Qux<'a, 'b, 'c, i32>,
+    //~^ ERROR this struct takes 1 lifetime argument
+    //~| HELP remove these lifetime arguments
+
+    qux4: Qux<'a, i32, 'b, 'c>,
+    //~^ ERROR this struct takes 1 lifetime argument
+    //~| HELP remove these lifetime arguments
+
+    qux5: Qux<'a, 'b, i32, 'c>,
+    //~^ ERROR this struct takes 1 lifetime argument
+    //~| HELP remove this lifetime argument
+
+    quux: Quux<'a, i32, 'b>,
+    //~^ ERROR this struct takes 0 lifetime arguments
+    //~| HELP remove this lifetime argument
 }
 
 fn main() {}
diff --git a/src/test/ui/error-codes/E0107.stderr b/src/test/ui/error-codes/E0107.stderr
index 299776b08f2..3c7aa6de541 100644
--- a/src/test/ui/error-codes/E0107.stderr
+++ b/src/test/ui/error-codes/E0107.stderr
@@ -1,5 +1,5 @@
 error[E0107]: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/E0107.rs:11:11
+  --> $DIR/E0107.rs:13:11
    |
 LL |     buzz: Buzz<'a>,
    |           ^^^^ -- supplied 1 lifetime argument
@@ -17,7 +17,7 @@ LL |     buzz: Buzz<'a, 'a>,
    |                  ^^^^
 
 error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/E0107.rs:15:10
+  --> $DIR/E0107.rs:17:10
    |
 LL |     bar: Bar<'a>,
    |          ^^^---- help: remove these generics
@@ -25,13 +25,13 @@ LL |     bar: Bar<'a>,
    |          expected 0 lifetime arguments
    |
 note: enum defined here, with 0 lifetime parameters
-  --> $DIR/E0107.rs:4:6
+  --> $DIR/E0107.rs:6:6
    |
 LL | enum Bar {
    |      ^^^
 
 error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
-  --> $DIR/E0107.rs:19:11
+  --> $DIR/E0107.rs:21:11
    |
 LL |     foo2: Foo<'a, 'b, 'c>,
    |           ^^^     ------ help: remove these lifetime arguments
@@ -44,6 +44,90 @@ note: struct defined here, with 1 lifetime parameter: `'a`
 LL | struct Foo<'a>(&'a str);
    |        ^^^ --
 
-error: aborting due to 3 previous errors
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+  --> $DIR/E0107.rs:25:11
+   |
+LL |     qux1: Qux<'a, 'b, i32>,
+   |           ^^^     -- help: remove this lifetime argument
+   |           |
+   |           expected 1 lifetime argument
+   |
+note: struct defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/E0107.rs:3:8
+   |
+LL | struct Qux<'a, T>(&'a T);
+   |        ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+  --> $DIR/E0107.rs:29:11
+   |
+LL |     qux2: Qux<'a, i32, 'b>,
+   |           ^^^          -- help: remove this lifetime argument
+   |           |
+   |           expected 1 lifetime argument
+   |
+note: struct defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/E0107.rs:3:8
+   |
+LL | struct Qux<'a, T>(&'a T);
+   |        ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+  --> $DIR/E0107.rs:33:11
+   |
+LL |     qux3: Qux<'a, 'b, 'c, i32>,
+   |           ^^^     ------ help: remove these lifetime arguments
+   |           |
+   |           expected 1 lifetime argument
+   |
+note: struct defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/E0107.rs:3:8
+   |
+LL | struct Qux<'a, T>(&'a T);
+   |        ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+  --> $DIR/E0107.rs:37:11
+   |
+LL |     qux4: Qux<'a, i32, 'b, 'c>,
+   |           ^^^          ------ help: remove these lifetime arguments
+   |           |
+   |           expected 1 lifetime argument
+   |
+note: struct defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/E0107.rs:3:8
+   |
+LL | struct Qux<'a, T>(&'a T);
+   |        ^^^ --
+
+error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied
+  --> $DIR/E0107.rs:41:11
+   |
+LL |     qux5: Qux<'a, 'b, i32, 'c>,
+   |           ^^^     -- help: remove this lifetime argument
+   |           |
+   |           expected 1 lifetime argument
+   |
+note: struct defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/E0107.rs:3:8
+   |
+LL | struct Qux<'a, T>(&'a T);
+   |        ^^^ --
+
+error[E0107]: this struct takes 0 lifetime arguments but 2 lifetime arguments were supplied
+  --> $DIR/E0107.rs:45:11
+   |
+LL |     quux: Quux<'a, i32, 'b>,
+   |           ^^^^ -- help: remove this lifetime argument
+   |           |
+   |           expected 0 lifetime arguments
+   |
+note: struct defined here, with 0 lifetime parameters
+  --> $DIR/E0107.rs:4:8
+   |
+LL | struct Quux<T>(T);
+   |        ^^^^
+
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr
index 43269c095d6..6314e7a3a8a 100644
--- a/src/test/ui/error-codes/E0605.stderr
+++ b/src/test/ui/error-codes/E0605.stderr
@@ -8,7 +8,12 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8`
   --> $DIR/E0605.rs:6:5
    |
 LL |     v as &u8;
-   |     ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+   |     ^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     &*v as &u8;
+   |     ^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr
index 04efea0b230..df0de7a9590 100644
--- a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr
+++ b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr
@@ -58,6 +58,14 @@ LL | const unsafe fn unsafe_transmute_fn_core_intrinsic() -> u32 { core::intrins
    = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable
    = note: `transmute` is only allowed in constants and statics for now
 
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+  --> $DIR/feature-gate-const_fn_transmute.rs:29:39
+   |
+LL | const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) }
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
 error[E0658]: `transmute` is not allowed in constant functions
   --> $DIR/feature-gate-const_fn_transmute.rs:29:39
    |
@@ -68,49 +76,41 @@ LL | const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) }
    = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable
    = note: `transmute` is only allowed in constants and statics for now
 
-error[E0658]: `transmute` is not allowed in constant functions
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
   --> $DIR/feature-gate-const_fn_transmute.rs:33:49
    |
 LL | const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) }
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
    |
-   = note: see issue #53605 <https://github.com/rust-lang/rust/issues/53605> for more information
-   = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable
-   = note: `transmute` is only allowed in constants and statics for now
+   = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0658]: `transmute` is not allowed in constant functions
-  --> $DIR/feature-gate-const_fn_transmute.rs:37:54
+  --> $DIR/feature-gate-const_fn_transmute.rs:33:49
    |
-LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) }
-   |                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) }
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #53605 <https://github.com/rust-lang/rust/issues/53605> for more information
    = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable
    = note: `transmute` is only allowed in constants and statics for now
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/feature-gate-const_fn_transmute.rs:29:39
-   |
-LL | const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) }
-   |                                       ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
-   |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
-
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/feature-gate-const_fn_transmute.rs:33:49
+  --> $DIR/feature-gate-const_fn_transmute.rs:37:54
    |
-LL | const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) }
-   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) }
+   |                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
    |
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
-error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+error[E0658]: `transmute` is not allowed in constant functions
   --> $DIR/feature-gate-const_fn_transmute.rs:37:54
    |
 LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) }
-   |                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
+   |                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: consult the function's documentation for information on how to avoid undefined behavior
+   = note: see issue #53605 <https://github.com/rust-lang/rust/issues/53605> for more information
+   = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable
+   = note: `transmute` is only allowed in constants and statics for now
 
 error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs
deleted file mode 100644
index f19fdb45f1f..00000000000
--- a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#[cfg(FALSE)]
-#[attr = multi::segment::path] //~ ERROR arbitrary expressions in key-value attributes are unstable
-#[attr = macro_call!()] //~ ERROR arbitrary expressions in key-value attributes are unstable
-#[attr = 1 + 2] //~ ERROR arbitrary expressions in key-value attributes are unstable
-#[attr = what?] //~ ERROR arbitrary expressions in key-value attributes are unstable
-struct S;
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr
deleted file mode 100644
index 9887814b907..00000000000
--- a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr
+++ /dev/null
@@ -1,39 +0,0 @@
-error[E0658]: arbitrary expressions in key-value attributes are unstable
-  --> $DIR/feature-gate-extended_key_value_attributes.rs:2:10
-   |
-LL | #[attr = multi::segment::path]
-   |          ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #78835 <https://github.com/rust-lang/rust/issues/78835> for more information
-   = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable
-
-error[E0658]: arbitrary expressions in key-value attributes are unstable
-  --> $DIR/feature-gate-extended_key_value_attributes.rs:3:10
-   |
-LL | #[attr = macro_call!()]
-   |          ^^^^^^^^^^^^^
-   |
-   = note: see issue #78835 <https://github.com/rust-lang/rust/issues/78835> for more information
-   = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable
-
-error[E0658]: arbitrary expressions in key-value attributes are unstable
-  --> $DIR/feature-gate-extended_key_value_attributes.rs:4:10
-   |
-LL | #[attr = 1 + 2]
-   |          ^^^^^
-   |
-   = note: see issue #78835 <https://github.com/rust-lang/rust/issues/78835> for more information
-   = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable
-
-error[E0658]: arbitrary expressions in key-value attributes are unstable
-  --> $DIR/feature-gate-extended_key_value_attributes.rs:5:10
-   |
-LL | #[attr = what?]
-   |          ^^^^^
-   |
-   = note: see issue #78835 <https://github.com/rust-lang/rust/issues/78835> for more information
-   = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.rs b/src/test/ui/feature-gates/feature-gate-member-constraints.rs
deleted file mode 100644
index f6a92b0d0bf..00000000000
--- a/src/test/ui/feature-gates/feature-gate-member-constraints.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-trait Trait<'a, 'b> {}
-impl<T> Trait<'_, '_> for T {}
-
-fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
-    //~^ ERROR ambiguous lifetime bound
-    //~| ERROR ambiguous lifetime bound
-    (x, y)
-}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr b/src/test/ui/feature-gates/feature-gate-member-constraints.stderr
deleted file mode 100644
index c2ec7ae16a3..00000000000
--- a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: ambiguous lifetime bound in `impl Trait`
-  --> $DIR/feature-gate-member-constraints.rs:4:43
-   |
-LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
-   |                                           ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other
-   |
-   = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: ambiguous lifetime bound in `impl Trait`
-  --> $DIR/feature-gate-member-constraints.rs:4:43
-   |
-LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> {
-   |                                           ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another
-   |
-   = help: add #![feature(member_constraints)] to the crate attributes to enable
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.stderr b/src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr
index 0bd3dbf6863..3afbea07931 100644
--- a/src/test/ui/generator/issue-45729-unsafe-in-generator.stderr
+++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/issue-45729-unsafe-in-generator.rs:5:9
+  --> $DIR/issue-45729-unsafe-in-generator.rs:8:9
    |
 LL |         *(1 as *mut u32) = 42;
    |         ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.rs b/src/test/ui/generator/issue-45729-unsafe-in-generator.rs
index 638a1994bb5..379c36d2ca3 100644
--- a/src/test/ui/generator/issue-45729-unsafe-in-generator.rs
+++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![feature(generators)]
 
 fn main() {
diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr b/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr
new file mode 100644
index 00000000000..10d768f19fc
--- /dev/null
+++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-45729-unsafe-in-generator.rs:8:9
+   |
+LL |         *(1 as *mut u32) = 42;
+   |         ^^^^^^^^^^^^^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr
index 78100318dc3..bd0d27ff3e9 100644
--- a/src/test/ui/generator/print/generator-print-verbose-1.stderr
+++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr
@@ -12,7 +12,7 @@ note: generator is not `Send` as this value is used across a yield
   --> $DIR/generator-print-verbose-1.rs:35:9
    |
 LL |         let _non_send_gen = make_non_send_generator();
-   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[317d]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[70c9]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
 LL |         yield;
    |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
 LL |     };
@@ -30,10 +30,10 @@ LL |     require_send(send_gen);
    = help: the trait `Sync` is not implemented for `RefCell<i32>`
    = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>`
    = note: required because it appears within the type `[make_gen2<Arc<RefCell<i32>>>::{closure#0} upvar_tys=(Arc<RefCell<i32>>) {()}]`
-   = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[317d]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
-   = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), [])`
-   = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}`
-   = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}]`
+   = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[70c9]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])`
+   = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), [])`
+   = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), []), ()}`
+   = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), []), ()}]`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/generator/static-mut-reference-across-yield.rs b/src/test/ui/generator/static-mut-reference-across-yield.rs
index 2926bba9978..0fa6d9cdc77 100644
--- a/src/test/ui/generator/static-mut-reference-across-yield.rs
+++ b/src/test/ui/generator/static-mut-reference-across-yield.rs
@@ -1,4 +1,7 @@
 // build-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
 #![feature(generators)]
 
 static mut A: [i32; 5] = [1, 2, 3, 4, 5];
diff --git a/src/test/ui/generics/wrong-number-of-args.rs b/src/test/ui/generics/wrong-number-of-args.rs
index ec2ed9926e2..272cd361968 100644
--- a/src/test/ui/generics/wrong-number-of-args.rs
+++ b/src/test/ui/generics/wrong-number-of-args.rs
@@ -66,6 +66,12 @@ mod lifetime_and_type {
     //~| ERROR missing lifetime specifier
     //~| HELP consider introducing
     //~| HELP add missing
+
+    type F = Ty<'static, usize, 'static, usize>;
+    //~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments
+    //~| ERROR this struct takes 1 generic argument but 2 generic arguments
+    //~| HELP remove this lifetime argument
+    //~| HELP remove this generic argument
 }
 
 mod type_and_type_and_type {
diff --git a/src/test/ui/generics/wrong-number-of-args.stderr b/src/test/ui/generics/wrong-number-of-args.stderr
index 17a924cedad..4e921db8c25 100644
--- a/src/test/ui/generics/wrong-number-of-args.stderr
+++ b/src/test/ui/generics/wrong-number-of-args.stderr
@@ -213,14 +213,42 @@ help: consider introducing a named lifetime parameter
 LL |     type E<'a> = Ty<'a>;
    |           ^^^^      ^^
 
+error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied
+  --> $DIR/wrong-number-of-args.rs:70:14
+   |
+LL |     type F = Ty<'static, usize, 'static, usize>;
+   |              ^^                 ------- help: remove this lifetime argument
+   |              |
+   |              expected 1 lifetime argument
+   |
+note: struct defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/wrong-number-of-args.rs:46:12
+   |
+LL |     struct Ty<'a, T>;
+   |            ^^ --
+
+error[E0107]: this struct takes 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/wrong-number-of-args.rs:70:14
+   |
+LL |     type F = Ty<'static, usize, 'static, usize>;
+   |              ^^                          ----- help: remove this generic argument
+   |              |
+   |              expected 1 generic argument
+   |
+note: struct defined here, with 1 generic parameter: `T`
+  --> $DIR/wrong-number-of-args.rs:46:12
+   |
+LL |     struct Ty<'a, T>;
+   |            ^^     -
+
 error[E0107]: missing generics for struct `type_and_type_and_type::Ty`
-  --> $DIR/wrong-number-of-args.rs:74:14
+  --> $DIR/wrong-number-of-args.rs:80:14
    |
 LL |     type A = Ty;
    |              ^^ expected at least 2 generic arguments
    |
 note: struct defined here, with at least 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:72:12
+  --> $DIR/wrong-number-of-args.rs:78:12
    |
 LL |     struct Ty<A, B, C = &'static str>;
    |            ^^ -  -
@@ -230,7 +258,7 @@ LL |     type A = Ty<A, B>;
    |              ^^^^^^^^
 
 error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:78:14
+  --> $DIR/wrong-number-of-args.rs:84:14
    |
 LL |     type B = Ty<usize>;
    |              ^^ ----- supplied 1 generic argument
@@ -238,7 +266,7 @@ LL |     type B = Ty<usize>;
    |              expected at least 2 generic arguments
    |
 note: struct defined here, with at least 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:72:12
+  --> $DIR/wrong-number-of-args.rs:78:12
    |
 LL |     struct Ty<A, B, C = &'static str>;
    |            ^^ -  -
@@ -248,7 +276,7 @@ LL |     type B = Ty<usize, B>;
    |                      ^^^
 
 error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:86:14
+  --> $DIR/wrong-number-of-args.rs:92:14
    |
 LL |     type E = Ty<usize, String, char, f64>;
    |              ^^                      --- help: remove this generic argument
@@ -256,19 +284,19 @@ LL |     type E = Ty<usize, String, char, f64>;
    |              expected at most 3 generic arguments
    |
 note: struct defined here, with at most 3 generic parameters: `A`, `B`, `C`
-  --> $DIR/wrong-number-of-args.rs:72:12
+  --> $DIR/wrong-number-of-args.rs:78:12
    |
 LL |     struct Ty<A, B, C = &'static str>;
    |            ^^ -  -  -
 
 error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:90:14
+  --> $DIR/wrong-number-of-args.rs:96:14
    |
 LL |     type F = Ty<>;
    |              ^^ expected at least 2 generic arguments
    |
 note: struct defined here, with at least 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:72:12
+  --> $DIR/wrong-number-of-args.rs:78:12
    |
 LL |     struct Ty<A, B, C = &'static str>;
    |            ^^ -  -
@@ -278,7 +306,7 @@ LL |     type F = Ty<A, B>;
    |                 ^^^^
 
 error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:110:22
+  --> $DIR/wrong-number-of-args.rs:116:22
    |
 LL |     type A = Box<dyn NonGeneric<usize>>;
    |                      ^^^^^^^^^^------- help: remove these generics
@@ -286,13 +314,13 @@ LL |     type A = Box<dyn NonGeneric<usize>>;
    |                      expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
-  --> $DIR/wrong-number-of-args.rs:98:11
+  --> $DIR/wrong-number-of-args.rs:104:11
    |
 LL |     trait NonGeneric {
    |           ^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:114:22
+  --> $DIR/wrong-number-of-args.rs:120:22
    |
 LL |     type B = Box<dyn GenericLifetime>;
    |                      ^^^^^^^^^^^^^^^ expected named lifetime parameter
@@ -303,7 +331,7 @@ LL |     type B<'a> = Box<dyn GenericLifetime<'a>>;
    |           ^^^^           ^^^^^^^^^^^^^^^^^^^
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:118:22
+  --> $DIR/wrong-number-of-args.rs:124:22
    |
 LL |     type C = Box<dyn GenericLifetime<'static, 'static>>;
    |                      ^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -311,19 +339,19 @@ LL |     type C = Box<dyn GenericLifetime<'static, 'static>>;
    |                      expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:102:11
+  --> $DIR/wrong-number-of-args.rs:108:11
    |
 LL |     trait GenericLifetime<'a> {
    |           ^^^^^^^^^^^^^^^ --
 
 error[E0107]: missing generics for trait `GenericType`
-  --> $DIR/wrong-number-of-args.rs:122:22
+  --> $DIR/wrong-number-of-args.rs:128:22
    |
 LL |     type D = Box<dyn GenericType>;
    |                      ^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:106:11
+  --> $DIR/wrong-number-of-args.rs:112:11
    |
 LL |     trait GenericType<A> {
    |           ^^^^^^^^^^^ -
@@ -333,7 +361,7 @@ LL |     type D = Box<dyn GenericType<A>>;
    |                      ^^^^^^^^^^^^^^
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:126:22
+  --> $DIR/wrong-number-of-args.rs:132:22
    |
 LL |     type E = Box<dyn GenericType<String, usize>>;
    |                      ^^^^^^^^^^^         ----- help: remove this generic argument
@@ -341,13 +369,13 @@ LL |     type E = Box<dyn GenericType<String, usize>>;
    |                      expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:106:11
+  --> $DIR/wrong-number-of-args.rs:112:11
    |
 LL |     trait GenericType<A> {
    |           ^^^^^^^^^^^ -
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:130:37
+  --> $DIR/wrong-number-of-args.rs:136:37
    |
 LL |     type F = Box<dyn GenericLifetime<>>;
    |                                     ^- expected named lifetime parameter
@@ -358,13 +386,13 @@ LL |     type F<'a> = Box<dyn GenericLifetime<'a>>;
    |           ^^^^                           ^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:134:22
+  --> $DIR/wrong-number-of-args.rs:140:22
    |
 LL |     type G = Box<dyn GenericType<>>;
    |                      ^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:106:11
+  --> $DIR/wrong-number-of-args.rs:112:11
    |
 LL |     trait GenericType<A> {
    |           ^^^^^^^^^^^ -
@@ -374,7 +402,7 @@ LL |     type G = Box<dyn GenericType<A>>;
    |                                  ^
 
 error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:145:26
+  --> $DIR/wrong-number-of-args.rs:151:26
    |
 LL |         type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
    |                          ^^^^^^^^^^^^------------------- help: remove these generics
@@ -382,13 +410,13 @@ LL |         type A = Box<dyn NonGenericAT<usize, AssocTy=()>>;
    |                          expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
-  --> $DIR/wrong-number-of-args.rs:141:15
+  --> $DIR/wrong-number-of-args.rs:147:15
    |
 LL |         trait NonGenericAT {
    |               ^^^^^^^^^^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:155:44
+  --> $DIR/wrong-number-of-args.rs:161:44
    |
 LL |         type A = Box<dyn GenericLifetimeAT<AssocTy=()>>;
    |                                            ^ expected named lifetime parameter
@@ -399,7 +427,7 @@ LL |         type A<'a> = Box<dyn GenericLifetimeAT<'a, AssocTy=()>>;
    |               ^^^^                             ^^^
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:159:26
+  --> $DIR/wrong-number-of-args.rs:165:26
    |
 LL |         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -407,13 +435,13 @@ LL |         type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>;
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:151:15
+  --> $DIR/wrong-number-of-args.rs:157:15
    |
 LL |         trait GenericLifetimeAT<'a> {
    |               ^^^^^^^^^^^^^^^^^ --
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:163:44
+  --> $DIR/wrong-number-of-args.rs:169:44
    |
 LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
    |                                            ^ expected named lifetime parameter
@@ -424,7 +452,7 @@ LL |         type C<'a> = Box<dyn GenericLifetimeAT<'a, (), AssocTy=()>>;
    |               ^^^^                             ^^^
 
 error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:163:26
+  --> $DIR/wrong-number-of-args.rs:169:26
    |
 LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument
@@ -432,19 +460,19 @@ LL |         type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>;
    |                          expected 0 generic arguments
    |
 note: trait defined here, with 0 generic parameters
-  --> $DIR/wrong-number-of-args.rs:151:15
+  --> $DIR/wrong-number-of-args.rs:157:15
    |
 LL |         trait GenericLifetimeAT<'a> {
    |               ^^^^^^^^^^^^^^^^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:175:26
+  --> $DIR/wrong-number-of-args.rs:181:26
    |
 LL |         type A = Box<dyn GenericTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:171:15
+  --> $DIR/wrong-number-of-args.rs:177:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
@@ -454,7 +482,7 @@ LL |         type A = Box<dyn GenericTypeAT<A, AssocTy=()>>;
    |                                        ^^
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:179:26
+  --> $DIR/wrong-number-of-args.rs:185:26
    |
 LL |         type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^     -- help: remove this generic argument
@@ -462,13 +490,13 @@ LL |         type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>;
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:171:15
+  --> $DIR/wrong-number-of-args.rs:177:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
 
 error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:183:26
+  --> $DIR/wrong-number-of-args.rs:189:26
    |
 LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^--------------------- help: remove these generics
@@ -476,19 +504,19 @@ LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
    |                          expected 0 lifetime arguments
    |
 note: trait defined here, with 0 lifetime parameters
-  --> $DIR/wrong-number-of-args.rs:171:15
+  --> $DIR/wrong-number-of-args.rs:177:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:183:26
+  --> $DIR/wrong-number-of-args.rs:189:26
    |
 LL |         type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:171:15
+  --> $DIR/wrong-number-of-args.rs:177:15
    |
 LL |         trait GenericTypeAT<A> {
    |               ^^^^^^^^^^^^^ -
@@ -498,7 +526,7 @@ LL |         type C = Box<dyn GenericTypeAT<'static, A, AssocTy=()>>;
    |                                               ^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:195:48
+  --> $DIR/wrong-number-of-args.rs:201:48
    |
 LL |         type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
    |                                                ^ expected named lifetime parameter
@@ -509,13 +537,13 @@ LL |         type A<'a> = Box<dyn GenericLifetimeTypeAT<'a, AssocTy=()>>;
    |               ^^^^                                 ^^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:195:26
+  --> $DIR/wrong-number-of-args.rs:201:26
    |
 LL |         type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
@@ -525,13 +553,13 @@ LL |         type A = Box<dyn GenericLifetimeTypeAT<A, AssocTy=()>>;
    |                                                ^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:201:26
+  --> $DIR/wrong-number-of-args.rs:207:26
    |
 LL |         type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
@@ -541,7 +569,7 @@ LL |         type B = Box<dyn GenericLifetimeTypeAT<'static, A, AssocTy=()>>;
    |                                                       ^^^
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:205:26
+  --> $DIR/wrong-number-of-args.rs:211:26
    |
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -549,19 +577,19 @@ LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:205:26
+  --> $DIR/wrong-number-of-args.rs:211:26
    |
 LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
@@ -571,7 +599,7 @@ LL |         type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, A, AssocTy
    |                                                                ^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:211:48
+  --> $DIR/wrong-number-of-args.rs:217:48
    |
 LL |         type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>;
    |                                                ^ expected named lifetime parameter
@@ -582,7 +610,7 @@ LL |         type D<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), AssocTy=()>>;
    |               ^^^^                                 ^^^
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/wrong-number-of-args.rs:215:48
+  --> $DIR/wrong-number-of-args.rs:221:48
    |
 LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
    |                                                ^ expected named lifetime parameter
@@ -593,7 +621,7 @@ LL |         type E<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), (), AssocTy=()>>
    |               ^^^^                                 ^^^
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:215:26
+  --> $DIR/wrong-number-of-args.rs:221:26
    |
 LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^     -- help: remove this generic argument
@@ -601,13 +629,13 @@ LL |         type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>;
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:221:26
+  --> $DIR/wrong-number-of-args.rs:227:26
    |
 LL |         type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -615,13 +643,13 @@ LL |         type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocT
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:225:26
+  --> $DIR/wrong-number-of-args.rs:231:26
    |
 LL |         type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^              -- help: remove this generic argument
@@ -629,13 +657,13 @@ LL |         type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
 error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:229:26
+  --> $DIR/wrong-number-of-args.rs:235:26
    |
 LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^          ------- help: remove this lifetime argument
@@ -643,13 +671,13 @@ LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), As
    |                          expected 1 lifetime argument
    |
 note: trait defined here, with 1 lifetime parameter: `'a`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^ --
 
 error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:229:26
+  --> $DIR/wrong-number-of-args.rs:235:26
    |
 LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^                       -- help: remove this generic argument
@@ -657,19 +685,19 @@ LL |         type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), As
    |                          expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:191:15
+  --> $DIR/wrong-number-of-args.rs:197:15
    |
 LL |         trait GenericLifetimeTypeAT<'a, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^     -
 
 error[E0107]: this trait takes 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:241:26
+  --> $DIR/wrong-number-of-args.rs:247:26
    |
 LL |         type A = Box<dyn GenericTypeTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^ expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:237:15
+  --> $DIR/wrong-number-of-args.rs:243:15
    |
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
@@ -679,7 +707,7 @@ LL |         type A = Box<dyn GenericTypeTypeAT<A, B, AssocTy=()>>;
    |                                            ^^^^^
 
 error[E0107]: this trait takes 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:245:26
+  --> $DIR/wrong-number-of-args.rs:251:26
    |
 LL |         type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^ -- supplied 1 generic argument
@@ -687,7 +715,7 @@ LL |         type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>;
    |                          expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:237:15
+  --> $DIR/wrong-number-of-args.rs:243:15
    |
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
@@ -697,7 +725,7 @@ LL |         type B = Box<dyn GenericTypeTypeAT<(), B, AssocTy=()>>;
    |                                              ^^^
 
 error[E0107]: this trait takes 2 generic arguments but 3 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:249:26
+  --> $DIR/wrong-number-of-args.rs:255:26
    |
 LL |         type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^         -- help: remove this generic argument
@@ -705,13 +733,13 @@ LL |         type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>;
    |                          expected 2 generic arguments
    |
 note: trait defined here, with 2 generic parameters: `A`, `B`
-  --> $DIR/wrong-number-of-args.rs:237:15
+  --> $DIR/wrong-number-of-args.rs:243:15
    |
 LL |         trait GenericTypeTypeAT<A, B> {
    |               ^^^^^^^^^^^^^^^^^ -  -
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/wrong-number-of-args.rs:259:52
+  --> $DIR/wrong-number-of-args.rs:265:52
    |
 LL |         type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>;
    |                                                    ^ expected 2 lifetime parameters
@@ -722,7 +750,7 @@ LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>>
    |               ^^^^                                     ^^^^^^^
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:263:26
+  --> $DIR/wrong-number-of-args.rs:269:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
@@ -730,7 +758,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>;
    |                          expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/wrong-number-of-args.rs:255:15
+  --> $DIR/wrong-number-of-args.rs:261:15
    |
 LL |         trait GenericLifetimeLifetimeAT<'a, 'b> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^ --  --
@@ -740,7 +768,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeAT<'static, 'b, AssocTy=()>
    |                                                           ^^^^
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/wrong-number-of-args.rs:273:56
+  --> $DIR/wrong-number-of-args.rs:279:56
    |
 LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
    |                                                        ^ expected 2 lifetime parameters
@@ -751,13 +779,13 @@ LL |         type A<'a> = Box<dyn GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy=
    |               ^^^^                                         ^^^^^^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:273:26
+  --> $DIR/wrong-number-of-args.rs:279:26
    |
 LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:269:15
+  --> $DIR/wrong-number-of-args.rs:275:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         -
@@ -767,7 +795,7 @@ LL |         type A = Box<dyn GenericLifetimeLifetimeTypeAT<A, AssocTy=()>>;
    |                                                        ^^
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:279:26
+  --> $DIR/wrong-number-of-args.rs:285:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
@@ -775,7 +803,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>
    |                          expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/wrong-number-of-args.rs:269:15
+  --> $DIR/wrong-number-of-args.rs:275:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --  --
@@ -785,13 +813,13 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, AssocTy
    |                                                               ^^^^
 
 error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:279:26
+  --> $DIR/wrong-number-of-args.rs:285:26
    |
 LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument
    |
 note: trait defined here, with 1 generic parameter: `A`
-  --> $DIR/wrong-number-of-args.rs:269:15
+  --> $DIR/wrong-number-of-args.rs:275:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         -
@@ -801,7 +829,7 @@ LL |         type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, A, AssocTy=
    |                                                               ^^^
 
 error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:285:26
+  --> $DIR/wrong-number-of-args.rs:291:26
    |
 LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy=()>>;
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument
@@ -809,7 +837,7 @@ LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy
    |                          expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'a`, `'b`
-  --> $DIR/wrong-number-of-args.rs:269:15
+  --> $DIR/wrong-number-of-args.rs:275:15
    |
 LL |         trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --  --
@@ -819,7 +847,7 @@ LL |         type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, (), Ass
    |                                                               ^^^^
 
 error[E0107]: missing generics for struct `HashMap`
-  --> $DIR/wrong-number-of-args.rs:295:18
+  --> $DIR/wrong-number-of-args.rs:301:18
    |
 LL |         type A = HashMap;
    |                  ^^^^^^^ expected at least 2 generic arguments
@@ -835,7 +863,7 @@ LL |         type A = HashMap<K, V>;
    |                  ^^^^^^^^^^^^^
 
 error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:299:18
+  --> $DIR/wrong-number-of-args.rs:305:18
    |
 LL |         type B = HashMap<String>;
    |                  ^^^^^^^ ------ supplied 1 generic argument
@@ -853,7 +881,7 @@ LL |         type B = HashMap<String, V>;
    |                                ^^^
 
 error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:303:18
+  --> $DIR/wrong-number-of-args.rs:309:18
    |
 LL |         type C = HashMap<'static>;
    |                  ^^^^^^^--------- help: remove these generics
@@ -867,7 +895,7 @@ LL | pub struct HashMap<K, V, S = RandomState> {
    |            ^^^^^^^
 
 error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:303:18
+  --> $DIR/wrong-number-of-args.rs:309:18
    |
 LL |         type C = HashMap<'static>;
    |                  ^^^^^^^ expected at least 2 generic arguments
@@ -883,7 +911,7 @@ LL |         type C = HashMap<'static, K, V>;
    |                                 ^^^^^^
 
 error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:309:18
+  --> $DIR/wrong-number-of-args.rs:315:18
    |
 LL |         type D = HashMap<usize, String, char, f64>;
    |                  ^^^^^^^                      --- help: remove this generic argument
@@ -897,7 +925,7 @@ LL | pub struct HashMap<K, V, S = RandomState> {
    |            ^^^^^^^ -  -  -
 
 error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:313:18
+  --> $DIR/wrong-number-of-args.rs:319:18
    |
 LL |         type E = HashMap<>;
    |                  ^^^^^^^ expected at least 2 generic arguments
@@ -913,7 +941,7 @@ LL |         type E = HashMap<K, V>;
    |                          ^^^^
 
 error[E0107]: missing generics for enum `Result`
-  --> $DIR/wrong-number-of-args.rs:319:18
+  --> $DIR/wrong-number-of-args.rs:325:18
    |
 LL |         type A = Result;
    |                  ^^^^^^ expected 2 generic arguments
@@ -929,7 +957,7 @@ LL |         type A = Result<T, E>;
    |                  ^^^^^^^^^^^^
 
 error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied
-  --> $DIR/wrong-number-of-args.rs:323:18
+  --> $DIR/wrong-number-of-args.rs:329:18
    |
 LL |         type B = Result<String>;
    |                  ^^^^^^ ------ supplied 1 generic argument
@@ -947,7 +975,7 @@ LL |         type B = Result<String, E>;
    |                               ^^^
 
 error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/wrong-number-of-args.rs:327:18
+  --> $DIR/wrong-number-of-args.rs:333:18
    |
 LL |         type C = Result<'static>;
    |                  ^^^^^^--------- help: remove these generics
@@ -961,7 +989,7 @@ LL | pub enum Result<T, E> {
    |          ^^^^^^
 
 error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:327:18
+  --> $DIR/wrong-number-of-args.rs:333:18
    |
 LL |         type C = Result<'static>;
    |                  ^^^^^^ expected 2 generic arguments
@@ -977,7 +1005,7 @@ LL |         type C = Result<'static, T, E>;
    |                                ^^^^^^
 
 error[E0107]: this enum takes 2 generic arguments but 3 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:333:18
+  --> $DIR/wrong-number-of-args.rs:339:18
    |
 LL |         type D = Result<usize, String, char>;
    |                  ^^^^^^                ---- help: remove this generic argument
@@ -991,7 +1019,7 @@ LL | pub enum Result<T, E> {
    |          ^^^^^^ -  -
 
 error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied
-  --> $DIR/wrong-number-of-args.rs:337:18
+  --> $DIR/wrong-number-of-args.rs:343:18
    |
 LL |         type E = Result<>;
    |                  ^^^^^^ expected 2 generic arguments
@@ -1006,7 +1034,7 @@ help: add missing generic arguments
 LL |         type E = Result<T, E>;
    |                         ^^^^
 
-error: aborting due to 69 previous errors
+error: aborting due to 71 previous errors
 
 Some errors have detailed explanations: E0106, E0107.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/src/test/ui/impl-trait/example-calendar.rs b/src/test/ui/impl-trait/example-calendar.rs
index 238f3fa31ed..45dcb74a6e0 100644
--- a/src/test/ui/impl-trait/example-calendar.rs
+++ b/src/test/ui/impl-trait/example-calendar.rs
@@ -3,7 +3,6 @@
 
 #![feature(fn_traits,
            step_trait,
-           step_trait_ext,
            unboxed_closures,
 )]
 
@@ -157,7 +156,7 @@ impl<'a, 'b> std::ops::Add<&'b NaiveDate> for &'a NaiveDate {
     }
 }
 
-unsafe impl std::iter::Step for NaiveDate {
+impl std::iter::Step for NaiveDate {
     fn steps_between(_: &Self, _: &Self) -> Option<usize> {
         unimplemented!()
     }
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr
index d7a9e5463b3..ff99d037d19 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr
@@ -1,5 +1,5 @@
 warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/error-handling.rs:6:32
+  --> $DIR/error-handling.rs:5:32
    |
 LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
    |                                ^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
    = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
 
 error: lifetime may not live long enough
-  --> $DIR/error-handling.rs:26:16
+  --> $DIR/error-handling.rs:25:16
    |
 LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
    |        --  -- lifetime `'b` defined here
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr
index e2d745cdec8..4b23ba81604 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/error-handling.rs:26:16
+  --> $DIR/error-handling.rs:25:16
    |
 LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> {
    |        --  -- lifetime `'b` defined here
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs
index b5adabb7abd..1ead78e02ed 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs
@@ -1,6 +1,5 @@
 // compile-flags:-Zborrowck=mir
 
-#![feature(member_constraints)]
 // revisions: min_tait full_tait
 #![feature(min_type_alias_impl_trait)]
 #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
index 3911769b0c6..41b6a9eb055 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs
@@ -3,8 +3,6 @@
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
-#![feature(member_constraints)]
-
 trait Trait<'a, 'b> {}
 impl<T> Trait<'_, '_> for T {}
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs
index 553dea7aa6e..d0277336b25 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs
@@ -3,10 +3,8 @@
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
-#![feature(member_constraints)]
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
 
 // Test case where we have elision in the impl trait and we have to
 // pick the right region.
@@ -26,4 +24,4 @@ fn upper_bounds3<'b>(a: &u8) -> impl Trait<'_, 'b> {
     (a, a)
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs
index 9d345502aab..b9857b7aa2f 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs
@@ -3,10 +3,9 @@
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
-#![feature(member_constraints)]
 #![feature(min_type_alias_impl_trait)]
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
 
 // Here we wind up selecting `'a` and `'b` in the hidden type because
 // those are the types that appear in the original values.
@@ -28,4 +27,4 @@ fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> Foo<'a, 'b> {
     (a, b)
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs
index c0930ec5944..be455f53350 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs
@@ -3,10 +3,8 @@
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
-#![feature(member_constraints)]
-
-trait Trait<'a, 'b> { }
-impl<T> Trait<'_, '_> for T { }
+trait Trait<'a, 'b> {}
+impl<T> Trait<'_, '_> for T {}
 
 // Here we wind up selecting `'a` and `'b` in the hidden type because
 // those are the types that appear in the original values.
@@ -26,4 +24,4 @@ fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> {
     (a, b)
 }
 
-fn main() { }
+fn main() {}
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs
index ed36bda7db7..7235d89019f 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs
@@ -3,8 +3,6 @@
 // revisions: migrate mir
 //[mir]compile-flags: -Z borrowck=mir
 
-#![feature(member_constraints)]
-
 trait Trait<'a, 'b> {}
 impl<T> Trait<'_, '_> for T {}
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr
index 129af80ce4a..8cf89f164b1 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr
@@ -1,5 +1,5 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ordinary-bounds-unrelated.rs:18:74
+  --> $DIR/ordinary-bounds-unrelated.rs:16:74
    |
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
    |                                                                          ^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
index db1641b0140..3a97624647e 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs
@@ -1,7 +1,5 @@
 // edition:2018
 
-#![feature(member_constraints)]
-
 trait Trait<'a, 'b> {}
 impl<T> Trait<'_, '_> for T {}
 
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
index b42ff1486f0..a6bc8fec283 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr
@@ -1,11 +1,11 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ordinary-bounds-unrelated.rs:18:74
+  --> $DIR/ordinary-bounds-unrelated.rs:16:74
    |
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
    |                                                                          ^^^^^^^^^^^^^^^^^^
    |
 note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
-  --> $DIR/ordinary-bounds-unrelated.rs:18:74
+  --> $DIR/ordinary-bounds-unrelated.rs:16:74
    |
 LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e>
    |                                                                          ^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr
index de6d5edcae5..1bcb28120ed 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr
@@ -1,5 +1,5 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ordinary-bounds-unsuited.rs:20:62
+  --> $DIR/ordinary-bounds-unsuited.rs:18:62
    |
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
    |                                                              ^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
index 7f9c92f15a2..d4c60a4e892 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs
@@ -1,7 +1,5 @@
 // edition:2018
 
-#![feature(member_constraints)]
-
 trait Trait<'a, 'b> {}
 impl<T> Trait<'_, '_> for T {}
 
@@ -18,7 +16,7 @@ struct Ordinary<'a>(&'a u8);
 // consider the loans for both `'a` and `'b` alive.
 
 fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
-    //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
+//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds
 {
     // We return a value:
     //
diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
index 254643c406c..a219e747415 100644
--- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
+++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr
@@ -1,11 +1,11 @@
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
-  --> $DIR/ordinary-bounds-unsuited.rs:20:62
+  --> $DIR/ordinary-bounds-unsuited.rs:18:62
    |
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
    |                                                              ^^^^^^^^^^^^^^^^^^
    |
 note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body
-  --> $DIR/ordinary-bounds-unsuited.rs:20:62
+  --> $DIR/ordinary-bounds-unsuited.rs:18:62
    |
 LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b>
    |                                                              ^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/impl-trait/needs_least_region_or_bound.rs b/src/test/ui/impl-trait/needs_least_region_or_bound.rs
index 3c8682bb62a..c4bcfe5b281 100644
--- a/src/test/ui/impl-trait/needs_least_region_or_bound.rs
+++ b/src/test/ui/impl-trait/needs_least_region_or_bound.rs
@@ -1,7 +1,5 @@
 // check-pass
 
-#![feature(member_constraints)]
-
 trait MultiRegionTrait<'a, 'b> {}
 impl<'a, 'b> MultiRegionTrait<'a, 'b> for (&'a u32, &'b u32) {}
 
diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs
index 2e96022318b..7beb2db3969 100644
--- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs
+++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs
@@ -10,8 +10,8 @@ fn make_unit() -> Result<(), Error> {
 
 fn main() {
     let fut = async {
-        make_unit()?; //~ ERROR type annotations needed
+        make_unit()?;
 
-        Ok(())
+        Ok(()) //~ ERROR type annotations needed
     };
 }
diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
index 2875cef6801..8e632fbc1de 100644
--- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
+++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr
@@ -8,14 +8,13 @@ LL | #![feature(impl_trait_in_bindings)]
    = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information
 
 error[E0282]: type annotations needed for `impl Future`
-  --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:13:20
+  --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:15:9
    |
 LL |     let fut = async {
-   |         --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified
-LL |         make_unit()?;
-   |                    ^ cannot infer type of error for `?` operator
-   |
-   = note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>`
+   |         --- consider giving `fut` the explicit type `impl Future`, where the type parameter `E` is specified
+...
+LL |         Ok(())
+   |         ^^ cannot infer type for type parameter `E` declared on the enum `Result`
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/inference/cannot-infer-async.rs b/src/test/ui/inference/cannot-infer-async.rs
index 05f62f3d8cb..e7fabd0ffbc 100644
--- a/src/test/ui/inference/cannot-infer-async.rs
+++ b/src/test/ui/inference/cannot-infer-async.rs
@@ -8,8 +8,8 @@ fn make_unit() -> Result<(), Error> {
 
 fn main() {
     let fut = async {
-        make_unit()?; //~ ERROR type annotations needed
+        make_unit()?;
 
-        Ok(())
+        Ok(()) //~ ERROR type annotations needed
     };
 }
diff --git a/src/test/ui/inference/cannot-infer-async.stderr b/src/test/ui/inference/cannot-infer-async.stderr
index 282bc13e9e7..23360483361 100644
--- a/src/test/ui/inference/cannot-infer-async.stderr
+++ b/src/test/ui/inference/cannot-infer-async.stderr
@@ -1,12 +1,11 @@
 error[E0282]: type annotations needed
-  --> $DIR/cannot-infer-async.rs:11:20
+  --> $DIR/cannot-infer-async.rs:13:9
    |
 LL |     let fut = async {
    |         --- consider giving `fut` a type
-LL |         make_unit()?;
-   |                    ^ cannot infer type of error for `?` operator
-   |
-   = note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>`
+...
+LL |         Ok(())
+   |         ^^ cannot infer type for type parameter `E` declared on the enum `Result`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/cannot-infer-closure-circular.stderr b/src/test/ui/inference/cannot-infer-closure-circular.stderr
index 211ae13e46d..a6ddb7ae908 100644
--- a/src/test/ui/inference/cannot-infer-closure-circular.stderr
+++ b/src/test/ui/inference/cannot-infer-closure-circular.stderr
@@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `Result<(), E>`
   --> $DIR/cannot-infer-closure-circular.rs:7:14
    |
 LL |     let x = |r| {
-   |              ^ consider giving this closure parameter the explicit type `Result<(), E>`, with the type parameters specified
+   |              ^ consider giving this closure parameter the explicit type `Result<(), E>`, where the type parameter `E` is specified
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/inference/cannot-infer-closure.rs b/src/test/ui/inference/cannot-infer-closure.rs
index 8f48483c254..6e84b6d5ad0 100644
--- a/src/test/ui/inference/cannot-infer-closure.rs
+++ b/src/test/ui/inference/cannot-infer-closure.rs
@@ -1,6 +1,6 @@
 fn main() {
     let x = |a: (), b: ()| {
-        Err(a)?; //~ ERROR type annotations needed for the closure
-        Ok(b)
+        Err(a)?;
+        Ok(b) //~ ERROR type annotations needed for the closure
     };
 }
diff --git a/src/test/ui/inference/cannot-infer-closure.stderr b/src/test/ui/inference/cannot-infer-closure.stderr
index 0dcce9e990b..e055d1a94ff 100644
--- a/src/test/ui/inference/cannot-infer-closure.stderr
+++ b/src/test/ui/inference/cannot-infer-closure.stderr
@@ -1,10 +1,9 @@
 error[E0282]: type annotations needed for the closure `fn((), ()) -> Result<(), _>`
-  --> $DIR/cannot-infer-closure.rs:3:15
+  --> $DIR/cannot-infer-closure.rs:4:9
    |
-LL |         Err(a)?;
-   |               ^ cannot infer type of error for `?` operator
+LL |         Ok(b)
+   |         ^^ cannot infer type for type parameter `E` declared on the enum `Result`
    |
-   = note: `?` implicitly converts the error value into a type implementing `From<()>`
 help: give this closure an explicit return type without `_` placeholders
    |
 LL |     let x = |a: (), b: ()| -> Result<(), _> {
diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.stderr b/src/test/ui/inference/cannot-infer-partial-try-return.stderr
index 86e2126e1ae..c394f6efbda 100644
--- a/src/test/ui/inference/cannot-infer-partial-try-return.stderr
+++ b/src/test/ui/inference/cannot-infer-partial-try-return.stderr
@@ -2,9 +2,8 @@ error[E0282]: type annotations needed for the closure `fn() -> Result<(), Qualif
   --> $DIR/cannot-infer-partial-try-return.rs:19:9
    |
 LL |         infallible()?;
-   |         ^^^^^^^^^^^^^ cannot infer type of error for `?` operator
+   |         ^^^^^^^^^^^^^ cannot infer type
    |
-   = note: `?` implicitly converts the error value into `QualifiedError<_>` using its implementation of `From<Infallible>`
 help: give this closure an explicit return type without `_` placeholders
    |
 LL |     let x = || -> Result<(), QualifiedError<_>> {
diff --git a/src/test/ui/intrinsics/issue-28575.stderr b/src/test/ui/intrinsics/issue-28575.mir.stderr
index 66369decf42..c42498390c7 100644
--- a/src/test/ui/intrinsics/issue-28575.stderr
+++ b/src/test/ui/intrinsics/issue-28575.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/issue-28575.rs:8:5
+  --> $DIR/issue-28575.rs:11:5
    |
 LL |     FOO()
    |     ^^^ use of extern static
diff --git a/src/test/ui/intrinsics/issue-28575.rs b/src/test/ui/intrinsics/issue-28575.rs
index 141136d25b2..410f664f89d 100644
--- a/src/test/ui/intrinsics/issue-28575.rs
+++ b/src/test/ui/intrinsics/issue-28575.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![feature(intrinsics)]
 
 extern "C" {
diff --git a/src/test/ui/intrinsics/issue-28575.thir.stderr b/src/test/ui/intrinsics/issue-28575.thir.stderr
new file mode 100644
index 00000000000..c42498390c7
--- /dev/null
+++ b/src/test/ui/intrinsics/issue-28575.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/issue-28575.rs:11:5
+   |
+LL |     FOO()
+   |     ^^^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
index 4a91198ab9f..72c0d7913e5 100644
--- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -1,5 +1,7 @@
 // run-pass
 // ignore-wasm32-bare compiled with panic=abort by default
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 // This test checks panic emitted from `mem::{uninitialized,zeroed}`.
 
diff --git a/src/test/ui/issues/issue-11740.rs b/src/test/ui/issues/issue-11740.rs
index dc10a205f24..9faeb7770a7 100644
--- a/src/test/ui/issues/issue-11740.rs
+++ b/src/test/ui/issues/issue-11740.rs
@@ -1,4 +1,6 @@
 // check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 struct Attr {
     name: String,
diff --git a/src/test/ui/issues/issue-14227.stderr b/src/test/ui/issues/issue-14227.mir.stderr
index f9cdbe452df..8e7a2514dd6 100644
--- a/src/test/ui/issues/issue-14227.stderr
+++ b/src/test/ui/issues/issue-14227.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/issue-14227.rs:4:21
+  --> $DIR/issue-14227.rs:7:21
    |
 LL | static CRASH: u32 = symbol;
    |                     ^^^^^^ use of extern static
diff --git a/src/test/ui/issues/issue-14227.rs b/src/test/ui/issues/issue-14227.rs
index a1fde14600a..5f866ec9061 100644
--- a/src/test/ui/issues/issue-14227.rs
+++ b/src/test/ui/issues/issue-14227.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 extern "C" {
     pub static symbol: u32;
 }
diff --git a/src/test/ui/issues/issue-14227.thir.stderr b/src/test/ui/issues/issue-14227.thir.stderr
new file mode 100644
index 00000000000..8e7a2514dd6
--- /dev/null
+++ b/src/test/ui/issues/issue-14227.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/issue-14227.rs:7:21
+   |
+LL | static CRASH: u32 = symbol;
+   |                     ^^^^^^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/issues/issue-16538.stderr b/src/test/ui/issues/issue-16538.mir.stderr
index 81a91db3711..d7e8c08bb01 100644
--- a/src/test/ui/issues/issue-16538.stderr
+++ b/src/test/ui/issues/issue-16538.mir.stderr
@@ -1,11 +1,11 @@
 error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/issue-16538.rs:11:27
+  --> $DIR/issue-16538.rs:14:27
    |
 LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0277]: `*const usize` cannot be shared between threads safely
-  --> $DIR/issue-16538.rs:11:1
+  --> $DIR/issue-16538.rs:14:1
    |
 LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely
@@ -14,7 +14,7 @@ LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
    = note: shared static variables must have a type that implements `Sync`
 
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/issue-16538.rs:11:34
+  --> $DIR/issue-16538.rs:14:34
    |
 LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
    |                                  ^^^^ use of extern static
diff --git a/src/test/ui/issues/issue-16538.rs b/src/test/ui/issues/issue-16538.rs
index 7d6eefa5b1e..1e8ecf015c8 100644
--- a/src/test/ui/issues/issue-16538.rs
+++ b/src/test/ui/issues/issue-16538.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 mod Y {
     pub type X = usize;
     extern "C" {
diff --git a/src/test/ui/issues/issue-16538.thir.stderr b/src/test/ui/issues/issue-16538.thir.stderr
new file mode 100644
index 00000000000..435334c3228
--- /dev/null
+++ b/src/test/ui/issues/issue-16538.thir.stderr
@@ -0,0 +1,27 @@
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/issue-16538.rs:14:34
+   |
+LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
+   |                                  ^^^^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+  --> $DIR/issue-16538.rs:14:27
+   |
+LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: `*const usize` cannot be shared between threads safely
+  --> $DIR/issue-16538.rs:14:1
+   |
+LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely
+   |
+   = help: the trait `Sync` is not implemented for `*const usize`
+   = note: shared static variables must have a type that implements `Sync`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0015, E0133, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/src/test/ui/issues/issue-22289.stderr b/src/test/ui/issues/issue-22289.stderr
index 60027853609..f90e89efb4a 100644
--- a/src/test/ui/issues/issue-22289.stderr
+++ b/src/test/ui/issues/issue-22289.stderr
@@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `i32` as `&(dyn Any + 'static)`
 LL |     0 as &dyn std::any::Any;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
    |
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
    |
 LL |     &0 as &dyn std::any::Any;
    |     ^
diff --git a/src/test/ui/issues/issue-22312.stderr b/src/test/ui/issues/issue-22312.stderr
index 823ffc6de6d..47ee544c02a 100644
--- a/src/test/ui/issues/issue-22312.stderr
+++ b/src/test/ui/issues/issue-22312.stderr
@@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `Self` as `&dyn Index<usize, Output = <Self as
 LL |         let indexer = &(*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
    |
-help: borrow the value for the cast to be valid
+help: consider borrowing the value
    |
 LL |         let indexer = &(&*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>);
    |                         ^
diff --git a/src/test/ui/issues/issue-28324.stderr b/src/test/ui/issues/issue-28324.mir.stderr
index d7dad992152..aff8bf7927d 100644
--- a/src/test/ui/issues/issue-28324.stderr
+++ b/src/test/ui/issues/issue-28324.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/issue-28324.rs:5:24
+  --> $DIR/issue-28324.rs:8:24
    |
 LL | pub static BAZ: u32 = *&error_message_count;
    |                        ^^^^^^^^^^^^^^^^^^^^ use of extern static
diff --git a/src/test/ui/issues/issue-28324.rs b/src/test/ui/issues/issue-28324.rs
index f74726e8166..fbe83e325ed 100644
--- a/src/test/ui/issues/issue-28324.rs
+++ b/src/test/ui/issues/issue-28324.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 extern "C" {
     static error_message_count: u32;
 }
diff --git a/src/test/ui/issues/issue-28324.thir.stderr b/src/test/ui/issues/issue-28324.thir.stderr
new file mode 100644
index 00000000000..c696c359830
--- /dev/null
+++ b/src/test/ui/issues/issue-28324.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/issue-28324.rs:8:25
+   |
+LL | pub static BAZ: u32 = *&error_message_count;
+   |                         ^^^^^^^^^^^^^^^^^^^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/issues/issue-2995.stderr b/src/test/ui/issues/issue-2995.stderr
index 9f5968399a3..b08fe8c7352 100644
--- a/src/test/ui/issues/issue-2995.stderr
+++ b/src/test/ui/issues/issue-2995.stderr
@@ -2,7 +2,12 @@ error[E0605]: non-primitive cast: `*const isize` as `&isize`
   --> $DIR/issue-2995.rs:2:22
    |
 LL |     let _q: &isize = p as &isize;
-   |                      ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+   |                      ^^^^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     let _q: &isize = &*p as &isize;
+   |                      ^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-30123.stderr b/src/test/ui/issues/issue-30123.stderr
index bc6731601f0..e9d934332f1 100644
--- a/src/test/ui/issues/issue-30123.stderr
+++ b/src/test/ui/issues/issue-30123.stderr
@@ -3,6 +3,9 @@ error[E0599]: no function or associated item named `new_undirected` found for st
    |
 LL |     let ug = Graph::<i32, i32>::new_undirected();
    |                                 ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph<i32, i32>`
+   |
+   = note: the function or associated item was found for
+           - `issue_30123_aux::Graph<N, E, Undirected>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr
index cc12c153621..2d020188198 100644
--- a/src/test/ui/issues/issue-32709.stderr
+++ b/src/test/ui/issues/issue-32709.stderr
@@ -7,7 +7,8 @@ LL |     Err(5)?;
    |           ^ the trait `From<{integer}>` is not implemented for `()`
    |
    = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
-   = note: required by `from`
+   = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, {integer}>>` for `Result<i32, ()>`
+   = note: required by `from_residual`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-39367.rs b/src/test/ui/issues/issue-39367.rs
index 8314be3d14c..e7beb8a0392 100644
--- a/src/test/ui/issues/issue-39367.rs
+++ b/src/test/ui/issues/issue-39367.rs
@@ -1,4 +1,7 @@
 // run-pass
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
 use std::ops::Deref;
 
 struct ArenaSet<U: Deref, V=<U as Deref>::Target>(U, &'static V)
diff --git a/src/test/ui/issues/issue-41880.stderr b/src/test/ui/issues/issue-41880.stderr
index 09d5594f73f..017dd831f71 100644
--- a/src/test/ui/issues/issue-41880.stderr
+++ b/src/test/ui/issues/issue-41880.stderr
@@ -1,4 +1,4 @@
-error[E0599]: no method named `iter` found for struct `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:31]>` in the current scope
+error[E0599]: no method named `iter` found for struct `Iterate` in the current scope
   --> $DIR/issue-41880.rs:27:24
    |
 LL | pub struct Iterate<T, F> {
diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr
index 321698e7636..9e9cbcf33ae 100644
--- a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr
+++ b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr
@@ -1,5 +1,5 @@
 error: unnecessary `unsafe` block
-  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:7:13
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13
    |
 LL |     unsafe {
    |     ------ because it's nested under this `unsafe` block
@@ -8,13 +8,13 @@ LL |             unsafe {
    |             ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:1:8
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8
    |
 LL | #[deny(unused_unsafe)]
    |        ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:9:38
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38
    |
 LL |     unsafe {
    |     ------ because it's nested under this `unsafe` block
@@ -23,7 +23,7 @@ LL |                 |w: &mut Vec<u32>| { unsafe {
    |                                      ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:13:34
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34
    |
 LL |     unsafe {
    |     ------ because it's nested under this `unsafe` block
diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs
index de275ff701a..ac1cfd62a05 100644
--- a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs
+++ b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
 #[deny(unused_unsafe)]
 fn main() {
     let mut v = Vec::<i32>::with_capacity(24);
diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr
new file mode 100644
index 00000000000..9e9cbcf33ae
--- /dev/null
+++ b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr
@@ -0,0 +1,35 @@
+error: unnecessary `unsafe` block
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+LL |         let f = |v: &mut Vec<_>| {
+LL |             unsafe {
+   |             ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8
+   |
+LL | #[deny(unused_unsafe)]
+   |        ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+...
+LL |                 |w: &mut Vec<u32>| { unsafe {
+   |                                      ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+...
+LL |             |x: &mut Vec<u32>| { unsafe {
+   |                                  ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/issues/issue-47412.stderr b/src/test/ui/issues/issue-47412.mir.stderr
index aebcbf07463..96e50ba6799 100644
--- a/src/test/ui/issues/issue-47412.stderr
+++ b/src/test/ui/issues/issue-47412.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/issue-47412.rs:11:11
+  --> $DIR/issue-47412.rs:14:11
    |
 LL |     match u.void {}
    |           ^^^^^^ access to union field
@@ -7,7 +7,7 @@ LL |     match u.void {}
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/issue-47412.rs:17:11
+  --> $DIR/issue-47412.rs:21:11
    |
 LL |     match *ptr {}
    |           ^^^^ dereference of raw pointer
diff --git a/src/test/ui/issues/issue-47412.rs b/src/test/ui/issues/issue-47412.rs
index 2d1ea72280b..d395285eee0 100644
--- a/src/test/ui/issues/issue-47412.rs
+++ b/src/test/ui/issues/issue-47412.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #[derive(Copy, Clone)]
 enum Void {}
 
@@ -9,7 +12,8 @@ fn union_field() {
     union Union { unit: (), void: Void }
     let u = Union { unit: () };
     match u.void {}
-    //~^ ERROR access to union field is unsafe
+    //[mir]~^ ERROR access to union field is unsafe
+    // FIXME(thir-unsafeck): AccessToUnionField unimplemented
 }
 
 fn raw_ptr_deref() {
diff --git a/src/test/ui/issues/issue-47412.thir.stderr b/src/test/ui/issues/issue-47412.thir.stderr
new file mode 100644
index 00000000000..66a0cfcd710
--- /dev/null
+++ b/src/test/ui/issues/issue-47412.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-47412.rs:21:11
+   |
+LL |     match *ptr {}
+   |           ^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/lang-item-missing-generator.rs b/src/test/ui/lang-items/lang-item-missing-generator.rs
index 0c329542928..0c329542928 100644
--- a/src/test/ui/lang-item-missing-generator.rs
+++ b/src/test/ui/lang-items/lang-item-missing-generator.rs
diff --git a/src/test/ui/lang-item-missing-generator.stderr b/src/test/ui/lang-items/lang-item-missing-generator.stderr
index fa13bf0b127..fa13bf0b127 100644
--- a/src/test/ui/lang-item-missing-generator.stderr
+++ b/src/test/ui/lang-items/lang-item-missing-generator.stderr
diff --git a/src/test/ui/lang-item-missing.rs b/src/test/ui/lang-items/lang-item-missing.rs
index 4e26343242e..4e26343242e 100644
--- a/src/test/ui/lang-item-missing.rs
+++ b/src/test/ui/lang-items/lang-item-missing.rs
diff --git a/src/test/ui/lang-item-missing.stderr b/src/test/ui/lang-items/lang-item-missing.stderr
index f7516c7d377..f7516c7d377 100644
--- a/src/test/ui/lang-item-missing.stderr
+++ b/src/test/ui/lang-items/lang-item-missing.stderr
diff --git a/src/test/ui/lang-items/wrong-number-generic-args-add.rs b/src/test/ui/lang-items/wrong-number-generic-args-add.rs
new file mode 100644
index 00000000000..9f4f2464a1e
--- /dev/null
+++ b/src/test/ui/lang-items/wrong-number-generic-args-add.rs
@@ -0,0 +1,20 @@
+// Checks whether declaring a lang item with the wrong number
+// of generic arguments crashes the compiler (issue #83893).
+
+#![feature(lang_items,no_core)]
+#![no_core]
+#![crate_type="lib"]
+
+#[lang = "sized"]
+trait MySized {}
+
+#[lang = "add"]
+trait MyAdd<'a, T> {}
+//~^^ ERROR: `add` language item must be applied to a trait with 1 generic argument [E0718]
+
+fn ice() {
+    let r = 5;
+    let a = 6;
+    r + a
+    //~^ ERROR: cannot add `{integer}` to `{integer}` [E0369]
+}
diff --git a/src/test/ui/lang-items/wrong-number-generic-args-add.stderr b/src/test/ui/lang-items/wrong-number-generic-args-add.stderr
new file mode 100644
index 00000000000..6f89441fd28
--- /dev/null
+++ b/src/test/ui/lang-items/wrong-number-generic-args-add.stderr
@@ -0,0 +1,20 @@
+error[E0718]: `add` language item must be applied to a trait with 1 generic argument
+  --> $DIR/wrong-number-generic-args-add.rs:11:1
+   |
+LL | #[lang = "add"]
+   | ^^^^^^^^^^^^^^^
+LL | trait MyAdd<'a, T> {}
+   |            ------- this trait has 2 generic arguments, not 1
+
+error[E0369]: cannot add `{integer}` to `{integer}`
+  --> $DIR/wrong-number-generic-args-add.rs:18:7
+   |
+LL |     r + a
+   |     - ^ - {integer}
+   |     |
+   |     {integer}
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0369, E0718.
+For more information about an error, try `rustc --explain E0369`.
diff --git a/src/test/ui/lang-items/wrong-number-generic-args-index.rs b/src/test/ui/lang-items/wrong-number-generic-args-index.rs
new file mode 100644
index 00000000000..1d90e63dc54
--- /dev/null
+++ b/src/test/ui/lang-items/wrong-number-generic-args-index.rs
@@ -0,0 +1,19 @@
+// Checks whether declaring a lang item with the wrong number
+// of generic arguments crashes the compiler (issue #83893).
+
+#![feature(lang_items,no_core)]
+#![no_core]
+#![crate_type="lib"]
+
+#[lang = "sized"]
+trait MySized {}
+
+#[lang = "index"]
+trait MyIndex<'a, T> {}
+//~^^ ERROR: `index` language item must be applied to a trait with 1 generic argument [E0718]
+
+fn ice() {
+    let arr = [0; 5];
+    let _ = arr[2];
+    //~^ ERROR: cannot index into a value of type `[{integer}; 5]` [E0608]
+}
diff --git a/src/test/ui/lang-items/wrong-number-generic-args-index.stderr b/src/test/ui/lang-items/wrong-number-generic-args-index.stderr
new file mode 100644
index 00000000000..bc3f19ff276
--- /dev/null
+++ b/src/test/ui/lang-items/wrong-number-generic-args-index.stderr
@@ -0,0 +1,18 @@
+error[E0718]: `index` language item must be applied to a trait with 1 generic argument
+  --> $DIR/wrong-number-generic-args-index.rs:11:1
+   |
+LL | #[lang = "index"]
+   | ^^^^^^^^^^^^^^^^^
+LL | trait MyIndex<'a, T> {}
+   |              ------- this trait has 2 generic arguments, not 1
+
+error[E0608]: cannot index into a value of type `[{integer}; 5]`
+  --> $DIR/wrong-number-generic-args-index.rs:17:13
+   |
+LL |     let _ = arr[2];
+   |             ^^^^^^
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0608, E0718.
+For more information about an error, try `rustc --explain E0608`.
diff --git a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs
new file mode 100644
index 00000000000..d4a5056ddf3
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs
@@ -0,0 +1,11 @@
+// compile-flags: --force-warns elided_lifetimes_in_paths
+// check-pass
+
+struct Foo<'a> {
+    x: &'a u32,
+}
+
+fn foo(x: &Foo) {}
+//~^ WARN hidden lifetime parameters in types are deprecated
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr
new file mode 100644
index 00000000000..0e0e934c765
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr
@@ -0,0 +1,10 @@
+warning: hidden lifetime parameters in types are deprecated
+  --> $DIR/force-allowed-by-default-lint.rs:8:12
+   |
+LL | fn foo(x: &Foo) {}
+   |            ^^^- help: indicate the anonymous lifetime: `<'_>`
+   |
+   = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs
new file mode 100644
index 00000000000..afd2d6ec322
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs
@@ -0,0 +1,9 @@
+// compile-flags: --force-warns const_err
+// check-pass
+
+#![allow(const_err)]
+const C: i32 = 1 / 0;
+//~^ WARN any use of this value will cause an error
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr
new file mode 100644
index 00000000000..bad12f94b18
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr
@@ -0,0 +1,14 @@
+warning: any use of this value will cause an error
+  --> $DIR/force-allowed-deny-by-default-lint.rs:5:16
+   |
+LL | const C: i32 = 1 / 0;
+   | ---------------^^^^^-
+   |                |
+   |                attempt to divide `1_i32` by zero
+   |
+   = note: warning forced by `force-warns` commandline option
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-allowed-warning.rs b/src/test/ui/lint/force-warn/force-allowed-warning.rs
new file mode 100644
index 00000000000..5c83c525e38
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-allowed-warning.rs
@@ -0,0 +1,9 @@
+// compile-flags: --force-warns dead_code
+// check-pass
+
+#![allow(dead_code)]
+
+fn dead_function() {}
+//~^ WARN function is never used
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-allowed-warning.stderr b/src/test/ui/lint/force-warn/force-allowed-warning.stderr
new file mode 100644
index 00000000000..145798a32a9
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-allowed-warning.stderr
@@ -0,0 +1,10 @@
+warning: function is never used: `dead_function`
+  --> $DIR/force-allowed-warning.rs:6:4
+   |
+LL | fn dead_function() {}
+   |    ^^^^^^^^^^^^^
+   |
+   = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs b/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs
new file mode 100644
index 00000000000..4f267f085d5
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs
@@ -0,0 +1,8 @@
+// compile-flags: --force-warns const_err
+// check-pass
+
+const C: i32 = 1 / 0;
+//~^ WARN any use of this value will cause an error
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr
new file mode 100644
index 00000000000..4b004cf367d
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr
@@ -0,0 +1,14 @@
+warning: any use of this value will cause an error
+  --> $DIR/force-deny-by-default-lint.rs:4:16
+   |
+LL | const C: i32 = 1 / 0;
+   | ---------------^^^^^-
+   |                |
+   |                attempt to divide `1_i32` by zero
+   |
+   = note: warning forced by `force-warns` commandline option
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs
new file mode 100644
index 00000000000..5501faa437a
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs
@@ -0,0 +1,9 @@
+// compile-flags: --force-warns dead_code
+// check-pass
+
+#![allow(warnings)]
+
+fn dead_function() {}
+//~^ WARN function is never used
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr
new file mode 100644
index 00000000000..577dbe1fea8
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr
@@ -0,0 +1,10 @@
+warning: function is never used: `dead_function`
+  --> $DIR/force-lint-allow-all-warnings.rs:6:4
+   |
+LL | fn dead_function() {}
+   |    ^^^^^^^^^^^^^
+   |
+   = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs
new file mode 100644
index 00000000000..9009971f0cf
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs
@@ -0,0 +1,9 @@
+// compile-flags: --force-warns nonstandard_style
+// check-pass
+
+#![allow(warnings)]
+
+pub fn FUNCTION() {}
+//~^ WARN function `FUNCTION` should have a snake case name
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr
new file mode 100644
index 00000000000..8665fa2610a
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr
@@ -0,0 +1,10 @@
+warning: function `FUNCTION` should have a snake case name
+  --> $DIR/force-lint-group-allow-all-warnings.rs:6:8
+   |
+LL | pub fn FUNCTION() {}
+   |        ^^^^^^^^ help: convert the identifier to snake case: `function`
+   |
+   = note: warning forced by `force-warns` commandline option
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs
new file mode 100644
index 00000000000..b68b979ca11
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs
@@ -0,0 +1,12 @@
+// compile-flags: --force-warns bare_trait_objects
+// check-pass
+
+#![allow(rust_2018_idioms)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr
new file mode 100644
index 00000000000..40750ffea8c
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr
@@ -0,0 +1,12 @@
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/force-lint-in-allowed-group.rs:8:25
+   |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+   |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+   = note: warning forced by `force-warns` commandline option
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs
new file mode 100644
index 00000000000..357a79b383d
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs
@@ -0,0 +1,12 @@
+// compile-flags: --force-warns rust_2018_idioms
+// check-pass
+
+#![allow(bare_trait_objects)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr
new file mode 100644
index 00000000000..88ae846caa0
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr
@@ -0,0 +1,12 @@
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/force-warn-group-allow-warning.rs:8:25
+   |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+   |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+   = note: warning forced by `force-warns` commandline option
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/force-warn/force-warn-group.rs b/src/test/ui/lint/force-warn/force-warn-group.rs
new file mode 100644
index 00000000000..a4615df42de
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-warn-group.rs
@@ -0,0 +1,12 @@
+// compile-flags: --force-warns rust_2018_idioms
+// check-pass
+
+#![allow(rust_2018_idioms)]
+
+pub trait SomeTrait {}
+
+pub fn function(_x: Box<SomeTrait>) {}
+//~^ WARN trait objects without an explicit `dyn` are deprecated
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/lint/force-warn/force-warn-group.stderr b/src/test/ui/lint/force-warn/force-warn-group.stderr
new file mode 100644
index 00000000000..f808727991e
--- /dev/null
+++ b/src/test/ui/lint/force-warn/force-warn-group.stderr
@@ -0,0 +1,12 @@
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/force-warn-group.rs:8:25
+   |
+LL | pub fn function(_x: Box<SomeTrait>) {}
+   |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
+   |
+   = note: warning forced by `force-warns` commandline option
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition!
+   = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/lint/lint-stability-deprecated.stderr b/src/test/ui/lint/lint-stability-deprecated.stderr
index 94fc1a7b46d..4b082fcd359 100644
--- a/src/test/ui/lint/lint-stability-deprecated.stderr
+++ b/src/test/ui/lint/lint-stability-deprecated.stderr
@@ -11,16 +11,16 @@ LL | #![warn(deprecated)]
    |         ^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text
-  --> $DIR/lint-stability-deprecated.rs:29:9
+  --> $DIR/lint-stability-deprecated.rs:29:16
    |
 LL |         Trait::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text
-  --> $DIR/lint-stability-deprecated.rs:31:9
+  --> $DIR/lint-stability-deprecated.rs:31:25
    |
 LL |         <Foo as Trait>::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated function `lint_stability::deprecated_text`: text
   --> $DIR/lint-stability-deprecated.rs:33:9
@@ -29,16 +29,16 @@ LL |         deprecated_text();
    |         ^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text
-  --> $DIR/lint-stability-deprecated.rs:38:9
+  --> $DIR/lint-stability-deprecated.rs:38:16
    |
 LL | ...   Trait::trait_deprecated_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text
-  --> $DIR/lint-stability-deprecated.rs:40:9
+  --> $DIR/lint-stability-deprecated.rs:40:25
    |
 LL | ...   <Foo as Trait>::trait_deprecated_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated function `lint_stability::deprecated_unstable`: text
   --> $DIR/lint-stability-deprecated.rs:42:9
@@ -47,16 +47,16 @@ LL |         deprecated_unstable();
    |         ^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text
-  --> $DIR/lint-stability-deprecated.rs:47:9
+  --> $DIR/lint-stability-deprecated.rs:47:16
    |
 LL | ...   Trait::trait_deprecated_unstable(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text
-  --> $DIR/lint-stability-deprecated.rs:49:9
+  --> $DIR/lint-stability-deprecated.rs:49:25
    |
 LL | ...   <Foo as Trait>::trait_deprecated_unstable(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated function `lint_stability::deprecated_unstable_text`: text
   --> $DIR/lint-stability-deprecated.rs:51:9
@@ -65,16 +65,16 @@ LL |         deprecated_unstable_text();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text
-  --> $DIR/lint-stability-deprecated.rs:56:9
+  --> $DIR/lint-stability-deprecated.rs:56:16
    |
 LL | ...   Trait::trait_deprecated_unstable_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text
-  --> $DIR/lint-stability-deprecated.rs:58:9
+  --> $DIR/lint-stability-deprecated.rs:58:25
    |
 LL | ...   <Foo as Trait>::trait_deprecated_unstable_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated struct `lint_stability::DeprecatedStruct`: text
   --> $DIR/lint-stability-deprecated.rs:108:17
@@ -101,16 +101,16 @@ LL |         let _ = DeprecatedUnstableUnitStruct;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated variant `lint_stability::Enum::DeprecatedVariant`: text
-  --> $DIR/lint-stability-deprecated.rs:123:17
+  --> $DIR/lint-stability-deprecated.rs:123:23
    |
 LL |         let _ = Enum::DeprecatedVariant;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated variant `lint_stability::Enum::DeprecatedUnstableVariant`: text
-  --> $DIR/lint-stability-deprecated.rs:124:17
+  --> $DIR/lint-stability-deprecated.rs:124:23
    |
 LL |         let _ = Enum::DeprecatedUnstableVariant;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated struct `lint_stability::DeprecatedTupleStruct`: text
   --> $DIR/lint-stability-deprecated.rs:128:17
@@ -143,52 +143,52 @@ LL |         macro_test_arg!(macro_test_arg!(deprecated_text()));
    |                                         ^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text
-  --> $DIR/lint-stability-deprecated.rs:145:9
+  --> $DIR/lint-stability-deprecated.rs:145:16
    |
 LL |         Trait::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text
-  --> $DIR/lint-stability-deprecated.rs:147:9
+  --> $DIR/lint-stability-deprecated.rs:147:25
    |
 LL |         <Foo as Trait>::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text
-  --> $DIR/lint-stability-deprecated.rs:149:9
+  --> $DIR/lint-stability-deprecated.rs:149:16
    |
 LL | ...   Trait::trait_deprecated_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text
-  --> $DIR/lint-stability-deprecated.rs:151:9
+  --> $DIR/lint-stability-deprecated.rs:151:25
    |
 LL | ...   <Foo as Trait>::trait_deprecated_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text
-  --> $DIR/lint-stability-deprecated.rs:153:9
+  --> $DIR/lint-stability-deprecated.rs:153:16
    |
 LL | ...   Trait::trait_deprecated_unstable(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text
-  --> $DIR/lint-stability-deprecated.rs:155:9
+  --> $DIR/lint-stability-deprecated.rs:155:25
    |
 LL | ...   <Foo as Trait>::trait_deprecated_unstable(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text
-  --> $DIR/lint-stability-deprecated.rs:157:9
+  --> $DIR/lint-stability-deprecated.rs:157:16
    |
 LL | ...   Trait::trait_deprecated_unstable_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text
-  --> $DIR/lint-stability-deprecated.rs:159:9
+  --> $DIR/lint-stability-deprecated.rs:159:25
    |
 LL | ...   <Foo as Trait>::trait_deprecated_unstable_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated trait `lint_stability::DeprecatedTrait`: text
   --> $DIR/lint-stability-deprecated.rs:187:10
@@ -203,10 +203,10 @@ LL |     trait LocalTrait2 : DeprecatedTrait { }
    |                         ^^^^^^^^^^^^^^^
 
 warning: use of deprecated function `inheritance::inherited_stability::unstable_mod::deprecated`: text
-  --> $DIR/lint-stability-deprecated.rs:208:9
+  --> $DIR/lint-stability-deprecated.rs:208:23
    |
 LL |         unstable_mod::deprecated();
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^
 
 warning: use of deprecated function `this_crate::deprecated`: text
   --> $DIR/lint-stability-deprecated.rs:330:9
@@ -215,16 +215,16 @@ LL |         deprecated();
    |         ^^^^^^^^^^
 
 warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
-  --> $DIR/lint-stability-deprecated.rs:335:9
+  --> $DIR/lint-stability-deprecated.rs:335:16
    |
 LL |         Trait::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
-  --> $DIR/lint-stability-deprecated.rs:337:9
+  --> $DIR/lint-stability-deprecated.rs:337:25
    |
 LL |         <Foo as Trait>::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated function `this_crate::deprecated_text`: text
   --> $DIR/lint-stability-deprecated.rs:339:9
@@ -233,16 +233,16 @@ LL |         deprecated_text();
    |         ^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
-  --> $DIR/lint-stability-deprecated.rs:344:9
+  --> $DIR/lint-stability-deprecated.rs:344:16
    |
 LL |         Trait::trait_deprecated_text(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
-  --> $DIR/lint-stability-deprecated.rs:346:9
+  --> $DIR/lint-stability-deprecated.rs:346:25
    |
 LL | ...   <Foo as Trait>::trait_deprecated_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated struct `this_crate::DeprecatedStruct`: text
   --> $DIR/lint-stability-deprecated.rs:384:17
@@ -257,10 +257,10 @@ LL |         let _ = DeprecatedUnitStruct;
    |                 ^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated unit variant `this_crate::Enum::DeprecatedVariant`: text
-  --> $DIR/lint-stability-deprecated.rs:395:17
+  --> $DIR/lint-stability-deprecated.rs:395:23
    |
 LL |         let _ = Enum::DeprecatedVariant;
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated tuple struct `this_crate::DeprecatedTupleStruct`: text
   --> $DIR/lint-stability-deprecated.rs:399:17
@@ -269,28 +269,28 @@ LL |         let _ = DeprecatedTupleStruct (1);
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
-  --> $DIR/lint-stability-deprecated.rs:406:9
+  --> $DIR/lint-stability-deprecated.rs:406:16
    |
 LL |         Trait::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
-  --> $DIR/lint-stability-deprecated.rs:408:9
+  --> $DIR/lint-stability-deprecated.rs:408:25
    |
 LL |         <Foo as Trait>::trait_deprecated(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
-  --> $DIR/lint-stability-deprecated.rs:410:9
+  --> $DIR/lint-stability-deprecated.rs:410:16
    |
 LL |         Trait::trait_deprecated_text(&foo);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
-  --> $DIR/lint-stability-deprecated.rs:412:9
+  --> $DIR/lint-stability-deprecated.rs:412:25
    |
 LL | ...   <Foo as Trait>::trait_deprecated_text(&foo);
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of deprecated function `this_crate::test_fn_body::fn_in_body`: text
   --> $DIR/lint-stability-deprecated.rs:439:9
diff --git a/src/test/ui/lto-duplicate-symbols.stderr b/src/test/ui/lto-duplicate-symbols.stderr
index 713b79bae32..891cda8016c 100644
--- a/src/test/ui/lto-duplicate-symbols.stderr
+++ b/src/test/ui/lto-duplicate-symbols.stderr
@@ -1,6 +1,6 @@
 warning: Linking globals named 'foo': symbol multiply defined!
 
-error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.3a1fbbbh-cgu.0.rcgu.o": 
+error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.288b404e693a75b4-cgu.0.rcgu.o": 
 
 error: aborting due to previous error; 1 warning emitted
 
diff --git a/src/test/ui/lto-still-runs-thread-dtors.rs b/src/test/ui/lto-still-runs-thread-dtors.rs
index 635ad783b31..1c7368b36e1 100644
--- a/src/test/ui/lto-still-runs-thread-dtors.rs
+++ b/src/test/ui/lto-still-runs-thread-dtors.rs
@@ -2,6 +2,8 @@
 // compile-flags: -C lto
 // no-prefer-dynamic
 // ignore-emscripten no threads support
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 use std::thread;
 
diff --git a/src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs b/src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs
new file mode 100644
index 00000000000..26d4c96d524
--- /dev/null
+++ b/src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs
@@ -0,0 +1,11 @@
+// edition:2018
+
+#[macro_export]
+macro_rules! custom_matches {
+    ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => {
+        match $expression {
+            $( $pattern )|+ $( if $guard )? => true,
+            _ => false
+        }
+    }
+}
diff --git a/src/test/ui/macros/cross-crate-pat-span.rs b/src/test/ui/macros/cross-crate-pat-span.rs
new file mode 100644
index 00000000000..ed67142ce3d
--- /dev/null
+++ b/src/test/ui/macros/cross-crate-pat-span.rs
@@ -0,0 +1,12 @@
+// edition:2021
+// check-pass
+// aux-build: foreign-crate-macro-pat.rs
+//
+// Tests that the edition of the foreign crate is used
+// when determining the behavior of the `:pat` matcher.
+
+extern crate foreign_crate_macro_pat;
+
+fn main() {
+    let _b = foreign_crate_macro_pat::custom_matches!(b'3', b'0' ..= b'9');
+}
diff --git a/src/test/ui/macros/issue-84429-matches-edition.rs b/src/test/ui/macros/issue-84429-matches-edition.rs
new file mode 100644
index 00000000000..53f134c265f
--- /dev/null
+++ b/src/test/ui/macros/issue-84429-matches-edition.rs
@@ -0,0 +1,9 @@
+// edition:2021
+// check-pass
+//
+// Regression test for issue #84429
+// Tests that we can properly invoke `matches!` from a 2021-edition crate.
+
+fn main() {
+    let _b = matches!(b'3', b'0' ..= b'9');
+}
diff --git a/src/test/ui/matches2021.rs b/src/test/ui/matches2021.rs
new file mode 100644
index 00000000000..1090b1578ba
--- /dev/null
+++ b/src/test/ui/matches2021.rs
@@ -0,0 +1,12 @@
+// run-pass
+// edition:2021
+// compile-flags: -Zunstable-options
+
+// regression test for https://github.com/rust-lang/rust/pull/85678
+
+#![feature(assert_matches)]
+
+fn main() {
+    assert!(matches!((), ()));
+    assert_matches!((), ());
+}
diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.rs b/src/test/ui/methods/method-not-found-generic-arg-elision.rs
new file mode 100644
index 00000000000..3df928b5d80
--- /dev/null
+++ b/src/test/ui/methods/method-not-found-generic-arg-elision.rs
@@ -0,0 +1,106 @@
+// Test for issue 81576
+// Remove generic arguments if no method is found for all possible generic argument
+
+use std::marker::PhantomData;
+
+struct Wrapper2<'a, T, const C: usize> {
+    x: &'a T,
+}
+
+impl<'a, const C: usize> Wrapper2<'a, i8, C> {
+    fn method(&self) {}
+}
+
+impl<'a, const C: usize> Wrapper2<'a, i16, C> {
+    fn method(&self) {}
+}
+
+impl<'a, const C: usize> Wrapper2<'a, i32, C> {
+    fn method(&self) {}
+}
+struct Wrapper<T>(T);
+
+impl Wrapper<i8> {
+    fn method(&self) {}
+}
+
+impl Wrapper<i16> {
+    fn method(&self) {}
+}
+
+impl Wrapper<i32> {
+    fn method(&self) {}
+}
+
+impl Wrapper<i64> {
+    fn method(&self) {}
+}
+
+impl Wrapper<u8> {
+    fn method(&self) {}
+}
+
+impl Wrapper<u16> {
+    fn method(&self) {}
+}
+
+struct Point<T> {
+    x: T,
+    y: T,
+}
+
+impl Point<f64> {
+    fn distance(&self) -> f64 {
+        self.x.hypot(self.y)
+    }
+}
+
+struct Other;
+
+impl Other {
+    fn other(&self) {}
+}
+
+struct Struct<T>{
+    _phatom: PhantomData<T>
+}
+
+impl<T> Default for Struct<T> {
+    fn default() -> Self {
+        Self{ _phatom: PhantomData }
+    }
+}
+
+impl<T: Clone + Copy + PartialEq + Eq + PartialOrd + Ord> Struct<T> {
+    fn method(&self) {}
+}
+
+fn main() {
+    let point_f64 = Point{ x: 1_f64, y: 1_f64};
+    let d = point_f64.distance();
+    let point_i32 = Point{ x: 1_i32, y: 1_i32};
+    let d = point_i32.distance();
+    //~^ ERROR no method named `distance` found for struct `Point<i32>
+    let d = point_i32.other();
+    //~^ ERROR no method named `other` found for struct `Point
+    let v = vec![1_i32, 2, 3];
+    v.iter().map(|x| x * x).extend(std::iter::once(100));
+    //~^ ERROR no method named `extend` found for struct `Map
+    let wrapper = Wrapper(true);
+    wrapper.method();
+    //~^ ERROR no method named `method` found for struct `Wrapper<bool>
+    wrapper.other();
+    //~^ ERROR no method named `other` found for struct `Wrapper
+    let boolean = true;
+    let wrapper = Wrapper2::<'_, _, 3> {x: &boolean};
+    wrapper.method();
+    //~^ ERROR no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>
+    wrapper.other();
+    //~^ ERROR no method named `other` found for struct `Wrapper2
+    let a = vec![1, 2, 3];
+    a.not_found();
+    //~^ ERROR no method named `not_found` found for struct `Vec
+    let s = Struct::<f64>::default();
+    s.method();
+    //~^ ERROR the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied
+}
diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr
new file mode 100644
index 00000000000..1671e5e5e64
--- /dev/null
+++ b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr
@@ -0,0 +1,97 @@
+error[E0599]: no method named `distance` found for struct `Point<i32>` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:82:23
+   |
+LL | struct Point<T> {
+   | --------------- method `distance` not found for this
+...
+LL |     let d = point_i32.distance();
+   |                       ^^^^^^^^ method not found in `Point<i32>`
+   |
+   = note: the method was found for
+           - `Point<f64>`
+
+error[E0599]: no method named `other` found for struct `Point` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:84:23
+   |
+LL | struct Point<T> {
+   | --------------- method `other` not found for this
+...
+LL |     let d = point_i32.other();
+   |                       ^^^^^ method not found in `Point<i32>`
+
+error[E0599]: no method named `extend` found for struct `Map` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:87:29
+   |
+LL |     v.iter().map(|x| x * x).extend(std::iter::once(100));
+   |                             ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:27]>`
+
+error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:90:13
+   |
+LL | struct Wrapper<T>(T);
+   | --------------------- method `method` not found for this
+...
+LL |     wrapper.method();
+   |             ^^^^^^ method not found in `Wrapper<bool>`
+   |
+   = note: the method was found for
+           - `Wrapper<i8>`
+           - `Wrapper<i16>`
+           - `Wrapper<i32>`
+           - `Wrapper<i64>`
+           and 2 more types
+
+error[E0599]: no method named `other` found for struct `Wrapper` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:92:13
+   |
+LL | struct Wrapper<T>(T);
+   | --------------------- method `other` not found for this
+...
+LL |     wrapper.other();
+   |             ^^^^^ method not found in `Wrapper<bool>`
+
+error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:96:13
+   |
+LL | struct Wrapper2<'a, T, const C: usize> {
+   | -------------------------------------- method `method` not found for this
+...
+LL |     wrapper.method();
+   |             ^^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
+   |
+   = note: the method was found for
+           - `Wrapper2<'a, i8, C>`
+           - `Wrapper2<'a, i16, C>`
+           - `Wrapper2<'a, i32, C>`
+
+error[E0599]: no method named `other` found for struct `Wrapper2` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:98:13
+   |
+LL | struct Wrapper2<'a, T, const C: usize> {
+   | -------------------------------------- method `other` not found for this
+...
+LL |     wrapper.other();
+   |             ^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>`
+
+error[E0599]: no method named `not_found` found for struct `Vec<{integer}>` in the current scope
+  --> $DIR/method-not-found-generic-arg-elision.rs:101:7
+   |
+LL |     a.not_found();
+   |       ^^^^^^^^^ method not found in `Vec<{integer}>`
+
+error[E0599]: the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied
+  --> $DIR/method-not-found-generic-arg-elision.rs:104:7
+   |
+LL | struct Struct<T>{
+   | ---------------- method `method` not found for this
+...
+LL |     s.method();
+   |       ^^^^^^ method cannot be called on `Struct<f64>` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `f64: Eq`
+           `f64: Ord`
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/mir/issue-80742.stderr b/src/test/ui/mir/issue-80742.stderr
index 8400aab308e..961234cf7e8 100644
--- a/src/test/ui/mir/issue-80742.stderr
+++ b/src/test/ui/mir/issue-80742.stderr
@@ -1,4 +1,4 @@
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL |     intrinsics::size_of::<T>()
@@ -35,7 +35,7 @@ LL |   pub trait Debug {
    = note: the following trait bounds were not satisfied:
            `dyn Debug: Sized`
 
-error[E0080]: evaluation of constant value failed
+error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
    |
 LL |     intrinsics::size_of::<T>()
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr
index 388c978d038..6a97d1ee3b8 100644
--- a/src/test/ui/mismatched_types/cast-rfc0401.stderr
+++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr
@@ -24,7 +24,12 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8`
   --> $DIR/cast-rfc0401.rs:29:13
    |
 LL |     let _ = v as &u8;
-   |             ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+   |             ^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL |     let _ = &*v as &u8;
+   |             ^^
 
 error[E0605]: non-primitive cast: `*const u8` as `E`
   --> $DIR/cast-rfc0401.rs:30:13
diff --git a/src/test/ui/no-stdio.rs b/src/test/ui/no-stdio.rs
index 68e6fa838b4..24985386a97 100644
--- a/src/test/ui/no-stdio.rs
+++ b/src/test/ui/no-stdio.rs
@@ -2,6 +2,8 @@
 // ignore-android
 // ignore-emscripten no processes
 // ignore-sgx no processes
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 #![feature(rustc_private)]
 
diff --git a/src/test/ui/option-to-result.stderr b/src/test/ui/option-to-result.stderr
deleted file mode 100644
index 551b9f4650a..00000000000
--- a/src/test/ui/option-to-result.stderr
+++ /dev/null
@@ -1,35 +0,0 @@
-error[E0277]: `?` couldn't convert the error to `()`
-  --> $DIR/option-to-result.rs:5:6
-   |
-LL | fn test_result() -> Result<(),()> {
-   |                     ------------- expected `()` because of this
-LL |     let a:Option<()> = Some(());
-LL |     a?;
-   |      ^ the trait `From<NoneError>` is not implemented for `()`
-   |
-   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
-   = note: required by `from`
-help: consider converting the `Option<T>` into a `Result<T, _>` using `Option::ok_or` or `Option::ok_or_else`
-   |
-LL |     a.ok_or_else(|| /* error value */)?;
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: `?` couldn't convert the error to `NoneError`
-  --> $DIR/option-to-result.rs:11:6
-   |
-LL | fn test_option() -> Option<i32>{
-   |                     ----------- expected `NoneError` because of this
-LL |     let a:Result<i32, i32> = Ok(5);
-LL |     a?;
-   |      ^ the trait `From<i32>` is not implemented for `NoneError`
-   |
-   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
-   = note: required by `from`
-help: consider converting the `Result<T, _>` into an `Option<T>` using `Result::ok`
-   |
-LL |     a.ok()?;
-   |      ^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/parser/fn-field-parse-error-ice.rs b/src/test/ui/parser/fn-field-parse-error-ice.rs
new file mode 100644
index 00000000000..4ea55062fc4
--- /dev/null
+++ b/src/test/ui/parser/fn-field-parse-error-ice.rs
@@ -0,0 +1,10 @@
+// Regression test for #85794
+
+struct Baz {
+    inner : dyn fn ()
+    //~^ ERROR expected `,`, or `}`, found keyword `fn`
+    //~| ERROR functions are not allowed in struct definitions
+    //~| ERROR cannot find type `dyn` in this scope
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/fn-field-parse-error-ice.stderr b/src/test/ui/parser/fn-field-parse-error-ice.stderr
new file mode 100644
index 00000000000..d582f61cc97
--- /dev/null
+++ b/src/test/ui/parser/fn-field-parse-error-ice.stderr
@@ -0,0 +1,24 @@
+error: expected `,`, or `}`, found keyword `fn`
+  --> $DIR/fn-field-parse-error-ice.rs:4:16
+   |
+LL |     inner : dyn fn ()
+   |                ^ help: try adding a comma: `,`
+
+error: functions are not allowed in struct definitions
+  --> $DIR/fn-field-parse-error-ice.rs:4:17
+   |
+LL |     inner : dyn fn ()
+   |                 ^^
+   |
+   = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks
+   = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information
+
+error[E0412]: cannot find type `dyn` in this scope
+  --> $DIR/fn-field-parse-error-ice.rs:4:13
+   |
+LL |     inner : dyn fn ()
+   |             ^^^ not found in this scope
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/src/test/ui/prelude2021.rs b/src/test/ui/prelude2021.rs
new file mode 100644
index 00000000000..3a9fd693228
--- /dev/null
+++ b/src/test/ui/prelude2021.rs
@@ -0,0 +1,7 @@
+// check-pass
+// edition:2021
+// compile-flags: -Zunstable-options
+
+fn main() {
+    let _: u16 = 123i32.try_into().unwrap();
+}
diff --git a/library/proc_macro/tests/test.rs b/src/test/ui/proc-macro/auxiliary/api/cmp.rs
index d2e6b0bb809..5784a6e5d94 100644
--- a/library/proc_macro/tests/test.rs
+++ b/src/test/ui/proc-macro/auxiliary/api/cmp.rs
@@ -1,8 +1,10 @@
-#![feature(proc_macro_span)]
+use proc_macro::{LineColumn, Punct, Spacing};
 
-use proc_macro::{LineColumn, Punct};
+pub fn test() {
+    test_line_column_ord();
+    test_punct_eq();
+}
 
-#[test]
 fn test_line_column_ord() {
     let line0_column0 = LineColumn { line: 0, column: 0 };
     let line0_column1 = LineColumn { line: 0, column: 1 };
@@ -11,10 +13,9 @@ fn test_line_column_ord() {
     assert!(line0_column1 < line1_column0);
 }
 
-#[test]
 fn test_punct_eq() {
-    // Good enough if it typechecks, since proc_macro::Punct can't exist in a test.
-    fn _check(punct: Punct) {
-        let _ = punct == ':';
-    }
+    let colon_alone = Punct::new(':', Spacing::Alone);
+    assert_eq!(colon_alone, ':');
+    let colon_joint = Punct::new(':', Spacing::Joint);
+    assert_eq!(colon_joint, ':');
 }
diff --git a/src/test/ui/proc-macro/auxiliary/api/mod.rs b/src/test/ui/proc-macro/auxiliary/api/mod.rs
new file mode 100644
index 00000000000..739c25132e7
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/api/mod.rs
@@ -0,0 +1,24 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![crate_name = "proc_macro_api_tests"]
+#![feature(proc_macro_span)]
+#![deny(dead_code)] // catch if a test function is never called
+
+extern crate proc_macro;
+
+mod cmp;
+mod parse;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn run(input: TokenStream) -> TokenStream {
+    assert!(input.is_empty());
+
+    cmp::test();
+    parse::test();
+
+    TokenStream::new()
+}
diff --git a/src/test/ui/proc-macro/auxiliary/api/parse.rs b/src/test/ui/proc-macro/auxiliary/api/parse.rs
new file mode 100644
index 00000000000..4105236b7f2
--- /dev/null
+++ b/src/test/ui/proc-macro/auxiliary/api/parse.rs
@@ -0,0 +1,23 @@
+use proc_macro::Literal;
+
+pub fn test() {
+    test_parse_literal();
+}
+
+fn test_parse_literal() {
+    assert_eq!("1".parse::<Literal>().unwrap().to_string(), "1");
+    assert_eq!("1.0".parse::<Literal>().unwrap().to_string(), "1.0");
+    assert_eq!("'a'".parse::<Literal>().unwrap().to_string(), "'a'");
+    assert_eq!("\"\n\"".parse::<Literal>().unwrap().to_string(), "\"\n\"");
+    assert_eq!("b\"\"".parse::<Literal>().unwrap().to_string(), "b\"\"");
+    assert_eq!("r##\"\"##".parse::<Literal>().unwrap().to_string(), "r##\"\"##");
+    assert_eq!("10ulong".parse::<Literal>().unwrap().to_string(), "10ulong");
+
+    assert!("0 1".parse::<Literal>().is_err());
+    assert!("'a".parse::<Literal>().is_err());
+    assert!(" 0".parse::<Literal>().is_err());
+    assert!("0 ".parse::<Literal>().is_err());
+    assert!("/* comment */0".parse::<Literal>().is_err());
+    assert!("0/* comment */".parse::<Literal>().is_err());
+    assert!("0// comment".parse::<Literal>().is_err());
+}
diff --git a/src/test/ui/proc-macro/test.rs b/src/test/ui/proc-macro/test.rs
new file mode 100644
index 00000000000..c96aa73175f
--- /dev/null
+++ b/src/test/ui/proc-macro/test.rs
@@ -0,0 +1,12 @@
+// check-pass
+// aux-build:api/mod.rs
+
+//! This is for everything that *would* be a #[test] inside of libproc_macro,
+//! except for the fact that proc_macro objects are not capable of existing
+//! inside of an ordinary Rust test execution, only inside a macro.
+
+extern crate proc_macro_api_tests;
+
+proc_macro_api_tests::run!();
+
+fn main() {}
diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr
index 381959b7ae4..db5042b40d8 100644
--- a/src/test/ui/question-mark-type-infer.stderr
+++ b/src/test/ui/question-mark-type-infer.stderr
@@ -1,11 +1,10 @@
-error[E0283]: type annotations needed
+error[E0284]: type annotations needed
   --> $DIR/question-mark-type-infer.rs:12:21
    |
 LL |     l.iter().map(f).collect()?
    |                     ^^^^^^^ cannot infer type
    |
-   = note: cannot satisfy `_: Try`
-   = note: required by `into_result`
+   = note: cannot satisfy `<_ as Try>::Residual == _`
 help: consider specifying the type argument in the method call
    |
 LL |     l.iter().map(f).collect::<B>()?
@@ -13,4 +12,4 @@ LL |     l.iter().map(f).collect::<B>()?
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0283`.
+For more information about this error, try `rustc --explain E0284`.
diff --git a/src/test/ui/resolve/issue-85348.rs b/src/test/ui/resolve/issue-85348.rs
new file mode 100644
index 00000000000..3a33c193408
--- /dev/null
+++ b/src/test/ui/resolve/issue-85348.rs
@@ -0,0 +1,12 @@
+// Checks whether shadowing a const parameter leads to an ICE (#85348).
+
+impl<const N: usize> ArrayWindowsExample {
+//~^ ERROR: cannot find type `ArrayWindowsExample` in this scope [E0412]
+    fn next() {
+        let mut N;
+        //~^ ERROR: let bindings cannot shadow const parameters [E0530]
+        //~| ERROR: type annotations needed [E0282]
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/issue-85348.stderr b/src/test/ui/resolve/issue-85348.stderr
new file mode 100644
index 00000000000..f475c26f32b
--- /dev/null
+++ b/src/test/ui/resolve/issue-85348.stderr
@@ -0,0 +1,25 @@
+error[E0530]: let bindings cannot shadow const parameters
+  --> $DIR/issue-85348.rs:6:17
+   |
+LL | impl<const N: usize> ArrayWindowsExample {
+   |            - the const parameter `N` is defined here
+...
+LL |         let mut N;
+   |                 ^ cannot be named the same as a const parameter
+
+error[E0412]: cannot find type `ArrayWindowsExample` in this scope
+  --> $DIR/issue-85348.rs:3:22
+   |
+LL | impl<const N: usize> ArrayWindowsExample {
+   |                      ^^^^^^^^^^^^^^^^^^^ not found in this scope
+
+error[E0282]: type annotations needed
+  --> $DIR/issue-85348.rs:6:13
+   |
+LL |         let mut N;
+   |             ^^^^^ consider giving `N` a type
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0282, E0412, E0530.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/resolve/shadow-const-param.rs b/src/test/ui/resolve/shadow-const-param.rs
new file mode 100644
index 00000000000..c435c16dc67
--- /dev/null
+++ b/src/test/ui/resolve/shadow-const-param.rs
@@ -0,0 +1,20 @@
+// Checks that const parameters cannot be shadowed with fresh bindings
+// even in syntactically unambiguous contexts. See
+// https://github.com/rust-lang/rust/issues/33118#issuecomment-233962221
+
+fn foo<const N: i32>(i: i32) -> bool {
+    match i {
+        N @ _ => true,
+        //~^ ERROR: match bindings cannot shadow const parameters [E0530]
+    }
+}
+
+fn bar<const N: i32>(i: i32) -> bool {
+    let N @ _ = 0;
+    //~^ ERROR: let bindings cannot shadow const parameters [E0530]
+    match i {
+        N @ _ => true,
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/resolve/shadow-const-param.stderr b/src/test/ui/resolve/shadow-const-param.stderr
new file mode 100644
index 00000000000..fbd0d811000
--- /dev/null
+++ b/src/test/ui/resolve/shadow-const-param.stderr
@@ -0,0 +1,20 @@
+error[E0530]: match bindings cannot shadow const parameters
+  --> $DIR/shadow-const-param.rs:7:9
+   |
+LL | fn foo<const N: i32>(i: i32) -> bool {
+   |              - the const parameter `N` is defined here
+LL |     match i {
+LL |         N @ _ => true,
+   |         ^ cannot be named the same as a const parameter
+
+error[E0530]: let bindings cannot shadow const parameters
+  --> $DIR/shadow-const-param.rs:13:9
+   |
+LL | fn bar<const N: i32>(i: i32) -> bool {
+   |              - the const parameter `N` is defined here
+LL |     let N @ _ = 0;
+   |         ^ cannot be named the same as a const parameter
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0530`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
index 1adce5e0150..6985f1b71a8 100644
--- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
+++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
@@ -502,10 +502,10 @@ LL |     if (let 0 = 0)? {}
    |        ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
    |
    = help: the trait `Try` is not implemented for `bool`
-   = note: required by `into_result`
+   = note: required by `branch`
 
-error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/disallowed-positions.rs:46:8
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/disallowed-positions.rs:46:19
    |
 LL | / fn nested_within_if_expr() {
 LL | |     if &let 0 = 0 {}
@@ -513,14 +513,14 @@ LL | |
 LL | |
 ...  |
 LL | |     if (let 0 = 0)? {}
-   | |        ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
+   | |                   ^ cannot use the `?` operator in a function that returns `()`
 ...  |
 LL | |     if let true = let true = true {}
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `()`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<_>` is not implemented for `()`
+   = note: required by `from_residual`
 
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:56:8
@@ -660,7 +660,7 @@ LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
-   = note: required by `into_result`
+   = note: required by `branch`
 
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:96:11
@@ -690,10 +690,10 @@ LL |     while (let 0 = 0)? {}
    |           ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
    |
    = help: the trait `Try` is not implemented for `bool`
-   = note: required by `into_result`
+   = note: required by `branch`
 
-error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/disallowed-positions.rs:110:11
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/disallowed-positions.rs:110:22
    |
 LL | / fn nested_within_while_expr() {
 LL | |     while &let 0 = 0 {}
@@ -701,14 +701,14 @@ LL | |
 LL | |
 ...  |
 LL | |     while (let 0 = 0)? {}
-   | |           ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
+   | |                      ^ cannot use the `?` operator in a function that returns `()`
 ...  |
 LL | |     while let true = let true = true {}
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `()`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<_>` is not implemented for `()`
+   = note: required by `from_residual`
 
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:120:11
@@ -848,7 +848,7 @@ LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
-   = note: required by `into_result`
+   = note: required by `branch`
 
 error[E0614]: type `bool` cannot be dereferenced
   --> $DIR/disallowed-positions.rs:173:5
@@ -869,10 +869,10 @@ LL |     (let 0 = 0)?;
    |     ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
    |
    = help: the trait `Try` is not implemented for `bool`
-   = note: required by `into_result`
+   = note: required by `branch`
 
-error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/disallowed-positions.rs:183:5
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/disallowed-positions.rs:183:16
    |
 LL | / fn outside_if_and_while_expr() {
 LL | |     &let 0 = 0;
@@ -880,14 +880,14 @@ LL | |
 LL | |     !let 0 = 0;
 ...  |
 LL | |     (let 0 = 0)?;
-   | |     ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
+   | |                ^ cannot use the `?` operator in a function that returns `()`
 ...  |
 LL | |
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `()`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<_>` is not implemented for `()`
+   = note: required by `from_residual`
 
 error[E0308]: mismatched types
   --> $DIR/disallowed-positions.rs:198:10
@@ -916,7 +916,7 @@ LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
-   = note: required by `into_result`
+   = note: required by `branch`
 
 error: aborting due to 104 previous errors; 2 warnings emitted
 
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs
index 58a2c271ecf..e0842bfa4cd 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs
@@ -8,6 +8,8 @@
 
 // check-pass
 // only-x86_64
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 
 #![feature(target_feature_11)]
 
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs
index af35bc2014b..a59d7c2d784 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs
@@ -1,6 +1,8 @@
 // Tests #73631: closures inherit `#[target_feature]` annotations
 
 // check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 // only-x86_64
 
 #![feature(target_feature_11)]
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
index 06cfdde3fb9..cf5815df56e 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/fn-ptr.rs:9:21
+  --> $DIR/fn-ptr.rs:11:21
    |
 LL | #[target_feature(enable = "sse2")]
    | ---------------------------------- `#[target_feature]` added here
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs
index 3ecea5c5313..c95d4a08e48 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs
@@ -1,3 +1,5 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 // only-x86_64
 
 #![feature(target_feature_11)]
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
new file mode 100644
index 00000000000..cf5815df56e
--- /dev/null
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
@@ -0,0 +1,18 @@
+error[E0308]: mismatched types
+  --> $DIR/fn-ptr.rs:11:21
+   |
+LL | #[target_feature(enable = "sse2")]
+   | ---------------------------------- `#[target_feature]` added here
+...
+LL |     let foo: fn() = foo;
+   |              ----   ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers
+   |              |
+   |              expected due to this
+   |
+   = note: expected fn pointer `fn()`
+                 found fn item `fn() {foo}`
+   = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr
index b9f748640b5..79273a1dcbf 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:21:5
+  --> $DIR/safe-calls.rs:23:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -7,7 +7,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:22:5
+  --> $DIR/safe-calls.rs:24:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -15,7 +15,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:23:5
+  --> $DIR/safe-calls.rs:25:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -23,7 +23,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:28:5
+  --> $DIR/safe-calls.rs:30:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -31,7 +31,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:29:5
+  --> $DIR/safe-calls.rs:31:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -39,7 +39,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:34:5
+  --> $DIR/safe-calls.rs:36:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -47,7 +47,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:35:5
+  --> $DIR/safe-calls.rs:37:5
    |
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
@@ -55,7 +55,7 @@ LL |     avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:36:5
+  --> $DIR/safe-calls.rs:38:5
    |
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
@@ -63,7 +63,7 @@ LL |     Quux.avx_bmi2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:42:5
+  --> $DIR/safe-calls.rs:44:5
    |
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
@@ -71,7 +71,7 @@ LL |     sse2();
    = note: can only be called if the required target features are available
 
 error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
-  --> $DIR/safe-calls.rs:45:18
+  --> $DIR/safe-calls.rs:47:18
    |
 LL | const name: () = sse2();
    |                  ^^^^^^ call to function with `#[target_feature]`
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
index 8da3affc447..de0b89f46ba 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
@@ -1,3 +1,5 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 // only-x86_64
 
 #![feature(target_feature_11)]
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
new file mode 100644
index 00000000000..79273a1dcbf
--- /dev/null
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
@@ -0,0 +1,83 @@
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:23:5
+   |
+LL |     sse2();
+   |     ^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:24:5
+   |
+LL |     avx_bmi2();
+   |     ^^^^^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:25:5
+   |
+LL |     Quux.avx_bmi2();
+   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:30:5
+   |
+LL |     avx_bmi2();
+   |     ^^^^^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:31:5
+   |
+LL |     Quux.avx_bmi2();
+   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:36:5
+   |
+LL |     sse2();
+   |     ^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:37:5
+   |
+LL |     avx_bmi2();
+   |     ^^^^^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:38:5
+   |
+LL |     Quux.avx_bmi2();
+   |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:44:5
+   |
+LL |     sse2();
+   |     ^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
+  --> $DIR/safe-calls.rs:47:18
+   |
+LL | const name: () = sse2();
+   |                  ^^^^^^ call to function with `#[target_feature]`
+   |
+   = note: can only be called if the required target features are available
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/running-with-no-runtime.rs b/src/test/ui/running-with-no-runtime.rs
index c321e86dc18..c575a6bec8e 100644
--- a/src/test/ui/running-with-no-runtime.rs
+++ b/src/test/ui/running-with-no-runtime.rs
@@ -1,6 +1,8 @@
 // run-pass
 // ignore-emscripten spawning processes is not supported
 // ignore-sgx no processes
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 #![feature(start)]
 
diff --git a/src/test/ui/safe-extern-statics-mut.stderr b/src/test/ui/safe-extern-statics-mut.mir.stderr
index 38803883414..cec5f9d9c9f 100644
--- a/src/test/ui/safe-extern-statics-mut.stderr
+++ b/src/test/ui/safe-extern-statics-mut.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics-mut.rs:11:13
+  --> $DIR/safe-extern-statics-mut.rs:13:13
    |
 LL |     let b = B;
    |             ^ use of mutable static
@@ -7,7 +7,7 @@ LL |     let b = B;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics-mut.rs:12:14
+  --> $DIR/safe-extern-statics-mut.rs:14:14
    |
 LL |     let rb = &B;
    |              ^^ use of mutable static
@@ -15,7 +15,7 @@ LL |     let rb = &B;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics-mut.rs:13:14
+  --> $DIR/safe-extern-statics-mut.rs:15:14
    |
 LL |     let xb = XB;
    |              ^^ use of mutable static
@@ -23,7 +23,7 @@ LL |     let xb = XB;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics-mut.rs:14:15
+  --> $DIR/safe-extern-statics-mut.rs:16:15
    |
 LL |     let xrb = &XB;
    |               ^^^ use of mutable static
diff --git a/src/test/ui/safe-extern-statics-mut.rs b/src/test/ui/safe-extern-statics-mut.rs
index 324fa443aa5..389a4589a71 100644
--- a/src/test/ui/safe-extern-statics-mut.rs
+++ b/src/test/ui/safe-extern-statics-mut.rs
@@ -1,4 +1,6 @@
 // aux-build:extern-statics.rs
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 
 extern crate extern_statics;
 use extern_statics::*;
diff --git a/src/test/ui/safe-extern-statics-mut.thir.stderr b/src/test/ui/safe-extern-statics-mut.thir.stderr
new file mode 100644
index 00000000000..8e6d2805a0b
--- /dev/null
+++ b/src/test/ui/safe-extern-statics-mut.thir.stderr
@@ -0,0 +1,35 @@
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics-mut.rs:13:13
+   |
+LL |     let b = B;
+   |             ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics-mut.rs:14:15
+   |
+LL |     let rb = &B;
+   |               ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics-mut.rs:15:14
+   |
+LL |     let xb = XB;
+   |              ^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics-mut.rs:16:16
+   |
+LL |     let xrb = &XB;
+   |                ^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/safe-extern-statics.stderr b/src/test/ui/safe-extern-statics.mir.stderr
index b42572ea3ee..102abd0816f 100644
--- a/src/test/ui/safe-extern-statics.stderr
+++ b/src/test/ui/safe-extern-statics.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics.rs:11:13
+  --> $DIR/safe-extern-statics.rs:13:13
    |
 LL |     let a = A;
    |             ^ use of extern static
@@ -7,7 +7,7 @@ LL |     let a = A;
    = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics.rs:12:14
+  --> $DIR/safe-extern-statics.rs:14:14
    |
 LL |     let ra = &A;
    |              ^^ use of extern static
@@ -15,7 +15,7 @@ LL |     let ra = &A;
    = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics.rs:13:14
+  --> $DIR/safe-extern-statics.rs:15:14
    |
 LL |     let xa = XA;
    |              ^^ use of extern static
@@ -23,7 +23,7 @@ LL |     let xa = XA;
    = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
-  --> $DIR/safe-extern-statics.rs:14:15
+  --> $DIR/safe-extern-statics.rs:16:15
    |
 LL |     let xra = &XA;
    |               ^^^ use of extern static
diff --git a/src/test/ui/safe-extern-statics.rs b/src/test/ui/safe-extern-statics.rs
index 6fa4c4aaca5..0aa90c442ea 100644
--- a/src/test/ui/safe-extern-statics.rs
+++ b/src/test/ui/safe-extern-statics.rs
@@ -1,4 +1,6 @@
 // aux-build:extern-statics.rs
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
 
 extern crate extern_statics;
 use extern_statics::*;
diff --git a/src/test/ui/safe-extern-statics.thir.stderr b/src/test/ui/safe-extern-statics.thir.stderr
new file mode 100644
index 00000000000..7fd2182c4c6
--- /dev/null
+++ b/src/test/ui/safe-extern-statics.thir.stderr
@@ -0,0 +1,35 @@
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics.rs:13:13
+   |
+LL |     let a = A;
+   |             ^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics.rs:14:15
+   |
+LL |     let ra = &A;
+   |               ^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics.rs:15:14
+   |
+LL |     let xa = XA;
+   |              ^^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+  --> $DIR/safe-extern-statics.rs:16:16
+   |
+LL |     let xra = &XA;
+   |                ^^ use of extern static
+   |
+   = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/sanitize/crt-static.rs b/src/test/ui/sanitize/crt-static.rs
new file mode 100644
index 00000000000..f5dd2a40cc4
--- /dev/null
+++ b/src/test/ui/sanitize/crt-static.rs
@@ -0,0 +1,5 @@
+// compile-flags: -Z sanitizer=address -C target-feature=+crt-static --target x86_64-unknown-linux-gnu
+
+#![feature(no_core)]
+#![no_core]
+#![no_main]
diff --git a/src/test/ui/sanitize/crt-static.stderr b/src/test/ui/sanitize/crt-static.stderr
new file mode 100644
index 00000000000..3a9c636d760
--- /dev/null
+++ b/src/test/ui/sanitize/crt-static.stderr
@@ -0,0 +1,4 @@
+error: Sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/simd/simd-intrinsic-generic-comparison.rs b/src/test/ui/simd/simd-intrinsic-generic-comparison.rs
index 103132c18ae..da5c42a1a98 100644
--- a/src/test/ui/simd/simd-intrinsic-generic-comparison.rs
+++ b/src/test/ui/simd/simd-intrinsic-generic-comparison.rs
@@ -1,5 +1,7 @@
 // run-pass
 // ignore-emscripten FIXME(#45351) hits an LLVM assert
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
 
 #![feature(repr_simd, platform_intrinsics, concat_idents)]
 #![allow(non_camel_case_types)]
diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr
index 723c4a7a1fb..b251e8a438a 100644
--- a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr
+++ b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr
@@ -1,11 +1,11 @@
-error: lifetime parameter `'b` only used once
-  --> $DIR/one-use-in-fn-argument-in-band.rs:11:22
+error: lifetime parameter `'a` only used once
+  --> $DIR/one-use-in-fn-argument-in-band.rs:11:10
    |
 LL | fn a(x: &'a u32, y: &'b u32) {
-   |                      ^^-
-   |                      |
-   |                      this lifetime is only used here
-   |                      help: elide the single-use lifetime
+   |          ^^-
+   |          |
+   |          this lifetime is only used here
+   |          help: elide the single-use lifetime
    |
 note: the lint level is defined here
   --> $DIR/one-use-in-fn-argument-in-band.rs:4:9
@@ -13,14 +13,14 @@ note: the lint level is defined here
 LL | #![deny(single_use_lifetimes)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: lifetime parameter `'a` only used once
-  --> $DIR/one-use-in-fn-argument-in-band.rs:11:10
+error: lifetime parameter `'b` only used once
+  --> $DIR/one-use-in-fn-argument-in-band.rs:11:22
    |
 LL | fn a(x: &'a u32, y: &'b u32) {
-   |          ^^-
-   |          |
-   |          this lifetime is only used here
-   |          help: elide the single-use lifetime
+   |                      ^^-
+   |                      |
+   |                      this lifetime is only used here
+   |                      help: elide the single-use lifetime
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/span/lint-unused-unsafe.stderr b/src/test/ui/span/lint-unused-unsafe.mir.stderr
index c35a3349121..c2adb7be7a2 100644
--- a/src/test/ui/span/lint-unused-unsafe.stderr
+++ b/src/test/ui/span/lint-unused-unsafe.mir.stderr
@@ -1,23 +1,23 @@
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:16:13
+  --> $DIR/lint-unused-unsafe.rs:19:13
    |
 LL | fn bad1() { unsafe {} }
    |             ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/lint-unused-unsafe.rs:4:9
+  --> $DIR/lint-unused-unsafe.rs:7:9
    |
 LL | #![deny(unused_unsafe)]
    |         ^^^^^^^^^^^^^
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:17:13
+  --> $DIR/lint-unused-unsafe.rs:20:13
    |
 LL | fn bad2() { unsafe { bad1() } }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:18:20
+  --> $DIR/lint-unused-unsafe.rs:21:20
    |
 LL | unsafe fn bad3() { unsafe {} }
    | ----------------   ^^^^^^ unnecessary `unsafe` block
@@ -25,13 +25,13 @@ LL | unsafe fn bad3() { unsafe {} }
    | because it's nested under this `unsafe` fn
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:19:13
+  --> $DIR/lint-unused-unsafe.rs:22:13
    |
 LL | fn bad4() { unsafe { callback(||{}) } }
    |             ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:20:20
+  --> $DIR/lint-unused-unsafe.rs:23:20
    |
 LL | unsafe fn bad5() { unsafe { unsf() } }
    | ----------------   ^^^^^^ unnecessary `unsafe` block
@@ -39,7 +39,7 @@ LL | unsafe fn bad5() { unsafe { unsf() } }
    | because it's nested under this `unsafe` fn
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:23:9
+  --> $DIR/lint-unused-unsafe.rs:26:9
    |
 LL |     unsafe {                             // don't put the warning here
    |     ------ because it's nested under this `unsafe` block
@@ -47,7 +47,7 @@ LL |         unsafe {
    |         ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:29:5
+  --> $DIR/lint-unused-unsafe.rs:32:5
    |
 LL | unsafe fn bad7() {
    | ---------------- because it's nested under this `unsafe` fn
@@ -55,7 +55,7 @@ LL |     unsafe {
    |     ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/lint-unused-unsafe.rs:30:9
+  --> $DIR/lint-unused-unsafe.rs:33:9
    |
 LL | unsafe fn bad7() {
    | ---------------- because it's nested under this `unsafe` fn
diff --git a/src/test/ui/span/lint-unused-unsafe.rs b/src/test/ui/span/lint-unused-unsafe.rs
index b6c4894d918..b889cc981ca 100644
--- a/src/test/ui/span/lint-unused-unsafe.rs
+++ b/src/test/ui/span/lint-unused-unsafe.rs
@@ -1,5 +1,8 @@
 // Exercise the unused_unsafe attribute in some positive and negative cases
 
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
 #![allow(dead_code)]
 #![deny(unused_unsafe)]
 
diff --git a/src/test/ui/span/lint-unused-unsafe.thir.stderr b/src/test/ui/span/lint-unused-unsafe.thir.stderr
new file mode 100644
index 00000000000..dda45c3679a
--- /dev/null
+++ b/src/test/ui/span/lint-unused-unsafe.thir.stderr
@@ -0,0 +1,66 @@
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:19:13
+   |
+LL | fn bad1() { unsafe {} }
+   |             ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/lint-unused-unsafe.rs:7:9
+   |
+LL | #![deny(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:20:13
+   |
+LL | fn bad2() { unsafe { bad1() } }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:21:20
+   |
+LL | unsafe fn bad3() { unsafe {} }
+   | ----------------   ^^^^^^ unnecessary `unsafe` block
+   | |
+   | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:22:13
+   |
+LL | fn bad4() { unsafe { callback(||{}) } }
+   |             ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:23:20
+   |
+LL | unsafe fn bad5() { unsafe { unsf() } }
+   | ----------------   ^^^^^^ unnecessary `unsafe` block
+   | |
+   | because it's nested under this `unsafe` fn
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:26:9
+   |
+LL |     unsafe {                             // don't put the warning here
+   |     ------ because it's nested under this `unsafe` block
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:33:9
+   |
+LL |     unsafe {
+   |     ------ because it's nested under this `unsafe` block
+LL |         unsafe {
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/lint-unused-unsafe.rs:32:5
+   |
+LL | unsafe fn bad7() {
+   | ---------------- because it's nested under this `unsafe` fn
+LL |     unsafe {
+   |     ^^^^^^ unnecessary `unsafe` block
+
+error: aborting due to 8 previous errors
+
diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
index fa59d7a0313..d2eea15f398 100644
--- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
+++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr
@@ -1,4 +1,4 @@
-error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id::This) }, (I,)), [])`
+error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[b09c]::Id::This) }, (I,)), [])`
   --> $DIR/repeated_projection_type.rs:19:1
    |
 LL | / impl<I, V: Id<This = (I,)>> X for V {
diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr
index 99523f8eb64..c3e3f543d79 100644
--- a/src/test/ui/stability-attribute/generics-default-stability.stderr
+++ b/src/test/ui/stability-attribute/generics-default-stability.stderr
@@ -169,10 +169,10 @@ LL |     let _: Alias5<isize> = Alias5::Some(0);
    |            ^^^^^^^^^^^^^
 
 warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test
-  --> $DIR/generics-default-stability.rs:231:27
+  --> $DIR/generics-default-stability.rs:231:34
    |
 LL |     let _: Enum4<isize> = Enum4::Some(1);
-   |                           ^^^^^^^^^^^
+   |                                  ^^^^
 
 warning: use of deprecated enum `unstable_generic_param::Enum4`: test
   --> $DIR/generics-default-stability.rs:231:12
@@ -193,10 +193,10 @@ LL |     let _: Enum4<usize> = ENUM4;
    |            ^^^^^^^^^^^^
 
 warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test
-  --> $DIR/generics-default-stability.rs:237:27
+  --> $DIR/generics-default-stability.rs:237:34
    |
 LL |     let _: Enum4<isize> = Enum4::Some(0);
-   |                           ^^^^^^^^^^^
+   |                                  ^^^^
 
 warning: use of deprecated enum `unstable_generic_param::Enum4`: test
   --> $DIR/generics-default-stability.rs:237:12
@@ -205,10 +205,10 @@ LL |     let _: Enum4<isize> = Enum4::Some(0);
    |            ^^^^^^^^^^^^
 
 warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test
-  --> $DIR/generics-default-stability.rs:242:27
+  --> $DIR/generics-default-stability.rs:242:34
    |
 LL |     let _: Enum5<isize> = Enum5::Some(1);
-   |                           ^^^^^^^^^^^
+   |                                  ^^^^
 
 warning: use of deprecated enum `unstable_generic_param::Enum5`: test
   --> $DIR/generics-default-stability.rs:242:12
@@ -229,10 +229,10 @@ LL |     let _: Enum5<usize> = ENUM5;
    |            ^^^^^^^^^^^^
 
 warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test
-  --> $DIR/generics-default-stability.rs:249:27
+  --> $DIR/generics-default-stability.rs:249:34
    |
 LL |     let _: Enum5<isize> = Enum5::Some(0);
-   |                           ^^^^^^^^^^^
+   |                                  ^^^^
 
 warning: use of deprecated enum `unstable_generic_param::Enum5`: test
   --> $DIR/generics-default-stability.rs:249:12
diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.stderr b/src/test/ui/static/static-mut-foreign-requires-unsafe.mir.stderr
index e7ed0b710b2..a4659bc8712 100644
--- a/src/test/ui/static/static-mut-foreign-requires-unsafe.stderr
+++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/static-mut-foreign-requires-unsafe.rs:6:5
+  --> $DIR/static-mut-foreign-requires-unsafe.rs:9:5
    |
 LL |     a += 3;
    |     ^^^^^^ use of mutable static
@@ -7,7 +7,7 @@ LL |     a += 3;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/static-mut-foreign-requires-unsafe.rs:7:5
+  --> $DIR/static-mut-foreign-requires-unsafe.rs:10:5
    |
 LL |     a = 4;
    |     ^^^^^ use of mutable static
@@ -15,7 +15,7 @@ LL |     a = 4;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/static-mut-foreign-requires-unsafe.rs:8:14
+  --> $DIR/static-mut-foreign-requires-unsafe.rs:11:14
    |
 LL |     let _b = a;
    |              ^ use of mutable static
diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.rs b/src/test/ui/static/static-mut-foreign-requires-unsafe.rs
index 90aa2537a82..4f96acb3375 100644
--- a/src/test/ui/static/static-mut-foreign-requires-unsafe.rs
+++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 extern "C" {
     static mut a: i32;
 }
diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr b/src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr
new file mode 100644
index 00000000000..2c62d4d8f3b
--- /dev/null
+++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr
@@ -0,0 +1,27 @@
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/static-mut-foreign-requires-unsafe.rs:9:5
+   |
+LL |     a += 3;
+   |     ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/static-mut-foreign-requires-unsafe.rs:10:5
+   |
+LL |     a = 4;
+   |     ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/static-mut-foreign-requires-unsafe.rs:11:14
+   |
+LL |     let _b = a;
+   |              ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/static/static-mut-requires-unsafe.stderr b/src/test/ui/static/static-mut-requires-unsafe.mir.stderr
index 85e468b333c..0d4ce056fc2 100644
--- a/src/test/ui/static/static-mut-requires-unsafe.stderr
+++ b/src/test/ui/static/static-mut-requires-unsafe.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/static-mut-requires-unsafe.rs:4:5
+  --> $DIR/static-mut-requires-unsafe.rs:7:5
    |
 LL |     a += 3;
    |     ^^^^^^ use of mutable static
@@ -7,7 +7,7 @@ LL |     a += 3;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/static-mut-requires-unsafe.rs:5:5
+  --> $DIR/static-mut-requires-unsafe.rs:8:5
    |
 LL |     a = 4;
    |     ^^^^^ use of mutable static
@@ -15,7 +15,7 @@ LL |     a = 4;
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error[E0133]: use of mutable static is unsafe and requires unsafe function or block
-  --> $DIR/static-mut-requires-unsafe.rs:6:14
+  --> $DIR/static-mut-requires-unsafe.rs:9:14
    |
 LL |     let _b = a;
    |              ^ use of mutable static
diff --git a/src/test/ui/static/static-mut-requires-unsafe.rs b/src/test/ui/static/static-mut-requires-unsafe.rs
index 413b97e431d..ea3ba095007 100644
--- a/src/test/ui/static/static-mut-requires-unsafe.rs
+++ b/src/test/ui/static/static-mut-requires-unsafe.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 static mut a: isize = 3;
 
 fn main() {
diff --git a/src/test/ui/static/static-mut-requires-unsafe.thir.stderr b/src/test/ui/static/static-mut-requires-unsafe.thir.stderr
new file mode 100644
index 00000000000..1a1cf14271a
--- /dev/null
+++ b/src/test/ui/static/static-mut-requires-unsafe.thir.stderr
@@ -0,0 +1,27 @@
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/static-mut-requires-unsafe.rs:7:5
+   |
+LL |     a += 3;
+   |     ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/static-mut-requires-unsafe.rs:8:5
+   |
+LL |     a = 4;
+   |     ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/static-mut-requires-unsafe.rs:9:14
+   |
+LL |     let _b = a;
+   |              ^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/suffixed-literal-meta.rs b/src/test/ui/suffixed-literal-meta.rs
index 319264aec9c..a6531490c01 100644
--- a/src/test/ui/suffixed-literal-meta.rs
+++ b/src/test/ui/suffixed-literal-meta.rs
@@ -1,4 +1,4 @@
-#![feature(rustc_attrs, extended_key_value_attributes)]
+#![feature(rustc_attrs)]
 
 #[rustc_dummy = 1usize] //~ ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1u8] //~ ERROR: suffixed literals are not allowed in attributes
diff --git a/src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs b/src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs
new file mode 100644
index 00000000000..d71747f9687
--- /dev/null
+++ b/src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs
@@ -0,0 +1,18 @@
+// force-host
+// no-prefer-dynamic
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::{quote, TokenStream};
+
+#[proc_macro_attribute]
+pub fn hello(_: TokenStream, _: TokenStream) -> TokenStream {
+    quote!(
+        fn f(_: &mut i32) {}
+        fn g() {
+            f(123);
+        }
+    )
+}
diff --git a/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr b/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr
index df483b3912d..bd060c92cd4 100644
--- a/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr
+++ b/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr
@@ -21,10 +21,10 @@ LL | fn foo<X: Trait>(_: X) {}
    |           ----- required by this bound in `foo`
 ...
 LL |   foo(s);
-   |       ^ the trait `Trait` is not implemented for `S`
-   |
-   = help: the following implementations were found:
-             <&'a mut S as Trait>
+   |       ^
+   |       |
+   |       expected an implementor of trait `Trait`
+   |       help: consider mutably borrowing here: `&mut s`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/suggestions/issue-72766.stderr b/src/test/ui/suggestions/issue-72766.stderr
index 5c9c549fa07..eb67170d47c 100644
--- a/src/test/ui/suggestions/issue-72766.stderr
+++ b/src/test/ui/suggestions/issue-72766.stderr
@@ -5,7 +5,7 @@ LL |     SadGirl {}.call()?;
    |     ^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future`
    |
    = help: the trait `Try` is not implemented for `impl Future`
-   = note: required by `into_result`
+   = note: required by `branch`
 help: consider `await`ing on the `Future`
    |
 LL |     SadGirl {}.call().await?;
diff --git a/src/test/ui/suggestions/issue-84973-2.rs b/src/test/ui/suggestions/issue-84973-2.rs
new file mode 100644
index 00000000000..050cf8c64b3
--- /dev/null
+++ b/src/test/ui/suggestions/issue-84973-2.rs
@@ -0,0 +1,13 @@
+// A slight variation of issue-84973.rs. Here, a mutable borrow is
+// required (and the obligation kind is different).
+
+trait Tr {}
+impl Tr for &mut i32 {}
+
+fn foo<T: Tr>(i: T) {}
+
+fn main() {
+    let a: i32 = 32;
+    foo(a);
+    //~^ ERROR: the trait bound `i32: Tr` is not satisfied [E0277]
+}
diff --git a/src/test/ui/suggestions/issue-84973-2.stderr b/src/test/ui/suggestions/issue-84973-2.stderr
new file mode 100644
index 00000000000..b6ed437b5ee
--- /dev/null
+++ b/src/test/ui/suggestions/issue-84973-2.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `i32: Tr` is not satisfied
+  --> $DIR/issue-84973-2.rs:11:9
+   |
+LL | fn foo<T: Tr>(i: T) {}
+   |           -- required by this bound in `foo`
+...
+LL |     foo(a);
+   |         ^
+   |         |
+   |         expected an implementor of trait `Tr`
+   |         help: consider mutably borrowing here: `&mut a`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/issue-84973-blacklist.rs b/src/test/ui/suggestions/issue-84973-blacklist.rs
new file mode 100644
index 00000000000..db954530b1b
--- /dev/null
+++ b/src/test/ui/suggestions/issue-84973-blacklist.rs
@@ -0,0 +1,29 @@
+// Checks that certain traits for which we don't want to suggest borrowing
+// are blacklisted and don't cause the suggestion to be issued.
+
+#![feature(generators)]
+
+fn f_copy<T: Copy>(t: T) {}
+fn f_clone<T: Clone>(t: T) {}
+fn f_unpin<T: Unpin>(t: T) {}
+fn f_sized<T: Sized>(t: T) {}
+fn f_send<T: Send>(t: T) {}
+
+struct S;
+
+fn main() {
+    f_copy("".to_string()); //~ ERROR: the trait bound `String: Copy` is not satisfied [E0277]
+    f_clone(S); //~ ERROR: the trait bound `S: Clone` is not satisfied [E0277]
+    f_unpin(static || { yield; });
+    //~^ ERROR: cannot be unpinned [E0277]
+
+    let cl = || ();
+    let ref_cl: &dyn Fn() -> () = &cl;
+    f_sized(*ref_cl);
+    //~^ ERROR: the size for values of type `dyn Fn()` cannot be known at compilation time [E0277]
+    //~| ERROR: the size for values of type `dyn Fn()` cannot be known at compilation time [E0277]
+
+    use std::rc::Rc;
+    let rc = Rc::new(0);
+    f_send(rc); //~ ERROR: `Rc<{integer}>` cannot be sent between threads safely [E0277]
+}
diff --git a/src/test/ui/suggestions/issue-84973-blacklist.stderr b/src/test/ui/suggestions/issue-84973-blacklist.stderr
new file mode 100644
index 00000000000..f1e6ef883ae
--- /dev/null
+++ b/src/test/ui/suggestions/issue-84973-blacklist.stderr
@@ -0,0 +1,64 @@
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/issue-84973-blacklist.rs:15:12
+   |
+LL | fn f_copy<T: Copy>(t: T) {}
+   |              ---- required by this bound in `f_copy`
+...
+LL |     f_copy("".to_string());
+   |            ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+
+error[E0277]: the trait bound `S: Clone` is not satisfied
+  --> $DIR/issue-84973-blacklist.rs:16:13
+   |
+LL | fn f_clone<T: Clone>(t: T) {}
+   |               ----- required by this bound in `f_clone`
+...
+LL |     f_clone(S);
+   |             ^ the trait `Clone` is not implemented for `S`
+
+error[E0277]: `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:33]` cannot be unpinned
+  --> $DIR/issue-84973-blacklist.rs:17:5
+   |
+LL | fn f_unpin<T: Unpin>(t: T) {}
+   |               ----- required by this bound in `f_unpin`
+...
+LL |     f_unpin(static || { yield; });
+   |     ^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:33]`
+   |
+   = note: consider using `Box::pin`
+
+error[E0277]: the size for values of type `dyn Fn()` cannot be known at compilation time
+  --> $DIR/issue-84973-blacklist.rs:22:13
+   |
+LL | fn f_sized<T: Sized>(t: T) {}
+   |            - required by this bound in `f_sized`
+...
+LL |     f_sized(*ref_cl);
+   |             ^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `dyn Fn()`
+
+error[E0277]: `Rc<{integer}>` cannot be sent between threads safely
+  --> $DIR/issue-84973-blacklist.rs:28:12
+   |
+LL | fn f_send<T: Send>(t: T) {}
+   |              ---- required by this bound in `f_send`
+...
+LL |     f_send(rc);
+   |            ^^ `Rc<{integer}>` cannot be sent between threads safely
+   |
+   = help: the trait `Send` is not implemented for `Rc<{integer}>`
+
+error[E0277]: the size for values of type `dyn Fn()` cannot be known at compilation time
+  --> $DIR/issue-84973-blacklist.rs:22:5
+   |
+LL |     f_sized(*ref_cl);
+   |     ^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `dyn Fn()`
+   = note: all function arguments must have a statically known size
+   = help: unsized fn params are gated as an unstable feature
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/issue-84973-negative.rs b/src/test/ui/suggestions/issue-84973-negative.rs
new file mode 100644
index 00000000000..f339251e57d
--- /dev/null
+++ b/src/test/ui/suggestions/issue-84973-negative.rs
@@ -0,0 +1,12 @@
+// Checks that we only suggest borrowing if &T actually implements the trait.
+
+trait Tr {}
+impl Tr for &f32 {}
+fn bar<T: Tr>(t: T) {}
+
+fn main() {
+    let a = 0i32;
+    let b = 0.0f32;
+    bar(a); //~ ERROR: the trait bound `i32: Tr` is not satisfied [E0277]
+    bar(b); //~ ERROR: the trait bound `f32: Tr` is not satisfied [E0277]
+}
diff --git a/src/test/ui/suggestions/issue-84973-negative.stderr b/src/test/ui/suggestions/issue-84973-negative.stderr
new file mode 100644
index 00000000000..94513eca0bf
--- /dev/null
+++ b/src/test/ui/suggestions/issue-84973-negative.stderr
@@ -0,0 +1,24 @@
+error[E0277]: the trait bound `i32: Tr` is not satisfied
+  --> $DIR/issue-84973-negative.rs:10:9
+   |
+LL | fn bar<T: Tr>(t: T) {}
+   |           -- required by this bound in `bar`
+...
+LL |     bar(a);
+   |         ^ the trait `Tr` is not implemented for `i32`
+
+error[E0277]: the trait bound `f32: Tr` is not satisfied
+  --> $DIR/issue-84973-negative.rs:11:9
+   |
+LL | fn bar<T: Tr>(t: T) {}
+   |           -- required by this bound in `bar`
+...
+LL |     bar(b);
+   |         ^
+   |         |
+   |         expected an implementor of trait `Tr`
+   |         help: consider borrowing here: `&b`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/issue-84973.rs b/src/test/ui/suggestions/issue-84973.rs
new file mode 100644
index 00000000000..42468478ed9
--- /dev/null
+++ b/src/test/ui/suggestions/issue-84973.rs
@@ -0,0 +1,33 @@
+// Checks whether borrowing is suggested when a trait bound is not satisfied
+// for found type `T`, but is for `&/&mut T`.
+
+fn main() {
+    let f = Fancy{};
+    let o = Other::new(f);
+    //~^ ERROR: the trait bound `Fancy: SomeTrait` is not satisfied [E0277]
+}
+
+struct Fancy {}
+
+impl <'a> SomeTrait for &'a Fancy {
+}
+
+trait SomeTrait {}
+
+struct Other<'a, G> {
+    a: &'a str,
+    g: G,
+}
+
+// Broadly copied from https://docs.rs/petgraph/0.5.1/src/petgraph/dot.rs.html#70
+impl<'a, G> Other<'a, G>
+where
+    G: SomeTrait,
+{
+    pub fn new(g: G) -> Self {
+        Other {
+            a: "hi",
+            g: g,
+        }
+    }
+}
diff --git a/src/test/ui/suggestions/issue-84973.stderr b/src/test/ui/suggestions/issue-84973.stderr
new file mode 100644
index 00000000000..49fa94da859
--- /dev/null
+++ b/src/test/ui/suggestions/issue-84973.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `Fancy: SomeTrait` is not satisfied
+  --> $DIR/issue-84973.rs:6:24
+   |
+LL |     let o = Other::new(f);
+   |                        ^
+   |                        |
+   |                        expected an implementor of trait `SomeTrait`
+   |                        help: consider borrowing here: `&f`
+...
+LL |     pub fn new(g: G) -> Self {
+   |     ------------------------ required by `Other::<'a, G>::new`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/issue-85347.rs b/src/test/ui/suggestions/issue-85347.rs
new file mode 100644
index 00000000000..f08e38689d6
--- /dev/null
+++ b/src/test/ui/suggestions/issue-85347.rs
@@ -0,0 +1,10 @@
+#![allow(incomplete_features)]
+#![feature(generic_associated_types)]
+use std::ops::Deref;
+trait Foo {
+    type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
+    //~^ ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+    //~| HELP add missing
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/issue-85347.stderr b/src/test/ui/suggestions/issue-85347.stderr
new file mode 100644
index 00000000000..60594baa29c
--- /dev/null
+++ b/src/test/ui/suggestions/issue-85347.stderr
@@ -0,0 +1,19 @@
+error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied
+  --> $DIR/issue-85347.rs:5:42
+   |
+LL |     type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
+   |                                          ^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/issue-85347.rs:5:10
+   |
+LL |     type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>;
+   |          ^^^ --
+help: add missing lifetime argument
+   |
+LL |     type Bar<'a>: Deref<Target = <Self>::Bar<'a, Target = Self>>;
+   |                                              ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs
index 924bfd82eb8..66e1e77c905 100644
--- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs
+++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs
@@ -17,7 +17,6 @@ fn main() {
     let fp = BufWriter::new(fp);
     //~^ ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
     //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
-    //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
 
     writeln!(fp, "hello world").unwrap(); //~ ERROR the method
 }
diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
index a9b06214fe8..71b09d43612 100644
--- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
+++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr
@@ -11,19 +11,6 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis
   --> $DIR/mut-borrow-needed-by-trait.rs:17:14
    |
 LL |     let fp = BufWriter::new(fp);
-   |              ^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
-   | 
-  ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
-   |
-LL | pub struct BufWriter<W: Write> {
-   |                         ----- required by this bound in `BufWriter`
-   |
-   = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write`
-
-error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied
-  --> $DIR/mut-borrow-needed-by-trait.rs:17:14
-   |
-LL |     let fp = BufWriter::new(fp);
    |              ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write`
    | 
   ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL
@@ -34,7 +21,7 @@ LL | pub struct BufWriter<W: Write> {
    = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write`
 
 error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn std::io::Write>`, but its trait bounds were not satisfied
-  --> $DIR/mut-borrow-needed-by-trait.rs:22:5
+  --> $DIR/mut-borrow-needed-by-trait.rs:21:5
    |
 LL |     writeln!(fp, "hello world").unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn std::io::Write>` due to unsatisfied trait bounds
@@ -49,7 +36,7 @@ LL | pub struct BufWriter<W: Write> {
            which is required by `BufWriter<&dyn std::io::Write>: std::io::Write`
    = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0277, E0599.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/suggestions/suggest-ref-macro.rs b/src/test/ui/suggestions/suggest-ref-macro.rs
new file mode 100644
index 00000000000..6f780f32a14
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-ref-macro.rs
@@ -0,0 +1,29 @@
+// run-check
+// aux-build:proc-macro-type-error.rs
+
+extern crate proc_macro_type_error;
+
+use proc_macro_type_error::hello;
+
+#[hello] //~ERROR mismatched types
+fn abc() {}
+
+fn x(_: &mut i32) {}
+
+macro_rules! bla {
+    () => {
+        x(123);
+        //~^ ERROR mismatched types
+        //~| SUGGESTION &mut 123
+    };
+    ($v:expr) => {
+        x($v)
+    }
+}
+
+fn main() {
+    bla!();
+    bla!(456);
+    //~^ ERROR mismatched types
+    //~| SUGGESTION &mut 456
+}
diff --git a/src/test/ui/suggestions/suggest-ref-macro.stderr b/src/test/ui/suggestions/suggest-ref-macro.stderr
new file mode 100644
index 00000000000..147001f0c94
--- /dev/null
+++ b/src/test/ui/suggestions/suggest-ref-macro.stderr
@@ -0,0 +1,34 @@
+error[E0308]: mismatched types
+  --> $DIR/suggest-ref-macro.rs:8:1
+   |
+LL | #[hello]
+   | ^^^^^^^^ expected `&mut i32`, found integer
+   |
+   = note: this error originates in the attribute macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-ref-macro.rs:15:11
+   |
+LL |         x(123);
+   |           ^^^
+   |           |
+   |           expected `&mut i32`, found integer
+   |           help: consider mutably borrowing here: `&mut 123`
+...
+LL |     bla!();
+   |     ------- in this macro invocation
+   |
+   = note: this error originates in the macro `bla` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-ref-macro.rs:26:10
+   |
+LL |     bla!(456);
+   |          ^^^
+   |          |
+   |          expected `&mut i32`, found integer
+   |          help: consider mutably borrowing here: `&mut 456`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/symbol-names/basic.legacy.stderr b/src/test/ui/symbol-names/basic.legacy.stderr
index 3dd2b19fbf9..de4d35e261c 100644
--- a/src/test/ui/symbol-names/basic.legacy.stderr
+++ b/src/test/ui/symbol-names/basic.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN5basic4main17h6c535bbea2051f85E)
+error: symbol-name(_ZN5basic4main17hd75b915511563828E)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic::main::h6c535bbea2051f85)
+error: demangling(basic::main::hd75b915511563828)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/basic.rs b/src/test/ui/symbol-names/basic.rs
index bd107c10207..d871a4ee829 100644
--- a/src/test/ui/symbol-names/basic.rs
+++ b/src/test/ui/symbol-names/basic.rs
@@ -9,8 +9,8 @@
 //[legacy]~^ ERROR symbol-name(_ZN5basic4main
 //[legacy]~| ERROR demangling(basic::main
 //[legacy]~| ERROR demangling-alt(basic::main)
- //[v0]~^^^^ ERROR symbol-name(_RNvCs21hi0yVfW1J_5basic4main)
-    //[v0]~| ERROR demangling(basic[17891616a171812d]::main)
+ //[v0]~^^^^ ERROR symbol-name(_RNvCsj6j3mjPNGKx_5basic4main)
+    //[v0]~| ERROR demangling(basic[de7d5b6b69c71f37]::main)
     //[v0]~| ERROR demangling-alt(basic::main)
 #[rustc_def_path]
 //[legacy]~^ ERROR def-path(main)
diff --git a/src/test/ui/symbol-names/basic.v0.stderr b/src/test/ui/symbol-names/basic.v0.stderr
index 519efc9d7b4..e30fa6f66d5 100644
--- a/src/test/ui/symbol-names/basic.v0.stderr
+++ b/src/test/ui/symbol-names/basic.v0.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_RNvCs21hi0yVfW1J_5basic4main)
+error: symbol-name(_RNvCsj6j3mjPNGKx_5basic4main)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic[17891616a171812d]::main)
+error: demangling(basic[de7d5b6b69c71f37]::main)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/const-generics-demangling.rs b/src/test/ui/symbol-names/const-generics-demangling.rs
index bd7e1c0f336..05c6b8352de 100644
--- a/src/test/ui/symbol-names/const-generics-demangling.rs
+++ b/src/test/ui/symbol-names/const-generics-demangling.rs
@@ -5,32 +5,32 @@
 pub struct Unsigned<const F: u8>;
 
 #[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMCs21hi0yVfW1J_25const_generics_demanglingINtB0_8UnsignedKhb_E)
-//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Unsigned<11: u8>>)
+//~^ ERROR symbol-name(_RMCsaP8qXevlYG3_25const_generics_demanglingINtB0_8UnsignedKhb_E)
+//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Unsigned<11: u8>>)
 //~| ERROR demangling-alt(<const_generics_demangling::Unsigned<11>>)
 impl Unsigned<11> {}
 
 pub struct Signed<const F: i16>;
 
 #[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs_Cs21hi0yVfW1J_25const_generics_demanglingINtB2_6SignedKsn98_E)
-//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Signed<-152: i16>>)
+//~^ ERROR symbol-name(_RMs_CsaP8qXevlYG3_25const_generics_demanglingINtB2_6SignedKsn98_E)
+//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Signed<-152: i16>>)
 //~| ERROR demangling-alt(<const_generics_demangling::Signed<-152>>)
 impl Signed<-152> {}
 
 pub struct Bool<const F: bool>;
 
 #[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs0_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4BoolKb1_E)
-//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Bool<true: bool>>)
+//~^ ERROR symbol-name(_RMs0_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4BoolKb1_E)
+//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Bool<true: bool>>)
 //~| ERROR demangling-alt(<const_generics_demangling::Bool<true>>)
 impl Bool<true> {}
 
 pub struct Char<const F: char>;
 
 #[rustc_symbol_name]
-//~^ ERROR symbol-name(_RMs1_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4CharKc2202_E)
-//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Char<'∂': char>>)
+//~^ ERROR symbol-name(_RMs1_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4CharKc2202_E)
+//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Char<'∂': char>>)
 //~| ERROR demangling-alt(<const_generics_demangling::Char<'∂'>>)
 impl Char<'∂'> {}
 
diff --git a/src/test/ui/symbol-names/const-generics-demangling.stderr b/src/test/ui/symbol-names/const-generics-demangling.stderr
index 13995403f77..05c485d001f 100644
--- a/src/test/ui/symbol-names/const-generics-demangling.stderr
+++ b/src/test/ui/symbol-names/const-generics-demangling.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_RMCs21hi0yVfW1J_25const_generics_demanglingINtB0_8UnsignedKhb_E)
+error: symbol-name(_RMCsaP8qXevlYG3_25const_generics_demanglingINtB0_8UnsignedKhb_E)
   --> $DIR/const-generics-demangling.rs:7:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<const_generics_demangling[17891616a171812d]::Unsigned<11: u8>>)
+error: demangling(<const_generics_demangling[7e153590edc26969]::Unsigned<11: u8>>)
   --> $DIR/const-generics-demangling.rs:7:1
    |
 LL | #[rustc_symbol_name]
@@ -16,13 +16,13 @@ error: demangling-alt(<const_generics_demangling::Unsigned<11>>)
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_RMs_Cs21hi0yVfW1J_25const_generics_demanglingINtB2_6SignedKsn98_E)
+error: symbol-name(_RMs_CsaP8qXevlYG3_25const_generics_demanglingINtB2_6SignedKsn98_E)
   --> $DIR/const-generics-demangling.rs:15:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<const_generics_demangling[17891616a171812d]::Signed<-152: i16>>)
+error: demangling(<const_generics_demangling[7e153590edc26969]::Signed<-152: i16>>)
   --> $DIR/const-generics-demangling.rs:15:1
    |
 LL | #[rustc_symbol_name]
@@ -34,13 +34,13 @@ error: demangling-alt(<const_generics_demangling::Signed<-152>>)
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_RMs0_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4BoolKb1_E)
+error: symbol-name(_RMs0_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4BoolKb1_E)
   --> $DIR/const-generics-demangling.rs:23:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<const_generics_demangling[17891616a171812d]::Bool<true: bool>>)
+error: demangling(<const_generics_demangling[7e153590edc26969]::Bool<true: bool>>)
   --> $DIR/const-generics-demangling.rs:23:1
    |
 LL | #[rustc_symbol_name]
@@ -52,13 +52,13 @@ error: demangling-alt(<const_generics_demangling::Bool<true>>)
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_RMs1_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4CharKc2202_E)
+error: symbol-name(_RMs1_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4CharKc2202_E)
   --> $DIR/const-generics-demangling.rs:31:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<const_generics_demangling[17891616a171812d]::Char<'∂': char>>)
+error: demangling(<const_generics_demangling[7e153590edc26969]::Char<'∂': char>>)
   --> $DIR/const-generics-demangling.rs:31:1
    |
 LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs
index b0b31a57d06..960049be793 100644
--- a/src/test/ui/symbol-names/impl1.rs
+++ b/src/test/ui/symbol-names/impl1.rs
@@ -15,8 +15,8 @@ mod foo {
         //[legacy]~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar
         //[legacy]~| ERROR demangling(impl1::foo::Foo::bar
         //[legacy]~| ERROR demangling-alt(impl1::foo::Foo::bar)
-         //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13fooNtB2_3Foo3bar)
-            //[v0]~| ERROR demangling(<impl1[17891616a171812d]::foo::Foo>::bar)
+         //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs2qSCrjELJET_5impl13fooNtB2_3Foo3bar)
+            //[v0]~| ERROR demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::bar)
             //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::bar)
         #[rustc_def_path]
         //[legacy]~^ ERROR def-path(foo::Foo::bar)
@@ -33,8 +33,8 @@ mod bar {
         //[legacy]~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz
         //[legacy]~| ERROR demangling(impl1::bar::<impl impl1::foo::Foo>::baz
         //[legacy]~| ERROR demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz)
-         //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13barNtNtB4_3foo3Foo3baz)
-            //[v0]~| ERROR demangling(<impl1[17891616a171812d]::foo::Foo>::baz)
+         //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs2qSCrjELJET_5impl13barNtNtB4_3foo3Foo3baz)
+            //[v0]~| ERROR demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::baz)
             //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::baz)
         #[rustc_def_path]
         //[legacy]~^ ERROR def-path(bar::<impl foo::Foo>::baz)
@@ -63,8 +63,8 @@ fn main() {
             //[legacy]~^ ERROR symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method
             //[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method
             //[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method)
-             //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs21hi0yVfW1J_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
-                //[v0]~| ERROR demangling(<[&dyn impl1[17891616a171812d]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[17891616a171812d]::AutoTrait; 3: usize] as impl1[17891616a171812d]::main::{closure#1}::Bar>::method)
+             //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs2qSCrjELJET_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
+                //[v0]~| ERROR demangling(<[&dyn impl1[1c5860ab79c9e305]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[1c5860ab79c9e305]::AutoTrait; 3: usize] as impl1[1c5860ab79c9e305]::main::{closure#1}::Bar>::method)
                 //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method)
             #[rustc_def_path]
             //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method)
diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr
index e5b0deee36e..a7c3a389909 100644
--- a/src/test/ui/symbol-names/impl1.v0.stderr
+++ b/src/test/ui/symbol-names/impl1.v0.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13fooNtB2_3Foo3bar)
+error: symbol-name(_RNvMNtCs2qSCrjELJET_5impl13fooNtB2_3Foo3bar)
   --> $DIR/impl1.rs:14:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<impl1[17891616a171812d]::foo::Foo>::bar)
+error: demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::bar)
   --> $DIR/impl1.rs:14:9
    |
 LL |         #[rustc_symbol_name]
@@ -22,13 +22,13 @@ error: def-path(foo::Foo::bar)
 LL |         #[rustc_def_path]
    |         ^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13barNtNtB4_3foo3Foo3baz)
+error: symbol-name(_RNvMNtCs2qSCrjELJET_5impl13barNtNtB4_3foo3Foo3baz)
   --> $DIR/impl1.rs:32:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<impl1[17891616a171812d]::foo::Foo>::baz)
+error: demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::baz)
   --> $DIR/impl1.rs:32:9
    |
 LL |         #[rustc_symbol_name]
@@ -46,13 +46,13 @@ error: def-path(bar::<impl foo::Foo>::baz)
 LL |         #[rustc_def_path]
    |         ^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_RNvXNCNvCs21hi0yVfW1J_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
+error: symbol-name(_RNvXNCNvCs2qSCrjELJET_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method)
   --> $DIR/impl1.rs:62:13
    |
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<[&dyn impl1[17891616a171812d]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[17891616a171812d]::AutoTrait; 3: usize] as impl1[17891616a171812d]::main::{closure#1}::Bar>::method)
+error: demangling(<[&dyn impl1[1c5860ab79c9e305]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[1c5860ab79c9e305]::AutoTrait; 3: usize] as impl1[1c5860ab79c9e305]::main::{closure#1}::Bar>::method)
   --> $DIR/impl1.rs:62:13
    |
 LL |             #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr
index 83576783992..52d0c666398 100644
--- a/src/test/ui/symbol-names/issue-60925.legacy.stderr
+++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h6244e5288326926aE)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h18eaa05e22e59176E)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h6244e5288326926a)
+error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h18eaa05e22e59176)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/issue-60925.rs b/src/test/ui/symbol-names/issue-60925.rs
index 3238eb1e579..a313c1ef383 100644
--- a/src/test/ui/symbol-names/issue-60925.rs
+++ b/src/test/ui/symbol-names/issue-60925.rs
@@ -22,8 +22,8 @@ mod foo {
         //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo
         //[legacy]~| ERROR demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo
         //[legacy]~| ERROR demangling-alt(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo)
-         //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs21hi0yVfW1J_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
-            //[v0]~| ERROR demangling(<issue_60925[17891616a171812d]::foo::Foo<issue_60925[17891616a171812d]::llvm::Foo>>::foo)
+         //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs8dUWfuENynB_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
+            //[v0]~| ERROR demangling(<issue_60925[5fcbb46c6fac4139]::foo::Foo<issue_60925[5fcbb46c6fac4139]::llvm::Foo>>::foo)
             //[v0]~| ERROR demangling-alt(<issue_60925::foo::Foo<issue_60925::llvm::Foo>>::foo)
         pub(crate) fn foo() {
             for _ in 0..0 {
diff --git a/src/test/ui/symbol-names/issue-60925.v0.stderr b/src/test/ui/symbol-names/issue-60925.v0.stderr
index 6a5885e1ea3..5d99abff59a 100644
--- a/src/test/ui/symbol-names/issue-60925.v0.stderr
+++ b/src/test/ui/symbol-names/issue-60925.v0.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_RNvMNtCs21hi0yVfW1J_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
+error: symbol-name(_RNvMNtCs8dUWfuENynB_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<issue_60925[17891616a171812d]::foo::Foo<issue_60925[17891616a171812d]::llvm::Foo>>::foo)
+error: demangling(<issue_60925[5fcbb46c6fac4139]::foo::Foo<issue_60925[5fcbb46c6fac4139]::llvm::Foo>>::foo)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/issue-75326.rs b/src/test/ui/symbol-names/issue-75326.rs
index 4d061cafef3..0f721fc1f89 100644
--- a/src/test/ui/symbol-names/issue-75326.rs
+++ b/src/test/ui/symbol-names/issue-75326.rs
@@ -42,8 +42,8 @@ where
     //[legacy]~^ ERROR symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next
     //[legacy]~| ERROR demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next
     //[legacy]~| ERROR demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next)
-    //[v0]~^^^^  ERROR symbol-name(_RNvXINICs21hi0yVfW1J_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
-    //[v0]~|     ERROR demangling(<issue_75326[17891616a171812d]::Foo<_, _> as issue_75326[17891616a171812d]::Iterator2>::next)
+    //[v0]~^^^^  ERROR symbol-name(_RNvXINICsiMBouZZ1iuD_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
+    //[v0]~|     ERROR demangling(<issue_75326[dac9b7624645f95d]::Foo<_, _> as issue_75326[dac9b7624645f95d]::Iterator2>::next)
     //[v0]~|     ERROR demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next)
     fn next(&mut self) -> Option<Self::Item> {
         self.find(|_| true)
diff --git a/src/test/ui/symbol-names/issue-75326.v0.stderr b/src/test/ui/symbol-names/issue-75326.v0.stderr
index 98844aafb65..093ba8c8576 100644
--- a/src/test/ui/symbol-names/issue-75326.v0.stderr
+++ b/src/test/ui/symbol-names/issue-75326.v0.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_RNvXINICs21hi0yVfW1J_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
+error: symbol-name(_RNvXINICsiMBouZZ1iuD_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_)
   --> $DIR/issue-75326.rs:41:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<issue_75326[17891616a171812d]::Foo<_, _> as issue_75326[17891616a171812d]::Iterator2>::next)
+error: demangling(<issue_75326[dac9b7624645f95d]::Foo<_, _> as issue_75326[dac9b7624645f95d]::Iterator2>::next)
   --> $DIR/issue-75326.rs:41:5
    |
 LL |     #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/trait-objects.rs b/src/test/ui/symbol-names/trait-objects.rs
new file mode 100644
index 00000000000..cea1a89d757
--- /dev/null
+++ b/src/test/ui/symbol-names/trait-objects.rs
@@ -0,0 +1,48 @@
+// Ensure that trait objects don't include more than one binder. See #83611
+
+// build-fail
+// revisions: v0
+//[v0]compile-flags: -Z symbol-mangling-version=v0
+//[v0]normalize-stderr-test: "Cs.*?_" -> "CRATE_HASH"
+//[v0]normalize-stderr-test: "core\[.*?\]" -> "core[HASH]"
+
+#![feature(rustc_attrs)]
+
+trait Bar {
+    fn method(&self) {}
+}
+
+impl Bar for &dyn FnMut(&u8) {
+    #[rustc_symbol_name]
+    //[v0]~^ ERROR symbol-name
+    //[v0]~| ERROR demangling
+    //[v0]~| ERROR demangling-alt
+    fn method(&self) {}
+}
+
+trait Foo {
+    fn method(&self) {}
+}
+
+impl Foo for &(dyn FnMut(&u8) + for<'b> Send) {
+    #[rustc_symbol_name]
+    //[v0]~^ ERROR symbol-name
+    //[v0]~| ERROR demangling
+    //[v0]~| ERROR demangling-alt
+    fn method(&self) {}
+}
+
+trait Baz {
+    fn method(&self) {}
+}
+
+impl Baz for &(dyn for<'b> Send + FnMut(&u8)) {
+    #[rustc_symbol_name]
+    //[v0]~^ ERROR symbol-name
+    //[v0]~| ERROR demangling
+    //[v0]~| ERROR demangling-alt
+    fn method(&self) {}
+}
+
+fn main() {
+}
diff --git a/src/test/ui/symbol-names/trait-objects.v0.stderr b/src/test/ui/symbol-names/trait-objects.v0.stderr
new file mode 100644
index 00000000000..5ada82dfb2d
--- /dev/null
+++ b/src/test/ui/symbol-names/trait-objects.v0.stderr
@@ -0,0 +1,56 @@
+error: symbol-name(_RNvXCRATE_HASH13trait_objectsRDG_INtNtNtCRATE_HASH4core3ops8function5FnMutTRL0_hEEp6OutputuEL_NtB2_3Bar6method)
+  --> $DIR/trait-objects.rs:16:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[3f8b57f879016e18]::Bar>::method)
+  --> $DIR/trait-objects.rs:16:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects::Bar>::method)
+  --> $DIR/trait-objects.rs:16:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RNvXs_CRATE_HASH13trait_objectsRDG_INtNtNtCRATE_HASH4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtBI_6marker4SendEL_NtB4_3Foo6method)
+  --> $DIR/trait-objects.rs:28:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3f8b57f879016e18]::Foo>::method)
+  --> $DIR/trait-objects.rs:28:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Foo>::method)
+  --> $DIR/trait-objects.rs:28:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RNvXs0_CRATE_HASH13trait_objectsRDG_INtNtNtCRATE_HASH4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtBJ_6marker4SendEL_NtB5_3Baz6method)
+  --> $DIR/trait-objects.rs:40:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3f8b57f879016e18]::Baz>::method)
+  --> $DIR/trait-objects.rs:40:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Baz>::method)
+  --> $DIR/trait-objects.rs:40:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
diff --git a/src/test/ui/target-feature/wasm-safe.rs b/src/test/ui/target-feature/wasm-safe.rs
new file mode 100644
index 00000000000..4b868684a52
--- /dev/null
+++ b/src/test/ui/target-feature/wasm-safe.rs
@@ -0,0 +1,44 @@
+// only-wasm32
+// check-pass
+
+#![feature(wasm_target_feature)]
+#![allow(dead_code)]
+
+#[target_feature(enable = "nontrapping-fptoint")]
+fn foo() {}
+
+#[target_feature(enable = "nontrapping-fptoint")]
+extern "C" fn bar() {}
+
+trait A {
+    fn foo();
+    fn bar(&self);
+}
+
+struct B;
+
+impl B {
+    #[target_feature(enable = "nontrapping-fptoint")]
+    fn foo() {}
+    #[target_feature(enable = "nontrapping-fptoint")]
+    fn bar(&self) {}
+}
+
+impl A for B {
+    #[target_feature(enable = "nontrapping-fptoint")]
+    fn foo() {}
+    #[target_feature(enable = "nontrapping-fptoint")]
+    fn bar(&self) {}
+}
+
+fn no_features_enabled_on_this_function() {
+    bar();
+    foo();
+    B.bar();
+    B::foo();
+    <B as A>::foo();
+    <B as A>::bar(&B);
+}
+
+#[target_feature(enable = "nontrapping-fptoint")]
+fn main() {}
diff --git a/src/test/ui/thread-local-static.rs b/src/test/ui/thread-local-static.rs
new file mode 100644
index 00000000000..c7fee9e6b4c
--- /dev/null
+++ b/src/test/ui/thread-local-static.rs
@@ -0,0 +1,16 @@
+// edition:2018
+
+#![feature(thread_local)]
+#![feature(const_swap)]
+#[thread_local]
+static mut STATIC_VAR_2: [u32; 8] = [4; 8];
+const fn g(x: &mut [u32; 8]) {
+    //~^ ERROR mutable references are not allowed
+    std::mem::swap(x, &mut STATIC_VAR_2)
+    //~^ ERROR thread-local statics cannot be accessed
+    //~| ERROR mutable references are not allowed
+    //~| ERROR use of mutable static is unsafe
+    //~| constant functions cannot refer to statics
+}
+
+fn main() {}
diff --git a/src/test/ui/thread-local-static.stderr b/src/test/ui/thread-local-static.stderr
new file mode 100644
index 00000000000..08bf593a5a7
--- /dev/null
+++ b/src/test/ui/thread-local-static.stderr
@@ -0,0 +1,44 @@
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/thread-local-static.rs:7:12
+   |
+LL | const fn g(x: &mut [u32; 8]) {
+   |            ^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0625]: thread-local statics cannot be accessed at compile-time
+  --> $DIR/thread-local-static.rs:9:28
+   |
+LL |     std::mem::swap(x, &mut STATIC_VAR_2)
+   |                            ^^^^^^^^^^^^
+
+error[E0013]: constant functions cannot refer to statics
+  --> $DIR/thread-local-static.rs:9:28
+   |
+LL |     std::mem::swap(x, &mut STATIC_VAR_2)
+   |                            ^^^^^^^^^^^^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0658]: mutable references are not allowed in constant functions
+  --> $DIR/thread-local-static.rs:9:23
+   |
+LL |     std::mem::swap(x, &mut STATIC_VAR_2)
+   |                       ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
+   = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
+
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+  --> $DIR/thread-local-static.rs:9:23
+   |
+LL |     std::mem::swap(x, &mut STATIC_VAR_2)
+   |                       ^^^^^^^^^^^^^^^^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0013, E0133, E0658.
+For more information about an error, try `rustc --explain E0013`.
diff --git a/src/test/ui/traits/alias/style_lint.rs b/src/test/ui/traits/alias/style_lint.rs
new file mode 100644
index 00000000000..33be20054b5
--- /dev/null
+++ b/src/test/ui/traits/alias/style_lint.rs
@@ -0,0 +1,8 @@
+// check-pass
+
+#![feature(trait_alias)]
+
+trait Foo = std::fmt::Display + std::fmt::Debug;
+trait bar = std::fmt::Display + std::fmt::Debug; //~WARN trait alias `bar` should have an upper camel case name
+
+fn main() {}
diff --git a/src/test/ui/traits/alias/style_lint.stderr b/src/test/ui/traits/alias/style_lint.stderr
new file mode 100644
index 00000000000..91e2ea90eb9
--- /dev/null
+++ b/src/test/ui/traits/alias/style_lint.stderr
@@ -0,0 +1,10 @@
+warning: trait alias `bar` should have an upper camel case name
+  --> $DIR/style_lint.rs:6:7
+   |
+LL | trait bar = std::fmt::Display + std::fmt::Debug;
+   |       ^^^ help: convert the identifier to upper camel case: `Bar`
+   |
+   = note: `#[warn(non_camel_case_types)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/traits/inductive-overflow/lifetime.rs b/src/test/ui/traits/inductive-overflow/lifetime.rs
index e23dfa57cd0..b75da1b512d 100644
--- a/src/test/ui/traits/inductive-overflow/lifetime.rs
+++ b/src/test/ui/traits/inductive-overflow/lifetime.rs
@@ -26,4 +26,6 @@ fn main() {
     // Should only be a few notes.
     is_send::<X<C<'static>>>();
     //~^ ERROR overflow evaluating
+    //~| 2 redundant requirements hidden
+    //~| required because of
 }
diff --git a/src/test/ui/traits/inductive-overflow/lifetime.stderr b/src/test/ui/traits/inductive-overflow/lifetime.stderr
index 752154b35ca..cc913930395 100644
--- a/src/test/ui/traits/inductive-overflow/lifetime.stderr
+++ b/src/test/ui/traits/inductive-overflow/lifetime.stderr
@@ -7,11 +7,13 @@ LL | fn is_send<S: NotAuto>() {}
 LL |     is_send::<X<C<'static>>>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: required because of the requirements on the impl of `NotAuto` for `X<C<'static>>`
+note: required because of the requirements on the impl of `NotAuto` for `X<C<'_>>`
   --> $DIR/lifetime.rs:19:12
    |
 LL | impl<T: Y> NotAuto for X<T> where T::P: NotAuto {}
    |            ^^^^^^^     ^^^^
+   = note: 2 redundant requirements hidden
+   = note: required because of the requirements on the impl of `NotAuto` for `X<C<'static>>`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/safety-fn-body.stderr b/src/test/ui/traits/safety-fn-body.mir.stderr
index 0aeb186828e..ea7b2048e83 100644
--- a/src/test/ui/traits/safety-fn-body.stderr
+++ b/src/test/ui/traits/safety-fn-body.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/safety-fn-body.rs:11:9
+  --> $DIR/safety-fn-body.rs:14:9
    |
 LL |         *self += 1;
    |         ^^^^^^^^^^ dereference of raw pointer
diff --git a/src/test/ui/traits/safety-fn-body.rs b/src/test/ui/traits/safety-fn-body.rs
index df527747305..2cc4fe1b344 100644
--- a/src/test/ui/traits/safety-fn-body.rs
+++ b/src/test/ui/traits/safety-fn-body.rs
@@ -1,6 +1,9 @@
 // Check that an unsafe impl does not imply that unsafe actions are
 // legal in the methods.
 
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 unsafe trait UnsafeTrait : Sized {
     fn foo(self) { }
 }
diff --git a/src/test/ui/traits/safety-fn-body.thir.stderr b/src/test/ui/traits/safety-fn-body.thir.stderr
new file mode 100644
index 00000000000..23696c32bef
--- /dev/null
+++ b/src/test/ui/traits/safety-fn-body.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/safety-fn-body.rs:14:9
+   |
+LL |         *self += 1;
+   |         ^^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/try-block/try-block-bad-type.rs b/src/test/ui/try-block/try-block-bad-type.rs
index ef6e690e1bd..30ae96763c0 100644
--- a/src/test/ui/try-block/try-block-bad-type.rs
+++ b/src/test/ui/try-block/try-block-bad-type.rs
@@ -15,8 +15,7 @@ pub fn main() {
     let res: Result<i32, i32> = try { }; //~ ERROR type mismatch
 
     let res: () = try { };
-    //~^ ERROR the trait bound `(): Try` is not satisfied
-    //~| ERROR the trait bound `(): Try` is not satisfied
+    //~^ ERROR a `try` block must return `Result` or `Option`
 
-    let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: Try` is not satisfied
+    let res: i32 = try { 5 }; //~ ERROR a `try` block must return `Result` or `Option`
 }
diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr
index 75a42c0d6b7..ec5e91f10c2 100644
--- a/src/test/ui/try-block/try-block-bad-type.stderr
+++ b/src/test/ui/try-block/try-block-bad-type.stderr
@@ -7,43 +7,40 @@ LL |         Err("")?;
    = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
    = help: the following implementations were found:
              <TryFromSliceError as From<Infallible>>
-   = note: required by `from`
+   = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, &str>>` for `Result<u32, TryFromSliceError>`
+   = note: required by `from_residual`
 
-error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Ok == &str`
+error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == &str`
   --> $DIR/try-block-bad-type.rs:12:9
    |
 LL |         ""
    |         ^^ expected `i32`, found `&str`
 
-error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Ok == ()`
+error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == ()`
   --> $DIR/try-block-bad-type.rs:15:39
    |
 LL |     let res: Result<i32, i32> = try { };
    |                                       ^ expected `i32`, found `()`
 
-error[E0277]: the trait bound `(): Try` is not satisfied
+error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
   --> $DIR/try-block-bad-type.rs:17:25
    |
 LL |     let res: () = try { };
-   |                         ^ the trait `Try` is not implemented for `()`
+   |                         ^ could not wrap the final value of the block as `()` doesn't implement `Try`
    |
-   = note: required by `from_ok`
+   = help: the trait `Try` is not implemented for `()`
+   = note: required by `from_output`
 
-error[E0277]: the trait bound `(): Try` is not satisfied
-  --> $DIR/try-block-bad-type.rs:17:25
-   |
-LL |     let res: () = try { };
-   |                         ^ the trait `Try` is not implemented for `()`
-
-error[E0277]: the trait bound `i32: Try` is not satisfied
-  --> $DIR/try-block-bad-type.rs:21:26
+error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
+  --> $DIR/try-block-bad-type.rs:20:26
    |
 LL |     let res: i32 = try { 5 };
-   |                          ^ the trait `Try` is not implemented for `i32`
+   |                          ^ could not wrap the final value of the block as `i32` doesn't implement `Try`
    |
-   = note: required by `from_ok`
+   = help: the trait `Try` is not implemented for `i32`
+   = note: required by `from_output`
 
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0271, E0277.
 For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/try-block/try-block-in-while.rs b/src/test/ui/try-block/try-block-in-while.rs
index 5d8748f1dd3..69793df525e 100644
--- a/src/test/ui/try-block/try-block-in-while.rs
+++ b/src/test/ui/try-block/try-block-in-while.rs
@@ -4,5 +4,5 @@
 
 fn main() {
     while try { false } {}
-    //~^ ERROR the trait bound `bool: Try` is not satisfied
+    //~^ ERROR a `try` block must
 }
diff --git a/src/test/ui/try-block/try-block-in-while.stderr b/src/test/ui/try-block/try-block-in-while.stderr
index 75a4e8d065c..c83351d5c43 100644
--- a/src/test/ui/try-block/try-block-in-while.stderr
+++ b/src/test/ui/try-block/try-block-in-while.stderr
@@ -1,10 +1,11 @@
-error[E0277]: the trait bound `bool: Try` is not satisfied
+error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`)
   --> $DIR/try-block-in-while.rs:6:17
    |
 LL |     while try { false } {}
-   |                 ^^^^^ the trait `Try` is not implemented for `bool`
+   |                 ^^^^^ could not wrap the final value of the block as `bool` doesn't implement `Try`
    |
-   = note: required by `from_ok`
+   = help: the trait `Try` is not implemented for `bool`
+   = note: required by `from_output`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/try-block/try-block-type-error.stderr b/src/test/ui/try-block/try-block-type-error.stderr
index df1441c83d4..3e9a584a551 100644
--- a/src/test/ui/try-block/try-block-type-error.stderr
+++ b/src/test/ui/try-block/try-block-type-error.stderr
@@ -1,4 +1,4 @@
-error[E0271]: type mismatch resolving `<Option<f32> as Try>::Ok == {integer}`
+error[E0271]: type mismatch resolving `<Option<f32> as Try>::Output == {integer}`
   --> $DIR/try-block-type-error.rs:10:9
    |
 LL |         42
@@ -7,7 +7,7 @@ LL |         42
    |         expected `f32`, found integer
    |         help: use a float literal: `42.0`
 
-error[E0271]: type mismatch resolving `<Option<i32> as Try>::Ok == ()`
+error[E0271]: type mismatch resolving `<Option<i32> as Try>::Output == ()`
   --> $DIR/try-block-type-error.rs:16:5
    |
 LL |     };
diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr
deleted file mode 100644
index ecd12c430f1..00000000000
--- a/src/test/ui/try-on-option.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error[E0277]: `?` couldn't convert the error to `()`
-  --> $DIR/try-on-option.rs:7:6
-   |
-LL | fn foo() -> Result<u32, ()> {
-   |             --------------- expected `()` because of this
-LL |     let x: Option<u32> = None;
-LL |     x?;
-   |      ^ the trait `From<NoneError>` is not implemented for `()`
-   |
-   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
-   = note: required by `from`
-help: consider converting the `Option<T>` into a `Result<T, _>` using `Option::ok_or` or `Option::ok_or_else`
-   |
-LL |     x.ok_or_else(|| /* error value */)?;
-   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option.rs:13:5
-   |
-LL | / fn bar() -> u32 {
-LL | |     let x: Option<u32> = None;
-LL | |     x?;
-   | |     ^^ cannot use the `?` operator in a function that returns `u32`
-LL | |     22
-LL | | }
-   | |_- this function should return `Result` or `Option` to accept `?`
-   |
-   = help: the trait `Try` is not implemented for `u32`
-   = note: required by `from_error`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/try-operator-custom.rs b/src/test/ui/try-operator-custom.rs
deleted file mode 100644
index 9993061ea61..00000000000
--- a/src/test/ui/try-operator-custom.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-// run-pass
-
-#![feature(try_trait)]
-
-use std::ops::Try;
-
-enum MyResult<T, U> {
-    Awesome(T),
-    Terrible(U)
-}
-
-impl<U, V> Try for MyResult<U, V> {
-    type Ok = U;
-    type Error = V;
-
-    fn from_ok(u: U) -> MyResult<U, V> {
-        MyResult::Awesome(u)
-    }
-
-    fn from_error(e: V) -> MyResult<U, V> {
-        MyResult::Terrible(e)
-    }
-
-    fn into_result(self) -> Result<U, V> {
-        match self {
-            MyResult::Awesome(u) => Ok(u),
-            MyResult::Terrible(e) => Err(e),
-        }
-    }
-}
-
-fn f(x: i32) -> Result<i32, String> {
-    if x == 0 {
-        Ok(42)
-    } else {
-        let y = g(x)?;
-        Ok(y)
-    }
-}
-
-fn g(x: i32) -> MyResult<i32, String> {
-    let _y = f(x - 1)?;
-    MyResult::Terrible("Hello".to_owned())
-}
-
-fn h() -> MyResult<i32, String> {
-    let a: Result<i32, &'static str> = Err("Hello");
-    let b = a?;
-    MyResult::Awesome(b)
-}
-
-fn i() -> MyResult<i32, String> {
-    let a: MyResult<i32, &'static str> = MyResult::Terrible("Hello");
-    let b = a?;
-    MyResult::Awesome(b)
-}
-
-fn main() {
-    assert!(f(0) == Ok(42));
-    assert!(f(10) == Err("Hello".to_owned()));
-    let _ = h();
-    let _ = i();
-}
diff --git a/src/test/ui/try-trait/bad-interconversion.rs b/src/test/ui/try-trait/bad-interconversion.rs
new file mode 100644
index 00000000000..385f5510fb4
--- /dev/null
+++ b/src/test/ui/try-trait/bad-interconversion.rs
@@ -0,0 +1,48 @@
+#![feature(control_flow_enum)]
+
+use std::ops::ControlFlow;
+
+fn result_to_result() -> Result<u64, u8> {
+    Ok(Err(123_i32)?)
+    //~^ ERROR `?` couldn't convert the error to `u8`
+}
+
+fn option_to_result() -> Result<u64, String> {
+    Some(3)?;
+    //~^ ERROR the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
+    Ok(10)
+}
+
+fn control_flow_to_result() -> Result<u64, String> {
+    Ok(ControlFlow::Break(123)?)
+    //~^ ERROR the `?` operator can only be used on `Result`s in a function that returns `Result`
+}
+
+fn result_to_option() -> Option<u16> {
+    Some(Err("hello")?)
+    //~^ ERROR the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
+}
+
+fn control_flow_to_option() -> Option<u64> {
+    Some(ControlFlow::Break(123)?)
+    //~^ ERROR the `?` operator can only be used on `Option`s in a function that returns `Option`
+}
+
+fn result_to_control_flow() -> ControlFlow<String> {
+    ControlFlow::Continue(Err("hello")?)
+    //~^ ERROR the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
+}
+
+fn option_to_control_flow() -> ControlFlow<u64> {
+    Some(3)?;
+    //~^ ERROR the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
+    ControlFlow::Break(10)
+}
+
+fn control_flow_to_control_flow() -> ControlFlow<i64> {
+    ControlFlow::Break(4_u8)?;
+    //~^ ERROR the `?` operator in a function that returns `ControlFlow<B, _>` can only be used on other `ControlFlow<B, _>`s
+    ControlFlow::Continue(())
+}
+
+fn main() {}
diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr
new file mode 100644
index 00000000000..f5b315c2519
--- /dev/null
+++ b/src/test/ui/try-trait/bad-interconversion.stderr
@@ -0,0 +1,113 @@
+error[E0277]: `?` couldn't convert the error to `u8`
+  --> $DIR/bad-interconversion.rs:6:20
+   |
+LL | fn result_to_result() -> Result<u64, u8> {
+   |                          --------------- expected `u8` because of this
+LL |     Ok(Err(123_i32)?)
+   |                    ^ the trait `From<i32>` is not implemented for `u8`
+   |
+   = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
+   = help: the following implementations were found:
+             <u8 as From<NonZeroU8>>
+             <u8 as From<bool>>
+   = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, i32>>` for `Result<u64, u8>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
+  --> $DIR/bad-interconversion.rs:11:12
+   |
+LL | / fn option_to_result() -> Result<u64, String> {
+LL | |     Some(3)?;
+   | |            ^ use `.ok_or(...)?` to provide an error compatible with `Result<u64, String>`
+LL | |
+LL | |     Ok(10)
+LL | | }
+   | |_- this function returns a `Result`
+   |
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result`
+  --> $DIR/bad-interconversion.rs:17:31
+   |
+LL | / fn control_flow_to_result() -> Result<u64, String> {
+LL | |     Ok(ControlFlow::Break(123)?)
+   | |                               ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result<u64, String>`
+LL | |
+LL | | }
+   | |_- this function returns a `Result`
+   |
+   = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
+  --> $DIR/bad-interconversion.rs:22:22
+   |
+LL | / fn result_to_option() -> Option<u16> {
+LL | |     Some(Err("hello")?)
+   | |                      ^ use `.ok()?` if you want to discard the `Result<Infallible, &str>` error information
+LL | |
+LL | | }
+   | |_- this function returns an `Option`
+   |
+   = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `Option<u16>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option`
+  --> $DIR/bad-interconversion.rs:27:33
+   |
+LL | / fn control_flow_to_option() -> Option<u64> {
+LL | |     Some(ControlFlow::Break(123)?)
+   | |                                 ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option<u64>`
+LL | |
+LL | | }
+   | |_- this function returns an `Option`
+   |
+   = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
+  --> $DIR/bad-interconversion.rs:32:39
+   |
+LL | / fn result_to_control_flow() -> ControlFlow<String> {
+LL | |     ControlFlow::Continue(Err("hello")?)
+   | |                                       ^ this `?` produces `Result<Infallible, &str>`, which is incompatible with `ControlFlow<String>`
+LL | |
+LL | | }
+   | |_- this function returns a `ControlFlow`
+   |
+   = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `ControlFlow<String>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow`
+  --> $DIR/bad-interconversion.rs:37:12
+   |
+LL | / fn option_to_control_flow() -> ControlFlow<u64> {
+LL | |     Some(3)?;
+   | |            ^ this `?` produces `Option<Infallible>`, which is incompatible with `ControlFlow<u64>`
+LL | |
+LL | |     ControlFlow::Break(10)
+LL | | }
+   | |_- this function returns a `ControlFlow`
+   |
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `ControlFlow<u64>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator in a function that returns `ControlFlow<B, _>` can only be used on other `ControlFlow<B, _>`s (with the same Break type)
+  --> $DIR/bad-interconversion.rs:43:29
+   |
+LL | / fn control_flow_to_control_flow() -> ControlFlow<i64> {
+LL | |     ControlFlow::Break(4_u8)?;
+   | |                             ^ this `?` produces `ControlFlow<u8, Infallible>`, which is incompatible with `ControlFlow<i64>`
+LL | |
+LL | |     ControlFlow::Continue(())
+LL | | }
+   | |_- this function returns a `ControlFlow`
+   |
+   = help: the trait `FromResidual<ControlFlow<u8, Infallible>>` is not implemented for `ControlFlow<i64>`
+   = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow`
+   = note: required by `from_residual`
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/option-to-result.rs b/src/test/ui/try-trait/option-to-result.rs
index 00e8b5244c5..45aaf361a9c 100644
--- a/src/test/ui/option-to-result.rs
+++ b/src/test/ui/try-trait/option-to-result.rs
@@ -2,12 +2,12 @@ fn main(){ }
 
 fn test_result() -> Result<(),()> {
     let a:Option<()> = Some(());
-    a?;//~ ERROR `?` couldn't convert the error
+    a?;//~ ERROR the `?` operator can only be used
     Ok(())
 }
 
 fn test_option() -> Option<i32>{
     let a:Result<i32, i32> = Ok(5);
-    a?;//~ ERROR `?` couldn't convert the error
+    a?;//~ ERROR the `?` operator can only be used
     Some(5)
 }
diff --git a/src/test/ui/try-trait/option-to-result.stderr b/src/test/ui/try-trait/option-to-result.stderr
new file mode 100644
index 00000000000..9f7d80d4f23
--- /dev/null
+++ b/src/test/ui/try-trait/option-to-result.stderr
@@ -0,0 +1,31 @@
+error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
+  --> $DIR/option-to-result.rs:5:6
+   |
+LL | / fn test_result() -> Result<(),()> {
+LL | |     let a:Option<()> = Some(());
+LL | |     a?;
+   | |      ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>`
+LL | |     Ok(())
+LL | | }
+   | |_- this function returns a `Result`
+   |
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option`
+  --> $DIR/option-to-result.rs:11:6
+   |
+LL | / fn test_option() -> Option<i32>{
+LL | |     let a:Result<i32, i32> = Ok(5);
+LL | |     a?;
+   | |      ^ use `.ok()?` if you want to discard the `Result<Infallible, i32>` error information
+LL | |     Some(5)
+LL | | }
+   | |_- this function returns an `Option`
+   |
+   = help: the trait `FromResidual<Result<Infallible, i32>>` is not implemented for `Option<i32>`
+   = note: required by `from_residual`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/try-trait/try-as-monad.rs b/src/test/ui/try-trait/try-as-monad.rs
new file mode 100644
index 00000000000..cf09838b304
--- /dev/null
+++ b/src/test/ui/try-trait/try-as-monad.rs
@@ -0,0 +1,24 @@
+// run-pass
+
+#![feature(try_trait_v2)]
+
+use std::ops::Try;
+
+fn monad_unit<T: Try>(x: <T as Try>::Output) -> T {
+    T::from_output(x)
+}
+
+fn monad_bind<T1: Try<Residual = R>, T2: Try<Residual = R>, R>(
+    mx: T1,
+    f: impl FnOnce(<T1 as Try>::Output) -> T2)
+-> T2 {
+    let x = mx?;
+    f(x)
+}
+
+fn main() {
+    let mx: Option<i32> = monad_unit(1);
+    let my = monad_bind(mx, |x| Some(x + 1));
+    let mz = monad_bind(my, |x| Some(-x));
+    assert_eq!(mz, Some(-2));
+}
diff --git a/src/test/ui/try-on-option-diagnostics.rs b/src/test/ui/try-trait/try-on-option-diagnostics.rs
index 63d17414c31..63d17414c31 100644
--- a/src/test/ui/try-on-option-diagnostics.rs
+++ b/src/test/ui/try-trait/try-on-option-diagnostics.rs
diff --git a/src/test/ui/try-on-option-diagnostics.stderr b/src/test/ui/try-trait/try-on-option-diagnostics.stderr
index a71ee20aacf..e7c67c21bb3 100644
--- a/src/test/ui/try-on-option-diagnostics.stderr
+++ b/src/test/ui/try-trait/try-on-option-diagnostics.stderr
@@ -1,57 +1,57 @@
-error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-diagnostics.rs:7:5
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-diagnostics.rs:7:6
    |
 LL | / fn a_function() -> u32 {
 LL | |     let x: Option<u32> = None;
 LL | |     x?;
-   | |     ^^ cannot use the `?` operator in a function that returns `u32`
+   | |      ^ cannot use the `?` operator in a function that returns `u32`
 LL | |     22
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `u32`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
+   = note: required by `from_residual`
 
-error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-diagnostics.rs:14:9
+error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-diagnostics.rs:14:10
    |
 LL |       let a_closure = || {
    |  _____________________-
 LL | |         let x: Option<u32> = None;
 LL | |         x?;
-   | |         ^^ cannot use the `?` operator in a closure that returns `{integer}`
+   | |          ^ cannot use the `?` operator in a closure that returns `{integer}`
 LL | |         22
 LL | |     };
    | |_____- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `{integer}`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}`
+   = note: required by `from_residual`
 
-error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-diagnostics.rs:26:13
+error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-diagnostics.rs:26:14
    |
 LL | /         fn a_method() {
 LL | |             let x: Option<u32> = None;
 LL | |             x?;
-   | |             ^^ cannot use the `?` operator in a method that returns `()`
+   | |              ^ cannot use the `?` operator in a method that returns `()`
 LL | |         }
    | |_________- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `()`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()`
+   = note: required by `from_residual`
 
-error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-on-option-diagnostics.rs:39:13
+error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option-diagnostics.rs:39:14
    |
 LL | /         fn a_trait_method() {
 LL | |             let x: Option<u32> = None;
 LL | |             x?;
-   | |             ^^ cannot use the `?` operator in a trait method that returns `()`
+   | |              ^ cannot use the `?` operator in a trait method that returns `()`
 LL | |         }
    | |_________- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `()`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()`
+   = note: required by `from_residual`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/try-on-option.rs b/src/test/ui/try-trait/try-on-option.rs
index 5d94cee8e37..f2012936a11 100644
--- a/src/test/ui/try-on-option.rs
+++ b/src/test/ui/try-trait/try-on-option.rs
@@ -4,7 +4,7 @@ fn main() {}
 
 fn foo() -> Result<u32, ()> {
     let x: Option<u32> = None;
-    x?; //~ ERROR `?` couldn't convert the error
+    x?; //~ ERROR the `?` operator
     Ok(22)
 }
 
diff --git a/src/test/ui/try-trait/try-on-option.stderr b/src/test/ui/try-trait/try-on-option.stderr
new file mode 100644
index 00000000000..604baa8550b
--- /dev/null
+++ b/src/test/ui/try-trait/try-on-option.stderr
@@ -0,0 +1,31 @@
+error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
+  --> $DIR/try-on-option.rs:7:6
+   |
+LL | / fn foo() -> Result<u32, ()> {
+LL | |     let x: Option<u32> = None;
+LL | |     x?;
+   | |      ^ use `.ok_or(...)?` to provide an error compatible with `Result<u32, ()>`
+LL | |     Ok(22)
+LL | | }
+   | |_- this function returns a `Result`
+   |
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>`
+   = note: required by `from_residual`
+
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-on-option.rs:13:6
+   |
+LL | / fn bar() -> u32 {
+LL | |     let x: Option<u32> = None;
+LL | |     x?;
+   | |      ^ cannot use the `?` operator in a function that returns `u32`
+LL | |     22
+LL | | }
+   | |_- this function should return `Result` or `Option` to accept `?`
+   |
+   = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32`
+   = note: required by `from_residual`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/try-trait/try-operator-custom.rs b/src/test/ui/try-trait/try-operator-custom.rs
new file mode 100644
index 00000000000..45636a7fced
--- /dev/null
+++ b/src/test/ui/try-trait/try-operator-custom.rs
@@ -0,0 +1,91 @@
+// run-pass
+
+#![feature(control_flow_enum)]
+#![feature(try_trait_v2)]
+
+use std::ops::{ControlFlow, FromResidual, Try};
+
+enum MyResult<T, U> {
+    Awesome(T),
+    Terrible(U)
+}
+
+enum Never {}
+
+impl<U, V> Try for MyResult<U, V> {
+    type Output = U;
+    type Residual = MyResult<Never, V>;
+
+    fn from_output(u: U) -> MyResult<U, V> {
+        MyResult::Awesome(u)
+    }
+
+    fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
+        match self {
+            MyResult::Awesome(u) => ControlFlow::Continue(u),
+            MyResult::Terrible(e) => ControlFlow::Break(MyResult::Terrible(e)),
+        }
+    }
+}
+
+impl<U, V, W> FromResidual<MyResult<Never, V>> for MyResult<U, W> where V: Into<W> {
+    fn from_residual(x: MyResult<Never, V>) -> Self {
+        match x {
+            MyResult::Awesome(u) => match u {},
+            MyResult::Terrible(e) => MyResult::Terrible(e.into()),
+        }
+    }
+}
+
+type ResultResidual<E> = Result<std::convert::Infallible, E>;
+
+impl<U, V, W> FromResidual<ResultResidual<V>> for MyResult<U, W> where V: Into<W> {
+    fn from_residual(x: ResultResidual<V>) -> Self {
+        match x {
+            Ok(v) => match v {}
+            Err(e) => MyResult::Terrible(e.into()),
+        }
+    }
+}
+
+impl<U, V, W> FromResidual<MyResult<Never, V>> for Result<U, W> where V: Into<W> {
+    fn from_residual(x: MyResult<Never, V>) -> Self {
+        match x {
+            MyResult::Awesome(u) => match u {},
+            MyResult::Terrible(e) => Err(e.into()),
+        }
+    }
+}
+
+fn f(x: i32) -> Result<i32, String> {
+    if x == 0 {
+        Ok(42)
+    } else {
+        let y = g(x)?;
+        Ok(y)
+    }
+}
+
+fn g(x: i32) -> MyResult<i32, String> {
+    let _y = f(x - 1)?;
+    MyResult::Terrible("Hello".to_owned())
+}
+
+fn h() -> MyResult<i32, String> {
+    let a: Result<i32, &'static str> = Err("Hello");
+    let b = a?;
+    MyResult::Awesome(b)
+}
+
+fn i() -> MyResult<i32, String> {
+    let a: MyResult<i32, &'static str> = MyResult::Terrible("Hello");
+    let b = a?;
+    MyResult::Awesome(b)
+}
+
+fn main() {
+    assert!(f(0) == Ok(42));
+    assert!(f(10) == Err("Hello".to_owned()));
+    let _ = h();
+    let _ = i();
+}
diff --git a/src/test/ui/try-operator-on-main.rs b/src/test/ui/try-trait/try-operator-on-main.rs
index e1b6cfbe5ae..3b364f7e7d3 100644
--- a/src/test/ui/try-operator-on-main.rs
+++ b/src/test/ui/try-trait/try-operator-on-main.rs
@@ -1,4 +1,4 @@
-#![feature(try_trait)]
+#![feature(try_trait_v2)]
 
 use std::ops::Try;
 
@@ -7,14 +7,13 @@ fn main() {
     std::fs::File::open("foo")?; //~ ERROR the `?` operator can only
 
     // a non-`Try` type on a non-`Try` fn
-    ()?; //~ ERROR the `?` operator can only
+    ()?; //~ ERROR the `?` operator can only be applied to
+    //~^ ERROR the `?` operator can only be used in a function that
 
     // an unrelated use of `Try`
     try_trait_generic::<()>(); //~ ERROR the trait bound
 }
 
-
-
 fn try_trait_generic<T: Try>() -> T {
     // and a non-`Try` object on a `Try` fn.
     ()?; //~ ERROR the `?` operator can only be applied to values that implement `Try`
diff --git a/src/test/ui/try-operator-on-main.stderr b/src/test/ui/try-trait/try-operator-on-main.stderr
index be17de2fe7c..7d42c2e4d10 100644
--- a/src/test/ui/try-operator-on-main.stderr
+++ b/src/test/ui/try-trait/try-operator-on-main.stderr
@@ -1,18 +1,18 @@
-error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`)
-  --> $DIR/try-operator-on-main.rs:7:5
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-operator-on-main.rs:7:31
    |
 LL | / fn main() {
 LL | |     // error for a `Try` type on a non-`Try` fn
 LL | |     std::fs::File::open("foo")?;
-   | |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
+   | |                               ^ cannot use the `?` operator in a function that returns `()`
 LL | |
 ...  |
 LL | |     try_trait_generic::<()>();
 LL | | }
    | |_- this function should return `Result` or `Option` to accept `?`
    |
-   = help: the trait `Try` is not implemented for `()`
-   = note: required by `from_error`
+   = help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
+   = note: required by `from_residual`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
   --> $DIR/try-operator-on-main.rs:10:5
@@ -21,10 +21,28 @@ LL |     ()?;
    |     ^^^ the `?` operator cannot be applied to type `()`
    |
    = help: the trait `Try` is not implemented for `()`
-   = note: required by `into_result`
+   = note: required by `branch`
+
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
+  --> $DIR/try-operator-on-main.rs:10:7
+   |
+LL | / fn main() {
+LL | |     // error for a `Try` type on a non-`Try` fn
+LL | |     std::fs::File::open("foo")?;
+LL | |
+LL | |     // a non-`Try` type on a non-`Try` fn
+LL | |     ()?;
+   | |       ^ cannot use the `?` operator in a function that returns `()`
+...  |
+LL | |     try_trait_generic::<()>();
+LL | | }
+   | |_- this function should return `Result` or `Option` to accept `?`
+   |
+   = help: the trait `FromResidual<_>` is not implemented for `()`
+   = note: required by `from_residual`
 
 error[E0277]: the trait bound `(): Try` is not satisfied
-  --> $DIR/try-operator-on-main.rs:13:25
+  --> $DIR/try-operator-on-main.rs:14:25
    |
 LL |     try_trait_generic::<()>();
    |                         ^^ the trait `Try` is not implemented for `()`
@@ -33,14 +51,14 @@ LL | fn try_trait_generic<T: Try>() -> T {
    |                         --- required by this bound in `try_trait_generic`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/try-operator-on-main.rs:20:5
+  --> $DIR/try-operator-on-main.rs:19:5
    |
 LL |     ()?;
    |     ^^^ the `?` operator cannot be applied to type `()`
    |
    = help: the trait `Try` is not implemented for `()`
-   = note: required by `into_result`
+   = note: required by `branch`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/try-poll.rs b/src/test/ui/try-trait/try-poll.rs
index d42e51c7405..d42e51c7405 100644
--- a/src/test/ui/try-poll.rs
+++ b/src/test/ui/try-trait/try-poll.rs
diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr b/src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr
index 0880136d71b..05b63a00dfb 100644
--- a/src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr
@@ -1,5 +1,5 @@
 warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-74761.rs:4:32
+  --> $DIR/issue-74761.rs:3:32
    |
 LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
    |                                ^^^^^^^^^^^^^^^^^^^^^
@@ -8,13 +8,13 @@ LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
    = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
 
 error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-74761.rs:11:6
+  --> $DIR/issue-74761.rs:10:6
    |
 LL | impl<'a, 'b> A for () {
    |      ^^ unconstrained lifetime parameter
 
 error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-74761.rs:11:10
+  --> $DIR/issue-74761.rs:10:10
    |
 LL | impl<'a, 'b> A for () {
    |          ^^ unconstrained lifetime parameter
diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr b/src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr
index 20ebdd9cb50..ad111e23b15 100644
--- a/src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr
@@ -1,11 +1,11 @@
 error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-74761.rs:11:6
+  --> $DIR/issue-74761.rs:10:6
    |
 LL | impl<'a, 'b> A for () {
    |      ^^ unconstrained lifetime parameter
 
 error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-74761.rs:11:10
+  --> $DIR/issue-74761.rs:10:10
    |
 LL | impl<'a, 'b> A for () {
    |          ^^ unconstrained lifetime parameter
diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.rs b/src/test/ui/type-alias-impl-trait/issue-74761.rs
index 66bb079b25a..bbc67ecc97a 100644
--- a/src/test/ui/type-alias-impl-trait/issue-74761.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-74761.rs
@@ -1,4 +1,3 @@
-#![feature(member_constraints)]
 // revisions: min_tait full_tait
 #![feature(min_type_alias_impl_trait)]
 #![cfg_attr(full_tait, feature(type_alias_impl_trait))]
diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr
index 88322c3a0a6..33f762ccf63 100644
--- a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr
+++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/issue-45087-unreachable-unsafe.rs:3:5
+  --> $DIR/issue-45087-unreachable-unsafe.rs:6:5
    |
 LL |     *(1 as *mut u32) = 42;
    |     ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs
index 5edf7a47e2f..071cea8fbd7 100644
--- a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs
+++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 fn main() {
     return;
     *(1 as *mut u32) = 42;
diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr
new file mode 100644
index 00000000000..73a113652b8
--- /dev/null
+++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/issue-45087-unreachable-unsafe.rs:6:5
+   |
+LL |     *(1 as *mut u32) = 42;
+   |     ^^^^^^^^^^^^^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs b/src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs
new file mode 100644
index 00000000000..72f7b674777
--- /dev/null
+++ b/src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs
@@ -0,0 +1,27 @@
+// check-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+// This is issue #85435. But the real story is reflected in issue #85561, where
+// a bug in the implementation of feature(capture_disjoint_fields) () was
+// exposed to non-feature-gated code by a diagnostic changing PR that removed
+// the gating in one case.
+
+// This test is double-checking that the case of interest continues to work as
+// expected in the *absence* of that feature gate. At the time of this writing,
+// enabling the feature gate will cause this test to fail. We obviously cannot
+// stabilize that feature until it can correctly handle this test.
+
+fn main() {
+    let val: u8 = 5;
+    let u8_ptr: *const u8 = &val;
+    let _closure = || {
+        unsafe {
+            let tmp = *u8_ptr;
+            tmp
+
+            // Just dereferencing and returning directly compiles fine:
+            // *u8_ptr
+        }
+    };
+}
diff --git a/src/test/ui/unsafe/ranged_ints.stderr b/src/test/ui/unsafe/ranged_ints.mir.stderr
index 4e43df495c0..f9ef7834e1e 100644
--- a/src/test/ui/unsafe/ranged_ints.stderr
+++ b/src/test/ui/unsafe/ranged_ints.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
-  --> $DIR/ranged_ints.rs:7:14
+  --> $DIR/ranged_ints.rs:10:14
    |
 LL |     let _x = NonZero(0);
    |              ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr
diff --git a/src/test/ui/unsafe/ranged_ints.rs b/src/test/ui/unsafe/ranged_ints.rs
index 0fa2da917e9..05efe87ba6e 100644
--- a/src/test/ui/unsafe/ranged_ints.rs
+++ b/src/test/ui/unsafe/ranged_ints.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![feature(rustc_attrs)]
 
 #[rustc_layout_scalar_valid_range_start(1)]
diff --git a/src/test/ui/unsafe/ranged_ints.thir.stderr b/src/test/ui/unsafe/ranged_ints.thir.stderr
new file mode 100644
index 00000000000..f9ef7834e1e
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
+  --> $DIR/ranged_ints.rs:10:14
+   |
+LL |     let _x = NonZero(0);
+   |              ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr
+   |
+   = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/ranged_ints_const.stderr b/src/test/ui/unsafe/ranged_ints_const.mir.stderr
index 584ad40a92b..33d134c7ce5 100644
--- a/src/test/ui/unsafe/ranged_ints_const.stderr
+++ b/src/test/ui/unsafe/ranged_ints_const.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
-  --> $DIR/ranged_ints_const.rs:8:34
+  --> $DIR/ranged_ints_const.rs:11:34
    |
 LL | const fn foo() -> NonZero<u32> { NonZero(0) }
    |                                  ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr
diff --git a/src/test/ui/unsafe/ranged_ints_const.rs b/src/test/ui/unsafe/ranged_ints_const.rs
index 8477772867e..472b0968150 100644
--- a/src/test/ui/unsafe/ranged_ints_const.rs
+++ b/src/test/ui/unsafe/ranged_ints_const.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![feature(rustc_attrs)]
 
 #[rustc_layout_scalar_valid_range_start(1)]
diff --git a/src/test/ui/unsafe/ranged_ints_const.thir.stderr b/src/test/ui/unsafe/ranged_ints_const.thir.stderr
new file mode 100644
index 00000000000..33d134c7ce5
--- /dev/null
+++ b/src/test/ui/unsafe/ranged_ints_const.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
+  --> $DIR/ranged_ints_const.rs:11:34
+   |
+LL | const fn foo() -> NonZero<u32> { NonZero(0) }
+   |                                  ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr
+   |
+   = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/ranged_ints_macro.rs b/src/test/ui/unsafe/ranged_ints_macro.rs
index 9192ecfe196..8293d029951 100644
--- a/src/test/ui/unsafe/ranged_ints_macro.rs
+++ b/src/test/ui/unsafe/ranged_ints_macro.rs
@@ -1,4 +1,7 @@
 // build-pass
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![feature(rustc_attrs)]
 
 macro_rules! apply {
diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr
index ad93267ca01..9a522fac65f 100644
--- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr
+++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr
@@ -1,18 +1,18 @@
 error: call to unsafe function is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:9:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
    |
 LL |     unsf();
    |     ^^^^^^ call to unsafe function
    |
 note: the lint level is defined here
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:1:9
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9
    |
 LL | #![deny(unsafe_op_in_unsafe_fn)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:11:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
    |
 LL |     *PTR;
    |     ^^^^ dereference of raw pointer
@@ -20,7 +20,7 @@ LL |     *PTR;
    = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: use of mutable static is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:13:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
    |
 LL |     VOID = ();
    |     ^^^^^^^^^ use of mutable static
@@ -28,25 +28,25 @@ LL |     VOID = ();
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5
    |
 LL |     unsafe {}
    |     ^^^^^^ unnecessary `unsafe` block
    |
 note: the lint level is defined here
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:5:9
    |
 LL | #![deny(unused_unsafe)]
    |         ^^^^^^^^^^^^^
 
 error: call to unsafe function is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
    |
 LL |     unsf();
    |     ^^^^^^ call to unsafe function
    |
 note: the lint level is defined here
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:8
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8
    |
 LL | #[deny(warnings)]
    |        ^^^^^^^^
@@ -54,7 +54,7 @@ LL | #[deny(warnings)]
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
    |
 LL |     *PTR;
    |     ^^^^ dereference of raw pointer
@@ -62,7 +62,7 @@ LL |     *PTR;
    = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
 
 error: use of mutable static is unsafe and requires unsafe block (error E0133)
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
    |
 LL |     VOID = ();
    |     ^^^^^^^^^ use of mutable static
@@ -70,13 +70,13 @@ LL |     VOID = ();
    = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:30:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
    |
 LL |     unsafe {}
    |     ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:44:14
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14
    |
 LL |     unsafe { unsafe { unsf() } }
    |     ------   ^^^^^^ unnecessary `unsafe` block
@@ -84,7 +84,7 @@ LL |     unsafe { unsafe { unsf() } }
    |     because it's nested under this `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:55:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5
    |
 LL | unsafe fn allow_level() {
    | ----------------------- because it's nested under this `unsafe` fn
@@ -93,7 +93,7 @@ LL |     unsafe { unsf() }
    |     ^^^^^^ unnecessary `unsafe` block
 
 error: unnecessary `unsafe` block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:67:9
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9
    |
 LL | unsafe fn nested_allow_level() {
    | ------------------------------ because it's nested under this `unsafe` fn
@@ -102,7 +102,7 @@ LL |         unsafe { unsf() }
    |         ^^^^^^ unnecessary `unsafe` block
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:73:5
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
    |
 LL |     unsf();
    |     ^^^^^^ call to unsafe function
@@ -110,7 +110,7 @@ LL |     unsf();
    = note: consult the function's documentation for information on how to avoid undefined behavior
 
 error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
-  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:77:9
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9
    |
 LL |         unsf();
    |         ^^^^^^ call to unsafe function
diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs
index c8400a6fc4d..7ca714b85c2 100644
--- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs
+++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
 #![deny(unsafe_op_in_unsafe_fn)]
 #![deny(unused_unsafe)]
 
diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr
new file mode 100644
index 00000000000..ad87690bb52
--- /dev/null
+++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr
@@ -0,0 +1,122 @@
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5
+   |
+LL |     unsf();
+   |     ^^^^^^ call to unsafe function
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9
+   |
+LL | #![deny(unsafe_op_in_unsafe_fn)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5
+   |
+LL |     *PTR;
+   |     ^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5
+   |
+LL |     VOID = ();
+   |     ^^^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5
+   |
+LL |     unsafe {}
+   |     ^^^^^^ unnecessary `unsafe` block
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:5:9
+   |
+LL | #![deny(unused_unsafe)]
+   |         ^^^^^^^^^^^^^
+
+error: call to unsafe function is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5
+   |
+LL |     unsf();
+   |     ^^^^^^ call to unsafe function
+   |
+note: the lint level is defined here
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8
+   |
+LL | #[deny(warnings)]
+   |        ^^^^^^^^
+   = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]`
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5
+   |
+LL |     *PTR;
+   |     ^^^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: use of mutable static is unsafe and requires unsafe block (error E0133)
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5
+   |
+LL |     VOID = ();
+   |     ^^^^ use of mutable static
+   |
+   = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5
+   |
+LL |     unsafe {}
+   |     ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14
+   |
+LL |     unsafe { unsafe { unsf() } }
+   |     ------   ^^^^^^ unnecessary `unsafe` block
+   |     |
+   |     because it's nested under this `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5
+   |
+LL | unsafe fn allow_level() {
+   | ----------------------- because it's nested under this `unsafe` fn
+...
+LL |     unsafe { unsf() }
+   |     ^^^^^^ unnecessary `unsafe` block
+
+error: unnecessary `unsafe` block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9
+   |
+LL | unsafe fn nested_allow_level() {
+   | ------------------------------ because it's nested under this `unsafe` fn
+...
+LL |         unsafe { unsf() }
+   |         ^^^^^^ unnecessary `unsafe` block
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5
+   |
+LL |     unsf();
+   |     ^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+  --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9
+   |
+LL |         unsf();
+   |         ^^^^^^ call to unsafe function
+   |
+   = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 13 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.mir.stderr
index b2a30f81e05..fee645e4118 100644
--- a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr
+++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/unsafe-fn-assign-deref-ptr.rs:2:5
+  --> $DIR/unsafe-fn-assign-deref-ptr.rs:5:5
    |
 LL |     *p = 0;
    |     ^^^^^^ dereference of raw pointer
diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs
index 91264e790c8..a94e94375ae 100644
--- a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs
+++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 fn f(p: *mut u8) {
     *p = 0; //~ ERROR dereference of raw pointer is unsafe
     return;
diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr
new file mode 100644
index 00000000000..bbe4a415b5e
--- /dev/null
+++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/unsafe-fn-assign-deref-ptr.rs:5:5
+   |
+LL |     *p = 0;
+   |     ^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-deref-ptr.mir.stderr
index 98cb7b876f8..a2614992445 100644
--- a/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr
+++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/unsafe-fn-deref-ptr.rs:2:12
+  --> $DIR/unsafe-fn-deref-ptr.rs:5:12
    |
 LL |     return *p;
    |            ^^ dereference of raw pointer
diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs b/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs
index 46445aa261d..dc989535bd6 100644
--- a/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs
+++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 fn f(p: *const u8) -> u8 {
     return *p; //~ ERROR dereference of raw pointer is unsafe
 }
diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr b/src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr
new file mode 100644
index 00000000000..a2614992445
--- /dev/null
+++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/unsafe-fn-deref-ptr.rs:5:12
+   |
+LL |     return *p;
+   |            ^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.mir.stderr
index 410d8d3fb40..99808495ea6 100644
--- a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr
+++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.mir.stderr
@@ -1,5 +1,5 @@
 error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
-  --> $DIR/unsafe-unstable-const-fn.rs:8:5
+  --> $DIR/unsafe-unstable-const-fn.rs:11:5
    |
 LL |     *a == b
    |     ^^ dereference of raw pointer
diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs
index c7120e05007..0476759ca6d 100644
--- a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs
+++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs
@@ -1,3 +1,6 @@
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
 #![stable(feature = "foo", since = "1.33.0")]
 #![feature(staged_api)]
 #![feature(const_raw_ptr_deref)]
diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr
new file mode 100644
index 00000000000..99808495ea6
--- /dev/null
+++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr
@@ -0,0 +1,11 @@
+error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block
+  --> $DIR/unsafe-unstable-const-fn.rs:11:5
+   |
+LL |     *a == b
+   |     ^^ dereference of raw pointer
+   |
+   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/wf/wf-static-method.nll.stderr b/src/test/ui/wf/wf-static-method.nll.stderr
index d031a68a51d..9c066a7bdb0 100644
--- a/src/test/ui/wf/wf-static-method.nll.stderr
+++ b/src/test/ui/wf/wf-static-method.nll.stderr
@@ -68,7 +68,7 @@ LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
    |                  --  -- lifetime `'b` defined here
    |                  |
    |                  lifetime `'a` defined here
-LL |     <Evil>::inherent_evil(b) // bug? shouldn't this be an error
+LL |     <Evil>::inherent_evil(b)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
diff --git a/src/test/ui/wf/wf-static-method.rs b/src/test/ui/wf/wf-static-method.rs
index e5a1092175d..6e805d61265 100644
--- a/src/test/ui/wf/wf-static-method.rs
+++ b/src/test/ui/wf/wf-static-method.rs
@@ -47,7 +47,8 @@ fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
 }
 
 fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
-    <Evil>::inherent_evil(b) // bug? shouldn't this be an error
+    <Evil>::inherent_evil(b)
+    //~^ ERROR cannot infer an appropriate lifetime
 }
 
 
diff --git a/src/test/ui/wf/wf-static-method.stderr b/src/test/ui/wf/wf-static-method.stderr
index 0c98a809025..c02a8fe4aaf 100644
--- a/src/test/ui/wf/wf-static-method.stderr
+++ b/src/test/ui/wf/wf-static-method.stderr
@@ -103,7 +103,34 @@ note: ...so that reference does not outlive borrowed content
 LL |     <IndirectEvil>::static_evil(b)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 5 previous errors
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements
+  --> $DIR/wf-static-method.rs:50:5
+   |
+LL |     <Evil>::inherent_evil(b)
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 49:22...
+  --> $DIR/wf-static-method.rs:49:22
+   |
+LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+   |                      ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/wf-static-method.rs:50:27
+   |
+LL |     <Evil>::inherent_evil(b)
+   |                           ^
+note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 49:18...
+  --> $DIR/wf-static-method.rs:49:18
+   |
+LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+   |                  ^^
+note: ...so that reference does not outlive borrowed content
+  --> $DIR/wf-static-method.rs:50:5
+   |
+LL |     <Evil>::inherent_evil(b)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0312, E0478, E0495.
 For more information about an error, try `rustc --explain E0312`.
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 070e459c2d8b79c5b2ac5218064e7603329c92a
+Subproject 0cecbd67323ca14a7eb6505900d0d7307b00355
diff --git a/src/tools/clippy/.cargo/config b/src/tools/clippy/.cargo/config
index 9b5add4df1c..e95ea224cb6 100644
--- a/src/tools/clippy/.cargo/config
+++ b/src/tools/clippy/.cargo/config
@@ -2,6 +2,7 @@
 uitest = "test --test compile-test"
 dev = "run --target-dir clippy_dev/target --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
 lintcheck = "run --target-dir lintcheck/target --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml  -- "
+collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored"
 
 [build]
 rustflags = ["-Zunstable-options"]
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index ae6f1aa1b30..f27fee87dc1 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -90,6 +90,11 @@ jobs:
     - name: Checkout
       uses: actions/checkout@v2.3.3
 
+    # FIXME: should not be necessary once 1.24.2 is the default version on the windows runner
+    - name: Update rustup
+      run: rustup self update
+      if: runner.os == 'Windows'
+
     - name: Install toolchain
       run: rustup show active-toolchain
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 204d56e2a98..41af8e190dd 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,195 @@ document.
 
 ## Unreleased / In Rust Nightly
 
-[6ed6f1e...master](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...master)
+[7c7683c...master](https://github.com/rust-lang/rust-clippy/compare/7c7683c...master)
+
+## Rust 1.53
+
+Current beta, release 2021-06-17
+
+[6ed6f1e...7c7683c](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...7c7683c)
+
+### New Lints
+
+* [`option_filter_map`]
+  [#6342](https://github.com/rust-lang/rust-clippy/pull/6342)
+* [`branches_sharing_code`]
+  [#6463](https://github.com/rust-lang/rust-clippy/pull/6463)
+* [`needless_for_each`]
+  [#6706](https://github.com/rust-lang/rust-clippy/pull/6706)
+* [`if_then_some_else_none`]
+  [#6859](https://github.com/rust-lang/rust-clippy/pull/6859)
+* [`non_octal_unix_permissions`]
+  [#7001](https://github.com/rust-lang/rust-clippy/pull/7001)
+* [`unnecessary_self_imports`]
+  [#7072](https://github.com/rust-lang/rust-clippy/pull/7072)
+* [`bool_assert_comparison`]
+  [#7083](https://github.com/rust-lang/rust-clippy/pull/7083)
+* [`cloned_instead_of_copied`]
+  [#7098](https://github.com/rust-lang/rust-clippy/pull/7098)
+* [`flat_map_option`]
+  [#7101](https://github.com/rust-lang/rust-clippy/pull/7101)
+
+### Moves and Deprecations
+
+* Deprecate [`filter_map`] lint
+  [#7059](https://github.com/rust-lang/rust-clippy/pull/7059)
+* Move [`transmute_ptr_to_ptr`] to `pedantic`
+  [#7102](https://github.com/rust-lang/rust-clippy/pull/7102)
+
+### Enhancements
+
+* [`mem_replace_with_default`]: Also lint on common std constructors
+  [#6820](https://github.com/rust-lang/rust-clippy/pull/6820)
+* [`wrong_self_convention`]: Also lint on `to_*_mut` methods
+  [#6828](https://github.com/rust-lang/rust-clippy/pull/6828)
+* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]:
+  [#6863](https://github.com/rust-lang/rust-clippy/pull/6863)
+    * Attempt to find a common path prefix in suggestion
+    * Don't lint on `Option` and `Result`
+    * Consider `Self` prefix
+* [`explicit_deref_methods`]: Also lint on chained `deref` calls
+  [#6865](https://github.com/rust-lang/rust-clippy/pull/6865)
+* [`or_fun_call`]: Also lint on `unsafe` blocks
+  [#6928](https://github.com/rust-lang/rust-clippy/pull/6928)
+* [`vec_box`], [`linkedlist`], [`option_option`]: Also lint in `const` and
+  `static` items [#6938](https://github.com/rust-lang/rust-clippy/pull/6938)
+* [`search_is_some`]: Also check for `is_none`
+  [#6942](https://github.com/rust-lang/rust-clippy/pull/6942)
+* [`string_lit_as_bytes`]: Also lint on `into_bytes`
+  [#6959](https://github.com/rust-lang/rust-clippy/pull/6959)
+* [`len_without_is_empty`]: Also lint if function signatures of `len` and
+  `is_empty` don't match
+  [#6980](https://github.com/rust-lang/rust-clippy/pull/6980)
+* [`redundant_pattern_matching`]: Also lint if the pattern is a `&` pattern
+  [#6991](https://github.com/rust-lang/rust-clippy/pull/6991)
+* [`clone_on_copy`]: Also lint on chained method calls taking `self` by value
+  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
+* [`missing_panics_doc`]: Also lint on `assert_eq!` and `assert_ne!`
+  [#7029](https://github.com/rust-lang/rust-clippy/pull/7029)
+* [`needless_return`]: Also lint in `async` functions
+  [#7067](https://github.com/rust-lang/rust-clippy/pull/7067)
+* [`unused_io_amount`]: Also lint on expressions like `_.read().ok()?`
+  [#7100](https://github.com/rust-lang/rust-clippy/pull/7100)
+* [`iter_cloned_collect`]: Also lint on large arrays, since const-generics are
+  now stable [#7138](https://github.com/rust-lang/rust-clippy/pull/7138)
+
+### False Positive Fixes
+
+* [`upper_case_acronyms`]: No longer lints on public items
+  [#6805](https://github.com/rust-lang/rust-clippy/pull/6805)
+* [`suspicious_map`]: No longer lints when side effects may occur inside the
+  `map` call [#6831](https://github.com/rust-lang/rust-clippy/pull/6831)
+* [`manual_map`], [`manual_unwrap_or`]: No longer lints in `const` functions
+  [#6917](https://github.com/rust-lang/rust-clippy/pull/6917)
+* [`wrong_self_convention`]: Now respects `Copy` types
+  [#6924](https://github.com/rust-lang/rust-clippy/pull/6924)
+* [`needless_question_mark`]: No longer lints if the `?` and the `Some(..)` come
+  from different macro contexts [#6935](https://github.com/rust-lang/rust-clippy/pull/6935)
+* [`map_entry`]: Better detect if the entry API can be used
+  [#6937](https://github.com/rust-lang/rust-clippy/pull/6937)
+* [`or_fun_call`]: No longer lints on some `len` function calls
+  [#6950](https://github.com/rust-lang/rust-clippy/pull/6950)
+* [`new_ret_no_self`]: No longer lints when `Self` is returned with different
+  generic arguments [#6952](https://github.com/rust-lang/rust-clippy/pull/6952)
+* [`upper_case_acronyms`]: No longer lints on public items
+  [#6981](https://github.com/rust-lang/rust-clippy/pull/6981)
+* [`explicit_into_iter_loop`]: Only lint when `into_iter` is an implementation
+  of `IntoIterator` [#6982](https://github.com/rust-lang/rust-clippy/pull/6982)
+* [`expl_impl_clone_on_copy`]: Take generic constraints into account before
+  suggesting to use `derive` instead
+  [#6993](https://github.com/rust-lang/rust-clippy/pull/6993)
+* [`missing_panics_doc`]: No longer lints when only debug-assertions are used
+  [#6996](https://github.com/rust-lang/rust-clippy/pull/6996)
+* [`clone_on_copy`]: Only lint when using the `Clone` trait
+  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
+* [`wrong_self_convention`]: No longer lints inside a trait implementation
+  [#7002](https://github.com/rust-lang/rust-clippy/pull/7002)
+* [`redundant_clone`]: No longer lints when the cloned value is modified while
+  the clone is in use
+  [#7011](https://github.com/rust-lang/rust-clippy/pull/7011)
+* [`same_item_push`]: No longer lints if the `Vec` is used in the loop body
+  [#7018](https://github.com/rust-lang/rust-clippy/pull/7018)
+* [`cargo_common_metadata`]: Remove author requirement
+  [#7026](https://github.com/rust-lang/rust-clippy/pull/7026)
+* [`panic_in_result_fn`]: No longer lints on `debug_assert` family
+  [#7060](https://github.com/rust-lang/rust-clippy/pull/7060)
+* [`panic`]: No longer wrongfully lints on `debug_assert` with message
+  [#7063](https://github.com/rust-lang/rust-clippy/pull/7063)
+* [`wrong_self_convention`]: No longer lints in trait implementations where no
+  `self` is involved [#7064](https://github.com/rust-lang/rust-clippy/pull/7064)
+* [`missing_const_for_fn`]: No longer lints when unstable `const` function is
+  involved [#7076](https://github.com/rust-lang/rust-clippy/pull/7076)
+* [`suspicious_else_formatting`]: Allow Allman style braces
+  [#7087](https://github.com/rust-lang/rust-clippy/pull/7087)
+* [`inconsistent_struct_constructor`]: No longer lints in macros
+  [#7097](https://github.com/rust-lang/rust-clippy/pull/7097)
+* [`single_component_path_imports`]: No longer lints on macro re-exports
+  [#7120](https://github.com/rust-lang/rust-clippy/pull/7120)
+
+### Suggestion Fixes/Improvements
+
+* [`redundant_pattern_matching`]: Add a note when applying this lint would
+  change the drop order
+  [#6568](https://github.com/rust-lang/rust-clippy/pull/6568)
+* [`write_literal`], [`print_literal`]: Add auto-applicable suggestion
+  [#6821](https://github.com/rust-lang/rust-clippy/pull/6821)
+* [`manual_map`]: Fix suggestion for complex `if let ... else` chains
+  [#6856](https://github.com/rust-lang/rust-clippy/pull/6856)
+* [`inconsistent_struct_constructor`]: Make lint description and message clearer
+  [#6892](https://github.com/rust-lang/rust-clippy/pull/6892)
+* [`map_entry`]: Now suggests `or_insert`, `insert_with` or `match _.entry(_)`
+  as appropriate [#6937](https://github.com/rust-lang/rust-clippy/pull/6937)
+* [`manual_flatten`]: Suggest to insert `copied` if necessary
+  [#6962](https://github.com/rust-lang/rust-clippy/pull/6962)
+* [`redundant_slicing`]: Fix suggestion when a re-borrow might be required or
+  when the value is from a macro call
+  [#6975](https://github.com/rust-lang/rust-clippy/pull/6975)
+* [`match_wildcard_for_single_variants`]: Fix suggestion for hidden variant
+  [#6988](https://github.com/rust-lang/rust-clippy/pull/6988)
+* [`clone_on_copy`]: Correct suggestion when the cloned value is a macro call
+  [#7000](https://github.com/rust-lang/rust-clippy/pull/7000)
+* [`manual_map`]: Fix suggestion at the end of an if chain
+  [#7004](https://github.com/rust-lang/rust-clippy/pull/7004)
+* Fix needless parenthesis output in multiple lint suggestions
+  [#7013](https://github.com/rust-lang/rust-clippy/pull/7013)
+* [`needless_collect`]: Better explanation in the lint message
+  [#7020](https://github.com/rust-lang/rust-clippy/pull/7020)
+* [`useless_vec`]: Now considers mutability
+  [#7036](https://github.com/rust-lang/rust-clippy/pull/7036)
+* [`useless_format`]: Wrap the content in braces if necessary
+  [#7092](https://github.com/rust-lang/rust-clippy/pull/7092)
+* [`single_match`]: Don't suggest an equality check for types which don't
+  implement `PartialEq`
+  [#7093](https://github.com/rust-lang/rust-clippy/pull/7093)
+* [`from_over_into`]: Mention type in help message
+  [#7099](https://github.com/rust-lang/rust-clippy/pull/7099)
+* [`manual_unwrap_or`]: Fix invalid code suggestion due to a macro call
+  [#7136](https://github.com/rust-lang/rust-clippy/pull/7136)
+
+### ICE Fixes
+
+* [`macro_use_imports`]
+  [#7022](https://github.com/rust-lang/rust-clippy/pull/7022)
+* [`missing_panics_doc`]
+  [#7034](https://github.com/rust-lang/rust-clippy/pull/7034)
+* [`tabs_in_doc_comments`]
+  [#7039](https://github.com/rust-lang/rust-clippy/pull/7039)
+* [`missing_const_for_fn`]
+  [#7128](https://github.com/rust-lang/rust-clippy/pull/7128)
+
+### Others
+
+* [Clippy's lint
+  list](https://rust-lang.github.io/rust-clippy/master/index.html) now supports
+  themes [#7030](https://github.com/rust-lang/rust-clippy/pull/7030)
+* Lints that were uplifted to `rustc` now mention the new `rustc` name in the
+  deprecation warning
+  [#7056](https://github.com/rust-lang/rust-clippy/pull/7056)
 
 ## Rust 1.52
 
-Current beta, release 2021-05-06
+Current stable, released 2021-05-06
 
 [3e41797...6ed6f1e](https://github.com/rust-lang/rust-clippy/compare/3e41797...6ed6f1e)
 
@@ -99,7 +283,7 @@ Current beta, release 2021-05-06
   [#6682](https://github.com/rust-lang/rust-clippy/pull/6682)
 * [`unit_arg`]: No longer lints on unit arguments when they come from a path expression.
   [#6601](https://github.com/rust-lang/rust-clippy/pull/6601)
-* [`cargo_common_metadata`]: No longer lints if 
+* [`cargo_common_metadata`]: No longer lints if
   [`publish = false`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field)
   is defined in the manifest
   [#6650](https://github.com/rust-lang/rust-clippy/pull/6650)
@@ -124,11 +308,11 @@ Current beta, release 2021-05-06
 
 * [`useless_format`]: Improved the documentation example
   [#6854](https://github.com/rust-lang/rust-clippy/pull/6854)
-* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper 
+* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper
   [#6782](https://github.com/rust-lang/rust-clippy/pull/6782)
 
 ### Others
-* Running `cargo clippy` after `cargo check` now works as expected 
+* Running `cargo clippy` after `cargo check` now works as expected
   (`cargo clippy` and `cargo check` no longer shares the same build cache)
   [#6687](https://github.com/rust-lang/rust-clippy/pull/6687)
 * Cargo now re-runs Clippy if arguments after `--` provided to `cargo clippy` are changed.
@@ -145,7 +329,7 @@ Current beta, release 2021-05-06
 
 ## Rust 1.51
 
-Current stable, released 2021-03-25
+Released 2021-03-25
 
 [4911ab1...3e41797](https://github.com/rust-lang/rust-clippy/compare/4911ab1...3e41797)
 
@@ -2309,6 +2493,7 @@ Released 2018-09-13
 [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or
 [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains
 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
+[`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat
 [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip
 [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or
@@ -2365,6 +2550,7 @@ Released 2018-09-13
 [`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer
 [`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount
 [`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type
+[`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool
 [`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
 [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
 [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference
@@ -2437,6 +2623,7 @@ Released 2018-09-13
 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
 [`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
 [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
+[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
 [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
 [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
@@ -2485,6 +2672,7 @@ Released 2018-09-13
 [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map
 [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl
 [`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings
+[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn
 [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
 [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
 [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
@@ -2538,6 +2726,7 @@ Released 2018-09-13
 [`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute
 [`unstable_as_mut_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_mut_slice
 [`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice
+[`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async
 [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
 [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
 [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
diff --git a/src/tools/clippy/COPYRIGHT b/src/tools/clippy/COPYRIGHT
index 80d64472c70..238c919b69d 100644
--- a/src/tools/clippy/COPYRIGHT
+++ b/src/tools/clippy/COPYRIGHT
@@ -1,4 +1,4 @@
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index f010e609604..b003b15a11d 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -33,12 +33,13 @@ tempfile = { version = "3.1.0", optional = true }
 cargo_metadata = "0.12"
 compiletest_rs = { version = "0.6.0", features = ["tmp"] }
 tester = "0.9"
-clippy-mini-macro-test = { version = "0.2", path = "mini-macro" }
 serde = { version = "1.0", features = ["derive"] }
 derive-new = "0.5"
 regex = "1.4"
 quote = "1"
 syn = { version = "1", features = ["full"] }
+# This is used by the `collect-metadata` alias.
+filetime = "0.2"
 
 # A noop dependency that changes in the Rust repository, it's a bit of a hack.
 # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
@@ -49,7 +50,7 @@ rustc-workspace-hack = "1.0.0"
 rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" }
 
 [features]
-deny-warnings = []
+deny-warnings = ["clippy_lints/deny-warnings"]
 integration = ["tempfile"]
 internal-lints = ["clippy_lints/internal-lints"]
 metadata-collector-lint = ["internal-lints", "clippy_lints/metadata-collector-lint"]
diff --git a/src/tools/clippy/LICENSE-APACHE b/src/tools/clippy/LICENSE-APACHE
index d821a4de2be..04169a42b8b 100644
--- a/src/tools/clippy/LICENSE-APACHE
+++ b/src/tools/clippy/LICENSE-APACHE
@@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
    same "printed page" as the copyright notice for easier
    identification within third-party archives.
 
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
diff --git a/src/tools/clippy/LICENSE-MIT b/src/tools/clippy/LICENSE-MIT
index b7c70dd4026..90a2d3950d1 100644
--- a/src/tools/clippy/LICENSE-MIT
+++ b/src/tools/clippy/LICENSE-MIT
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2014-2020 The Rust Project Developers
+Copyright (c) 2014-2021 The Rust Project Developers
 
 Permission is hereby granted, free of charge, to any
 person obtaining a copy of this software and associated
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index 8c0c16c443d..6c556f579ca 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -147,6 +147,7 @@ Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml
 value` mapping eg.
 
 ```toml
+avoid-breaking-exported-api = false
 blacklisted-names = ["toto", "tata", "titi"]
 cognitive-complexity-threshold = 30
 ```
@@ -236,7 +237,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT
 
 ## License
 
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2021 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license
diff --git a/src/tools/clippy/build.rs b/src/tools/clippy/build.rs
index 018375dbada..b5484bec3c8 100644
--- a/src/tools/clippy/build.rs
+++ b/src/tools/clippy/build.rs
@@ -14,6 +14,6 @@ fn main() {
     );
     println!(
         "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}",
-        rustc_tools_util::get_channel().unwrap_or_default()
+        rustc_tools_util::get_channel()
     );
 }
diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml
new file mode 100644
index 00000000000..cda8d17eed4
--- /dev/null
+++ b/src/tools/clippy/clippy.toml
@@ -0,0 +1 @@
+avoid-breaking-exported-api = false
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 1e5a140e964..69f42aca8b6 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -1,5 +1,7 @@
-#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![feature(once_cell)]
+#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
 
 use itertools::Itertools;
 use regex::Regex;
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index f4da783502c..7040c257c83 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -1,4 +1,6 @@
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
 
 use clap::{App, Arg, ArgMatches, SubCommand};
 use clippy_dev::{bless, fmt, ide_setup, new_lint, serve, stderr_length_check, update_lints};
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 7ceb1da6a6e..48f2972ec58 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -30,7 +30,7 @@ rustc-semver = "1.1.0"
 url = { version = "2.1.0", features = ["serde"] }
 
 [features]
-deny-warnings = []
+deny-warnings = ["clippy_utils/deny-warnings"]
 # build clippy with internal lints enabled, off by default
 internal-lints = ["clippy_utils/internal-lints"]
 metadata-collector-lint = ["serde_json", "clippy_utils/metadata-collector-lint"]
diff --git a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs
index 5fbf4bdbd18..49d4350123f 100644
--- a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs
@@ -3,9 +3,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
-use crate::consts::{constant, Constant};
-
 use clippy_utils::comparisons::{normalize_comparison, Rel};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_isize_or_usize;
diff --git a/src/tools/clippy/clippy_lints/src/arithmetic.rs b/src/tools/clippy/clippy_lints/src/arithmetic.rs
index c560f545d6a..24c2a972811 100644
--- a/src/tools/clippy/clippy_lints/src/arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/arithmetic.rs
@@ -1,4 +1,4 @@
-use crate::consts::constant_simple;
+use clippy_utils::consts::constant_simple;
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index c565e29d078..5235b2642d1 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call};
@@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
                 &format!("`assert!(false, {})` should probably be replaced", panic_message),
                 None,
                 &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message),
-            )
+            );
         };
 
         if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") {
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index c5b01461c1c..932cd58bf62 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -273,7 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         let attrs = cx.tcx.hir().attrs(item.hir_id());
         if is_relevant_item(cx, item) {
-            check_attrs(cx, item.span, item.ident.name, attrs)
+            check_attrs(cx, item.span, item.ident.name, attrs);
         }
         match item.kind {
             ItemKind::ExternCrate(..) | ItemKind::Use(..) => {
@@ -343,13 +343,13 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
         if is_relevant_impl(cx, item) {
-            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()))
+            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
         }
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
         if is_relevant_trait(cx, item) {
-            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()))
+            check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id()));
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/bit_mask.rs b/src/tools/clippy/clippy_lints/src/bit_mask.rs
index f7daf3dab49..991ed94572c 100644
--- a/src/tools/clippy/clippy_lints/src/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/bit_mask.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
@@ -115,9 +115,9 @@ impl<'tcx> LateLintPass<'tcx> for BitMask {
         if let ExprKind::Binary(cmp, left, right) = &e.kind {
             if cmp.node.is_comparison() {
                 if let Some(cmp_opt) = fetch_int_literal(cx, right) {
-                    check_compare(cx, left, cmp.node, cmp_opt, e.span)
+                    check_compare(cx, left, cmp.node, cmp_opt, e.span);
                 } else if let Some(cmp_val) = fetch_int_literal(cx, left) {
-                    check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span)
+                    check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span);
                 }
             }
         }
@@ -171,7 +171,7 @@ fn check_compare(cx: &LateContext<'_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp
         }
         fetch_int_literal(cx, right)
             .or_else(|| fetch_int_literal(cx, left))
-            .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span))
+            .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span));
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 67f0e0c7870..e72399af232 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
         _: Span,
         _: HirId,
     ) {
-        NonminimalBoolVisitor { cx }.visit_body(body)
+        NonminimalBoolVisitor { cx }.visit_body(body);
     }
 }
 
@@ -184,7 +184,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
                 Term(n) => {
                     let terminal = self.terminals[n as usize];
                     if let Some(str) = simplify_not(self.cx, terminal) {
-                        self.output.push_str(&str)
+                        self.output.push_str(&str);
                     } else {
                         self.output.push('!');
                         let snip = snippet_opt(self.cx, terminal.span)?;
@@ -452,7 +452,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
         }
         match &e.kind {
             ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => {
-                self.bool_expr(e)
+                self.bool_expr(e);
             },
             ExprKind::Unary(UnOp::Not, inner) => {
                 if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 040e0ca8864..c9c111a2847 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{method_chain_args, sext};
 use if_chain::if_chain;
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index dae5c86bd44..6e950738239 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -92,7 +92,7 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]);
 impl EarlyLintPass for CollapsibleIf {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
         if !expr.span.from_expansion() {
-            check_if(cx, expr)
+            check_if(cx, expr);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index 2a61d58e653..b6999bef6e7 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
             "`if` chain can be rewritten with `match`",
             None,
             "consider rewriting the `if` chain to use `cmp` and `match`",
-        )
+        );
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs
deleted file mode 100644
index 7e87f53e3fb..00000000000
--- a/src/tools/clippy/clippy_lints/src/consts.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub use clippy_utils::consts::*;
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index f956d171bfb..376a14b8181 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -476,7 +476,7 @@ fn emit_branches_sharing_code_lint(
         }
 
         suggestions.push(("end", span, suggestion.to_string()));
-        add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit()
+        add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit();
     }
 
     let add_optional_msgs = |diag: &mut DiagnosticBuilder<'_>| {
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 6e883942680..759f7d4062d 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -181,9 +181,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
         match stmt.kind {
             StmtKind::Local(local) => {
                 if local.ty.is_some() {
-                    self.ty_bounds.push(TyBound::Any)
+                    self.ty_bounds.push(TyBound::Any);
                 } else {
-                    self.ty_bounds.push(TyBound::Nothing)
+                    self.ty_bounds.push(TyBound::Nothing);
                 }
             },
 
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index 4688b3d5105..04f3d77464f 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -1,6 +1,13 @@
+/// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This
+/// enables the simple extraction of the metadata without changing the current deprecation
+/// declaration.
+pub struct ClippyDeprecatedLint;
+
 macro_rules! declare_deprecated_lint {
-    (pub $name: ident, $_reason: expr) => {
-        declare_lint!(pub $name, Allow, "deprecated lint")
+    { $(#[$attr:meta])* pub $name: ident, $_reason: expr} => {
+        $(#[$attr])*
+        #[allow(dead_code)]
+        pub static $name: ClippyDeprecatedLint = ClippyDeprecatedLint {};
     }
 }
 
@@ -134,3 +141,22 @@ declare_deprecated_lint! {
     pub FILTER_MAP,
     "this lint has been replaced by `manual_filter_map`, a more specific lint"
 }
+
+declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which
+    /// enables the `enum_variant_names` lint for public items.
+    /// ```
+    pub PUB_ENUM_VARIANT_NAMES,
+    "set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items"
+}
+
+declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which
+    /// enables the `wrong_self_conversion` lint for public items.
+    pub WRONG_PUB_SELF_CONVENTION,
+    "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items"
+}
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index e742cd626ab..840c1eba79d 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -12,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{source_map::Span};
+use rustc_span::source_map::Span;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for deriving `Hash` but implementing `PartialEq`
@@ -310,15 +310,11 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &T
     // there's a Copy impl for any instance of the adt.
     if !is_copy(cx, ty) {
         if ty_subs.non_erasable_generics().next().is_some() {
-            let has_copy_impl = cx
-                .tcx
-                .all_local_trait_impls(())
-                .get(&copy_id)
-                .map_or(false, |impls| {
-                    impls
-                        .iter()
-                        .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did == adt.did))
-                });
+            let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(&copy_id).map_or(false, |impls| {
+                impls
+                    .iter()
+                    .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did == adt.did))
+            });
             if !has_copy_impl {
                 return;
             }
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index fb53b55ebd6..e67ec4e06c5 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -383,7 +383,7 @@ pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span:
     let mut no_stars = String::with_capacity(doc.len());
     for line in doc.lines() {
         let mut chars = line.chars();
-        while let Some(c) = chars.next() {
+        for c in &mut chars {
             if c.is_whitespace() {
                 no_stars.push(c);
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/double_comparison.rs b/src/tools/clippy/clippy_lints/src/double_comparison.rs
index 58543ae6e4e..4966638cb1b 100644
--- a/src/tools/clippy/clippy_lints/src/double_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/double_comparison.rs
@@ -70,16 +70,16 @@ impl<'tcx> DoubleComparisons {
         #[rustfmt::skip]
         match (op, lkind, rkind) {
             (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => {
-                lint_double_comparison!(<=)
+                lint_double_comparison!(<=);
             },
             (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => {
-                lint_double_comparison!(>=)
+                lint_double_comparison!(>=);
             },
             (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => {
-                lint_double_comparison!(!=)
+                lint_double_comparison!(!=);
             },
             (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => {
-                lint_double_comparison!(==)
+                lint_double_comparison!(==);
             },
             _ => (),
         };
diff --git a/src/tools/clippy/clippy_lints/src/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/duration_subsec.rs
index 529807770f3..94b09bf7173 100644
--- a/src/tools/clippy/clippy_lints/src/duration_subsec.rs
+++ b/src/tools/clippy/clippy_lints/src/duration_subsec.rs
@@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Spanned;
 
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::paths;
 
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 8db5050a5ac..2eb8b1422ed 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -469,7 +469,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> {
                     let mut is_map_used = self.is_map_used;
                     for arm in arms {
                         if let Some(Guard::If(guard) | Guard::IfLet(_, guard)) = arm.guard {
-                            self.visit_non_tail_expr(guard)
+                            self.visit_non_tail_expr(guard);
                         }
                         is_map_used |= self.visit_cond_arm(arm.body);
                     }
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index 7a98ae39d3a..021136ac5e0 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -1,7 +1,7 @@
 //! lint on C-like enums that are `repr(isize/usize)` and have values that
 //! don't fit into an `i32`
 
-use crate::consts::{miri_to_const, Constant};
+use clippy_utils::consts::{miri_to_const, Constant};
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs
index 0ecc0bc3eb6..b1a105a51c1 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs
@@ -3,8 +3,8 @@
 use clippy_utils::camel_case;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::source::is_present_in_source;
-use rustc_ast::ast::{EnumDef, Item, ItemKind, VisibilityKind};
-use rustc_lint::{EarlyContext, EarlyLintPass, Lint};
+use rustc_hir::{EnumDef, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
@@ -40,36 +40,6 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Detects public enumeration variants that are
-    /// prefixed or suffixed by the same characters.
-    ///
-    /// **Why is this bad?** Public enumeration variant names should specify their variant,
-    /// not repeat the enumeration name.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// pub enum Cake {
-    ///     BlackForestCake,
-    ///     HummingbirdCake,
-    ///     BattenbergCake,
-    /// }
-    /// ```
-    /// Could be written as:
-    /// ```rust
-    /// pub enum Cake {
-    ///     BlackForest,
-    ///     Hummingbird,
-    ///     Battenberg,
-    /// }
-    /// ```
-    pub PUB_ENUM_VARIANT_NAMES,
-    pedantic,
-    "public enums where all variants share a prefix/postfix"
-}
-
-declare_clippy_lint! {
     /// **What it does:** Detects type names that are prefixed or suffixed by the
     /// containing module's name.
     ///
@@ -127,21 +97,22 @@ declare_clippy_lint! {
 pub struct EnumVariantNames {
     modules: Vec<(Symbol, String)>,
     threshold: u64,
+    avoid_breaking_exported_api: bool,
 }
 
 impl EnumVariantNames {
     #[must_use]
-    pub fn new(threshold: u64) -> Self {
+    pub fn new(threshold: u64, avoid_breaking_exported_api: bool) -> Self {
         Self {
             modules: Vec::new(),
             threshold,
+            avoid_breaking_exported_api,
         }
     }
 }
 
 impl_lint_pass!(EnumVariantNames => [
     ENUM_VARIANT_NAMES,
-    PUB_ENUM_VARIANT_NAMES,
     MODULE_NAME_REPETITIONS,
     MODULE_INCEPTION
 ]);
@@ -167,33 +138,42 @@ fn partial_rmatch(post: &str, name: &str) -> usize {
 }
 
 fn check_variant(
-    cx: &EarlyContext<'_>,
+    cx: &LateContext<'_>,
     threshold: u64,
-    def: &EnumDef,
+    def: &EnumDef<'_>,
     item_name: &str,
     item_name_chars: usize,
     span: Span,
-    lint: &'static Lint,
 ) {
     if (def.variants.len() as u64) < threshold {
         return;
     }
-    for var in &def.variants {
+    for var in def.variants {
         let name = var.ident.name.as_str();
         if partial_match(item_name, &name) == item_name_chars
             && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
             && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
         {
-            span_lint(cx, lint, var.span, "variant name starts with the enum's name");
+            span_lint(
+                cx,
+                ENUM_VARIANT_NAMES,
+                var.span,
+                "variant name starts with the enum's name",
+            );
         }
         if partial_rmatch(item_name, &name) == item_name_chars {
-            span_lint(cx, lint, var.span, "variant name ends with the enum's name");
+            span_lint(
+                cx,
+                ENUM_VARIANT_NAMES,
+                var.span,
+                "variant name ends with the enum's name",
+            );
         }
     }
     let first = &def.variants[0].ident.name.as_str();
     let mut pre = &first[..camel_case::until(&*first)];
     let mut post = &first[camel_case::from(&*first)..];
-    for var in &def.variants {
+    for var in def.variants {
         let name = var.ident.name.as_str();
 
         let pre_match = partial_match(pre, &name);
@@ -226,7 +206,7 @@ fn check_variant(
     };
     span_lint_and_help(
         cx,
-        lint,
+        ENUM_VARIANT_NAMES,
         span,
         &format!("all variants have the same {}fix: `{}`", what, value),
         None,
@@ -261,14 +241,14 @@ fn to_camel_case(item_name: &str) -> String {
     s
 }
 
-impl EarlyLintPass for EnumVariantNames {
-    fn check_item_post(&mut self, _cx: &EarlyContext<'_>, _item: &Item) {
+impl LateLintPass<'_> for EnumVariantNames {
+    fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
         let last = self.modules.pop();
         assert!(last.is_some());
     }
 
     #[allow(clippy::similar_names)]
-    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         let item_name = item.ident.name.as_str();
         let item_name_chars = item_name.chars().count();
         let item_camel = to_camel_case(&item_name);
@@ -286,7 +266,7 @@ impl EarlyLintPass for EnumVariantNames {
                             );
                         }
                     }
-                    if item.vis.kind.is_pub() {
+                    if item.vis.node.is_pub() {
                         let matching = partial_match(mod_camel, &item_camel);
                         let rmatching = partial_rmatch(mod_camel, &item_camel);
                         let nchars = mod_camel.chars().count();
@@ -317,11 +297,9 @@ impl EarlyLintPass for EnumVariantNames {
             }
         }
         if let ItemKind::Enum(ref def, _) = item.kind {
-            let lint = match item.vis.kind {
-                VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES,
-                _ => ENUM_VARIANT_NAMES,
-            };
-            check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint);
+            if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.hir_id())) {
+                check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span);
+            }
         }
         self.modules.push((item.ident.name, item_camel));
     }
diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs
index 90f391b5f5c..a3a8e748d99 100644
--- a/src/tools/clippy/clippy_lints/src/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/eq_op.rs
@@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                                         vec![(left.span, lsnip), (right.span, rsnip)],
                                     );
                                 },
-                            )
+                            );
                         } else if lcpy
                             && !rcpy
                             && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()])
@@ -175,7 +175,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                                         Applicability::MaybeIncorrect, // FIXME #2597
                                     );
                                 },
-                            )
+                            );
                         } else if !lcpy
                             && rcpy
                             && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()])
@@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                                         Applicability::MaybeIncorrect, // FIXME #2597
                                     );
                                 },
-                            )
+                            );
                         }
                     },
                     // &foo == bar
@@ -218,7 +218,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                                         Applicability::MaybeIncorrect, // FIXME #2597
                                     );
                                 },
-                            )
+                            );
                         }
                     },
                     // foo == &bar
@@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                                     rsnip,
                                     Applicability::MaybeIncorrect, // FIXME #2597
                                 );
-                            })
+                            });
                         }
                     },
                     _ => {},
diff --git a/src/tools/clippy/clippy_lints/src/erasing_op.rs b/src/tools/clippy/clippy_lints/src/erasing_op.rs
index f95ca86a2d0..4aa9c25b1b0 100644
--- a/src/tools/clippy/clippy_lints/src/erasing_op.rs
+++ b/src/tools/clippy/clippy_lints/src/erasing_op.rs
@@ -1,11 +1,10 @@
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 
-use crate::consts::{constant_simple, Constant};
-
 declare_clippy_lint! {
     /// **What it does:** Checks for erasing operations, e.g., `x * 0`.
     ///
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 2f1aa53236d..8d066f305ee 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
                 for arg in args {
                     // skip `foo(macro!())`
                     if arg.span.ctxt() == expr.span.ctxt() {
-                        check_closure(cx, arg)
+                        check_closure(cx, arg);
                     }
                 }
             },
@@ -92,17 +92,19 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) {
         let ex = &body.value;
 
         if ex.span.ctxt() != expr.span.ctxt() {
-            if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
-                // replace `|| vec![]` with `Vec::new`
-                span_lint_and_sugg(
-                    cx,
-                    REDUNDANT_CLOSURE,
-                    expr.span,
-                    "redundant closure",
-                    "replace the closure with `Vec::new`",
-                    "std::vec::Vec::new".into(),
-                    Applicability::MachineApplicable,
-                );
+            if decl.inputs.is_empty() {
+                if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) {
+                    // replace `|| vec![]` with `Vec::new`
+                    span_lint_and_sugg(
+                        cx,
+                        REDUNDANT_CLOSURE,
+                        expr.span,
+                        "redundant closure",
+                        "replace the closure with `Vec::new`",
+                        "std::vec::Vec::new".into(),
+                        Applicability::MachineApplicable,
+                    );
+                }
             }
             // skip `foo(|| macro!())`
             return;
@@ -188,9 +190,10 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a
     cx.tcx.impl_of_method(method_def_id).and_then(|_| {
         //a type may implicitly implement other type's methods (e.g. Deref)
         if match_types(expected_type_of_self, actual_type_of_self) {
-            return Some(get_type_name(cx, actual_type_of_self));
+            Some(get_type_name(cx, actual_type_of_self))
+        } else {
+            None
         }
-        None
     })
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
index 41acf55dd7d..5fdf5bc9e9d 100644
--- a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
+++ b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs
@@ -110,7 +110,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
                 self.visit_expr(e);
                 for arm in arms {
                     if let Some(Guard::If(if_expr)) = arm.guard {
-                        self.visit_expr(if_expr)
+                        self.visit_expr(if_expr);
                     }
                     // make sure top level arm expressions aren't linted
                     self.maybe_walk_expr(&*arm.body);
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index e0b687b0205..e38384b01d4 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -1,4 +1,4 @@
-use crate::consts::{
+use clippy_utils::consts::{
     constant, constant_simple, Constant,
     Constant::{Int, F32, F64},
 };
@@ -323,7 +323,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                         cx,
                         SUBOPTIMAL_FLOPS,
                         parent.span,
-                        "square can be computed more efficiently",
+                        "multiply and add expressions can be calculated more efficiently and accurately",
                         "consider using",
                         format!(
                             "{}.mul_add({}, {})",
@@ -337,16 +337,6 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) {
                     return;
                 }
             }
-
-            span_lint_and_sugg(
-                cx,
-                SUBOPTIMAL_FLOPS,
-                expr.span,
-                "square can be computed more efficiently",
-                "consider using",
-                format!("{} * {}", Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, &args[0], "..")),
-                Applicability::MachineApplicable,
-            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index 20288427b4a..7f4fb68cf2f 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -240,7 +240,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
                 }
             },
             Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => {
-                self.mutates_static |= is_mutated_static(target)
+                self.mutates_static |= is_mutated_static(target);
             },
             _ => {},
         }
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index b8ea6990866..af759a48e10 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -116,7 +116,7 @@ impl<'a, 'tcx> DerefVisitor<'a, 'tcx> {
                     self.cx,
                     NOT_UNSAFE_PTR_ARG_DEREF,
                     ptr.span,
-                    "this public function dereferences a raw pointer but is not marked `unsafe`",
+                    "this public function might dereference a raw pointer but is not marked `unsafe`",
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
index aa5494d5a7d..a666fee1a4a 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
@@ -4,7 +4,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_span::Span;
 
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::source::snippet;
+use clippy_utils::source::snippet_opt;
 
 use super::TOO_MANY_LINES;
 
@@ -13,15 +13,25 @@ pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<'
         return;
     }
 
-    let code_snippet = snippet(cx, body.value.span, "..");
+    let code_snippet = match snippet_opt(cx, body.value.span) {
+        Some(s) => s,
+        _ => return,
+    };
     let mut line_count: u64 = 0;
     let mut in_comment = false;
     let mut code_in_line;
 
-    // Skip the surrounding function decl.
-    let start_brace_idx = code_snippet.find('{').map_or(0, |i| i + 1);
-    let end_brace_idx = code_snippet.rfind('}').unwrap_or_else(|| code_snippet.len());
-    let function_lines = code_snippet[start_brace_idx..end_brace_idx].lines();
+    let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..))
+        && code_snippet.as_bytes().first().copied() == Some(b'{')
+        && code_snippet.as_bytes().last().copied() == Some(b'}')
+    {
+        // Removing the braces from the enclosing block
+        &code_snippet[1..code_snippet.len() - 1]
+    } else {
+        &code_snippet
+    }
+    .trim() // Remove leading and trailing blank lines
+    .lines();
 
     for mut line in function_lines {
         code_in_line = false;
@@ -63,6 +73,6 @@ pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<'
                 "this function has too many lines ({}/{})",
                 line_count, too_many_lines_threshold
             ),
-        )
+        );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 04730ace887..515b8887453 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
                                         ));
                                     }
                                 }
-                            })
+                            });
                         },
                     );
                 }
diff --git a/src/tools/clippy/clippy_lints/src/identity_op.rs b/src/tools/clippy/clippy_lints/src/identity_op.rs
index 366b3b46a8a..99c461930e4 100644
--- a/src/tools/clippy/clippy_lints/src/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/identity_op.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{clip, unsext};
 
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index 30174fa2100..f2f830ca5c0 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -67,7 +67,7 @@ fn lint_break(cx: &LateContext<'_>, break_span: Span, expr_span: Span) {
         "change `break` to `return` as shown",
         format!("return {}", snip),
         app,
-    )
+    );
 }
 
 #[derive(Clone, Copy, PartialEq, Eq)]
@@ -147,7 +147,11 @@ fn lint_implicit_returns(
             visit_break_exprs(block, |break_expr, dest, sub_expr| {
                 if dest.target_id.ok() == Some(expr.hir_id) {
                     if call_site_span.is_none() && break_expr.span.ctxt() == ctxt {
-                        lint_break(cx, break_expr.span, sub_expr.unwrap().span);
+                        // At this point sub_expr can be `None` in async functions which either diverge, or return the
+                        // unit type.
+                        if let Some(sub_expr) = sub_expr {
+                            lint_break(cx, break_expr.span, sub_expr.span);
+                        }
                     } else {
                         // the break expression is from a macro call, add a return to the loop
                         add_return = true;
diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
index d138c3a8acf..3b635071f28 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -58,7 +58,7 @@ declare_clippy_lint! {
     /// Foo { x, y };
     /// ```
     pub INCONSISTENT_STRUCT_CONSTRUCTOR,
-    style,
+    pedantic,
     "the order of the field init shorthand is inconsistent with the order in the struct definition"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 1c54599abc4..bfa284f333a 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -1,6 +1,6 @@
 //! lint on indexing and slicing operations
 
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::higher;
 use rustc_ast::ast::RangeLimits;
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index afee20ce43e..6b887da2630 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter {
                 return;
             },
         };
-        span_lint(cx, lint, expr.span, msg)
+        span_lint(cx, lint, expr.span, msg);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index 4e0b1ae78df..ee41c4aea2f 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -1,12 +1,13 @@
 //! lint on inherent implementations
 
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::in_macro;
-use rustc_hir::def_id::DefIdMap;
-use rustc_hir::{Crate, Impl, Item, ItemKind};
+use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::{in_macro, is_allowed};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::{def_id::LocalDefId, Crate, Item, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
+use std::collections::hash_map::Entry;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for multiple inherent implementations of a struct
@@ -40,51 +41,96 @@ declare_clippy_lint! {
     "Multiple inherent impl that could be grouped"
 }
 
-#[allow(clippy::module_name_repetitions)]
-#[derive(Default)]
-pub struct MultipleInherentImpl {
-    impls: DefIdMap<Span>,
-}
-
-impl_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
+declare_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]);
 
 impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl {
-    fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let ItemKind::Impl(Impl {
-            ref generics,
-            of_trait: None,
-            ..
-        }) = item.kind
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Crate<'_>) {
+        // Map from a type to it's first impl block. Needed to distinguish generic arguments.
+        // e.g. `Foo<Bar>` and `Foo<Baz>`
+        let mut type_map = FxHashMap::default();
+        // List of spans to lint. (lint_span, first_span)
+        let mut lint_spans = Vec::new();
+
+        for (_, impl_ids) in cx
+            .tcx
+            .crate_inherent_impls(())
+            .inherent_impls
+            .iter()
+            .filter(|(&id, impls)| {
+                impls.len() > 1
+                    // Check for `#[allow]` on the type definition
+                    && !is_allowed(
+                        cx,
+                        MULTIPLE_INHERENT_IMPL,
+                        cx.tcx.hir().local_def_id_to_hir_id(id),
+                    )
+            })
         {
-            // Remember for each inherent implementation encountered its span and generics
-            // but filter out implementations that have generic params (type or lifetime)
-            // or are derived from a macro
-            if !in_macro(item.span) && generics.params.is_empty() {
-                self.impls.insert(item.def_id.to_def_id(), item.span);
+            for impl_id in impl_ids.iter().map(|id| id.expect_local()) {
+                match type_map.entry(cx.tcx.type_of(impl_id)) {
+                    Entry::Vacant(e) => {
+                        // Store the id for the first impl block of this type. The span is retrieved lazily.
+                        e.insert(IdOrSpan::Id(impl_id));
+                    },
+                    Entry::Occupied(mut e) => {
+                        if let Some(span) = get_impl_span(cx, impl_id) {
+                            let first_span = match *e.get() {
+                                IdOrSpan::Span(s) => s,
+                                IdOrSpan::Id(id) => {
+                                    if let Some(s) = get_impl_span(cx, id) {
+                                        // Remember the span of the first block.
+                                        *e.get_mut() = IdOrSpan::Span(s);
+                                        s
+                                    } else {
+                                        // The first impl block isn't considered by the lint. Replace it with the
+                                        // current one.
+                                        *e.get_mut() = IdOrSpan::Span(span);
+                                        continue;
+                                    }
+                                },
+                            };
+                            lint_spans.push((span, first_span));
+                        }
+                    },
+                }
             }
+
+            // Switching to the next type definition, no need to keep the current entries around.
+            type_map.clear();
         }
-    }
 
-    fn check_crate_post(&mut self, cx: &LateContext<'tcx>, krate: &'tcx Crate<'_>) {
-        if !krate.items.is_empty() {
-            // Retrieve all inherent implementations from the crate, grouped by type
-            for impls in cx.tcx.crate_inherent_impls(()).inherent_impls.values() {
-                // Filter out implementations that have generic params (type or lifetime)
-                let mut impl_spans = impls.iter().filter_map(|impl_def| self.impls.get(impl_def));
-                if let Some(initial_span) = impl_spans.next() {
-                    impl_spans.for_each(|additional_span| {
-                        span_lint_and_then(
-                            cx,
-                            MULTIPLE_INHERENT_IMPL,
-                            *additional_span,
-                            "multiple implementations of this structure",
-                            |diag| {
-                                diag.span_note(*initial_span, "first implementation here");
-                            },
-                        )
-                    })
-                }
-            }
+        // `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first.
+        lint_spans.sort_by_key(|x| x.0.lo());
+        for (span, first_span) in lint_spans {
+            span_lint_and_note(
+                cx,
+                MULTIPLE_INHERENT_IMPL,
+                span,
+                "multiple implementations of this structure",
+                Some(first_span),
+                "first implementation here",
+            );
         }
     }
 }
+
+/// Gets the span for the given impl block unless it's not being considered by the lint.
+fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> {
+    let id = cx.tcx.hir().local_def_id_to_hir_id(id);
+    if let Node::Item(&Item {
+        kind: ItemKind::Impl(ref impl_item),
+        span,
+        ..
+    }) = cx.tcx.hir().get(id)
+    {
+        (!in_macro(span) && impl_item.generics.params.is_empty() && !is_allowed(cx, MULTIPLE_INHERENT_IMPL, id))
+            .then(|| span)
+    } else {
+        None
+    }
+}
+
+enum IdOrSpan {
+    Id(LocalDefId),
+    Span(Span),
+}
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index c67c02eefa5..37011f5578d 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -7,9 +7,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 use rustc_target::abi::LayoutOf;
 
-use crate::consts::{constant, Constant};
-
 use clippy_utils::comparisons::Rel;
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::source::snippet;
 use clippy_utils::{comparisons, sext};
@@ -177,7 +176,7 @@ fn upcast_comparison_bounds_err<'tcx>(
                 },
                 Rel::Eq | Rel::Ne => unreachable!(),
             } {
-                err_upcast_comparison(cx, span, lhs, true)
+                err_upcast_comparison(cx, span, lhs, true);
             } else if match rel {
                 Rel::Lt => {
                     if invert {
@@ -195,7 +194,7 @@ fn upcast_comparison_bounds_err<'tcx>(
                 },
                 Rel::Eq | Rel::Ne => unreachable!(),
             } {
-                err_upcast_comparison(cx, span, lhs, false)
+                err_upcast_comparison(cx, span, lhs, false);
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index bb57adff7be..583514b22f9 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -380,9 +380,9 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
             }
         }
 
-        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to)
+        check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to);
     } else {
-        check_empty_expr(cx, span, method, lit, op)
+        check_empty_expr(cx, span, method, lit, op);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 17e23781db7..e627b1385bc 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                         None,
                         "consider using an underscore-prefixed named \
                             binding or dropping explicitly with `std::mem::drop`"
-                    )
+                    );
                 } else if init_ty.needs_drop(cx.tcx, cx.param_env) {
                     span_lint_and_help(
                         cx,
@@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                         None,
                         "consider using an underscore-prefixed named \
                             binding or dropping explicitly with `std::mem::drop`"
-                    )
+                    );
                 } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
                     span_lint_and_help(
                         cx,
@@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                         "non-binding let on an expression with `#[must_use]` type",
                         None,
                         "consider explicitly using expression value"
-                    )
+                    );
                 } else if is_must_use_func_call(cx, init) {
                     span_lint_and_help(
                         cx,
@@ -163,7 +163,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
                         "non-binding let on a result of a `#[must_use]` function",
                         None,
                         "consider explicitly using function result"
-                    )
+                    );
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 725aa54157e..e7dd3952b3a 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -6,7 +6,6 @@
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
 #![feature(once_cell)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
 #![feature(control_flow_enum)]
@@ -42,6 +41,9 @@ extern crate rustc_target;
 extern crate rustc_trait_selection;
 extern crate rustc_typeck;
 
+#[macro_use]
+extern crate clippy_utils;
+
 use clippy_utils::parse_msrv;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_lint::LintId;
@@ -146,22 +148,8 @@ macro_rules! declare_clippy_lint {
     };
 }
 
-#[macro_export]
-macro_rules! sym {
-    ( $($x:tt)* ) => { clippy_utils::sym!($($x)*) }
-}
-
-#[macro_export]
-macro_rules! unwrap_cargo_metadata {
-    ( $($x:tt)* ) => { clippy_utils::unwrap_cargo_metadata!($($x)*) }
-}
-
-macro_rules! extract_msrv_attr {
-    ( $($x:tt)* ) => { clippy_utils::extract_msrv_attr!($($x)*); }
-}
-
-mod consts;
-#[macro_use]
+#[cfg(feature = "metadata-collector-lint")]
+mod deprecated_lints;
 mod utils;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
@@ -289,6 +277,7 @@ mod mut_reference;
 mod mutable_debug_assertion;
 mod mutex_atomic;
 mod needless_arbitrary_self_type;
+mod needless_bitwise_bool;
 mod needless_bool;
 mod needless_borrow;
 mod needless_borrowed_ref;
@@ -363,6 +352,7 @@ mod unnecessary_sort_by;
 mod unnecessary_wraps;
 mod unnested_or_patterns;
 mod unsafe_removed_from_name;
+mod unused_async;
 mod unused_io_amount;
 mod unused_self;
 mod unused_unit;
@@ -402,7 +392,6 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) {
 
 #[doc(hidden)]
 pub fn read_conf(sess: &Session) -> Conf {
-    use std::path::Path;
     let file_name = match utils::conf::lookup_conf_file() {
         Ok(Some(path)) => path,
         Ok(None) => return Conf::default(),
@@ -413,16 +402,6 @@ pub fn read_conf(sess: &Session) -> Conf {
         },
     };
 
-    let file_name = if file_name.is_relative() {
-        sess.local_crate_source_file
-            .as_deref()
-            .and_then(Path::parent)
-            .unwrap_or_else(|| Path::new(""))
-            .join(file_name)
-    } else {
-        file_name
-    };
-
     let TryConf { conf, errors } = utils::conf::read(&file_name);
     // all conf errors are non-fatal, we just use the default conf in case of error
     for error in errors {
@@ -502,6 +481,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         "clippy::filter_map",
         "this lint has been replaced by `manual_filter_map`, a more specific lint",
     );
+    store.register_removed(
+        "clippy::pub_enum_variant_names",
+        "set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items",
+    );
+    store.register_removed(
+        "clippy::wrong_pub_self_convention",
+        "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items",
+    );
     // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 
     // begin register lints, do not remove this comment, it’s used in `update_lints`
@@ -615,7 +602,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         enum_variants::ENUM_VARIANT_NAMES,
         enum_variants::MODULE_INCEPTION,
         enum_variants::MODULE_NAME_REPETITIONS,
-        enum_variants::PUB_ENUM_VARIANT_NAMES,
         eq_op::EQ_OP,
         eq_op::OP_REF,
         erasing_op::ERASING_OP,
@@ -776,6 +762,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         methods::MANUAL_FILTER_MAP,
         methods::MANUAL_FIND_MAP,
         methods::MANUAL_SATURATING_ARITHMETIC,
+        methods::MANUAL_STR_REPEAT,
         methods::MAP_COLLECT_RESULT_UNIT,
         methods::MAP_FLATTEN,
         methods::MAP_UNWRAP_OR,
@@ -793,13 +780,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         methods::SKIP_WHILE_NEXT,
         methods::STRING_EXTEND_CHARS,
         methods::SUSPICIOUS_MAP,
+        methods::SUSPICIOUS_SPLITN,
         methods::UNINIT_ASSUMED_INIT,
         methods::UNNECESSARY_FILTER_MAP,
         methods::UNNECESSARY_FOLD,
         methods::UNNECESSARY_LAZY_EVALUATIONS,
         methods::UNWRAP_USED,
         methods::USELESS_ASREF,
-        methods::WRONG_PUB_SELF_CONVENTION,
         methods::WRONG_SELF_CONVENTION,
         methods::ZST_OFFSET,
         minmax::MIN_MAX,
@@ -834,9 +821,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         mutex_atomic::MUTEX_ATOMIC,
         mutex_atomic::MUTEX_INTEGER,
         needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE,
+        needless_bitwise_bool::NEEDLESS_BITWISE_BOOL,
         needless_bool::BOOL_COMPARISON,
         needless_bool::NEEDLESS_BOOL,
         needless_borrow::NEEDLESS_BORROW,
+        needless_borrow::REF_BINDING_TO_REFERENCE,
         needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE,
         needless_continue::NEEDLESS_CONTINUE,
         needless_for_each::NEEDLESS_FOR_EACH,
@@ -960,6 +949,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         unnecessary_wraps::UNNECESSARY_WRAPS,
         unnested_or_patterns::UNNESTED_OR_PATTERNS,
         unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME,
+        unused_async::UNUSED_ASYNC,
         unused_io_amount::UNUSED_IO_AMOUNT,
         unused_self::UNUSED_SELF,
         unused_unit::UNUSED_UNIT,
@@ -990,289 +980,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     ]);
     // end register lints, do not remove this comment, it’s used in `update_lints`
 
-    // all the internal lints
-    #[cfg(feature = "internal-lints")]
-    {
-        store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
-        store.register_early_pass(|| box utils::internal_lints::ProduceIce);
-        store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
-        store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
-        store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
-        store.register_late_pass(|| box utils::internal_lints::IfChainStyle);
-        store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
-        store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
-        store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
-        store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
-        store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
-    }
-    #[cfg(feature = "metadata-collector-lint")]
-    {
-        if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
-            store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::default());
-        }
-    }
-
-    store.register_late_pass(|| box utils::author::Author);
-    store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
-    store.register_late_pass(|| box serde_api::SerdeApi);
-    let vec_box_size_threshold = conf.vec_box_size_threshold;
-    let type_complexity_threshold = conf.type_complexity_threshold;
-    store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
-    store.register_late_pass(|| box booleans::NonminimalBool);
-    store.register_late_pass(|| box eq_op::EqOp);
-    store.register_late_pass(|| box enum_clike::UnportableVariant);
-    store.register_late_pass(|| box float_literal::FloatLiteral);
-    let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
-    store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
-    store.register_late_pass(|| box ptr::Ptr);
-    store.register_late_pass(|| box ptr_eq::PtrEq);
-    store.register_late_pass(|| box needless_bool::NeedlessBool);
-    store.register_late_pass(|| box needless_bool::BoolComparison);
-    store.register_late_pass(|| box needless_for_each::NeedlessForEach);
-    store.register_late_pass(|| box approx_const::ApproxConstant);
-    store.register_late_pass(|| box misc::MiscLints);
-    store.register_late_pass(|| box eta_reduction::EtaReduction);
-    store.register_late_pass(|| box identity_op::IdentityOp);
-    store.register_late_pass(|| box erasing_op::ErasingOp);
-    store.register_late_pass(|| box mut_mut::MutMut);
-    store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed);
-    store.register_late_pass(|| box len_zero::LenZero);
-    store.register_late_pass(|| box attrs::Attributes);
-    store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
-    store.register_late_pass(|| box collapsible_match::CollapsibleMatch);
-    store.register_late_pass(|| box unicode::Unicode);
-    store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
-    store.register_late_pass(|| box strings::StringAdd);
-    store.register_late_pass(|| box implicit_return::ImplicitReturn);
-    store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
-    store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
-    store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
-    store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
-    store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports);
-
-    let msrv = conf.msrv.as_ref().and_then(|s| {
-        parse_msrv(s, None, None).or_else(|| {
-            sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
-            None
-        })
-    });
-
-    store.register_late_pass(move || box methods::Methods::new(msrv));
-    store.register_late_pass(move || box matches::Matches::new(msrv));
-    store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv));
-    store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv));
-    store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv));
-    store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv));
-    store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
-    store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
-    store.register_late_pass(move || box ranges::Ranges::new(msrv));
-    store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
-    store.register_late_pass(move || box use_self::UseSelf::new(msrv));
-    store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
-    store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark);
-    store.register_late_pass(move || box casts::Casts::new(msrv));
-    store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
-
-    store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
-    store.register_late_pass(|| box map_clone::MapClone);
-    store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
-    store.register_late_pass(|| box shadow::Shadow);
-    store.register_late_pass(|| box unit_types::UnitTypes);
-    store.register_late_pass(|| box loops::Loops);
-    store.register_late_pass(|| box main_recursion::MainRecursion::default());
-    store.register_late_pass(|| box lifetimes::Lifetimes);
-    store.register_late_pass(|| box entry::HashMapPass);
-    store.register_late_pass(|| box minmax::MinMaxPass);
-    store.register_late_pass(|| box open_options::OpenOptions);
-    store.register_late_pass(|| box zero_div_zero::ZeroDiv);
-    store.register_late_pass(|| box mutex_atomic::Mutex);
-    store.register_late_pass(|| box needless_update::NeedlessUpdate);
-    store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default());
-    store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef);
-    store.register_late_pass(|| box no_effect::NoEffect);
-    store.register_late_pass(|| box temporary_assignment::TemporaryAssignment);
-    store.register_late_pass(|| box transmute::Transmute);
-    let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
-    store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
-    let too_large_for_stack = conf.too_large_for_stack;
-    store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
-    store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
-    store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
-    store.register_late_pass(|| box strings::StringLitAsBytes);
-    store.register_late_pass(|| box derive::Derive);
-    store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
-    store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
-    store.register_late_pass(|| box empty_enum::EmptyEnum);
-    store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons);
-    store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons);
-    store.register_late_pass(|| box regex::Regex::default());
-    store.register_late_pass(|| box copies::CopyAndPaste);
-    store.register_late_pass(|| box copy_iterator::CopyIterator);
-    store.register_late_pass(|| box format::UselessFormat);
-    store.register_late_pass(|| box swap::Swap);
-    store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional);
-    store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
-    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
-    let too_many_arguments_threshold = conf.too_many_arguments_threshold;
-    let too_many_lines_threshold = conf.too_many_lines_threshold;
-    store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold));
-    let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
-    store.register_late_pass(|| box neg_multiply::NegMultiply);
-    store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
-    store.register_late_pass(|| box mem_forget::MemForget);
-    store.register_late_pass(|| box arithmetic::Arithmetic::default());
-    store.register_late_pass(|| box assign_ops::AssignOps);
-    store.register_late_pass(|| box let_if_seq::LetIfSeq);
-    store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
-    store.register_late_pass(|| box missing_doc::MissingDoc::new());
-    store.register_late_pass(|| box missing_inline::MissingInline);
-    store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
-    store.register_late_pass(|| box if_let_some_result::OkIfLet);
-    store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
-    store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
-    let enum_variant_size_threshold = conf.enum_variant_size_threshold;
-    store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold));
-    store.register_late_pass(|| box explicit_write::ExplicitWrite);
-    store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue);
-    let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
-        conf.trivial_copy_size_limit,
-        conf.pass_by_value_size_limit,
-        &sess.target,
-    );
-    store.register_late_pass(move || box pass_by_ref_or_value);
-    store.register_late_pass(|| box ref_option_ref::RefOptionRef);
-    store.register_late_pass(|| box try_err::TryErr);
-    store.register_late_pass(|| box bytecount::ByteCount);
-    store.register_late_pass(|| box infinite_iter::InfiniteIter);
-    store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
-    store.register_late_pass(|| box useless_conversion::UselessConversion::default());
-    store.register_late_pass(|| box implicit_hasher::ImplicitHasher);
-    store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
-    store.register_late_pass(|| box double_comparison::DoubleComparisons);
-    store.register_late_pass(|| box question_mark::QuestionMark);
-    store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings);
-    store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
-    store.register_late_pass(|| box map_unit_fn::MapUnit);
-    store.register_late_pass(|| box inherent_impl::MultipleInherentImpl::default());
-    store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
-    store.register_late_pass(|| box unwrap::Unwrap);
-    store.register_late_pass(|| box duration_subsec::DurationSubsec);
-    store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
-    store.register_late_pass(|| box non_copy_const::NonCopyConst);
-    store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
-    store.register_late_pass(|| box redundant_clone::RedundantClone);
-    store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
-    store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
-    store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps);
-    store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
-    store.register_late_pass(|| box transmuting_null::TransmutingNull);
-    store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
-    store.register_late_pass(|| box integer_division::IntegerDivision);
-    store.register_late_pass(|| box inherent_to_string::InherentToString);
-    let max_trait_bounds = conf.max_trait_bounds;
-    store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
-    store.register_late_pass(|| box comparison_chain::ComparisonChain);
-    store.register_late_pass(|| box mut_key::MutableKeyType);
-    store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
-    store.register_early_pass(|| box reference::DerefAddrOf);
-    store.register_early_pass(|| box reference::RefInDeref);
-    store.register_early_pass(|| box double_parens::DoubleParens);
-    store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
-    store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
-    store.register_early_pass(|| box if_not_else::IfNotElse);
-    store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
-    store.register_early_pass(|| box int_plus_one::IntPlusOne);
-    store.register_early_pass(|| box formatting::Formatting);
-    store.register_early_pass(|| box misc_early::MiscEarlyLints);
-    store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
-    store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
-    store.register_early_pass(|| box unused_unit::UnusedUnit);
-    store.register_late_pass(|| box returns::Return);
-    store.register_early_pass(|| box collapsible_if::CollapsibleIf);
-    store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
-    store.register_early_pass(|| box precedence::Precedence);
-    store.register_early_pass(|| box needless_continue::NeedlessContinue);
-    store.register_early_pass(|| box redundant_else::RedundantElse);
-    store.register_late_pass(|| box create_dir::CreateDir);
-    store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
-    let cargo_ignore_publish = conf.cargo_ignore_publish;
-    store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish));
-    store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
-    store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
-    let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
-    store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability));
-    let literal_representation_threshold = conf.literal_representation_threshold;
-    store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold));
-    let enum_variant_name_threshold = conf.enum_variant_name_threshold;
-    store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold));
-    store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
-    let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
-    store.register_early_pass(move || box upper_case_acronyms::UpperCaseAcronyms::new(upper_case_acronyms_aggressive));
-    store.register_late_pass(|| box default::Default::default());
-    store.register_late_pass(|| box unused_self::UnusedSelf);
-    store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
-    store.register_late_pass(|| box exit::Exit);
-    store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
-    let array_size_threshold = conf.array_size_threshold;
-    store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
-    store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
-    store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
-    store.register_early_pass(|| box as_conversions::AsConversions);
-    store.register_late_pass(|| box let_underscore::LetUnderscore);
-    store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
-    store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports);
-    let max_fn_params_bools = conf.max_fn_params_bools;
-    let max_struct_bools = conf.max_struct_bools;
-    store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
-    store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
-    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
-    store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
-    store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
-    store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
-    store.register_late_pass(|| box unnamed_address::UnnamedAddress);
-    store.register_late_pass(|| box dereference::Dereferencing::default());
-    store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
-    store.register_late_pass(|| box future_not_send::FutureNotSend);
-    store.register_late_pass(|| box if_let_mutex::IfLetMutex);
-    store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
-    store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
-    store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
-    store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
-    store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
-    let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
-    store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
-        single_char_binding_names_threshold,
-    });
-    store.register_late_pass(|| box macro_use::MacroUseImports::default());
-    store.register_late_pass(|| box map_identity::MapIdentity);
-    store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
-    store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
-    store.register_late_pass(|| box repeat_once::RepeatOnce);
-    store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
-    store.register_late_pass(|| box self_assignment::SelfAssignment);
-    store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
-    store.register_late_pass(|| box manual_ok_or::ManualOkOr);
-    store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
-    store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned);
-    store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
-    let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
-    store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
-    store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
-    store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
-    store.register_late_pass(|| box strings::StrToString);
-    store.register_late_pass(|| box strings::StringToString);
-    store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
-    store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
-    store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
-    store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
-    store.register_late_pass(|| box from_str_radix_10::FromStrRadix10);
-    store.register_late_pass(|| box manual_map::ManualMap);
-    store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
-    store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
-
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(arithmetic::FLOAT_ARITHMETIC),
         LintId::of(arithmetic::INTEGER_ARITHMETIC),
@@ -1303,7 +1010,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(methods::FILETYPE_IS_FILE),
         LintId::of(methods::GET_UNWRAP),
         LintId::of(methods::UNWRAP_USED),
-        LintId::of(methods::WRONG_PUB_SELF_CONVENTION),
         LintId::of(misc::FLOAT_CMP_CONST),
         LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
         LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
@@ -1315,7 +1021,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(panic_unimplemented::UNIMPLEMENTED),
         LintId::of(panic_unimplemented::UNREACHABLE),
         LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH),
-        LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
         LintId::of(shadow::SHADOW_REUSE),
         LintId::of(shadow::SHADOW_SAME),
         LintId::of(strings::STRING_ADD),
@@ -1356,7 +1061,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(doc::MISSING_PANICS_DOC),
         LintId::of(empty_enum::EMPTY_ENUM),
         LintId::of(enum_variants::MODULE_NAME_REPETITIONS),
-        LintId::of(enum_variants::PUB_ENUM_VARIANT_NAMES),
         LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
         LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
         LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
@@ -1365,6 +1069,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(if_not_else::IF_NOT_ELSE),
         LintId::of(implicit_hasher::IMPLICIT_HASHER),
         LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB),
+        LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
         LintId::of(infinite_iter::MAYBE_INFINITE_ITER),
         LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS),
         LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS),
@@ -1392,6 +1097,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(misc::USED_UNDERSCORE_BINDING),
         LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
         LintId::of(mut_mut::MUT_MUT),
+        LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
+        LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
         LintId::of(needless_continue::NEEDLESS_CONTINUE),
         LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
         LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
@@ -1403,6 +1110,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(ranges::RANGE_PLUS_ONE),
         LintId::of(redundant_else::REDUNDANT_ELSE),
         LintId::of(ref_option_ref::REF_OPTION_REF),
+        LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
         LintId::of(shadow::SHADOW_UNRELATED),
         LintId::of(strings::STRING_ADD_ASSIGN),
         LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
@@ -1415,6 +1123,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(unit_types::LET_UNIT_VALUE),
         LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
         LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS),
+        LintId::of(unused_async::UNUSED_ASYNC),
         LintId::of(unused_self::UNUSED_SELF),
         LintId::of(wildcard_imports::ENUM_GLOB_USE),
         LintId::of(wildcard_imports::WILDCARD_IMPORTS),
@@ -1511,7 +1220,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(identity_op::IDENTITY_OP),
         LintId::of(if_let_mutex::IF_LET_MUTEX),
         LintId::of(if_let_some_result::IF_LET_SOME_RESULT),
-        LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
         LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
         LintId::of(infinite_iter::INFINITE_ITER),
         LintId::of(inherent_to_string::INHERENT_TO_STRING),
@@ -1591,6 +1299,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(methods::MANUAL_FILTER_MAP),
         LintId::of(methods::MANUAL_FIND_MAP),
         LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
+        LintId::of(methods::MANUAL_STR_REPEAT),
         LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
         LintId::of(methods::NEW_RET_NO_SELF),
         LintId::of(methods::OK_EXPECT),
@@ -1606,6 +1315,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(methods::SKIP_WHILE_NEXT),
         LintId::of(methods::STRING_EXTEND_CHARS),
         LintId::of(methods::SUSPICIOUS_MAP),
+        LintId::of(methods::SUSPICIOUS_SPLITN),
         LintId::of(methods::UNINIT_ASSUMED_INIT),
         LintId::of(methods::UNNECESSARY_FILTER_MAP),
         LintId::of(methods::UNNECESSARY_FOLD),
@@ -1635,6 +1345,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
         LintId::of(needless_bool::BOOL_COMPARISON),
         LintId::of(needless_bool::NEEDLESS_BOOL),
+        LintId::of(needless_borrow::NEEDLESS_BORROW),
         LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE),
         LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK),
         LintId::of(needless_update::NEEDLESS_UPDATE),
@@ -1681,7 +1392,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
         LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
         LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
-        LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
         LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
         LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
         LintId::of(swap::ALMOST_SWAPPED),
@@ -1764,7 +1474,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(functions::MUST_USE_UNIT),
         LintId::of(functions::RESULT_UNIT_ERR),
         LintId::of(if_let_some_result::IF_LET_SOME_RESULT),
-        LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR),
         LintId::of(inherent_to_string::INHERENT_TO_STRING),
         LintId::of(len_zero::COMPARISON_TO_EMPTY),
         LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
@@ -1819,6 +1528,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(misc_early::REDUNDANT_PATTERN),
         LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
         LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
+        LintId::of(needless_borrow::NEEDLESS_BORROW),
         LintId::of(neg_multiply::NEG_MULTIPLY),
         LintId::of(new_without_default::NEW_WITHOUT_DEFAULT),
         LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST),
@@ -1835,7 +1545,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(returns::LET_AND_RETURN),
         LintId::of(returns::NEEDLESS_RETURN),
         LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS),
-        LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
         LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS),
         LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME),
         LintId::of(try_err::TRY_ERR),
@@ -1983,6 +1692,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
         LintId::of(methods::CLONE_DOUBLE_REF),
         LintId::of(methods::ITERATOR_STEP_BY_ZERO),
+        LintId::of(methods::SUSPICIOUS_SPLITN),
         LintId::of(methods::UNINIT_ASSUMED_INIT),
         LintId::of(methods::ZST_OFFSET),
         LintId::of(minmax::MIN_MAX),
@@ -2027,6 +1737,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(loops::NEEDLESS_COLLECT),
         LintId::of(methods::EXPECT_FUN_CALL),
         LintId::of(methods::ITER_NTH),
+        LintId::of(methods::MANUAL_STR_REPEAT),
         LintId::of(methods::OR_FUN_CALL),
         LintId::of(methods::SINGLE_CHAR_PATTERN),
         LintId::of(misc::CMP_OWNED),
@@ -2058,14 +1769,304 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
         LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
         LintId::of(mutex_atomic::MUTEX_INTEGER),
-        LintId::of(needless_borrow::NEEDLESS_BORROW),
         LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
         LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE),
         LintId::of(regex::TRIVIAL_REGEX),
         LintId::of(strings::STRING_LIT_AS_BYTES),
+        LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
         LintId::of(transmute::USELESS_TRANSMUTE),
         LintId::of(use_self::USE_SELF),
     ]);
+
+    #[cfg(feature = "metadata-collector-lint")]
+    {
+        if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
+            store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::new());
+            return;
+        }
+    }
+
+    // all the internal lints
+    #[cfg(feature = "internal-lints")]
+    {
+        store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal);
+        store.register_early_pass(|| box utils::internal_lints::ProduceIce);
+        store.register_late_pass(|| box utils::inspector::DeepCodeInspector);
+        store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
+        store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
+        store.register_late_pass(|| box utils::internal_lints::IfChainStyle);
+        store.register_late_pass(|| box utils::internal_lints::InvalidPaths);
+        store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default());
+        store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default());
+        store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
+        store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass);
+    }
+
+    store.register_late_pass(|| box utils::author::Author);
+    store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
+    store.register_late_pass(|| box serde_api::SerdeApi);
+    let vec_box_size_threshold = conf.vec_box_size_threshold;
+    let type_complexity_threshold = conf.type_complexity_threshold;
+    store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold));
+    store.register_late_pass(|| box booleans::NonminimalBool);
+    store.register_late_pass(|| box needless_bitwise_bool::NeedlessBitwiseBool);
+    store.register_late_pass(|| box eq_op::EqOp);
+    store.register_late_pass(|| box enum_clike::UnportableVariant);
+    store.register_late_pass(|| box float_literal::FloatLiteral);
+    let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
+    store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
+    store.register_late_pass(|| box ptr::Ptr);
+    store.register_late_pass(|| box ptr_eq::PtrEq);
+    store.register_late_pass(|| box needless_bool::NeedlessBool);
+    store.register_late_pass(|| box needless_bool::BoolComparison);
+    store.register_late_pass(|| box needless_for_each::NeedlessForEach);
+    store.register_late_pass(|| box approx_const::ApproxConstant);
+    store.register_late_pass(|| box misc::MiscLints);
+    store.register_late_pass(|| box eta_reduction::EtaReduction);
+    store.register_late_pass(|| box identity_op::IdentityOp);
+    store.register_late_pass(|| box erasing_op::ErasingOp);
+    store.register_late_pass(|| box mut_mut::MutMut);
+    store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed);
+    store.register_late_pass(|| box len_zero::LenZero);
+    store.register_late_pass(|| box attrs::Attributes);
+    store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
+    store.register_late_pass(|| box collapsible_match::CollapsibleMatch);
+    store.register_late_pass(|| box unicode::Unicode);
+    store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
+    store.register_late_pass(|| box strings::StringAdd);
+    store.register_late_pass(|| box implicit_return::ImplicitReturn);
+    store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
+    store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback);
+    store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor);
+    store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions);
+    store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports);
+
+    let msrv = conf.msrv.as_ref().and_then(|s| {
+        parse_msrv(s, None, None).or_else(|| {
+            sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
+            None
+        })
+    });
+
+    let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
+    store.register_late_pass(move || box methods::Methods::new(avoid_breaking_exported_api, msrv));
+    store.register_late_pass(move || box matches::Matches::new(msrv));
+    store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv));
+    store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv));
+    store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv));
+    store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv));
+    store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv));
+    store.register_late_pass(move || box mem_replace::MemReplace::new(msrv));
+    store.register_late_pass(move || box ranges::Ranges::new(msrv));
+    store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv));
+    store.register_late_pass(move || box use_self::UseSelf::new(msrv));
+    store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv));
+    store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark);
+    store.register_late_pass(move || box casts::Casts::new(msrv));
+    store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv));
+
+    store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount);
+    store.register_late_pass(|| box map_clone::MapClone);
+    store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
+    store.register_late_pass(|| box shadow::Shadow);
+    store.register_late_pass(|| box unit_types::UnitTypes);
+    store.register_late_pass(|| box loops::Loops);
+    store.register_late_pass(|| box main_recursion::MainRecursion::default());
+    store.register_late_pass(|| box lifetimes::Lifetimes);
+    store.register_late_pass(|| box entry::HashMapPass);
+    store.register_late_pass(|| box minmax::MinMaxPass);
+    store.register_late_pass(|| box open_options::OpenOptions);
+    store.register_late_pass(|| box zero_div_zero::ZeroDiv);
+    store.register_late_pass(|| box mutex_atomic::Mutex);
+    store.register_late_pass(|| box needless_update::NeedlessUpdate);
+    store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default());
+    store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef);
+    store.register_late_pass(|| box no_effect::NoEffect);
+    store.register_late_pass(|| box temporary_assignment::TemporaryAssignment);
+    store.register_late_pass(|| box transmute::Transmute);
+    let cognitive_complexity_threshold = conf.cognitive_complexity_threshold;
+    store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold));
+    let too_large_for_stack = conf.too_large_for_stack;
+    store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack});
+    store.register_late_pass(move || box vec::UselessVec{too_large_for_stack});
+    store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented);
+    store.register_late_pass(|| box strings::StringLitAsBytes);
+    store.register_late_pass(|| box derive::Derive);
+    store.register_late_pass(|| box get_last_with_len::GetLastWithLen);
+    store.register_late_pass(|| box drop_forget_ref::DropForgetRef);
+    store.register_late_pass(|| box empty_enum::EmptyEnum);
+    store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons);
+    store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons);
+    store.register_late_pass(|| box regex::Regex::default());
+    store.register_late_pass(|| box copies::CopyAndPaste);
+    store.register_late_pass(|| box copy_iterator::CopyIterator);
+    store.register_late_pass(|| box format::UselessFormat);
+    store.register_late_pass(|| box swap::Swap);
+    store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional);
+    store.register_late_pass(|| box new_without_default::NewWithoutDefault::default());
+    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_names.clone()));
+    let too_many_arguments_threshold = conf.too_many_arguments_threshold;
+    let too_many_lines_threshold = conf.too_many_lines_threshold;
+    store.register_late_pass(move || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold));
+    let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone()));
+    store.register_late_pass(|| box neg_multiply::NegMultiply);
+    store.register_late_pass(|| box mem_discriminant::MemDiscriminant);
+    store.register_late_pass(|| box mem_forget::MemForget);
+    store.register_late_pass(|| box arithmetic::Arithmetic::default());
+    store.register_late_pass(|| box assign_ops::AssignOps);
+    store.register_late_pass(|| box let_if_seq::LetIfSeq);
+    store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence);
+    store.register_late_pass(|| box missing_doc::MissingDoc::new());
+    store.register_late_pass(|| box missing_inline::MissingInline);
+    store.register_late_pass(move || box exhaustive_items::ExhaustiveItems);
+    store.register_late_pass(|| box if_let_some_result::OkIfLet);
+    store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl);
+    store.register_late_pass(|| box unused_io_amount::UnusedIoAmount);
+    let enum_variant_size_threshold = conf.enum_variant_size_threshold;
+    store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold));
+    store.register_late_pass(|| box explicit_write::ExplicitWrite);
+    store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue);
+    let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new(
+        conf.trivial_copy_size_limit,
+        conf.pass_by_value_size_limit,
+        conf.avoid_breaking_exported_api,
+        &sess.target,
+    );
+    store.register_late_pass(move || box pass_by_ref_or_value);
+    store.register_late_pass(|| box ref_option_ref::RefOptionRef);
+    store.register_late_pass(|| box try_err::TryErr);
+    store.register_late_pass(|| box bytecount::ByteCount);
+    store.register_late_pass(|| box infinite_iter::InfiniteIter);
+    store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody);
+    store.register_late_pass(|| box useless_conversion::UselessConversion::default());
+    store.register_late_pass(|| box implicit_hasher::ImplicitHasher);
+    store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom);
+    store.register_late_pass(|| box double_comparison::DoubleComparisons);
+    store.register_late_pass(|| box question_mark::QuestionMark);
+    store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings);
+    store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl);
+    store.register_late_pass(|| box map_unit_fn::MapUnit);
+    store.register_late_pass(|| box inherent_impl::MultipleInherentImpl);
+    store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd);
+    store.register_late_pass(|| box unwrap::Unwrap);
+    store.register_late_pass(|| box duration_subsec::DurationSubsec);
+    store.register_late_pass(|| box indexing_slicing::IndexingSlicing);
+    store.register_late_pass(|| box non_copy_const::NonCopyConst);
+    store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast);
+    store.register_late_pass(|| box redundant_clone::RedundantClone);
+    store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit);
+    store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy);
+    store.register_late_pass(move || box unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api));
+    store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants);
+    store.register_late_pass(|| box transmuting_null::TransmutingNull);
+    store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite);
+    store.register_late_pass(|| box integer_division::IntegerDivision);
+    store.register_late_pass(|| box inherent_to_string::InherentToString);
+    let max_trait_bounds = conf.max_trait_bounds;
+    store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds));
+    store.register_late_pass(|| box comparison_chain::ComparisonChain);
+    store.register_late_pass(|| box mut_key::MutableKeyType);
+    store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic);
+    store.register_early_pass(|| box reference::DerefAddrOf);
+    store.register_early_pass(|| box reference::RefInDeref);
+    store.register_early_pass(|| box double_parens::DoubleParens);
+    store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new());
+    store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval);
+    store.register_early_pass(|| box if_not_else::IfNotElse);
+    store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse);
+    store.register_early_pass(|| box int_plus_one::IntPlusOne);
+    store.register_early_pass(|| box formatting::Formatting);
+    store.register_early_pass(|| box misc_early::MiscEarlyLints);
+    store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
+    store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
+    store.register_early_pass(|| box unused_unit::UnusedUnit);
+    store.register_late_pass(|| box returns::Return);
+    store.register_early_pass(|| box collapsible_if::CollapsibleIf);
+    store.register_early_pass(|| box items_after_statements::ItemsAfterStatements);
+    store.register_early_pass(|| box precedence::Precedence);
+    store.register_early_pass(|| box needless_continue::NeedlessContinue);
+    store.register_early_pass(|| box redundant_else::RedundantElse);
+    store.register_late_pass(|| box create_dir::CreateDir);
+    store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType);
+    let cargo_ignore_publish = conf.cargo_ignore_publish;
+    store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish));
+    store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions);
+    store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies);
+    let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions;
+    store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability));
+    let literal_representation_threshold = conf.literal_representation_threshold;
+    store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold));
+    let enum_variant_name_threshold = conf.enum_variant_name_threshold;
+    store.register_late_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold, avoid_breaking_exported_api));
+    store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments);
+    let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive;
+    store.register_late_pass(move || box upper_case_acronyms::UpperCaseAcronyms::new(avoid_breaking_exported_api, upper_case_acronyms_aggressive));
+    store.register_late_pass(|| box default::Default::default());
+    store.register_late_pass(|| box unused_self::UnusedSelf);
+    store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall);
+    store.register_late_pass(|| box exit::Exit);
+    store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome);
+    let array_size_threshold = conf.array_size_threshold;
+    store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold));
+    store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold));
+    store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic);
+    store.register_early_pass(|| box as_conversions::AsConversions);
+    store.register_late_pass(|| box let_underscore::LetUnderscore);
+    store.register_late_pass(|| box atomic_ordering::AtomicOrdering);
+    store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports);
+    let max_fn_params_bools = conf.max_fn_params_bools;
+    let max_struct_bools = conf.max_struct_bools;
+    store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
+    store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
+    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
+    store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
+    store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
+    store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
+    store.register_late_pass(|| box unnamed_address::UnnamedAddress);
+    store.register_late_pass(|| box dereference::Dereferencing::default());
+    store.register_late_pass(|| box option_if_let_else::OptionIfLetElse);
+    store.register_late_pass(|| box future_not_send::FutureNotSend);
+    store.register_late_pass(|| box if_let_mutex::IfLetMutex);
+    store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
+    store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
+    store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
+    store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
+    store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn);
+    let single_char_binding_names_threshold = conf.single_char_binding_names_threshold;
+    store.register_early_pass(move || box non_expressive_names::NonExpressiveNames {
+        single_char_binding_names_threshold,
+    });
+    store.register_late_pass(|| box macro_use::MacroUseImports::default());
+    store.register_late_pass(|| box map_identity::MapIdentity);
+    store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
+    store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
+    store.register_late_pass(|| box repeat_once::RepeatOnce);
+    store.register_late_pass(|| box unwrap_in_result::UnwrapInResult);
+    store.register_late_pass(|| box self_assignment::SelfAssignment);
+    store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr);
+    store.register_late_pass(|| box manual_ok_or::ManualOkOr);
+    store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs);
+    store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned);
+    store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync);
+    let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
+    store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
+    store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
+    store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
+    store.register_late_pass(|| box strings::StrToString);
+    store.register_late_pass(|| box strings::StringToString);
+    store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues);
+    store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default());
+    store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons);
+    store.register_late_pass(|| box redundant_slicing::RedundantSlicing);
+    store.register_late_pass(|| box from_str_radix_10::FromStrRadix10);
+    store.register_late_pass(|| box manual_map::ManualMap);
+    store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
+    store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
+    store.register_late_pass(|| box unused_async::UnusedAsync);
+
 }
 
 #[rustfmt::skip]
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 116ad072837..5ae68ba5b2f 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -205,7 +205,7 @@ fn could_use_elision<'tcx>(
         output_visitor.visit_ty(ty);
     }
     for lt in named_generics {
-        input_visitor.visit_generic_param(lt)
+        input_visitor.visit_generic_param(lt);
     }
 
     if input_visitor.abort() || output_visitor.abort() {
@@ -463,7 +463,7 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker {
         // `'b` in `'a: 'b` is useless unless used elsewhere in
         // a non-lifetime bound
         if let GenericParamKind::Type { .. } = param.kind {
-            walk_generic_param(self, param)
+            walk_generic_param(self, param);
         }
     }
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index e93b2e36b86..e0c5578bd60 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -231,7 +231,7 @@ impl EarlyLintPass for LiteralDigitGrouping {
         }
 
         if let ExprKind::Lit(ref lit) = expr.kind {
-            self.check_lit(cx, lit)
+            self.check_lit(cx, lit);
         }
     }
 }
@@ -294,7 +294,7 @@ impl LiteralDigitGrouping {
                         }
                     };
                     if should_warn {
-                        warning_type.display(num_lit.format(), cx, lit.span)
+                        warning_type.display(num_lit.format(), cx, lit.span);
                     }
                 }
             }
@@ -424,7 +424,7 @@ impl EarlyLintPass for DecimalLiteralRepresentation {
         }
 
         if let ExprKind::Lit(ref lit) = expr.kind {
-            self.check_lit(cx, lit)
+            self.check_lit(cx, lit);
         }
     }
 }
@@ -446,7 +446,7 @@ impl DecimalLiteralRepresentation {
                 let hex = format!("{:#X}", val);
                 let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
                 let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
-                    warning_type.display(num_lit.format(), cx, lit.span)
+                    warning_type.display(num_lit.format(), cx, lit.span);
                 });
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index ce02ad013be..f0327b5d777 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -43,7 +43,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, m
         "to write this more concisely, try",
         format!("&{}{}", muta, object),
         applicability,
-    )
+    );
 }
 
 /// Returns `true` if the type of expr is one that provides `IntoIterator` impls
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index 1425d50f560..d07b5a93b67 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -88,10 +88,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
         if let ty::BorrowKind::MutBorrow = bk {
             if let PlaceBase::Local(id) = cmt.place.base {
                 if Some(id) == self.hir_id_low {
-                    self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
+                    self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id));
                 }
                 if Some(id) == self.hir_id_high {
-                    self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
+                    self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id));
                 }
             }
         }
@@ -100,10 +100,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> {
     fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
         if let PlaceBase::Local(id) = cmt.place.base {
             if Some(id) == self.hir_id_low {
-                self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id))
+                self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id));
             }
             if Some(id) == self.hir_id_high {
-                self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id))
+                self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id));
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
index 9662a0b22a3..eb82c9c27c3 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
@@ -1,16 +1,15 @@
 use super::NEEDLESS_COLLECT;
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::snippet;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
+use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{is_type_diagnostic_item, match_type};
-use clippy_utils::{is_trait_method, path_to_local_id, paths};
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_trait_method, path_to_local_id};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
 use rustc_hir::{Block, Expr, ExprKind, GenericArg, GenericArgs, HirId, Local, Pat, PatKind, QPath, StmtKind, Ty};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
-
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{MultiSpan, Span};
 
@@ -28,23 +27,37 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
         if let Some(generic_args) = chain_method.args;
         if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
         if let Some(ty) = cx.typeck_results().node_type_opt(ty.hir_id);
-        if is_type_diagnostic_item(cx, ty, sym::vec_type)
-            || is_type_diagnostic_item(cx, ty, sym::vecdeque_type)
-            || match_type(cx, ty, &paths::BTREEMAP)
-            || is_type_diagnostic_item(cx, ty, sym::hashmap_type);
-        if let Some(sugg) = match &*method.ident.name.as_str() {
-            "len" => Some("count()".to_string()),
-            "is_empty" => Some("next().is_none()".to_string()),
-            "contains" => {
-                let contains_arg = snippet(cx, args[1].span, "??");
-                let (arg, pred) = contains_arg
-                    .strip_prefix('&')
-                    .map_or(("&x", &*contains_arg), |s| ("x", s));
-                Some(format!("any(|{}| x == {})", arg, pred))
-            }
-            _ => None,
-        };
         then {
+            let mut applicability = Applicability::MachineApplicable;
+            let is_empty_sugg = "next().is_none()".to_string();
+            let method_name = &*method.ident.name.as_str();
+            let sugg = if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
+                        is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
+                        is_type_diagnostic_item(cx, ty, sym::LinkedList) ||
+                        is_type_diagnostic_item(cx, ty, sym::BinaryHeap) {
+                match method_name {
+                    "len" => "count()".to_string(),
+                    "is_empty" => is_empty_sugg,
+                    "contains" => {
+                        let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability);
+                        let (arg, pred) = contains_arg
+                            .strip_prefix('&')
+                            .map_or(("&x", &*contains_arg), |s| ("x", s));
+                        format!("any(|{}| x == {})", arg, pred)
+                    }
+                    _ => return,
+                }
+            }
+            else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) ||
+                is_type_diagnostic_item(cx, ty, sym::hashmap_type) {
+                match method_name {
+                    "is_empty" => is_empty_sugg,
+                    _ => return,
+                }
+            }
+            else {
+                return;
+            };
             span_lint_and_sugg(
                 cx,
                 NEEDLESS_COLLECT,
@@ -52,7 +65,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
                 NEEDLESS_COLLECT_MSG,
                 "replace with",
                 sugg,
-                Applicability::MachineApplicable,
+                applicability,
             );
         }
     }
@@ -86,7 +99,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
                 if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
                     is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
                     is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
-                    match_type(cx, ty, &paths::LINKED_LIST);
+                    is_type_diagnostic_item(cx, ty, sym::LinkedList);
                 if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
                 if let [iter_call] = &*iter_calls;
                 then {
@@ -103,9 +116,10 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
                     // Suggest replacing iter_call with iter_replacement, and removing stmt
                     let mut span = MultiSpan::from_span(collect_span);
                     span.push_span_label(iter_call.span, "the iterator could be used here instead".into());
-                    span_lint_and_then(
+                    span_lint_hir_and_then(
                         cx,
                         super::NEEDLESS_COLLECT,
+                        init_expr.hir_id,
                         span,
                         NEEDLESS_COLLECT_MSG,
                         |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index cb2c83e9029..0f6cd5de761 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -35,7 +35,7 @@ pub(super) fn check<'tcx>(
                 "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})",
                 item_str, vec_str, item_str
             ),
-        )
+        );
     }
 
     if !matches!(pat.kind, PatKind::Wild) {
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 4db6644b9d7..2f7360210ba 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -80,10 +80,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
                         }
                     },
                     ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => {
-                        *state = IncrementVisitorVarState::DontWarn
+                        *state = IncrementVisitorVarState::DontWarn;
                     },
                     ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
-                        *state = IncrementVisitorVarState::DontWarn
+                        *state = IncrementVisitorVarState::DontWarn;
                     },
                     _ => (),
                 }
@@ -207,7 +207,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
                         }
                     },
                     ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
-                        self.state = InitializeVisitorState::DontWarn
+                        self.state = InitializeVisitorState::DontWarn;
                     },
                     _ => (),
                 }
@@ -292,7 +292,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
                 return;
             }
         }
-        walk_pat(self, pat)
+        walk_pat(self, pat);
     }
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
index 55404b87ec9..5f9ebad25e8 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs
@@ -1,5 +1,5 @@
 use super::WHILE_IMMUTABLE_CONDITION;
-use crate::consts::constant;
+use clippy_utils::consts::constant;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::usage::mutated_variables;
 use if_chain::if_chain;
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
index 82715d9bafa..63560047578 100644
--- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -1,170 +1,347 @@
-use super::utils::{LoopNestVisitor, Nesting};
 use super::WHILE_LET_ON_ITERATOR;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::implements_trait;
-use clippy_utils::usage::mutated_variables;
-use clippy_utils::{
-    get_enclosing_block, is_refutable, is_trait_method, last_path_segment, path_to_local, path_to_local_id,
-};
+use clippy_utils::{get_enclosing_loop, is_refutable, is_trait_method, match_def_path, paths, visitors::is_res_used};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
-use rustc_hir::{Expr, ExprKind, HirId, MatchSource, Node, PatKind};
+use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor};
+use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, MatchSource, Node, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
-use rustc_span::symbol::sym;
+use rustc_span::{symbol::sym, Span, Symbol};
 
 pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    if let ExprKind::Match(match_expr, arms, MatchSource::WhileLetDesugar) = expr.kind {
-        let pat = &arms[0].pat.kind;
-        if let (&PatKind::TupleStruct(ref qpath, pat_args, _), &ExprKind::MethodCall(method_path, _, method_args, _)) =
-            (pat, &match_expr.kind)
-        {
-            let iter_expr = &method_args[0];
-
-            // Don't lint when the iterator is recreated on every iteration
-            if_chain! {
-                if let ExprKind::MethodCall(..) | ExprKind::Call(..) = iter_expr.kind;
-                if let Some(iter_def_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
-                if implements_trait(cx, cx.typeck_results().expr_ty(iter_expr), iter_def_id, &[]);
-                then {
-                    return;
-                }
-            }
+    let (scrutinee_expr, iter_expr, some_pat, loop_expr) = if_chain! {
+        if let ExprKind::Match(scrutinee_expr, [arm, _], MatchSource::WhileLetDesugar) = expr.kind;
+        // check for `Some(..)` pattern
+        if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = arm.pat.kind;
+        if let Res::Def(_, pat_did) = pat_path.res;
+        if match_def_path(cx, pat_did, &paths::OPTION_SOME);
+        // check for call to `Iterator::next`
+        if let ExprKind::MethodCall(method_name, _, [iter_expr], _) = scrutinee_expr.kind;
+        if method_name.ident.name == sym::next;
+        if is_trait_method(cx, scrutinee_expr, sym::Iterator);
+        if let Some(iter_expr) = try_parse_iter_expr(cx, iter_expr);
+        // get the loop containing the match expression
+        if let Some((_, Node::Expr(loop_expr))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1);
+        if !uses_iter(cx, &iter_expr, arm.body);
+        then {
+            (scrutinee_expr, iter_expr, some_pat, loop_expr)
+        } else {
+            return;
+        }
+    };
 
-            let lhs_constructor = last_path_segment(qpath);
-            if method_path.ident.name == sym::next
-                && is_trait_method(cx, match_expr, sym::Iterator)
-                && lhs_constructor.ident.name == sym::Some
-                && (pat_args.is_empty()
-                    || !is_refutable(cx, pat_args[0])
-                        && !is_used_inside(cx, iter_expr, arms[0].body)
-                        && !is_iterator_used_after_while_let(cx, iter_expr)
-                        && !is_nested(cx, expr, &method_args[0]))
-            {
-                let mut applicability = Applicability::MachineApplicable;
-                let iterator = snippet_with_applicability(cx, method_args[0].span, "_", &mut applicability);
-                let loop_var = if pat_args.is_empty() {
-                    "_".to_string()
-                } else {
-                    snippet_with_applicability(cx, pat_args[0].span, "_", &mut applicability).into_owned()
-                };
-                span_lint_and_sugg(
-                    cx,
-                    WHILE_LET_ON_ITERATOR,
-                    expr.span.with_hi(match_expr.span.hi()),
-                    "this loop could be written as a `for` loop",
-                    "try",
-                    format!("for {} in {}", loop_var, iterator),
-                    applicability,
-                );
-            }
+    let mut applicability = Applicability::MachineApplicable;
+    let loop_var = if let Some(some_pat) = some_pat.first() {
+        if is_refutable(cx, some_pat) {
+            // Refutable patterns don't work with for loops.
+            return;
         }
-    }
-}
+        snippet_with_applicability(cx, some_pat.span, "..", &mut applicability)
+    } else {
+        "_".into()
+    };
 
-fn is_used_inside<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, container: &'tcx Expr<'_>) -> bool {
-    let def_id = match path_to_local(expr) {
-        Some(id) => id,
-        None => return false,
+    // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be
+    // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used
+    // afterwards a mutable borrow of a field isn't necessary.
+    let ref_mut = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) {
+        "&mut "
+    } else {
+        ""
     };
-    if let Some(used_mutably) = mutated_variables(container, cx) {
-        if used_mutably.contains(&def_id) {
-            return true;
+
+    let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability);
+    span_lint_and_sugg(
+        cx,
+        WHILE_LET_ON_ITERATOR,
+        expr.span.with_hi(scrutinee_expr.span.hi()),
+        "this loop could be written as a `for` loop",
+        "try",
+        format!("for {} in {}{}", loop_var, ref_mut, iterator),
+        applicability,
+    );
+}
+
+#[derive(Debug)]
+struct IterExpr {
+    /// The span of the whole expression, not just the path and fields stored here.
+    span: Span,
+    /// The fields used, in order of child to parent.
+    fields: Vec<Symbol>,
+    /// The path being used.
+    path: Res,
+}
+/// Parses any expression to find out which field of which variable is used. Will return `None` if
+/// the expression might have side effects.
+fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExpr> {
+    let span = e.span;
+    let mut fields = Vec::new();
+    loop {
+        match e.kind {
+            ExprKind::Path(ref path) => {
+                break Some(IterExpr {
+                    span,
+                    fields,
+                    path: cx.qpath_res(path, e.hir_id),
+                });
+            },
+            ExprKind::Field(base, name) => {
+                fields.push(name.name);
+                e = base;
+            },
+            // Dereferencing a pointer has no side effects and doesn't affect which field is being used.
+            ExprKind::Unary(UnOp::Deref, base) if cx.typeck_results().expr_ty(base).is_ref() => e = base,
+
+            // Shouldn't have side effects, but there's no way to trace which field is used. So forget which fields have
+            // already been seen.
+            ExprKind::Index(base, idx) if !idx.can_have_side_effects() => {
+                fields.clear();
+                e = base;
+            },
+            ExprKind::Unary(UnOp::Deref, base) => {
+                fields.clear();
+                e = base;
+            },
+
+            // No effect and doesn't affect which field is being used.
+            ExprKind::DropTemps(base) | ExprKind::AddrOf(_, _, base) | ExprKind::Type(base, _) => e = base,
+            _ => break None,
         }
     }
-    false
 }
 
-fn is_iterator_used_after_while_let<'tcx>(cx: &LateContext<'tcx>, iter_expr: &'tcx Expr<'_>) -> bool {
-    let def_id = match path_to_local(iter_expr) {
-        Some(id) => id,
-        None => return false,
-    };
-    let mut visitor = VarUsedAfterLoopVisitor {
-        def_id,
-        iter_expr_id: iter_expr.hir_id,
-        past_while_let: false,
-        var_used_after_while_let: false,
-    };
-    if let Some(enclosing_block) = get_enclosing_block(cx, def_id) {
-        walk_block(&mut visitor, enclosing_block);
+fn is_expr_same_field(cx: &LateContext<'_>, mut e: &Expr<'_>, mut fields: &[Symbol], path_res: Res) -> bool {
+    loop {
+        match (&e.kind, fields) {
+            (&ExprKind::Field(base, name), [head_field, tail_fields @ ..]) if name.name == *head_field => {
+                e = base;
+                fields = tail_fields;
+            },
+            (ExprKind::Path(path), []) => {
+                break cx.qpath_res(path, e.hir_id) == path_res;
+            },
+            (&(ExprKind::DropTemps(base) | ExprKind::AddrOf(_, _, base) | ExprKind::Type(base, _)), _) => e = base,
+            _ => break false,
+        }
     }
-    visitor.var_used_after_while_let
 }
 
-fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool {
-    if_chain! {
-        if let Some(loop_block) = get_enclosing_block(cx, match_expr.hir_id);
-        let parent_node = cx.tcx.hir().get_parent_node(loop_block.hir_id);
-        if let Some(Node::Expr(loop_expr)) = cx.tcx.hir().find(parent_node);
-        then {
-            return is_loop_nested(cx, loop_expr, iter_expr)
-        }
+/// Checks if the given expression is the same field as, is a child of, or is the parent of the
+/// given field. Used to check if the expression can be used while the given field is borrowed
+/// mutably. e.g. if checking for `x.y`, then `x.y`, `x.y.z`, and `x` will all return true, but
+/// `x.z`, and `y` will return false.
+fn is_expr_same_child_or_parent_field(cx: &LateContext<'_>, expr: &Expr<'_>, fields: &[Symbol], path_res: Res) -> bool {
+    match expr.kind {
+        ExprKind::Field(base, name) => {
+            if let Some((head_field, tail_fields)) = fields.split_first() {
+                if name.name == *head_field && is_expr_same_field(cx, base, fields, path_res) {
+                    return true;
+                }
+                // Check if the expression is a parent field
+                let mut fields_iter = tail_fields.iter();
+                while let Some(field) = fields_iter.next() {
+                    if *field == name.name && is_expr_same_field(cx, base, fields_iter.as_slice(), path_res) {
+                        return true;
+                    }
+                }
+            }
+
+            // Check if the expression is a child field.
+            let mut e = base;
+            loop {
+                match e.kind {
+                    ExprKind::Field(..) if is_expr_same_field(cx, e, fields, path_res) => break true,
+                    ExprKind::Field(base, _) | ExprKind::DropTemps(base) | ExprKind::Type(base, _) => e = base,
+                    ExprKind::Path(ref path) if fields.is_empty() => {
+                        break cx.qpath_res(path, e.hir_id) == path_res;
+                    },
+                    _ => break false,
+                }
+            }
+        },
+        // If the path matches, this is either an exact match, or the expression is a parent of the field.
+        ExprKind::Path(ref path) => cx.qpath_res(path, expr.hir_id) == path_res,
+        ExprKind::DropTemps(base) | ExprKind::Type(base, _) | ExprKind::AddrOf(_, _, base) => {
+            is_expr_same_child_or_parent_field(cx, base, fields, path_res)
+        },
+        _ => false,
     }
-    false
 }
 
-fn is_loop_nested(cx: &LateContext<'_>, loop_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool {
-    let mut id = loop_expr.hir_id;
-    let iter_id = if let Some(id) = path_to_local(iter_expr) {
-        id
-    } else {
-        return true;
+/// Strips off all field and path expressions. This will return true if a field or path has been
+/// skipped. Used to skip them after failing to check for equality.
+fn skip_fields_and_path(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool) {
+    let mut e = expr;
+    let e = loop {
+        match e.kind {
+            ExprKind::Field(base, _) | ExprKind::DropTemps(base) | ExprKind::Type(base, _) => e = base,
+            ExprKind::Path(_) => return (None, true),
+            _ => break e,
+        }
     };
-    loop {
-        let parent = cx.tcx.hir().get_parent_node(id);
-        if parent == id {
-            return false;
+    (Some(e), e.hir_id != expr.hir_id)
+}
+
+/// Checks if the given expression uses the iterator.
+fn uses_iter(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr<'_>) -> bool {
+    struct V<'a, 'b, 'tcx> {
+        cx: &'a LateContext<'tcx>,
+        iter_expr: &'b IterExpr,
+        uses_iter: bool,
+    }
+    impl Visitor<'tcx> for V<'_, '_, 'tcx> {
+        type Map = ErasedMap<'tcx>;
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+            NestedVisitorMap::None
         }
-        match cx.tcx.hir().find(parent) {
-            Some(Node::Expr(expr)) => {
-                if let ExprKind::Loop(..) = expr.kind {
-                    return true;
-                };
-            },
-            Some(Node::Block(block)) => {
-                let mut block_visitor = LoopNestVisitor {
-                    hir_id: id,
-                    iterator: iter_id,
-                    nesting: Nesting::Unknown,
-                };
-                walk_block(&mut block_visitor, block);
-                if block_visitor.nesting == Nesting::RuledOut {
-                    return false;
+
+        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+            if self.uses_iter {
+                // return
+            } else if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
+                self.uses_iter = true;
+            } else if let (e, true) = skip_fields_and_path(e) {
+                if let Some(e) = e {
+                    self.visit_expr(e);
                 }
-            },
-            Some(Node::Stmt(_)) => (),
-            _ => {
-                return false;
-            },
+            } else if let ExprKind::Closure(_, _, id, _, _) = e.kind {
+                if is_res_used(self.cx, self.iter_expr.path, id) {
+                    self.uses_iter = true;
+                }
+            } else {
+                walk_expr(self, e);
+            }
         }
-        id = parent;
     }
-}
 
-struct VarUsedAfterLoopVisitor {
-    def_id: HirId,
-    iter_expr_id: HirId,
-    past_while_let: bool,
-    var_used_after_while_let: bool,
+    let mut v = V {
+        cx,
+        iter_expr,
+        uses_iter: false,
+    };
+    v.visit_expr(container);
+    v.uses_iter
 }
 
-impl<'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor {
-    type Map = Map<'tcx>;
+#[allow(clippy::too_many_lines)]
+fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr: &'tcx Expr<'_>) -> bool {
+    struct AfterLoopVisitor<'a, 'b, 'tcx> {
+        cx: &'a LateContext<'tcx>,
+        iter_expr: &'b IterExpr,
+        loop_id: HirId,
+        after_loop: bool,
+        used_iter: bool,
+    }
+    impl Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
+        type Map = ErasedMap<'tcx>;
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+            NestedVisitorMap::None
+        }
 
-    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-        if self.past_while_let {
-            if path_to_local_id(expr, self.def_id) {
-                self.var_used_after_while_let = true;
+        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+            if self.used_iter {
+                return;
+            }
+            if self.after_loop {
+                if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
+                    self.used_iter = true;
+                } else if let (e, true) = skip_fields_and_path(e) {
+                    if let Some(e) = e {
+                        self.visit_expr(e);
+                    }
+                } else if let ExprKind::Closure(_, _, id, _, _) = e.kind {
+                    self.used_iter = is_res_used(self.cx, self.iter_expr.path, id);
+                } else {
+                    walk_expr(self, e);
+                }
+            } else if self.loop_id == e.hir_id {
+                self.after_loop = true;
+            } else {
+                walk_expr(self, e);
+            }
+        }
+    }
+
+    struct NestedLoopVisitor<'a, 'b, 'tcx> {
+        cx: &'a LateContext<'tcx>,
+        iter_expr: &'b IterExpr,
+        local_id: HirId,
+        loop_id: HirId,
+        after_loop: bool,
+        found_local: bool,
+        used_after: bool,
+    }
+    impl Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
+        type Map = ErasedMap<'tcx>;
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+            NestedVisitorMap::None
+        }
+
+        fn visit_local(&mut self, l: &'tcx Local<'_>) {
+            if !self.after_loop {
+                l.pat.each_binding_or_first(&mut |_, id, _, _| {
+                    if id == self.local_id {
+                        self.found_local = true;
+                    }
+                });
+            }
+            if let Some(e) = l.init {
+                self.visit_expr(e);
+            }
+        }
+
+        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+            if self.used_after {
+                return;
+            }
+            if self.after_loop {
+                if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) {
+                    self.used_after = true;
+                } else if let (e, true) = skip_fields_and_path(e) {
+                    if let Some(e) = e {
+                        self.visit_expr(e);
+                    }
+                } else if let ExprKind::Closure(_, _, id, _, _) = e.kind {
+                    self.used_after = is_res_used(self.cx, self.iter_expr.path, id);
+                } else {
+                    walk_expr(self, e);
+                }
+            } else if e.hir_id == self.loop_id {
+                self.after_loop = true;
+            } else {
+                walk_expr(self, e);
             }
-        } else if self.iter_expr_id == expr.hir_id {
-            self.past_while_let = true;
         }
-        walk_expr(self, expr);
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
+
+    if let Some(e) = get_enclosing_loop(cx.tcx, loop_expr) {
+        // The iterator expression will be used on the next iteration unless it is declared within the outer
+        // loop.
+        let local_id = match iter_expr.path {
+            Res::Local(id) => id,
+            _ => return true,
+        };
+        let mut v = NestedLoopVisitor {
+            cx,
+            iter_expr,
+            local_id,
+            loop_id: loop_expr.hir_id,
+            after_loop: false,
+            found_local: false,
+            used_after: false,
+        };
+        v.visit_expr(e);
+        v.used_after || !v.found_local
+    } else {
+        let mut v = AfterLoopVisitor {
+            cx,
+            iter_expr,
+            loop_id: loop_expr.hir_id,
+            after_loop: false,
+            used_iter: false,
+        };
+        v.visit_expr(&cx.tcx.hir().body(cx.enclosing_body.unwrap()).value);
+        v.used_iter
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index 314bf11e2d6..66479ae264e 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -47,7 +47,12 @@ pub struct MacroRefData {
 
 impl MacroRefData {
     pub fn new(name: String, callee: Span, cx: &LateContext<'_>) -> Self {
-        let mut path = cx.sess().source_map().span_to_filename(callee).prefer_local().to_string();
+        let mut path = cx
+            .sess()
+            .source_map()
+            .span_to_filename(callee)
+            .prefer_local()
+            .to_string();
 
         // std lib paths are <::std::module::file type>
         // so remove brackets, space and type.
@@ -96,7 +101,8 @@ impl MacroUseImports {
         let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_");
         if let Some(callee) = span.source_callee() {
             if !self.collected.contains(&call_site) {
-                self.mac_refs.push(MacroRefData::new(name.to_string(), callee.def_site, cx));
+                self.mac_refs
+                    .push(MacroRefData::new(name.to_string(), callee.def_site, cx));
                 self.collected.insert(call_site);
             }
         }
@@ -174,7 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
                                 .push((*item).to_string());
                             check_dup.push((*item).to_string());
                         }
-                    }
+                    },
                     [root, rest @ ..] => {
                         if rest.iter().all(|item| !check_dup.contains(&(*item).to_string())) {
                             let filtered = rest
@@ -198,7 +204,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
                                 .push(rest.join("::"));
                             check_dup.extend(rest.iter().map(ToString::to_string));
                         }
-                    }
+                    },
                 }
             }
         }
@@ -206,9 +212,9 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
         let mut suggestions = vec![];
         for ((root, span), path) in used {
             if path.len() == 1 {
-                suggestions.push((span, format!("{}::{}", root, path[0])))
+                suggestions.push((span, format!("{}::{}", root, path[0])));
             } else {
-                suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))))
+                suggestions.push((span, format!("{}::{{{}}}", root, path.join(", "))));
             }
         }
 
@@ -225,7 +231,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
                     "remove the attribute and import the macro directly, try",
                     help,
                     Applicability::MaybeIncorrect,
-                )
+                );
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 23428524dee..61b5fe81fa9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
 use clippy_utils::usage::mutated_variables;
@@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
                                           kind_word,
                                           snippet(cx, pattern.span, "..")))]
                             .into_iter().chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))),
-                        )
+                        );
                     });
                 }
             }
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
index 520162559e5..18038dd7819 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
@@ -1,4 +1,4 @@
-use crate::consts::constant_simple;
+use clippy_utils::consts::constant_simple;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -53,21 +53,6 @@ impl LateLintPass<'_> for ManualUnwrapOr {
     }
 }
 
-#[derive(Copy, Clone)]
-enum Case {
-    Option,
-    Result,
-}
-
-impl Case {
-    fn unwrap_fn_path(&self) -> &str {
-        match self {
-            Case::Option => "Option::unwrap_or",
-            Case::Result => "Result::unwrap_or",
-        }
-    }
-}
-
 fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
     fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> {
         if_chain! {
@@ -86,6 +71,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk);
             if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind;
             if path_to_local_id(unwrap_arm.body, binding_hir_id);
+            if cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty();
             if !contains_return_break_continue_macro(or_arm.body);
             then {
                 Some(or_arm)
@@ -98,10 +84,10 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
     if_chain! {
         if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind;
         let ty = cx.typeck_results().expr_ty(scrutinee);
-        if let Some(case) = if is_type_diagnostic_item(cx, ty, sym::option_type) {
-            Some(Case::Option)
+        if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::option_type) {
+            Some("Option")
         } else if is_type_diagnostic_item(cx, ty, sym::result_type) {
-            Some(Case::Result)
+            Some("Result")
         } else {
             None
         };
@@ -124,7 +110,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             span_lint_and_sugg(
                 cx,
                 MANUAL_UNWRAP_OR, expr.span,
-                &format!("this pattern reimplements `{}`", case.unwrap_fn_path()),
+                &format!("this pattern reimplements `{}::unwrap_or`", ty_name),
                 "replace with",
                 format!(
                     "{}.unwrap_or({})",
diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs
index 99c35ae3bbf..e1f80ab025c 100644
--- a/src/tools/clippy/clippy_lints/src/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/map_clone.rs
@@ -125,7 +125,7 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
         "remove the `map` call",
         String::new(),
         Applicability::MachineApplicable,
-    )
+    );
 }
 
 fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
@@ -142,7 +142,7 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
                 snippet_with_applicability(cx, root, "..", &mut applicability)
             ),
             applicability,
-        )
+        );
     } else {
         span_lint_and_sugg(
             cx,
@@ -155,6 +155,6 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
                 snippet_with_applicability(cx, root, "..", &mut applicability)
             ),
             applicability,
-        )
+        );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
index a70e8b26087..cd3e3b97928 100644
--- a/src/tools/clippy/clippy_lints/src/matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, miri_to_const, Constant};
+use clippy_utils::consts::{constant, miri_to_const, Constant};
 use clippy_utils::diagnostics::{
     multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
 };
@@ -1144,7 +1144,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
                 "try this",
                 suggestions.join(" | "),
                 Applicability::MaybeIncorrect,
-            )
+            );
         },
     };
 }
@@ -1242,7 +1242,7 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp
                     cast,
                 ),
                 applicability,
-            )
+            );
         }
     }
 }
@@ -1478,15 +1478,34 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A
             );
         },
         PatKind::Wild => {
-            span_lint_and_sugg(
-                cx,
-                MATCH_SINGLE_BINDING,
-                expr.span,
-                "this match could be replaced by its body itself",
-                "consider using the match body instead",
-                snippet_body,
-                Applicability::MachineApplicable,
-            );
+            if ex.can_have_side_effects() {
+                let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0));
+                let sugg = format!(
+                    "{};\n{}{}",
+                    snippet_with_applicability(cx, ex.span, "..", &mut applicability),
+                    indent,
+                    snippet_body
+                );
+                span_lint_and_sugg(
+                    cx,
+                    MATCH_SINGLE_BINDING,
+                    expr.span,
+                    "this match could be replaced by its scrutinee and body",
+                    "consider using the scrutinee and body instead",
+                    sugg,
+                    applicability,
+                );
+            } else {
+                span_lint_and_sugg(
+                    cx,
+                    MATCH_SINGLE_BINDING,
+                    expr.span,
+                    "this match could be replaced by its body itself",
+                    "consider using the match body instead",
+                    snippet_body,
+                    Applicability::MachineApplicable,
+                );
+            }
         },
         _ => (),
     }
@@ -1728,7 +1747,7 @@ mod redundant_pattern_match {
             match match_source {
                 MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms),
                 MatchSource::IfLetDesugar { contains_else_clause } => {
-                    find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause)
+                    find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause);
                 },
                 MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, &arms[0], "while", false),
                 _ => {},
@@ -1857,7 +1876,7 @@ mod redundant_pattern_match {
                             {
                                 self.res = true;
                             } else {
-                                self.visit_expr(self_arg)
+                                self.visit_expr(self_arg);
                             }
                         }
                         args.iter().for_each(|arg| self.visit_expr(arg));
diff --git a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs
index a735c616f6e..aca96e06ef2 100644
--- a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use std::iter;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for calls of `mem::discriminant()` on a non-enum type.
@@ -67,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for MemDiscriminant {
                                 }
                             }
 
-                            let derefs: String = iter::repeat('*').take(derefs_needed).collect();
+                            let derefs = "*".repeat(derefs_needed);
                             diag.span_suggestion(
                                 param.span,
                                 "try dereferencing",
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index 287bff886bf..da428a7b487 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -135,7 +135,7 @@ pub(crate) trait BindInsteadOfMap {
                         .into_iter()
                         .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())),
                 ),
-            )
+            );
         });
         true
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index ce2e8fa8b10..1a32af5dc7a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -8,7 +8,6 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, adjustment::Adjust};
 use rustc_span::symbol::{sym, Symbol};
-use std::iter;
 
 use super::CLONE_DOUBLE_REF;
 use super::CLONE_ON_COPY;
@@ -54,8 +53,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
                             ty = inner;
                             n += 1;
                         }
-                        let refs: String = iter::repeat('&').take(n + 1).collect();
-                        let derefs: String = iter::repeat('*').take(n).collect();
+                        let refs = "&".repeat(n + 1);
+                        let derefs = "*".repeat(n);
                         let explicit = format!("<{}{}>::clone({})", refs, ty, snip);
                         diag.span_suggestion(
                             expr.span,
diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
index ecec6da3aa0..f5b4b6bf8ea 100644
--- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
@@ -41,5 +41,5 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span,
         "try",
         "copied".into(),
         Applicability::MachineApplicable,
-    )
+    );
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
index 12d560653ed..32d40d97bf4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
@@ -30,5 +30,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg
         "try",
         "filter_map".into(),
         Applicability::MachineApplicable,
-    )
+    );
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
index 28d0e8cd4ae..b4188d9ed30 100644
--- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
@@ -37,6 +37,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp
 }
 
 fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String {
+    fn strip_angle_brackets(s: &str) -> Option<&str> {
+        s.strip_prefix('<')?.strip_suffix('>')
+    }
+
     let call_site = expr.span.source_callsite();
     if_chain! {
         if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site);
@@ -44,23 +48,32 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -
         if let Some((_, elements)) = snippet_split.split_last();
 
         then {
-            // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
-            if let Some(type_specifier) = snippet_split.iter().find(|e| e.starts_with('<') && e.ends_with('>')) {
-                // remove the type specifier from the path elements
-                let without_ts = elements.iter().filter_map(|e| {
-                    if e == type_specifier { None } else { Some((*e).to_string()) }
-                }).collect::<Vec<_>>();
-                // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
-                format!("{}{}", without_ts.join("::"), type_specifier)
-            } else {
-                // type is not explicitly specified so wildcards are needed
-                // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
-                let ty_str = ty.to_string();
-                let start = ty_str.find('<').unwrap_or(0);
-                let end = ty_str.find('>').unwrap_or_else(|| ty_str.len());
-                let nb_wildcard = ty_str[start..end].split(',').count();
-                let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
-                format!("{}<{}>", elements.join("::"), wildcards)
+            if_chain! {
+                if let [type_specifier, _] = snippet_split.as_slice();
+                if let Some(type_specifier) = strip_angle_brackets(type_specifier);
+                if let Some((type_specifier, ..)) = type_specifier.split_once(" as ");
+                then {
+                    type_specifier.to_string()
+                } else {
+                    // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
+                    if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) {
+                        // remove the type specifier from the path elements
+                        let without_ts = elements.iter().filter_map(|e| {
+                            if e == type_specifier { None } else { Some((*e).to_string()) }
+                        }).collect::<Vec<_>>();
+                        // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
+                        format!("{}{}", without_ts.join("::"), type_specifier)
+                    } else {
+                        // type is not explicitly specified so wildcards are needed
+                        // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
+                        let ty_str = ty.to_string();
+                        let start = ty_str.find('<').unwrap_or(0);
+                        let end = ty_str.find('>').unwrap_or_else(|| ty_str.len());
+                        let nb_wildcard = ty_str[start..end].split(',').count();
+                        let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
+                        format!("{}<{}>", elements.join("::"), wildcards)
+                    }
+                }
             }
         } else {
             ty.to_string()
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
index 52d7c15332e..68d906c3ea3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_trait_method;
 use clippy_utils::source::snippet_with_applicability;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
index 06b12998b1a..64c09214a76 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::is_trait_method;
 use rustc_hir as hir;
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
new file mode 100644
index 00000000000..919e2628c52
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
@@ -0,0 +1,99 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type};
+use clippy_utils::{is_expr_path_def_path, paths};
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty, TyS};
+use rustc_span::symbol::sym;
+use std::borrow::Cow;
+
+use super::MANUAL_STR_REPEAT;
+
+enum RepeatKind {
+    String,
+    Char(char),
+}
+
+fn get_ty_param(ty: Ty<'_>) -> Option<Ty<'_>> {
+    if let ty::Adt(_, subs) = ty.kind() {
+        subs.types().next()
+    } else {
+        None
+    }
+}
+
+fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> {
+    if let ExprKind::Lit(lit) = &e.kind {
+        match lit.node {
+            LitKind::Str(..) => Some(RepeatKind::String),
+            LitKind::Char(c) => Some(RepeatKind::Char(c)),
+            _ => None,
+        }
+    } else {
+        let ty = cx.typeck_results().expr_ty(e);
+        if is_type_diagnostic_item(cx, ty, sym::string_type)
+            || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, TyS::is_str))
+            || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, TyS::is_str))
+        {
+            Some(RepeatKind::String)
+        } else {
+            let ty = ty.peel_refs();
+            (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::string_type)).then(|| RepeatKind::String)
+        }
+    }
+}
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    collect_expr: &Expr<'_>,
+    take_expr: &Expr<'_>,
+    take_self_arg: &Expr<'_>,
+    take_arg: &Expr<'_>,
+) {
+    if_chain! {
+        if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind;
+        if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT);
+        if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::string_type);
+        if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id);
+        if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id);
+        if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
+        if cx.tcx.trait_of_item(collect_id) == Some(iter_trait_id);
+        if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id);
+        if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg);
+        let ctxt = collect_expr.span.ctxt();
+        if ctxt == take_expr.span.ctxt();
+        if ctxt == take_self_arg.span.ctxt();
+        then {
+            let mut app = Applicability::MachineApplicable;
+            let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0;
+
+            let val_str = match repeat_kind {
+                RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return,
+                RepeatKind::Char('\'') => r#""'""#.into(),
+                RepeatKind::Char('"') => r#""\"""#.into(),
+                RepeatKind::Char(_) =>
+                    match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) {
+                        Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])),
+                        s @ Cow::Borrowed(_) => s,
+                    },
+                RepeatKind::String =>
+                    Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app).maybe_par().to_string().into(),
+            };
+
+            span_lint_and_sugg(
+                cx,
+                MANUAL_STR_REPEAT,
+                collect_expr.span,
+                "manual implementation of `str::repeat` using iterators",
+                "try this",
+                format!("{}.repeat({})", val_str, count_snip),
+                app
+            )
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 0b1b6304def..c8ae972f18c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -32,6 +32,7 @@ mod iter_nth_zero;
 mod iter_skip_next;
 mod iterator_step_by_zero;
 mod manual_saturating_arithmetic;
+mod manual_str_repeat;
 mod map_collect_result_unit;
 mod map_flatten;
 mod map_unwrap_or;
@@ -48,6 +49,7 @@ mod single_char_push_string;
 mod skip_while_next;
 mod string_extend_chars;
 mod suspicious_map;
+mod suspicious_splitn;
 mod uninit_assumed_init;
 mod unnecessary_filter_map;
 mod unnecessary_fold;
@@ -61,7 +63,7 @@ mod zst_offset;
 use bind_instead_of_map::BindInsteadOfMap;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item};
-use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, paths, return_ty};
+use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -283,30 +285,6 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
-    /// **What it does:** This is the same as
-    /// [`wrong_self_convention`](#wrong_self_convention), but for public items.
-    ///
-    /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention).
-    ///
-    /// **Known problems:** Actually *renaming* the function may break clients if
-    /// the function is part of the public interface. In that case, be mindful of
-    /// the stability guarantees you've given your users.
-    ///
-    /// **Example:**
-    /// ```rust
-    /// # struct X;
-    /// impl<'a> X {
-    ///     pub fn as_str(self) -> &'a str {
-    ///         "foo"
-    ///     }
-    /// }
-    /// ```
-    pub WRONG_PUB_SELF_CONVENTION,
-    restriction,
-    "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention"
-}
-
-declare_clippy_lint! {
     /// **What it does:** Checks for usage of `ok().expect(..)`.
     ///
     /// **Why is this bad?** Because you usually call `expect()` on the `Result`
@@ -1657,14 +1635,69 @@ declare_clippy_lint! {
     "replace `.iter().count()` with `.len()`"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for calls to [`splitn`]
+    /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and
+    /// related functions with either zero or one splits.
+    ///
+    /// **Why is this bad?** These calls don't actually split the value and are
+    /// likely to be intended as a different number.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// // Bad
+    /// let s = "";
+    /// for x in s.splitn(1, ":") {
+    ///     // use x
+    /// }
+    ///
+    /// // Good
+    /// let s = "";
+    /// for x in s.splitn(2, ":") {
+    ///     // use x
+    /// }
+    /// ```
+    pub SUSPICIOUS_SPLITN,
+    correctness,
+    "checks for `.splitn(0, ..)` and `.splitn(1, ..)`"
+}
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for manual implementations of `str::repeat`
+    ///
+    /// **Why is this bad?** These are both harder to read, as well as less performant.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// // Bad
+    /// let x: String = std::iter::repeat('x').take(10).collect();
+    ///
+    /// // Good
+    /// let x: String = "x".repeat(10);
+    /// ```
+    pub MANUAL_STR_REPEAT,
+    perf,
+    "manual implementation of `str::repeat`"
+}
+
 pub struct Methods {
+    avoid_breaking_exported_api: bool,
     msrv: Option<RustcVersion>,
 }
 
 impl Methods {
     #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
-        Self { msrv }
+    pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Self {
+        Self {
+            avoid_breaking_exported_api,
+            msrv,
+        }
     }
 }
 
@@ -1673,7 +1706,6 @@ impl_lint_pass!(Methods => [
     EXPECT_USED,
     SHOULD_IMPLEMENT_TRAIT,
     WRONG_SELF_CONVENTION,
-    WRONG_PUB_SELF_CONVENTION,
     OK_EXPECT,
     MAP_UNWRAP_OR,
     RESULT_MAP_OR_INTO_OPTION,
@@ -1726,7 +1758,9 @@ impl_lint_pass!(Methods => [
     MAP_COLLECT_RESULT_UNIT,
     FROM_ITER_INSTEAD_OF_COLLECT,
     INSPECT_FOR_EACH,
-    IMPLICIT_CLONE
+    IMPLICIT_CLONE,
+    SUSPICIOUS_SPLITN,
+    MANUAL_STR_REPEAT
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -1838,16 +1872,20 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                     }
                 }
 
-                wrong_self_convention::check(
-                    cx,
-                    &name,
-                    item.vis.node.is_pub(),
-                    self_ty,
-                    first_arg_ty,
-                    first_arg.pat.span,
-                    implements_trait,
-                    false
-                );
+                if sig.decl.implicit_self.has_implicit_self()
+                    && !(self.avoid_breaking_exported_api
+                        && cx.access_levels.is_exported(impl_item.hir_id()))
+                {
+                    wrong_self_convention::check(
+                        cx,
+                        &name,
+                        self_ty,
+                        first_arg_ty,
+                        first_arg.pat.span,
+                        implements_trait,
+                        false
+                    );
+                }
             }
         }
 
@@ -1903,7 +1941,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
 
         if_chain! {
             if let TraitItemKind::Fn(ref sig, _) = item.kind;
+            if sig.decl.implicit_self.has_implicit_self();
             if let Some(first_arg_ty) = sig.decl.inputs.iter().next();
+
             then {
                 let first_arg_span = first_arg_ty.span;
                 let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
@@ -1911,7 +1951,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 wrong_self_convention::check(
                     cx,
                     &item.ident.name.as_str(),
-                    false,
                     self_ty,
                     first_arg_ty,
                     first_arg_span,
@@ -1947,7 +1986,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
     if let Some((name, [recv, args @ ..], span)) = method_call!(expr) {
         match (name, args) {
             ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [recv, _]) => {
-                zst_offset::check(cx, expr, recv)
+                zst_offset::check(cx, expr, recv);
             },
             ("and_then", [arg]) => {
                 let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
@@ -1965,6 +2004,11 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 Some(("map", [m_recv, m_arg], _)) => {
                     map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv);
                 },
+                Some(("take", [take_self_arg, take_arg], _)) => {
+                    if meets_msrv(msrv, &msrvs::STR_REPEAT) {
+                        manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
+                    }
+                },
                 _ => {},
             },
             ("count", []) => match method_call!(recv) {
@@ -2008,7 +2052,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                         ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
                         ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
                         ("filter", [f_arg]) => {
-                            filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false)
+                            filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false);
                         },
                         ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true),
                         _ => {},
@@ -2040,6 +2084,9 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                     unnecessary_lazy_eval::check(cx, expr, recv, arg, "or");
                 }
             },
+            ("splitn" | "splitn_mut" | "rsplitn" | "rsplitn_mut", [count_arg, _]) => {
+                suspicious_splitn::check(cx, name, expr, recv, count_arg);
+            },
             ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
             ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
                 implicit_clone::check(cx, name, expr, recv, span);
@@ -2054,7 +2101,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                     manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
                 },
                 Some(("map", [m_recv, m_arg], span)) => {
-                    option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span)
+                    option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
                 },
                 _ => {},
             },
@@ -2069,7 +2116,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
 
 fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
     if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call!(recv) {
-        search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span)
+        search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
new file mode 100644
index 00000000000..a271df60572
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs
@@ -0,0 +1,56 @@
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_note;
+use if_chain::if_chain;
+use rustc_ast::LitKind;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+
+use super::SUSPICIOUS_SPLITN;
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    method_name: &str,
+    expr: &Expr<'_>,
+    self_arg: &Expr<'_>,
+    count_arg: &Expr<'_>,
+) {
+    if_chain! {
+        if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg);
+        if count <= 1;
+        if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
+        if let Some(impl_id) = cx.tcx.impl_of_method(call_id);
+        let lang_items = cx.tcx.lang_items();
+        if lang_items.slice_impl() == Some(impl_id) || lang_items.str_impl() == Some(impl_id);
+        then {
+            // Ignore empty slice and string literals when used with a literal count.
+            if (matches!(self_arg.kind, ExprKind::Array([]))
+                || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty())
+            ) && matches!(count_arg.kind, ExprKind::Lit(_))
+            {
+                return;
+            }
+
+            let (msg, note_msg) = if count == 0 {
+                (format!("`{}` called with `0` splits", method_name),
+                "the resulting iterator will always return `None`")
+            } else {
+                (format!("`{}` called with `1` split", method_name),
+                if lang_items.slice_impl() == Some(impl_id) {
+                    "the resulting iterator will always return the entire slice followed by `None`"
+                } else {
+                    "the resulting iterator will always return the entire string followed by `None`"
+                })
+            };
+
+            span_lint_and_note(
+                cx,
+                SUSPICIOUS_SPLITN,
+                expr.span,
+                &msg,
+                None,
+                note_msg,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index 75517c48a21..4c4034437da 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -87,7 +87,7 @@ pub(super) fn check(
             ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
             ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false),
             ast::LitKind::Int(1, _) => {
-                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false)
+                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false);
             },
             _ => (),
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
index 6e2bcb113c2..a2e09e5ecec 100644
--- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
@@ -6,7 +6,6 @@ use rustc_middle::ty::TyS;
 use rustc_span::source_map::Span;
 use std::fmt;
 
-use super::WRONG_PUB_SELF_CONVENTION;
 use super::WRONG_SELF_CONVENTION;
 
 #[rustfmt::skip]
@@ -21,9 +20,9 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [
 
     // Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types).
     // Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv
-    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), 
-    Convention::IsTraitItem(false)], &[SelfKind::Ref]),
-    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), 
+    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false),
+    Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]),
+    (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true),
     Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]),
 ];
 
@@ -85,18 +84,12 @@ impl fmt::Display for Convention {
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     item_name: &str,
-    is_pub: bool,
     self_ty: &'tcx TyS<'tcx>,
     first_arg_ty: &'tcx TyS<'tcx>,
     first_arg_span: Span,
     implements_trait: bool,
     is_trait_item: bool,
 ) {
-    let lint = if is_pub {
-        WRONG_PUB_SELF_CONVENTION
-    } else {
-        WRONG_SELF_CONVENTION
-    };
     if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| {
         convs
             .iter()
@@ -142,7 +135,7 @@ pub(super) fn check<'tcx>(
 
             span_lint_and_help(
                 cx,
-                lint,
+                WRONG_SELF_CONVENTION,
                 first_arg_span,
                 &format!(
                     "{} usually take {}",
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index 45948f4d926..ff3473b744e 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{match_def_path, match_trait_method, paths};
 use if_chain::if_chain;
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 6966d798c53..804c04fe1b8 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -17,7 +17,7 @@ use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::{ExpnKind, Span};
 use rustc_span::symbol::sym;
 
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
     expr_path_res, get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const,
@@ -355,8 +355,10 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
             if binop.node == BinOpKind::And || binop.node == BinOpKind::Or;
             if let Some(sugg) = Sugg::hir_opt(cx, a);
             then {
-                span_lint_and_then(cx,
+                span_lint_hir_and_then(
+                    cx,
                     SHORT_CIRCUIT_STATEMENT,
+                    expr.hir_id,
                     stmt.span,
                     "boolean short circuit operator in statement may be clearer using an explicit test",
                     |diag| {
@@ -660,7 +662,14 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool {
     use rustc_span::hygiene::MacroKind;
     if expr.span.from_expansion() {
         let data = expr.span.ctxt().outer_expn_data();
-        matches!(data.kind, ExpnKind::Macro { kind: MacroKind::Attr, name: _, proc_macro: _ })
+        matches!(
+            data.kind,
+            ExpnKind::Macro {
+                kind: MacroKind::Attr,
+                name: _,
+                proc_macro: _
+            }
+        )
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index dd38316fa25..050b6805b7c 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -310,7 +310,7 @@ impl EarlyLintPass for MiscEarlyLints {
         if in_external_macro(cx.sess(), expr.span) {
             return;
         }
-        double_neg::check(cx, expr)
+        double_neg::check(cx, expr);
     }
 }
 
@@ -334,15 +334,15 @@ impl MiscEarlyLints {
             };
             unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
             if lit_snip.starts_with("0x") {
-                mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip)
+                mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
             } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
-                /* nothing to do */
+                // nothing to do
             } else if value != 0 && lit_snip.starts_with('0') {
-                zero_prefixed_literal::check(cx, lit, &lit_snip)
+                zero_prefixed_literal::check(cx, lit, &lit_snip);
             }
         } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
             let suffix = float_ty.name_str();
-            unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float")
+            unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index dfab3e8a931..ec1572c26c2 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -93,9 +93,9 @@ impl MissingDoc {
             return;
         }
 
-        let has_doc = attrs.iter().any(|a| {
-            a.is_doc_comment() || a.doc_str().is_some() || a.value_str().is_some() || Self::has_include(a.meta())
-        });
+        let has_doc = attrs
+            .iter()
+            .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
         if !has_doc {
             span_lint(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
index 64e9dc85466..1414fdc1b11 100644
--- a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sext;
 use if_chain::if_chain;
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index cea6fce1195..6efe8ffcde0 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
                 let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
                 let substs = cx.typeck_results().node_substs(e.hir_id);
                 let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
-                check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method")
+                check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method");
             },
             _ => (),
         }
diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
index 7dfe12cd4eb..25645a0e7a2 100644
--- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
+++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
@@ -107,7 +107,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
             _ if !self.found => self.expr_span = Some(expr.span),
             _ => return,
         }
-        walk_expr(self, expr)
+        walk_expr(self, expr);
     }
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
index 3e2b2782ed5..fe3c4455be5 100644
--- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -121,7 +121,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType {
         match &p.ty.kind {
             TyKind::Path(None, path) => {
                 if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind {
-                    check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl)
+                    check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl);
                 }
             },
             TyKind::Rptr(lifetime, mut_ty) => {
@@ -129,7 +129,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType {
                 if let TyKind::Path(None, path) = &mut_ty.ty.kind;
                 if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind;
                     then {
-                        check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl)
+                        check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl);
                     }
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs
new file mode 100644
index 00000000000..b30bfbd4294
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs
@@ -0,0 +1,86 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::in_macro;
+use clippy_utils::source::snippet_opt;
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:**
+    /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using
+    /// a lazy and.
+    ///
+    /// **Why is this bad?**
+    /// The bitwise operators do not support short-circuiting, so it may hinder code performance.
+    /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold`
+    ///
+    /// **Known problems:**
+    /// This lint evaluates only when the right side is determined to have no side effects. At this time, that
+    /// determination is quite conservative.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let (x,y) = (true, false);
+    /// if x & !y {} // where both x and y are booleans
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let (x,y) = (true, false);
+    /// if x && !y {}
+    /// ```
+    pub NEEDLESS_BITWISE_BOOL,
+    pedantic,
+    "Boolean expressions that use bitwise rather than lazy operators"
+}
+
+declare_lint_pass!(NeedlessBitwiseBool => [NEEDLESS_BITWISE_BOOL]);
+
+fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.typeck_results().expr_ty(expr);
+    if_chain! {
+        if !in_macro(expr.span);
+        if let (&ExprKind::Binary(ref op, _, right), &ty::Bool) = (&expr.kind, &ty.kind());
+        if op.node == BinOpKind::BitAnd || op.node == BinOpKind::BitOr;
+        if let ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..) = right.kind;
+        if !right.can_have_side_effects();
+        then {
+            return true;
+        }
+    }
+    false
+}
+
+fn suggession_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
+    if let ExprKind::Binary(ref op, left, right) = expr.kind {
+        if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) {
+            let op_snippet = match op.node {
+                BinOpKind::BitAnd => "&&",
+                _ => "||",
+            };
+            return Some(format!("{} {} {}", l_snippet, op_snippet, r_snippet));
+        }
+    }
+    None
+}
+
+impl LateLintPass<'_> for NeedlessBitwiseBool {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if is_bitwise_operation(cx, expr) {
+            span_lint_and_then(
+                cx,
+                NEEDLESS_BITWISE_BOOL,
+                expr.span,
+                "use of bitwise operator instead of lazy operator between booleans",
+                |diag| {
+                    if let Some(sugg) = suggession_snippet(cx, expr) {
+                        diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable);
+                    }
+                },
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index dd458198637..3b3736fd3a1 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
                 }
 
                 if is_else_clause(cx.tcx, e) {
-                    snip = snip.blockify()
+                    snip = snip.blockify();
                 }
 
                 span_lint_and_sugg(
@@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison {
                         |h: Sugg<'_>| !h,
                         "equality checks against false can be replaced by a negation",
                     ));
-                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal)
+                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
                 },
                 BinOpKind::Ne => {
                     let true_case = Some((
@@ -152,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison {
                         "inequality checks against true can be replaced by a negation",
                     ));
                     let false_case = Some((|h| h, "inequality checks against false are unnecessary"));
-                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal)
+                    check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal);
                 },
                 BinOpKind::Lt => check_comparison(
                     cx,
@@ -251,22 +251,22 @@ fn check_comparison<'a, 'tcx>(
                             snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability)
                         ),
                         applicability,
-                    )
+                    );
                 }
             }
 
             match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) {
                 (Bool(true), Other) => left_true.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+                    suggest_bool_comparison(cx, e, right_side, applicability, m, h);
                 }),
                 (Other, Bool(true)) => right_true.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+                    suggest_bool_comparison(cx, e, left_side, applicability, m, h);
                 }),
                 (Bool(false), Other) => left_false.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, right_side, applicability, m, h)
+                    suggest_bool_comparison(cx, e, right_side, applicability, m, h);
                 }),
                 (Other, Bool(false)) => right_false.map_or((), |(h, m)| {
-                    suggest_bool_comparison(cx, e, left_side, applicability, m, h)
+                    suggest_bool_comparison(cx, e, left_side, applicability, m, h);
                 }),
                 (Other, Other) => no_literal.map_or((), |(h, m)| {
                     let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability);
@@ -279,7 +279,7 @@ fn check_comparison<'a, 'tcx>(
                         "try simplifying it as shown",
                         h(left_side, right_side).to_string(),
                         applicability,
-                    )
+                    );
                 }),
                 _ => (),
             }
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
index eef3c16730b..dd1dfa2bdfb 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs
@@ -3,16 +3,18 @@
 //! This lint is **warn** by default
 
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_automatically_derived;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::source::{snippet_opt, snippet_with_applicability, snippet_with_context};
+use clippy_utils::{get_parent_expr, in_macro, path_to_local};
 use if_chain::if_chain;
+use rustc_ast::util::parser::PREC_POSTFIX;
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, Item, Mutability, Pat, PatKind};
+use rustc_hir::{BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::def_id::LocalDefId;
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for address of operations (`&`) that are going to
@@ -32,20 +34,70 @@ declare_clippy_lint! {
     /// let x: &i32 = &5;
     /// ```
     pub NEEDLESS_BORROW,
-    nursery,
+    style,
     "taking a reference that is going to be automatically dereferenced"
 }
 
+declare_clippy_lint! {
+    /// **What it does:** Checks for `ref` bindings which create a reference to a reference.
+    ///
+    /// **Why is this bad?** The address-of operator at the use site is clearer about the need for a reference.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// ```rust
+    /// // Bad
+    /// let x = Some("");
+    /// if let Some(ref x) = x {
+    ///     // use `x` here
+    /// }
+    ///
+    /// // Good
+    /// let x = Some("");
+    /// if let Some(x) = x {
+    ///     // use `&x` here
+    /// }
+    /// ```
+    pub REF_BINDING_TO_REFERENCE,
+    pedantic,
+    "`ref` binding to a reference"
+}
+
+impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW, REF_BINDING_TO_REFERENCE]);
 #[derive(Default)]
 pub struct NeedlessBorrow {
-    derived_item: Option<LocalDefId>,
+    /// The body the first local was found in. Used to emit lints when the traversal of the body has
+    /// been finished. Note we can't lint at the end of every body as they can be nested within each
+    /// other.
+    current_body: Option<BodyId>,
+    /// The list of locals currently being checked by the lint.
+    /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted.
+    /// This is needed for or patterns where one of the branches can be linted, but another can not
+    /// be.
+    ///
+    /// e.g. `m!(x) | Foo::Bar(ref x)`
+    ref_locals: FxIndexMap<HirId, Option<RefPat>>,
 }
 
-impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW]);
+struct RefPat {
+    /// Whether every usage of the binding is dereferenced.
+    always_deref: bool,
+    /// The spans of all the ref bindings for this local.
+    spans: Vec<Span>,
+    /// The applicability of this suggestion.
+    app: Applicability,
+    /// All the replacements which need to be made.
+    replacements: Vec<(Span, String)>,
+}
 
 impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if e.span.from_expansion() || self.derived_item.is_some() {
+        if let Some(local) = path_to_local(e) {
+            self.check_local_usage(cx, e, local);
+        }
+
+        if e.span.from_expansion() {
             return;
         }
         if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = e.kind {
@@ -85,50 +137,131 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow {
             }
         }
     }
+
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
-        if pat.span.from_expansion() || self.derived_item.is_some() {
-            return;
+        if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind {
+            if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) {
+                // This binding id has been seen before. Add this pattern to the list of changes.
+                if let Some(prev_pat) = opt_prev_pat {
+                    if in_macro(pat.span) {
+                        // Doesn't match the context of the previous pattern. Can't lint here.
+                        *opt_prev_pat = None;
+                    } else {
+                        prev_pat.spans.push(pat.span);
+                        prev_pat.replacements.push((
+                            pat.span,
+                            snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut prev_pat.app)
+                                .0
+                                .into(),
+                        ));
+                    }
+                }
+                return;
+            }
+
+            if_chain! {
+                if !in_macro(pat.span);
+                if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind();
+                // only lint immutable refs, because borrowed `&mut T` cannot be moved out
+                if let ty::Ref(_, _, Mutability::Not) = *tam.kind();
+                then {
+                    let mut app = Applicability::MachineApplicable;
+                    let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0;
+                    self.current_body = self.current_body.or(cx.enclosing_body);
+                    self.ref_locals.insert(
+                        id,
+                        Some(RefPat {
+                            always_deref: true,
+                            spans: vec![pat.span],
+                            app,
+                            replacements: vec![(pat.span, snip.into())],
+                        }),
+                    );
+                }
+            }
         }
-        if_chain! {
-            if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind;
-            if let ty::Ref(_, tam, mutbl) = *cx.typeck_results().pat_ty(pat).kind();
-            if mutbl == Mutability::Not;
-            if let ty::Ref(_, _, mutbl) = *tam.kind();
-            // only lint immutable refs, because borrowed `&mut T` cannot be moved out
-            if mutbl == Mutability::Not;
-            then {
+    }
+
+    fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
+        if Some(body.id()) == self.current_body {
+            for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) {
+                let replacements = pat.replacements;
+                let app = pat.app;
                 span_lint_and_then(
                     cx,
-                    NEEDLESS_BORROW,
-                    pat.span,
+                    if pat.always_deref {
+                        NEEDLESS_BORROW
+                    } else {
+                        REF_BINDING_TO_REFERENCE
+                    },
+                    pat.spans,
                     "this pattern creates a reference to a reference",
                     |diag| {
-                        if let Some(snippet) = snippet_opt(cx, name.span) {
-                            diag.span_suggestion(
-                                pat.span,
-                                "change this to",
-                                snippet,
-                                Applicability::MachineApplicable,
-                            );
-                        }
-                    }
-                )
+                        diag.multipart_suggestion("try this", replacements, app);
+                    },
+                );
             }
+            self.current_body = None;
         }
     }
-
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        let attrs = cx.tcx.hir().attrs(item.hir_id());
-        if is_automatically_derived(attrs) {
-            debug_assert!(self.derived_item.is_none());
-            self.derived_item = Some(item.def_id);
-        }
-    }
-
-    fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let Some(id) = self.derived_item {
-            if item.def_id == id {
-                self.derived_item = None;
+}
+impl NeedlessBorrow {
+    fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) {
+        if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
+            if let Some(pat) = outer_pat {
+                // Check for auto-deref
+                if !matches!(
+                    cx.typeck_results().expr_adjustments(e),
+                    [
+                        Adjustment {
+                            kind: Adjust::Deref(_),
+                            ..
+                        },
+                        Adjustment {
+                            kind: Adjust::Deref(_),
+                            ..
+                        },
+                        ..
+                    ]
+                ) {
+                    match get_parent_expr(cx, e) {
+                        // Field accesses are the same no matter the number of references.
+                        Some(Expr {
+                            kind: ExprKind::Field(..),
+                            ..
+                        }) => (),
+                        Some(&Expr {
+                            span,
+                            kind: ExprKind::Unary(UnOp::Deref, _),
+                            ..
+                        }) if !in_macro(span) => {
+                            // Remove explicit deref.
+                            let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0;
+                            pat.replacements.push((span, snip.into()));
+                        },
+                        Some(parent) if !in_macro(parent.span) => {
+                            // Double reference might be needed at this point.
+                            if parent.precedence().order() == PREC_POSTFIX {
+                                // Parentheses would be needed here, don't lint.
+                                *outer_pat = None;
+                            } else {
+                                pat.always_deref = false;
+                                let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0;
+                                pat.replacements.push((e.span, format!("&{}", snip)));
+                            }
+                        },
+                        _ if !in_macro(e.span) => {
+                            // Double reference might be needed at this point.
+                            pat.always_deref = false;
+                            let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);
+                            pat.replacements.push((e.span, format!("&{}", snip)));
+                        },
+                        // Edge case for macros. The span of the identifier will usually match the context of the
+                        // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc
+                        // macros
+                        _ => *outer_pat = None,
+                    }
+                }
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 079b6642d58..a723a472a25 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -142,10 +142,10 @@ impl<'tcx> Visitor<'tcx> for RetCollector {
         match expr.kind {
             ExprKind::Ret(..) => {
                 if self.loop_depth > 0 && !self.ret_in_loop {
-                    self.ret_in_loop = true
+                    self.ret_in_loop = true;
                 }
 
-                self.spans.push(expr.span)
+                self.spans.push(expr.span);
             },
 
             ExprKind::Loop(..) => {
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index 7b156a8c49d..c64491c63e2 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -1,14 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_lang_ctor;
 use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{differing_macro_contexts, is_lang_ctor};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionSome, ResultOk};
 use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TyS;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// **What it does:**
@@ -63,12 +62,6 @@ declare_clippy_lint! {
 
 declare_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]);
 
-#[derive(Debug)]
-enum SomeOkCall<'a> {
-    SomeCall(&'a Expr<'a>, &'a Expr<'a>),
-    OkCall(&'a Expr<'a>, &'a Expr<'a>),
-}
-
 impl LateLintPass<'_> for NeedlessQuestionMark {
     /*
      * The question mark operator is compatible with both Result<T, E> and Option<T>,
@@ -90,104 +83,37 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
      */
 
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
-        let e = match &expr.kind {
-            ExprKind::Ret(Some(e)) => e,
-            _ => return,
-        };
-
-        if let Some(ok_some_call) = is_some_or_ok_call(cx, e) {
-            emit_lint(cx, &ok_some_call);
+        if let ExprKind::Ret(Some(e)) = expr.kind {
+            check(cx, e);
         }
     }
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
-        // Function / Closure block
-        let expr_opt = if let ExprKind::Block(block, _) = &body.value.kind {
-            block.expr
-        } else {
-            // Single line closure
-            Some(&body.value)
-        };
-
-        if_chain! {
-            if let Some(expr) = expr_opt;
-            if let Some(ok_some_call) = is_some_or_ok_call(cx, expr);
-            then {
-                emit_lint(cx, &ok_some_call);
-            }
-        };
+        check(cx, body.value.peel_blocks());
     }
 }
 
-fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) {
-    let (entire_expr, inner_expr) = match expr {
-        SomeOkCall::OkCall(outer, inner) | SomeOkCall::SomeCall(outer, inner) => (outer, inner),
+fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
+    let inner_expr = if_chain! {
+        if let ExprKind::Call(path, [arg]) = &expr.kind;
+        if let ExprKind::Path(ref qpath) = &path.kind;
+        if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk);
+        if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &arg.kind;
+        if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind;
+        if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)) = &called.kind;
+        if expr.span.ctxt() == inner_expr.span.ctxt();
+        let expr_ty = cx.typeck_results().expr_ty(expr);
+        let inner_ty = cx.typeck_results().expr_ty(inner_expr);
+        if TyS::same_type(expr_ty, inner_ty);
+        then { inner_expr } else { return; }
     };
-
     span_lint_and_sugg(
         cx,
         NEEDLESS_QUESTION_MARK,
-        entire_expr.span,
+        expr.span,
         "question mark operator is useless here",
         "try",
         format!("{}", snippet(cx, inner_expr.span, r#""...""#)),
         Applicability::MachineApplicable,
     );
 }
-
-fn is_some_or_ok_call<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<SomeOkCall<'a>> {
-    if_chain! {
-        // Check outer expression matches CALL_IDENT(ARGUMENT) format
-        if let ExprKind::Call(path, args) = &expr.kind;
-        if let ExprKind::Path(ref qpath) = &path.kind;
-        if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk);
-
-        // Extract inner expression from ARGUMENT
-        if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &args[0].kind;
-        if let ExprKind::Call(called, args) = &inner_expr_with_q.kind;
-        if args.len() == 1;
-
-        if let ExprKind::Path(QPath::LangItem(LangItem::TryIntoResult, _)) = &called.kind;
-        then {
-            // Extract inner expr type from match argument generated by
-            // question mark operator
-            let inner_expr = &args[0];
-
-            // if the inner expr is inside macro but the outer one is not, do not lint (#6921)
-            if  differing_macro_contexts(expr.span, inner_expr.span) {
-                return None;
-            }
-
-            let inner_ty = cx.typeck_results().expr_ty(inner_expr);
-            let outer_ty = cx.typeck_results().expr_ty(expr);
-
-            // Check if outer and inner type are Option
-            let outer_is_some = is_type_diagnostic_item(cx, outer_ty, sym::option_type);
-            let inner_is_some = is_type_diagnostic_item(cx, inner_ty, sym::option_type);
-
-            // Check for Option MSRV
-            if outer_is_some && inner_is_some {
-                return Some(SomeOkCall::SomeCall(expr, inner_expr));
-            }
-
-            // Check if outer and inner type are Result
-            let outer_is_result = is_type_diagnostic_item(cx, outer_ty, sym::result_type);
-            let inner_is_result = is_type_diagnostic_item(cx, inner_ty, sym::result_type);
-
-            // Additional check: if the error type of the Result can be converted
-            // via the From trait, then don't match
-            let does_not_call_from = !has_implicit_error_from(cx, expr, inner_expr);
-
-            // Must meet Result MSRV
-            if outer_is_result && inner_is_result && does_not_call_from {
-                return Some(SomeOkCall::OkCall(expr, inner_expr));
-            }
-        }
-    }
-
-    None
-}
-
-fn has_implicit_error_from(cx: &LateContext<'_>, entire_expr: &Expr<'_>, inner_result_expr: &Expr<'_>) -> bool {
-    return cx.typeck_results().expr_ty(entire_expr) != cx.typeck_results().expr_ty(inner_result_expr);
-}
diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
index 0704173a011..c824f6f54b5 100644
--- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
@@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd {
                         types produces code that is hard to read and refactor, please \
                         consider using the `partial_cmp` method instead, to make it \
                         clear that the two values could be incomparable"
-                    )
+                    );
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index 34fd012572f..d5e1ea6d242 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -1,3 +1,4 @@
+use clippy_utils::consts::{self, Constant};
 use clippy_utils::diagnostics::span_lint;
 use if_chain::if_chain;
 use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
@@ -5,8 +6,6 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 
-use crate::consts::{self, Constant};
-
 declare_clippy_lint! {
     /// **What it does:** Checks for multiplication by -1 as a form of negation.
     ///
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index cfcaf509471..b2206a82208 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::has_drop;
 use rustc_errors::Applicability;
@@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if let StmtKind::Semi(expr) = stmt.kind {
             if has_no_effect(cx, expr) {
-                span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect");
+                span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect");
             } else if let Some(reduced) = reduce_expression(cx, expr) {
                 let mut snippet = String::new();
                 for e in reduced {
@@ -106,14 +106,15 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
                         return;
                     }
                 }
-                span_lint_and_sugg(
+                span_lint_hir_and_then(
                     cx,
                     UNNECESSARY_OPERATION,
+                    expr.hir_id,
                     stmt.span,
                     "statement can be reduced",
-                    "replace it with",
-                    snippet,
-                    Applicability::MachineApplicable,
+                    |diag| {
+                        diag.span_suggestion(stmt.span, "replace it with", snippet, Applicability::MachineApplicable);
+                    },
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index 4c8bceaf2cb..5292af5f076 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -126,6 +126,7 @@ const ALLOWED_TO_BE_SIMILAR: &[&[&str]] = &[
     &["args", "arms"],
     &["qpath", "path"],
     &["lit", "lint"],
+    &["wparam", "lparam"],
 ];
 
 struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>);
diff --git a/src/tools/clippy/clippy_lints/src/open_options.rs b/src/tools/clippy/clippy_lints/src/open_options.rs
index 9efe45336bf..fded48038e3 100644
--- a/src/tools/clippy/clippy_lints/src/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/open_options.rs
@@ -123,7 +123,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `create` is called more than once",
                     );
                 } else {
-                    create = true
+                    create = true;
                 }
                 create_arg = create_arg || (arg == Argument::True);
             },
@@ -136,7 +136,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `append` is called more than once",
                     );
                 } else {
-                    append = true
+                    append = true;
                 }
                 append_arg = append_arg || (arg == Argument::True);
             },
@@ -149,7 +149,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `truncate` is called more than once",
                     );
                 } else {
-                    truncate = true
+                    truncate = true;
                 }
                 truncate_arg = truncate_arg || (arg == Argument::True);
             },
@@ -162,7 +162,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `read` is called more than once",
                     );
                 } else {
-                    read = true
+                    read = true;
                 }
                 read_arg = read_arg || (arg == Argument::True);
             },
@@ -175,7 +175,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)],
                         "the method `write` is called more than once",
                     );
                 } else {
-                    write = true
+                    write = true;
                 }
                 write_arg = write_arg || (arg == Argument::True);
             },
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index e527adbb892..b6af4175edf 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::usage::contains_return_break_continue_macro;
-use clippy_utils::{eager_or_lazy, get_enclosing_block, in_macro, is_lang_ctor};
+use clippy_utils::{eager_or_lazy, in_macro, is_else_clause, is_lang_ctor};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionSome;
@@ -81,7 +81,6 @@ struct OptionIfLetElseOccurence {
     method_sugg: String,
     some_expr: String,
     none_expr: String,
-    wrap_braces: bool,
 }
 
 /// Extracts the body of a given arm. If the arm contains only an expression,
@@ -106,37 +105,6 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> {
     }
 }
 
-/// If this is the else body of an if/else expression, then we need to wrap
-/// it in curly braces. Otherwise, we don't.
-fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| {
-        let mut should_wrap = false;
-
-        if let Some(Expr {
-            kind:
-                ExprKind::Match(
-                    _,
-                    arms,
-                    MatchSource::IfLetDesugar {
-                        contains_else_clause: true,
-                    },
-                ),
-            ..
-        }) = parent.expr
-        {
-            should_wrap = expr.hir_id == arms[1].body.hir_id;
-        } else if let Some(Expr {
-            kind: ExprKind::If(_, _, Some(else_clause)),
-            ..
-        }) = parent.expr
-        {
-            should_wrap = expr.hir_id == else_clause.hir_id;
-        }
-
-        should_wrap
-    })
-}
-
 fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String {
     format!(
         "{}{}",
@@ -161,6 +129,7 @@ fn detect_option_if_let_else<'tcx>(
     if_chain! {
         if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly
         if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind;
+        if !is_else_clause(cx.tcx, expr);
         if arms.len() == 2;
         if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already
         if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind;
@@ -168,13 +137,13 @@ fn detect_option_if_let_else<'tcx>(
         if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind;
         if !contains_return_break_continue_macro(arms[0].body);
         if !contains_return_break_continue_macro(arms[1].body);
+
         then {
             let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" };
             let some_body = extract_body_from_arm(&arms[0])?;
             let none_body = extract_body_from_arm(&arms[1])?;
             let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" };
             let capture_name = id.name.to_ident_string();
-            let wrap_braces = should_wrap_in_braces(cx, expr);
             let (as_ref, as_mut) = match &cond_expr.kind {
                 ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
                 ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
@@ -190,7 +159,6 @@ fn detect_option_if_let_else<'tcx>(
                 method_sugg: method_sugg.to_string(),
                 some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir(cx, some_body, "..")),
                 none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir(cx, none_body, "..")),
-                wrap_braces,
             })
         } else {
             None
@@ -208,13 +176,8 @@ impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse {
                 format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(),
                 "try",
                 format!(
-                    "{}{}.{}({}, {}){}",
-                    if detection.wrap_braces { "{ " } else { "" },
-                    detection.option,
-                    detection.method_sugg,
-                    detection.none_expr,
-                    detection.some_expr,
-                    if detection.wrap_braces { " }" } else { "" },
+                    "{}.{}({}, {})",
+                    detection.option, detection.method_sugg, detection.none_expr, detection.some_expr,
                 ),
                 Applicability::MaybeIncorrect,
             );
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 6b64846c24d..f6a70478559 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -102,10 +102,16 @@ declare_clippy_lint! {
 pub struct PassByRefOrValue {
     ref_min_size: u64,
     value_max_size: u64,
+    avoid_breaking_exported_api: bool,
 }
 
 impl<'tcx> PassByRefOrValue {
-    pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> Self {
+    pub fn new(
+        ref_min_size: Option<u64>,
+        value_max_size: u64,
+        avoid_breaking_exported_api: bool,
+        target: &Target,
+    ) -> Self {
         let ref_min_size = ref_min_size.unwrap_or_else(|| {
             let bit_width = u64::from(target.pointer_width);
             // Cap the calculated bit width at 32-bits to reduce
@@ -120,10 +126,14 @@ impl<'tcx> PassByRefOrValue {
         Self {
             ref_min_size,
             value_max_size,
+            avoid_breaking_exported_api,
         }
     }
 
     fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
+        if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) {
+            return;
+        }
         let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
 
         let fn_sig = cx.tcx.fn_sig(fn_def_id);
@@ -184,7 +194,6 @@ impl<'tcx> PassByRefOrValue {
                     }
 
                     if_chain! {
-                        if !cx.access_levels.is_exported(hir_id);
                         if is_copy(cx, ty);
                         if !is_self_ty(input);
                         if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index b0674f90678..12c44436874 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -211,7 +211,7 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     ];
 
     if_chain! {
-        if let ExprKind::Call(ref fun, ref args) = expr.kind;
+        if let ExprKind::Call(fun, args) = expr.kind;
         if let ExprKind::Path(ref qpath) = fun.kind;
         if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
         let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::<Vec<_>>();
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index 30bee213900..d66bac52243 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -88,7 +88,7 @@ impl QuestionMark {
                         "replace it with",
                         replacement_str,
                         applicability,
-                    )
+                    );
                 }
             }
         }
@@ -129,7 +129,7 @@ impl QuestionMark {
                     "replace it with",
                     replacement,
                     applicability,
-                )
+                );
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 7169f96eaf1..ae5f0627fd6 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 92921bedf4d..8f56a21ac5b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -57,7 +57,7 @@ impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor {
             self.found_return = true;
         }
 
-        ast_visit::walk_expr(self, ex)
+        ast_visit::walk_expr(self, ex);
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index e091095de13..05f9e01acb4 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
                                 Applicability::MachineApplicable,
                             );
                         },
-                    )
+                    );
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 4b5306de58e..75151167454 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant, Constant};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::{match_def_path, paths};
 use if_chain::if_chain;
diff --git a/src/tools/clippy/clippy_lints/src/repeat_once.rs b/src/tools/clippy/clippy_lints/src/repeat_once.rs
index 560a5e7c920..b479c40bca6 100644
--- a/src/tools/clippy/clippy_lints/src/repeat_once.rs
+++ b/src/tools/clippy/clippy_lints/src/repeat_once.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant_context, Constant};
+use clippy_utils::consts::{constant_context, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::in_macro;
 use clippy_utils::source::snippet;
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index b565c77aaec..251d527c265 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for Return {
                 } else {
                     RetReplacement::Empty
                 };
-                check_final_expr(cx, &body.value, Some(body.value.span), replacement)
+                check_final_expr(cx, &body.value, Some(body.value.span), replacement);
             },
             FnKind::ItemFn(..) | FnKind::Method(..) => {
                 if let ExprKind::Block(block, _) = body.value.kind {
@@ -241,7 +241,7 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Spa
                 if let Some(snippet) = snippet_opt(cx, inner_span) {
                     diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
                 }
-            })
+            });
         },
         None => match replacement {
             RetReplacement::Empty => {
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
index 553987a426b..16e4d73851f 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -8,11 +8,11 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
-    /// **What it does:** Looks for blocks of expressions and fires if the last expression returns `()`
-    /// but is not followed by a semicolon.
+    /// **What it does:** Looks for blocks of expressions and fires if the last expression returns
+    /// `()` but is not followed by a semicolon.
     ///
-    /// **Why is this bad?** The semicolon might be optional but when
-    /// extending the block with new code, it doesn't require a change in previous last line.
+    /// **Why is this bad?** The semicolon might be optional but when extending the block with new
+    /// code, it doesn't require a change in previous last line.
     ///
     /// **Known problems:** None.
     ///
@@ -30,7 +30,7 @@ declare_clippy_lint! {
     /// }
     /// ```
     pub SEMICOLON_IF_NOTHING_RETURNED,
-    restriction,
+    pedantic,
     "add a semicolon if nothing is returned"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index d6101bd5e36..ac3f7ebd14b 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -120,7 +120,7 @@ fn check_fn<'tcx>(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Bo
     let mut bindings = Vec::with_capacity(decl.inputs.len());
     for arg in iter_input_pats(decl, body) {
         if let PatKind::Binding(.., ident, _) = arg.pat.kind {
-            bindings.push((ident.name, ident.span))
+            bindings.push((ident.name, ident.span));
         }
     }
     check_expr(cx, &body.value, &mut bindings);
@@ -156,7 +156,7 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: &
         ..
     } = *local;
     if let Some(t) = *ty {
-        check_ty(cx, t, bindings)
+        check_ty(cx, t, bindings);
     }
     if let Some(o) = *init {
         check_expr(cx, o, bindings);
@@ -324,14 +324,14 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut
     }
     match expr.kind {
         ExprKind::Unary(_, e) | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Box(e) => {
-            check_expr(cx, e, bindings)
+            check_expr(cx, e, bindings);
         },
         ExprKind::Block(block, _) | ExprKind::Loop(block, ..) => check_block(cx, block, bindings),
         // ExprKind::Call
         // ExprKind::MethodCall
         ExprKind::Array(v) | ExprKind::Tup(v) => {
             for e in v {
-                check_expr(cx, e, bindings)
+                check_expr(cx, e, bindings);
             }
         },
         ExprKind::If(cond, then, ref otherwise) => {
@@ -374,7 +374,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<(
         TyKind::Ptr(MutTy { ty: mty, .. }) | TyKind::Rptr(_, MutTy { ty: mty, .. }) => check_ty(cx, mty, bindings),
         TyKind::Tup(tup) => {
             for t in tup {
-                check_ty(cx, t, bindings)
+                check_ty(cx, t, bindings);
             }
         },
         TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings),
diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
index a45bb102389..1eaad438237 100644
--- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
@@ -70,7 +70,7 @@ fn check_mod(cx: &EarlyContext<'_>, items: &[P<Item>]) {
     for item in items {
         track_uses(
             cx,
-            &item,
+            item,
             &mut imports_reused_with_self,
             &mut single_use_usages,
             &mut macros,
@@ -117,7 +117,7 @@ fn track_uses(
 
     match &item.kind {
         ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => {
-            check_mod(cx, &items);
+            check_mod(cx, items);
         },
         ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => {
             macros.push(item.ident.name);
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index a9ae2b77119..e5c58d70b60 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -158,7 +158,7 @@ impl SlowVectorInit {
     ) {
         match initialization {
             InitializationType::Extend(e) | InitializationType::Resize(e) => {
-                Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization")
+                Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization");
             },
         };
     }
@@ -290,7 +290,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
     fn visit_block(&mut self, block: &'tcx Block<'_>) {
         if self.initialization_found {
             if let Some(s) = block.stmts.get(0) {
-                self.visit_stmt(s)
+                self.visit_stmt(s);
             }
 
             self.initialization_found = false;
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index 4272935bc31..bb707f78fcc 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -59,7 +59,7 @@ declare_clippy_lint! {
     /// }
     /// ```
     pub SUSPICIOUS_OPERATION_GROUPINGS,
-    style,
+    nursery,
     "groupings of binary operations that look suspiciously like typos"
 }
 
@@ -266,7 +266,7 @@ fn emit_suggestion(cx: &EarlyContext<'_>, span: Span, sugg: String, applicabilit
         "did you mean",
         sugg,
         applicability,
-    )
+    );
 }
 
 fn ident_swap_sugg(
@@ -475,7 +475,7 @@ impl Add for IdentLocation {
 
 impl AddAssign for IdentLocation {
     fn add_assign(&mut self, other: Self) {
-        *self = *self + other
+        *self = *self + other;
     }
 }
 
@@ -506,7 +506,7 @@ impl Add for IdentDifference {
 
 impl AddAssign for IdentDifference {
     fn add_assign(&mut self, other: Self) {
-        *self = *self + other
+        *self = *self + other;
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index b0589b0512e..74a94db1800 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -3,6 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::{in_macro, SpanlessHash};
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
 use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, TyKind, WherePredicate};
 use rustc_lint::{LateContext, LateLintPass};
@@ -100,7 +101,7 @@ impl TraitBounds {
             hasher.hash_ty(ty);
             hasher.finish()
         };
-        let mut map = FxHashMap::default();
+        let mut map: UnhashMap<u64, Vec<&GenericBound<'_>>> = UnhashMap::default();
         let mut applicability = Applicability::MaybeIncorrect;
         for bound in gen.where_clause.predicates {
             if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmuting_null.rs
index 888ecab1046..b57d158293d 100644
--- a/src/tools/clippy/clippy_lints/src/transmuting_null.rs
+++ b/src/tools/clippy/clippy_lints/src/transmuting_null.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant_context, Constant};
+use clippy_utils::consts::{constant_context, Constant};
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::{is_expr_path_def_path, paths};
 use if_chain::if_chain;
diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs
index ebb39ea4877..f2ba2b2ecf6 100644
--- a/src/tools/clippy/clippy_lints/src/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/try_err.rs
@@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr {
             if let ExprKind::Match(match_arg, _, MatchSource::TryDesugar) = expr.kind;
             if let ExprKind::Call(match_fun, try_args) = match_arg.kind;
             if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
-            if matches!(match_fun_path, QPath::LangItem(LangItem::TryIntoResult, _));
+            if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, _));
             if let Some(try_arg) = try_args.get(0);
             if let ExprKind::Call(err_fun, err_args) = try_arg.kind;
             if let Some(err_arg) = err_args.get(0);
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index d9b47a699dc..70b9e8adef8 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -306,7 +306,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
     fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
         match item.kind {
             TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => {
-                self.check_ty(cx, ty, CheckTyContext::default())
+                self.check_ty(cx, ty, CheckTyContext::default());
             },
             TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, CheckTyContext::default()),
             TraitItemKind::Type(..) => (),
@@ -433,7 +433,7 @@ impl Types {
             },
             TyKind::Slice(ty) | TyKind::Array(ty, _) | TyKind::Ptr(MutTy { ty, .. }) => {
                 context.is_nested_call = true;
-                self.check_ty(cx, ty, context)
+                self.check_ty(cx, ty, context);
             },
             TyKind::Tup(tys) => {
                 context.is_nested_call = true;
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index d81e31f5a21..45291a120ed 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -71,7 +71,7 @@ impl LateLintPass<'_> for Unicode {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
         if let ExprKind::Lit(ref lit) = expr.kind {
             if let LitKind::Str(_, _) = lit.node {
-                check_str(cx, lit.span, expr.hir_id)
+                check_str(cx, lit.span, expr.hir_id);
             }
         }
     }
@@ -82,7 +82,7 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String {
     for c in s {
         if c as u32 > 0x7F {
             for d in c.escape_unicode() {
-                result.push(d)
+                result.push(d);
             }
         } else {
             result.push(c);
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
index d22f7d9a96b..04542146516 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
@@ -8,7 +8,12 @@ use super::UNIT_CMP;
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if expr.span.from_expansion() {
         if let Some(callee) = expr.span.source_callee() {
-            if let ExpnKind::Macro { kind: MacroKind::Bang, name: symbol, proc_macro: _ } = callee.kind {
+            if let ExpnKind::Macro {
+                kind: MacroKind::Bang,
+                name: symbol,
+                proc_macro: _,
+            } = callee.kind
+            {
                 if let ExprKind::Binary(ref cmp, left, _) = expr.kind {
                     let op = cmp.node;
                     if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() {
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index f2f1410aed7..a85ffa6aa95 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -8,7 +8,7 @@ use rustc_hir::LangItem::{OptionSome, ResultOk};
 use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 
@@ -52,7 +52,19 @@ declare_clippy_lint! {
     "functions that only return `Ok` or `Some`"
 }
 
-declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
+pub struct UnnecessaryWraps {
+    avoid_breaking_exported_api: bool,
+}
+
+impl_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]);
+
+impl UnnecessaryWraps {
+    pub fn new(avoid_breaking_exported_api: bool) -> Self {
+        Self {
+            avoid_breaking_exported_api,
+        }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
     fn check_fn(
@@ -66,13 +78,12 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
     ) {
         // Abort if public function/method or closure.
         match fn_kind {
-            FnKind::ItemFn(.., visibility) | FnKind::Method(.., Some(visibility)) => {
-                if visibility.node.is_pub() {
+            FnKind::ItemFn(..) | FnKind::Method(..) => {
+                if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) {
                     return;
                 }
             },
             FnKind::Closure => return,
-            FnKind::Method(..) => (),
         }
 
         // Abort if the method is implementing a trait or of it a trait method.
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
new file mode 100644
index 00000000000..18ee07d3a95
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -0,0 +1,92 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnHeader, HirId, IsAsync, Item, ItemKind, YieldSource};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for functions that are declared `async` but have no `.await`s inside of them.
+    ///
+    /// **Why is this bad?** Async functions with no async code create overhead, both mentally and computationally.
+    /// Callers of async methods either need to be calling from an async function themselves or run it on an executor, both of which
+    /// causes runtime overhead and hassle for the caller.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// // Bad
+    /// async fn get_random_number() -> i64 {
+    ///     4 // Chosen by fair dice roll. Guaranteed to be random.
+    /// }
+    /// let number_future = get_random_number();
+    ///
+    /// // Good
+    /// fn get_random_number_improved() -> i64 {
+    ///     4 // Chosen by fair dice roll. Guaranteed to be random.
+    /// }
+    /// let number_future = async { get_random_number_improved() };
+    /// ```
+    pub UNUSED_ASYNC,
+    pedantic,
+    "finds async functions with no await statements"
+}
+
+declare_lint_pass!(UnusedAsync => [UNUSED_ASYNC]);
+
+struct AsyncFnVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    found_await: bool,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
+        if let ExprKind::Yield(_, YieldSource::Await { .. }) = ex.kind {
+            self.found_await = true;
+        }
+        walk_expr(self, ex);
+    }
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
+    fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if let ItemKind::Trait(..) = item.kind {
+            return;
+        }
+    }
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        fn_kind: FnKind<'tcx>,
+        fn_decl: &'tcx FnDecl<'tcx>,
+        body: &Body<'tcx>,
+        span: Span,
+        hir_id: HirId,
+    ) {
+        if let FnKind::ItemFn(_, _, FnHeader { asyncness, .. }, _) = &fn_kind {
+            if matches!(asyncness, IsAsync::Async) {
+                let mut visitor = AsyncFnVisitor { cx, found_await: false };
+                walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), span, hir_id);
+                if !visitor.found_await {
+                    span_lint_and_help(
+                        cx,
+                        UNUSED_ASYNC,
+                        span,
+                        "unused `async` for function with no await statements",
+                        None,
+                        "consider removing the `async` from this function",
+                    );
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 3387f35bac3..ee082d30d93 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
                 if let hir::ExprKind::Call(func, args) = res.kind {
                     if matches!(
                         func.kind,
-                        hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryIntoResult, _))
+                        hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, _))
                     ) {
                         check_map_error(cx, &args[0], expr);
                     }
@@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
 
 fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
     let mut call = call;
-    while let hir::ExprKind::MethodCall(ref path, _, ref args, _) = call.kind {
+    while let hir::ExprKind::MethodCall(path, _, args, _) = call.kind {
         if matches!(&*path.ident.as_str(), "or" | "or_else" | "ok") {
             call = &args[0];
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index 4ac2ec55b98..0b58c6c0917 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use itertools::Itertools;
-use rustc_ast::ast::{Item, ItemKind, VisibilityKind};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_hir::{Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::Ident;
@@ -38,12 +38,14 @@ declare_clippy_lint! {
 
 #[derive(Default)]
 pub struct UpperCaseAcronyms {
+    avoid_breaking_exported_api: bool,
     upper_case_acronyms_aggressive: bool,
 }
 
 impl UpperCaseAcronyms {
-    pub fn new(aggressive: bool) -> Self {
+    pub fn new(avoid_breaking_exported_api: bool, aggressive: bool) -> Self {
         Self {
+            avoid_breaking_exported_api,
             upper_case_acronyms_aggressive: aggressive,
         }
     }
@@ -72,7 +74,7 @@ fn correct_ident(ident: &str) -> String {
     ident
 }
 
-fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) {
+fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) {
     let span = ident.span;
     let ident = &ident.as_str();
     let corrected = correct_ident(ident);
@@ -92,27 +94,31 @@ fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) {
             "consider making the acronym lowercase, except the initial letter",
             corrected,
             Applicability::MaybeIncorrect,
-        )
+        );
     }
 }
 
-impl EarlyLintPass for UpperCaseAcronyms {
-    fn check_item(&mut self, cx: &EarlyContext<'_>, it: &Item) {
+impl LateLintPass<'_> for UpperCaseAcronyms {
+    fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
         // do not lint public items or in macros
-        if !in_external_macro(cx.sess(), it.span) && !matches!(it.vis.kind, VisibilityKind::Public) {
-            if matches!(
-                it.kind,
-                ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..)
-            ) {
+        if in_external_macro(cx.sess(), it.span)
+            || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.hir_id()))
+        {
+            return;
+        }
+        match it.kind {
+            ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..) => {
                 check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive);
-            } else if let ItemKind::Enum(ref enumdef, _) = it.kind {
+            },
+            ItemKind::Enum(ref enumdef, _) => {
                 // check enum variants seperately because again we only want to lint on private enums and
                 // the fn check_variant does not know about the vis of the enum of its variants
                 enumdef
                     .variants
                     .iter()
                     .for_each(|variant| check_ident(cx, &variant.ident, self.upper_case_acronyms_aggressive));
-            }
+            },
+            _ => {},
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index aa4d16633ff..254b104bdef 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::same_type_and_consts;
 use clippy_utils::{in_macro, meets_msrv, msrvs};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir as hir;
-use rustc_hir::def::DefKind;
 use rustc_hir::{
-    def,
+    self as hir,
+    def::{self, DefKind},
     def_id::LocalDefId,
     intravisit::{walk_ty, NestedVisitorMap, Visitor},
     Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Node, Path, PathSegment,
@@ -14,7 +14,7 @@ use rustc_hir::{
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
-use rustc_middle::ty::{AssocKind, Ty, TyS};
+use rustc_middle::ty::{AssocKind, Ty};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{BytePos, Span};
@@ -356,7 +356,7 @@ impl<'tcx> Visitor<'tcx> for SkipTyCollector {
     fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) {
         self.types_to_skip.push(hir_ty.hir_id);
 
-        walk_ty(self, hir_ty)
+        walk_ty(self, hir_ty);
     }
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -385,7 +385,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LintTyCollector<'a, 'tcx> {
             }
         }
 
-        walk_ty(self, hir_ty)
+        walk_ty(self, hir_ty);
     }
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
@@ -459,7 +459,7 @@ fn in_impl(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> bool {
 
 fn should_lint_ty(hir_ty: &hir::Ty<'_>, ty: Ty<'_>, self_ty: Ty<'_>) -> bool {
     if_chain! {
-        if TyS::same_type(ty, self_ty);
+        if same_type_and_consts(ty, self_ty);
         if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
         then {
             !matches!(path.res, def::Res::SelfTy(..))
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 7edb280be73..2be99fb761b 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 use clippy_utils::source::{snippet, snippet_with_macro_callsite};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts};
 use clippy_utils::{get_parent_expr, match_def_path, match_trait_method, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, TyS};
+use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::sym;
 
@@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                 if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" {
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(&args[0]);
-                    if TyS::same_type(a, b) {
+                    if same_type_and_consts(a, b) {
                         let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
                         span_lint_and_sugg(
                             cx,
@@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     }
                     let a = cx.typeck_results().expr_ty(e);
                     let b = cx.typeck_results().expr_ty(&args[0]);
-                    if TyS::same_type(a, b) {
+                    if same_type_and_consts(a, b) {
                         let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
                         span_lint_and_sugg(
                             cx,
@@ -110,7 +110,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     if is_type_diagnostic_item(cx, a, sym::result_type);
                     if let ty::Adt(_, substs) = a.kind();
                     if let Some(a_type) = substs.types().next();
-                    if TyS::same_type(a_type, b);
+                    if same_type_and_consts(a_type, b);
+
                     then {
                         span_lint_and_help(
                             cx,
@@ -137,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                             if is_type_diagnostic_item(cx, a, sym::result_type);
                             if let ty::Adt(_, substs) = a.kind();
                             if let Some(a_type) = substs.types().next();
-                            if TyS::same_type(a_type, b);
+                            if same_type_and_consts(a_type, b);
 
                             then {
                                 let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from"));
@@ -154,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
 
                         if_chain! {
                             if match_def_path(cx, def_id, &paths::FROM_FROM);
-                            if TyS::same_type(a, b);
+                            if same_type_and_consts(a, b);
 
                             then {
                                 let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par();
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index e70f8a09ebe..39ef170ae36 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -292,7 +292,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
                     LitKind::Str(ref text, _) => {
                         let str_pat = self.next("s");
                         println!("    if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat);
-                        println!("    if {}.as_str() == {:?}", str_pat, &*text.as_str())
+                        println!("    if {}.as_str() == {:?}", str_pat, &*text.as_str());
                     },
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 52c1dc3bdd2..0e33ae740d9 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -26,13 +26,13 @@ impl TryConf {
 
 macro_rules! define_Conf {
     ($(
-        #[$doc:meta]
+        #[doc = $doc:literal]
         $(#[conf_deprecated($dep:literal)])?
         ($name:ident: $ty:ty = $default:expr),
     )*) => {
         /// Clippy lint configuration
         pub struct Conf {
-            $(#[$doc] pub $name: $ty,)*
+            $(#[doc = $doc] pub $name: $ty,)*
         }
 
         mod defaults {
@@ -89,12 +89,42 @@ macro_rules! define_Conf {
                 Ok(TryConf { conf, errors })
             }
         }
+
+        #[cfg(feature = "metadata-collector-lint")]
+        pub mod metadata {
+            use crate::utils::internal_lints::metadata_collector::ClippyConfiguration;
+
+            macro_rules! wrap_option {
+                () => (None);
+                ($x:literal) => (Some($x));
+            }
+
+            pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
+                vec![
+                    $(
+                        {
+                            let deprecation_reason = wrap_option!($($dep)?);
+
+                            ClippyConfiguration::new(
+                                stringify!($name),
+                                stringify!($ty),
+                                format!("{:?}", super::defaults::$name()),
+                                $doc,
+                                deprecation_reason,
+                            )
+                        },
+                    )+
+                ]
+            }
+        }
     };
 }
 
 // N.B., this macro is parsed by util/lintlib.py
 define_Conf! {
-    /// Lint: CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports
+    /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION. Suppress lints whenever the suggested change would cause breakage for other crates.
+    (avoid_breaking_exported_api: bool = true),
+    /// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports
     (msrv: Option<String> = None),
     /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
     (blacklisted_names: Vec<String> = ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
@@ -180,15 +210,13 @@ pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> {
         .map_or_else(|| PathBuf::from("."), PathBuf::from);
     loop {
         for config_file_name in &CONFIG_FILE_NAMES {
-            let config_file = current.join(config_file_name);
-            match fs::metadata(&config_file) {
-                // Only return if it's a file to handle the unlikely situation of a directory named
-                // `clippy.toml`.
-                Ok(ref md) if !md.is_dir() => return Ok(Some(config_file)),
-                // Return the error if it's something other than `NotFound`; otherwise we didn't
-                // find the project file yet, and continue searching.
-                Err(e) if e.kind() != io::ErrorKind::NotFound => return Err(e),
-                _ => {},
+            if let Ok(config_file) = current.join(config_file_name).canonicalize() {
+                match fs::metadata(&config_file) {
+                    Err(e) if e.kind() == io::ErrorKind::NotFound => {},
+                    Err(e) => return Err(e),
+                    Ok(md) if md.is_dir() => {},
+                    Ok(_) => return Ok(Some(config_file)),
+                }
             }
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index ee7be24eae8..b1523e032af 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::match_type;
@@ -1100,7 +1100,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
                 IF_CHAIN_STYLE,
                 if_chain_local_span(cx, local, if_chain_span),
                 "`let` expression should be inside `then { .. }`",
-            )
+            );
         }
     }
 
@@ -1141,7 +1141,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
         if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span)
             && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span)
         {
-            span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`")
+            span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`");
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index e85637ca758..46af03663b8 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -8,9 +8,6 @@
 //! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
 //! a simple mistake)
 
-// # NITs
-// - TODO xFrednet 2021-02-13: Collect depreciations and maybe renames
-
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{
@@ -22,13 +19,14 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{sym, Loc, Span, Symbol};
 use serde::{ser::SerializeStruct, Serialize, Serializer};
 use std::collections::BinaryHeap;
+use std::fmt;
 use std::fs::{self, OpenOptions};
 use std::io::prelude::*;
 use std::path::Path;
 
 use crate::utils::internal_lints::is_lint_ref_type;
 use clippy_utils::{
-    diagnostics::span_lint, last_path_segment, match_function_call, match_path, paths, ty::match_type,
+    diagnostics::span_lint, last_path_segment, match_def_path, match_function_call, match_path, paths, ty::match_type,
     ty::walk_ptrs_ty_depth,
 };
 
@@ -39,8 +37,52 @@ const BLACK_LISTED_LINTS: [&str; 3] = ["lint_author", "deep_code_inspection", "i
 /// These groups will be ignored by the lint group matcher. This is useful for collections like
 /// `clippy::all`
 const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"];
-/// Lints within this group will be excluded from the collection
-const EXCLUDED_LINT_GROUPS: [&str; 1] = ["clippy::internal"];
+/// Lints within this group will be excluded from the collection. These groups
+/// have to be defined without the `clippy::` prefix.
+const EXCLUDED_LINT_GROUPS: [&str; 1] = ["internal"];
+/// Collected deprecated lint will be assigned to this group in the JSON output
+const DEPRECATED_LINT_GROUP_STR: &str = "deprecated";
+/// This is the lint level for deprecated lints that will be displayed in the lint list
+const DEPRECATED_LINT_LEVEL: &str = "none";
+/// This array holds Clippy's lint groups with their corresponding default lint level. The
+/// lint level for deprecated lints is set in `DEPRECATED_LINT_LEVEL`.
+const DEFAULT_LINT_LEVELS: [(&str, &str); 8] = [
+    ("correctness", "deny"),
+    ("restriction", "allow"),
+    ("style", "warn"),
+    ("pedantic", "allow"),
+    ("complexity", "warn"),
+    ("perf", "warn"),
+    ("cargo", "allow"),
+    ("nursery", "allow"),
+];
+/// This prefix is in front of the lint groups in the lint store. The prefix will be trimmed
+/// to only keep the actual lint group in the output.
+const CLIPPY_LINT_GROUP_PREFIX: &str = "clippy::";
+
+/// This template will be used to format the configuration section in the lint documentation.
+/// The `configurations` parameter will be replaced with one or multiple formatted
+/// `ClippyConfiguration` instances. See `CONFIGURATION_VALUE_TEMPLATE` for further customizations
+macro_rules! CONFIGURATION_SECTION_TEMPLATE {
+    () => {
+        r#"
+**Configuration**
+This lint has the following configuration variables:
+
+{configurations}
+"#
+    };
+}
+/// This template will be used to format an individual `ClippyConfiguration` instance in the
+/// lint documentation.
+///
+/// The format function will provide strings for the following parameters: `name`, `ty`, `doc` and
+/// `default`
+macro_rules! CONFIGURATION_VALUE_TEMPLATE {
+    () => {
+        "* {name}: {ty}: {doc} (defaults to `{default}`)\n"
+    };
+}
 
 const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [
     &["clippy_utils", "diagnostics", "span_lint"],
@@ -66,6 +108,7 @@ const SUGGESTION_FUNCTIONS: [&[&str]; 2] = [
     &["clippy_utils", "diagnostics", "multispan_sugg"],
     &["clippy_utils", "diagnostics", "multispan_sugg_with_applicability"],
 ];
+const DEPRECATED_LINT_TYPE: [&str; 3] = ["clippy_lints", "deprecated_lints", "ClippyDeprecatedLint"];
 
 /// The index of the applicability name of `paths::APPLICABILITY_VALUES`
 const APPLICABILITY_NAME_INDEX: usize = 2;
@@ -102,13 +145,33 @@ declare_clippy_lint! {
 impl_lint_pass!(MetadataCollector => [INTERNAL_METADATA_COLLECTOR]);
 
 #[allow(clippy::module_name_repetitions)]
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone)]
 pub struct MetadataCollector {
     /// All collected lints
     ///
     /// We use a Heap here to have the lints added in alphabetic order in the export
     lints: BinaryHeap<LintMetadata>,
     applicability_info: FxHashMap<String, ApplicabilityInfo>,
+    config: Vec<ClippyConfiguration>,
+}
+
+impl MetadataCollector {
+    pub fn new() -> Self {
+        Self {
+            lints: BinaryHeap::<LintMetadata>::default(),
+            applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(),
+            config: collect_configs(),
+        }
+    }
+
+    fn get_lint_configs(&self, lint_name: &str) -> Option<String> {
+        self.config
+            .iter()
+            .filter(|config| config.lints.iter().any(|lint| lint == lint_name))
+            .map(ToString::to_string)
+            .reduce(|acc, x| acc + &x)
+            .map(|configurations| format!(CONFIGURATION_SECTION_TEMPLATE!(), configurations = configurations))
+    }
 }
 
 impl Drop for MetadataCollector {
@@ -143,6 +206,7 @@ struct LintMetadata {
     id: String,
     id_span: SerializableSpan,
     group: String,
+    level: &'static str,
     docs: String,
     /// This field is only used in the output and will only be
     /// mapped shortly before the actual output.
@@ -150,11 +214,12 @@ struct LintMetadata {
 }
 
 impl LintMetadata {
-    fn new(id: String, id_span: SerializableSpan, group: String, docs: String) -> Self {
+    fn new(id: String, id_span: SerializableSpan, group: String, level: &'static str, docs: String) -> Self {
         Self {
             id,
             id_span,
             group,
+            level,
             docs,
             applicability: None,
         }
@@ -182,7 +247,7 @@ impl SerializableSpan {
         let loc: Loc = cx.sess().source_map().lookup_char_pos(span.lo());
 
         Self {
-            path: format!("{}", loc.file.name),
+            path: format!("{}", loc.file.name.prefer_remapped()),
             line: loc.line,
         }
     }
@@ -214,6 +279,95 @@ impl Serialize for ApplicabilityInfo {
     }
 }
 
+// ==================================================================
+// Configuration
+// ==================================================================
+#[derive(Debug, Clone, Default)]
+pub struct ClippyConfiguration {
+    name: String,
+    config_type: &'static str,
+    default: String,
+    lints: Vec<String>,
+    doc: String,
+    deprecation_reason: Option<&'static str>,
+}
+
+impl ClippyConfiguration {
+    pub fn new(
+        name: &'static str,
+        config_type: &'static str,
+        default: String,
+        doc_comment: &'static str,
+        deprecation_reason: Option<&'static str>,
+    ) -> Self {
+        let (lints, doc) = parse_config_field_doc(doc_comment)
+            .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
+
+        Self {
+            name: to_kebab(name),
+            lints,
+            doc,
+            config_type,
+            default,
+            deprecation_reason,
+        }
+    }
+}
+
+fn collect_configs() -> Vec<ClippyConfiguration> {
+    crate::utils::conf::metadata::get_configuration_metadata()
+}
+
+/// This parses the field documentation of the config struct.
+///
+/// ```rust, ignore
+/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
+/// ```
+///
+/// Would yield:
+/// ```rust, ignore
+/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
+/// ```
+fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
+    const DOC_START: &str = " Lint: ";
+    if_chain! {
+        if doc_comment.starts_with(DOC_START);
+        if let Some(split_pos) = doc_comment.find('.');
+        then {
+            let mut doc_comment = doc_comment.to_string();
+            let documentation = doc_comment.split_off(split_pos);
+
+            doc_comment.make_ascii_lowercase();
+            let lints: Vec<String> = doc_comment.split_off(DOC_START.len()).split(", ").map(str::to_string).collect();
+
+            Some((lints, documentation))
+        } else {
+            None
+        }
+    }
+}
+
+/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
+fn to_kebab(config_name: &str) -> String {
+    config_name.replace('_', "-")
+}
+
+impl fmt::Display for ClippyConfiguration {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            CONFIGURATION_VALUE_TEMPLATE!(),
+            name = self.name,
+            ty = self.config_type,
+            doc = self.doc,
+            default = self.default
+        )
+    }
+}
+
+// ==================================================================
+// Lint pass
+// ==================================================================
 impl<'hir> LateLintPass<'hir> for MetadataCollector {
     /// Collecting lint declarations like:
     /// ```rust, ignore
@@ -225,23 +379,48 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
     /// }
     /// ```
     fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) {
-        if_chain! {
-            // item validation
-            if let ItemKind::Static(ref ty, Mutability::Not, _) = item.kind;
-            if is_lint_ref_type(cx, ty);
-            // blacklist check
-            let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
-            if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
-            // metadata extraction
-            if let Some(group) = get_lint_group_or_lint(cx, &lint_name, item);
-            if let Some(docs) = extract_attr_docs_or_lint(cx, item);
-            then {
-                self.lints.push(LintMetadata::new(
-                    lint_name,
-                    SerializableSpan::from_item(cx, item),
-                    group,
-                    docs,
-                ));
+        if let ItemKind::Static(ty, Mutability::Not, _) = item.kind {
+            // Normal lint
+            if_chain! {
+                // item validation
+                if is_lint_ref_type(cx, ty);
+                // blacklist check
+                let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
+                if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
+                // metadata extraction
+                if let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item);
+                if let Some(mut docs) = extract_attr_docs_or_lint(cx, item);
+                then {
+                    if let Some(configuration_section) = self.get_lint_configs(&lint_name) {
+                        docs.push_str(&configuration_section);
+                    }
+
+                    self.lints.push(LintMetadata::new(
+                        lint_name,
+                        SerializableSpan::from_item(cx, item),
+                        group,
+                        level,
+                        docs,
+                    ));
+                }
+            }
+
+            if_chain! {
+                if is_deprecated_lint(cx, ty);
+                // blacklist check
+                let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
+                if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
+                // Metadata the little we can get from a deprecated lint
+                if let Some(docs) = extract_attr_docs_or_lint(cx, item);
+                then {
+                    self.lints.push(LintMetadata::new(
+                        lint_name,
+                        SerializableSpan::from_item(cx, item),
+                        DEPRECATED_LINT_GROUP_STR.to_string(),
+                        DEPRECATED_LINT_LEVEL,
+                        docs,
+                    ));
+                }
             }
         }
     }
@@ -268,7 +447,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
                 // - src/misc.rs:734:9
                 // - src/methods/mod.rs:3545:13
                 // - src/methods/mod.rs:3496:13
-                // We are basically unable to resolve the lint name it self.
+                // We are basically unable to resolve the lint name itself.
                 return;
             }
 
@@ -310,7 +489,7 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
         .hir()
         .attrs(item.hir_id())
         .iter()
-        .filter_map(|ref x| x.doc_str().map(|sym| sym.as_str().to_string()))
+        .filter_map(|x| x.doc_str().map(|sym| sym.as_str().to_string()))
         .reduce(|mut acc, sym| {
             acc.push_str(&sym);
             acc.push('\n');
@@ -318,15 +497,32 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
         })
 }
 
-fn get_lint_group_or_lint(cx: &LateContext<'_>, lint_name: &str, item: &'hir Item<'_>) -> Option<String> {
+fn get_lint_group_and_level_or_lint(
+    cx: &LateContext<'_>,
+    lint_name: &str,
+    item: &'hir Item<'_>,
+) -> Option<(String, &'static str)> {
     let result = cx.lint_store.check_lint_name(lint_name, Some(sym::clippy));
     if let CheckLintNameResult::Tool(Ok(lint_lst)) = result {
-        get_lint_group(cx, lint_lst[0])
-            .or_else(|| {
-                lint_collection_error_item(cx, item, "Unable to determine lint group");
+        if let Some(group) = get_lint_group(cx, lint_lst[0]) {
+            if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) {
+                return None;
+            }
+
+            if let Some(level) = get_lint_level_from_group(&group) {
+                Some((group, level))
+            } else {
+                lint_collection_error_item(
+                    cx,
+                    item,
+                    &format!("Unable to determine lint level for found group `{}`", group),
+                );
                 None
-            })
-            .filter(|group| !EXCLUDED_LINT_GROUPS.contains(&group.as_str()))
+            }
+        } else {
+            lint_collection_error_item(cx, item, "Unable to determine lint group");
+            None
+        }
     } else {
         lint_collection_error_item(cx, item, "Unable to find lint in lint_store");
         None
@@ -339,14 +535,31 @@ fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option<String> {
             continue;
         }
 
-        if lints.iter().any(|x| *x == lint_id) {
-            return Some((*group_name).to_string());
+        if lints.iter().any(|group_lint| *group_lint == lint_id) {
+            let group = group_name.strip_prefix(CLIPPY_LINT_GROUP_PREFIX).unwrap_or(group_name);
+            return Some((*group).to_string());
         }
     }
 
     None
 }
 
+fn get_lint_level_from_group(lint_group: &str) -> Option<&'static str> {
+    DEFAULT_LINT_LEVELS
+        .iter()
+        .find_map(|(group_name, group_level)| (*group_name == lint_group).then(|| *group_level))
+}
+
+fn is_deprecated_lint(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
+    if let hir::TyKind::Path(ref path) = ty.kind {
+        if let hir::def::Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, ty.hir_id) {
+            return match_def_path(cx, def_id, &DEPRECATED_LINT_TYPE);
+        }
+    }
+
+    false
+}
+
 // ==================================================================
 // Lint emission
 // ==================================================================
@@ -383,7 +596,7 @@ fn extract_emission_info<'hir>(
     let mut multi_part = false;
 
     for arg in args {
-        let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(&arg));
+        let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(arg));
 
         if match_type(cx, arg_ty, &paths::LINT) {
             // If we found the lint arg, extract the lint name
@@ -458,7 +671,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> {
             if let ExprKind::Path(qpath) = &expr.kind;
             if let QPath::Resolved(_, path) = qpath;
 
-            let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr));
+            let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
             if match_type(self.cx, expr_ty, &paths::LINT);
             then {
                 if let hir::def::Res::Def(DefKind::Static, _) = path.res {
@@ -517,7 +730,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
     }
 
     fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
-        let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr));
+        let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr));
 
         if_chain! {
             if match_type(self.cx, expr_ty, &paths::APPLICABILITY);
@@ -605,7 +818,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> {
                     .any(|func_path| match_function_call(self.cx, fn_expr, func_path).is_some());
                 if found_function {
                     // These functions are all multi part suggestions
-                    self.add_single_span_suggestion()
+                    self.add_single_span_suggestion();
                 }
             },
             ExprKind::MethodCall(path, _path_span, arg, _arg_span) => {
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index febd4b6ff7b..1d5b7c98d31 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -1,5 +1,5 @@
-use crate::consts::{constant, Constant};
 use crate::rustc_target::abi::LayoutOf;
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher;
 use clippy_utils::source::snippet_with_applicability;
diff --git a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
index ec209b30951..3ab68df2b6d 100644
--- a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
+++ b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for VerboseFileReads {
                 "use of `File::read_to_string`",
                 None,
                 "consider using `fs::read_to_string` instead",
-            )
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 7e962472c07..5229a705865 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -279,8 +279,15 @@ impl EarlyLintPass for Write {
             span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`");
             self.lint_println_empty_string(cx, mac);
         } else if mac.path == sym!(write) {
-            if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), true) {
+            if let (Some(fmt_str), dest) = self.check_tts(cx, mac.args.inner_tokens(), true) {
                 if check_newlines(&fmt_str) {
+                    let (nl_span, only_nl) = newline_span(&fmt_str);
+                    let nl_span = match (dest, only_nl) {
+                        // Special case of `write!(buf, "\n")`: Mark everything from the end of
+                        // `buf` for removal so no trailing comma [`writeln!(buf, )`] remains.
+                        (Some(dest_expr), true) => Span::new(dest_expr.span.hi(), nl_span.hi(), nl_span.ctxt()),
+                        _ => nl_span,
+                    };
                     span_lint_and_then(
                         cx,
                         WRITE_WITH_NEWLINE,
@@ -289,14 +296,11 @@ impl EarlyLintPass for Write {
                         |err| {
                             err.multipart_suggestion(
                                 "use `writeln!()` instead",
-                                vec![
-                                    (mac.path.span, String::from("writeln")),
-                                    (newline_span(&fmt_str), String::new()),
-                                ],
+                                vec![(mac.path.span, String::from("writeln")), (nl_span, String::new())],
                                 Applicability::MachineApplicable,
                             );
                         },
-                    )
+                    );
                 }
             }
         } else if mac.path == sym!(writeln) {
@@ -329,12 +333,13 @@ impl EarlyLintPass for Write {
 
 /// Given a format string that ends in a newline and its span, calculates the span of the
 /// newline, or the format string itself if the format string consists solely of a newline.
-fn newline_span(fmtstr: &StrLit) -> Span {
+/// Return this and a boolean indicating whether it only consisted of a newline.
+fn newline_span(fmtstr: &StrLit) -> (Span, bool) {
     let sp = fmtstr.span;
     let contents = &fmtstr.symbol.as_str();
 
     if *contents == r"\n" {
-        return sp;
+        return (sp, true);
     }
 
     let newline_sp_hi = sp.hi()
@@ -351,7 +356,7 @@ fn newline_span(fmtstr: &StrLit) -> Span {
         panic!("expected format string to contain a newline");
     };
 
-    sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi)
+    (sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi), false)
 }
 
 /// Stores a list of replacement spans for each argument, but only if all the replacements used an
@@ -613,7 +618,7 @@ impl Write {
                     |err| {
                         err.multipart_suggestion(
                             &format!("use `{}!` instead", suggested),
-                            vec![(mac.path.span, suggested), (newline_span(&fmt_str), String::new())],
+                            vec![(mac.path.span, suggested), (newline_span(&fmt_str).0, String::new())],
                             Applicability::MachineApplicable,
                         );
                     },
diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
index 350b1cf25ff..a1ea743ba80 100644
--- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
@@ -1,4 +1,4 @@
-use crate::consts::{constant_simple, Constant};
+use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
 use if_chain::if_chain;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 0a1d4e11142..93ed3b18400 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -14,6 +14,7 @@ unicode-normalization = "0.1"
 rustc-semver="1.1.0"
 
 [features]
+deny-warnings = []
 internal-lints = []
 metadata-collector-lint = []
 
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index c0584e1e226..0318c483959 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -115,7 +115,7 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'
     for attr in get_attr(sess, attrs, name) {
         if let Some(ref value) = attr.value_str() {
             if let Ok(value) = FromStr::from_str(&value.as_str()) {
-                f(value)
+                f(value);
             } else {
                 sess.span_err(attr.span, "not a number");
             }
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 2a305d8bcbe..0d7fdeeb920 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -229,25 +229,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
     pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
         match e.kind {
             ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
-            ExprKind::Block(ref block, _) => self.block(block),
+            ExprKind::Block(block, _) => self.block(block),
             ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))),
-            ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec),
-            ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple),
-            ExprKind::Repeat(ref value, _) => {
+            ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),
+            ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
+            ExprKind::Repeat(value, _) => {
                 let n = match self.typeck_results.expr_ty(e).kind() {
                     ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?,
                     _ => span_bug!(e.span, "typeck error"),
                 };
                 self.expr(value).map(|v| Constant::Repeat(Box::new(v), n))
             },
-            ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op {
+            ExprKind::Unary(op, operand) => self.expr(operand).and_then(|o| match op {
                 UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)),
                 UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)),
                 UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }),
             }),
-            ExprKind::If(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
-            ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right),
-            ExprKind::Call(ref callee, ref args) => {
+            ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise),
+            ExprKind::Binary(op, left, right) => self.binop(op, left, right),
+            ExprKind::Call(callee, args) => {
                 // We only handle a few const functions for now.
                 if_chain! {
                     if args.is_empty();
@@ -273,8 +273,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                     }
                 }
             },
-            ExprKind::Index(ref arr, ref index) => self.index(arr, index),
-            ExprKind::AddrOf(_, _, ref inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
+            ExprKind::Index(arr, index) => self.index(arr, index),
+            ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))),
             // TODO: add other expressions.
             _ => None,
         }
@@ -349,7 +349,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
                     )
                     .ok()
                     .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?;
-                let result = miri_to_const(&result);
+                let result = miri_to_const(result);
                 if result.is_some() {
                     self.needed_resolution = true;
                 }
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index a4efae54894..7c94474cb35 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -167,7 +167,7 @@ pub fn span_lint_hir_and_then(
     cx: &LateContext<'_>,
     lint: &'static Lint,
     hir_id: HirId,
-    sp: Span,
+    sp: impl Into<MultiSpan>,
     msg: &str,
     f: impl FnOnce(&mut DiagnosticBuilder<'_>),
 ) {
@@ -223,7 +223,7 @@ pub fn multispan_sugg<I>(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg:
 where
     I: IntoIterator<Item = (Span, String)>,
 {
-    multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg)
+    multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg);
 }
 
 /// Create a suggestion made from several `span → replacement`.
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 0c0e4d3b4ce..8be36756b33 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -58,7 +58,7 @@ pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
     }
 
     match expr.kind {
-        hir::ExprKind::Call(ref path, ref args)
+        hir::ExprKind::Call(path, args)
             if matches!(
                 path.kind,
                 hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _))
@@ -70,7 +70,7 @@ pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> {
                 limits: ast::RangeLimits::Closed,
             })
         },
-        hir::ExprKind::Struct(ref path, ref fields, None) => match path {
+        hir::ExprKind::Struct(path, fields, None) => match path {
             hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range {
                 start: None,
                 end: None,
@@ -112,7 +112,7 @@ pub fn is_from_for_desugar(local: &hir::Local<'_>) -> bool {
     // }
     // ```
     if_chain! {
-        if let Some(ref expr) = local.init;
+        if let Some(expr) = local.init;
         if let hir::ExprKind::Match(_, _, hir::MatchSource::ForLoopDesugar) = expr.kind;
         then {
             return true;
@@ -140,14 +140,14 @@ pub fn for_loop<'tcx>(
     expr: &'tcx hir::Expr<'tcx>,
 ) -> Option<(&hir::Pat<'_>, &'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>, Span)> {
     if_chain! {
-        if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
-        if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind;
+        if let hir::ExprKind::Match(iterexpr, arms, hir::MatchSource::ForLoopDesugar) = expr.kind;
+        if let hir::ExprKind::Call(_, iterargs) = iterexpr.kind;
         if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none();
-        if let hir::ExprKind::Loop(ref block, ..) = arms[0].body.kind;
+        if let hir::ExprKind::Loop(block, ..) = arms[0].body.kind;
         if block.expr.is_none();
         if let [ _, _, ref let_stmt, ref body ] = *block.stmts;
-        if let hir::StmtKind::Local(ref local) = let_stmt.kind;
-        if let hir::StmtKind::Expr(ref expr) = body.kind;
+        if let hir::StmtKind::Local(local) = let_stmt.kind;
+        if let hir::StmtKind::Expr(expr) = body.kind;
         then {
             return Some((&*local.pat, &iterargs[0], expr, arms[0].span));
         }
@@ -182,7 +182,7 @@ pub enum VecArgs<'a> {
 /// from `vec!`.
 pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<VecArgs<'e>> {
     if_chain! {
-        if let hir::ExprKind::Call(ref fun, ref args) = expr.kind;
+        if let hir::ExprKind::Call(fun, args) = expr.kind;
         if let hir::ExprKind::Path(ref qpath) = fun.kind;
         if is_expn_of(fun.span, "vec").is_some();
         if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
@@ -194,8 +194,8 @@ pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<Ve
             else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
                 // `vec![a, b, c]` case
                 if_chain! {
-                    if let hir::ExprKind::Box(ref boxed) = args[0].kind;
-                    if let hir::ExprKind::Array(ref args) = boxed.kind;
+                    if let hir::ExprKind::Box(boxed) = args[0].kind;
+                    if let hir::ExprKind::Array(args) = boxed.kind;
                     then {
                         return Some(VecArgs::Vec(&*args));
                     }
@@ -227,7 +227,7 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx
     /// compared
     fn ast_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option<Vec<&Expr<'_>>> {
         if_chain! {
-            if let ExprKind::Match(ref headerexpr, _, _) = &matchblock_expr.kind;
+            if let ExprKind::Match(headerexpr, _, _) = &matchblock_expr.kind;
             if let ExprKind::Tup([lhs, rhs]) = &headerexpr.kind;
             if let ExprKind::AddrOf(BorrowKind::Ref, _, lhs) = lhs.kind;
             if let ExprKind::AddrOf(BorrowKind::Ref, _, rhs) = rhs.kind;
@@ -238,12 +238,12 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx
         None
     }
 
-    if let ExprKind::Block(ref block, _) = e.kind {
+    if let ExprKind::Block(block, _) = e.kind {
         if block.stmts.len() == 1 {
-            if let StmtKind::Semi(ref matchexpr) = block.stmts.get(0)?.kind {
+            if let StmtKind::Semi(matchexpr) = block.stmts.get(0)?.kind {
                 // macros with unique arg: `{debug_}assert!` (e.g., `debug_assert!(some_condition)`)
                 if_chain! {
-                    if let ExprKind::If(ref clause, _, _)  = matchexpr.kind;
+                    if let ExprKind::If(clause, _, _)  = matchexpr.kind;
                     if let ExprKind::Unary(UnOp::Not, condition) = clause.kind;
                     then {
                         return Some(vec![condition]);
@@ -252,8 +252,8 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx
 
                 // debug macros with two args: `debug_assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
                 if_chain! {
-                    if let ExprKind::Block(ref matchblock,_) = matchexpr.kind;
-                    if let Some(ref matchblock_expr) = matchblock.expr;
+                    if let ExprKind::Block(matchblock,_) = matchexpr.kind;
+                    if let Some(matchblock_expr) = matchblock.expr;
                     then {
                         return ast_matchblock(matchblock_expr);
                     }
@@ -261,7 +261,7 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx
             }
         } else if let Some(matchblock_expr) = block.expr {
             // macros with two args: `assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
-            return ast_matchblock(&matchblock_expr);
+            return ast_matchblock(matchblock_expr);
         }
     }
     None
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 3b01158acd9..a21ad42c061 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -2,20 +2,19 @@ use crate::consts::{constant_context, constant_simple};
 use crate::differing_macro_contexts;
 use crate::source::snippet_opt;
 use rustc_ast::ast::InlineAsmTemplatePiece;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::fx::FxHasher;
 use rustc_hir::def::Res;
 use rustc_hir::HirIdMap;
 use rustc_hir::{
-    BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprField, ExprKind, FnRetTy, GenericArg,
-    GenericArgs, Guard, HirId, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path,
-    PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding,
+    BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
+    InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
+    StmtKind, Ty, TyKind, TypeBinding,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::LateContext;
-use rustc_middle::ich::StableHashingContextProvider;
 use rustc_middle::ty::TypeckResults;
 use rustc_span::Symbol;
-use std::hash::Hash;
+use std::hash::{Hash, Hasher};
 
 /// Type used to check whether two ast are the same. This is different from the
 /// operator
@@ -95,12 +94,12 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> {
 impl HirEqInterExpr<'_, '_, '_> {
     pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
         match (&left.kind, &right.kind) {
-            (&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => {
+            (&StmtKind::Local(l), &StmtKind::Local(r)) => {
                 // This additional check ensures that the type of the locals are equivalent even if the init
                 // expression or type have some inferred parts.
                 if let Some(typeck) = self.inner.maybe_typeck_results {
-                    let l_ty = typeck.pat_ty(&l.pat);
-                    let r_ty = typeck.pat_ty(&r.pat);
+                    let l_ty = typeck.pat_ty(l.pat);
+                    let r_ty = typeck.pat_ty(r.pat);
                     if !rustc_middle::ty::TyS::same_type(l_ty, r_ty) {
                         return false;
                     }
@@ -110,11 +109,9 @@ impl HirEqInterExpr<'_, '_, '_> {
                 // these only get added if the init and type is equal.
                 both(&l.init, &r.init, |l, r| self.eq_expr(l, r))
                     && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r))
-                    && self.eq_pat(&l.pat, &r.pat)
-            },
-            (&StmtKind::Expr(ref l), &StmtKind::Expr(ref r)) | (&StmtKind::Semi(ref l), &StmtKind::Semi(ref r)) => {
-                self.eq_expr(l, r)
+                    && self.eq_pat(l.pat, r.pat)
             },
+            (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r),
             _ => false,
         }
     }
@@ -165,12 +162,18 @@ impl HirEqInterExpr<'_, '_, '_> {
                 left.eq(right)
             },
             _ => {
-                over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r))
+                over(left.stmts, right.stmts, |l, r| self.eq_stmt(l, r))
                     && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r))
             },
         }
     }
 
+    pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
+        let cx = self.inner.cx;
+        let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
+        eval_const(left) == eval_const(right)
+    }
+
     #[allow(clippy::similar_names)]
     pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
         if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) {
@@ -192,20 +195,20 @@ impl HirEqInterExpr<'_, '_, '_> {
             &reduce_exprkind(self.inner.cx, &left.kind),
             &reduce_exprkind(self.inner.cx, &right.kind),
         ) {
-            (&ExprKind::AddrOf(lb, l_mut, ref le), &ExprKind::AddrOf(rb, r_mut, ref re)) => {
+            (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => {
                 lb == rb && l_mut == r_mut && self.eq_expr(le, re)
             },
             (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
                 both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
             },
-            (&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => {
+            (&ExprKind::Assign(ll, lr, _), &ExprKind::Assign(rl, rr, _)) => {
                 self.inner.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
             },
-            (&ExprKind::AssignOp(ref lo, ref ll, ref lr), &ExprKind::AssignOp(ref ro, ref rl, ref rr)) => {
+            (&ExprKind::AssignOp(ref lo, ll, lr), &ExprKind::AssignOp(ref ro, rl, rr)) => {
                 self.inner.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
             },
-            (&ExprKind::Block(ref l, _), &ExprKind::Block(ref r, _)) => self.eq_block(l, r),
-            (&ExprKind::Binary(l_op, ref ll, ref lr), &ExprKind::Binary(r_op, ref rl, ref rr)) => {
+            (&ExprKind::Block(l, _), &ExprKind::Block(r, _)) => self.eq_block(l, r),
+            (&ExprKind::Binary(l_op, ll, lr), &ExprKind::Binary(r_op, rl, rr)) => {
                 l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
                     || swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
                         l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
@@ -215,58 +218,50 @@ impl HirEqInterExpr<'_, '_, '_> {
                 both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name)
                     && both(le, re, |l, r| self.eq_expr(l, r))
             },
-            (&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r),
+            (&ExprKind::Box(l), &ExprKind::Box(r)) => self.eq_expr(l, r),
             (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
                 self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
             },
-            (&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt))
-            | (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => {
+            (&ExprKind::Cast(lx, lt), &ExprKind::Cast(rx, rt)) | (&ExprKind::Type(lx, lt), &ExprKind::Type(rx, rt)) => {
                 self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
             },
-            (&ExprKind::Field(ref l_f_exp, ref l_f_ident), &ExprKind::Field(ref r_f_exp, ref r_f_ident)) => {
+            (&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => {
                 l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp)
             },
-            (&ExprKind::Index(ref la, ref li), &ExprKind::Index(ref ra, ref ri)) => {
-                self.eq_expr(la, ra) && self.eq_expr(li, ri)
-            },
-            (&ExprKind::If(ref lc, ref lt, ref le), &ExprKind::If(ref rc, ref rt, ref re)) => {
+            (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
+            (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
                 self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
             },
             (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node,
-            (&ExprKind::Loop(ref lb, ref ll, ref lls, _), &ExprKind::Loop(ref rb, ref rl, ref rls, _)) => {
+            (&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
                 lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name)
             },
-            (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => {
+            (&ExprKind::Match(le, la, ref ls), &ExprKind::Match(re, ra, ref rs)) => {
                 ls == rs
                     && self.eq_expr(le, re)
                     && over(la, ra, |l, r| {
-                        self.eq_pat(&l.pat, &r.pat)
+                        self.eq_pat(l.pat, r.pat)
                             && both(&l.guard, &r.guard, |l, r| self.eq_guard(l, r))
-                            && self.eq_expr(&l.body, &r.body)
+                            && self.eq_expr(l.body, r.body)
                     })
             },
             (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
                 self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
             },
-            (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => {
-                let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(ll_id.body));
-                let ll = celcx.expr(&self.inner.cx.tcx.hir().body(ll_id.body).value);
-                let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(rl_id.body));
-                let rl = celcx.expr(&self.inner.cx.tcx.hir().body(rl_id.body).value);
-
-                self.eq_expr(le, re) && ll == rl
+            (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => {
+                self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body)
             },
             (&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
             (&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
-            (&ExprKind::Struct(ref l_path, ref lf, ref lo), &ExprKind::Struct(ref r_path, ref rf, ref ro)) => {
+            (&ExprKind::Struct(l_path, lf, ref lo), &ExprKind::Struct(r_path, rf, ref ro)) => {
                 self.eq_qpath(l_path, r_path)
                     && both(lo, ro, |l, r| self.eq_expr(l, r))
                     && over(lf, rf, |l, r| self.eq_expr_field(l, r))
             },
             (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
-            (&ExprKind::Unary(l_op, ref le), &ExprKind::Unary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re),
+            (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
             (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
-            (&ExprKind::DropTemps(ref le), &ExprKind::DropTemps(ref re)) => self.eq_expr(le, re),
+            (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
             _ => false,
         };
         is_eq || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right))
@@ -277,7 +272,7 @@ impl HirEqInterExpr<'_, '_, '_> {
     }
 
     fn eq_expr_field(&mut self, left: &ExprField<'_>, right: &ExprField<'_>) -> bool {
-        left.ident.name == right.ident.name && self.eq_expr(&left.expr, &right.expr)
+        left.ident.name == right.ident.name && self.eq_expr(left.expr, right.expr)
     }
 
     fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool {
@@ -290,6 +285,7 @@ impl HirEqInterExpr<'_, '_, '_> {
 
     fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool {
         match (left, right) {
+            (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body),
             (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt),
             (GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty),
             _ => false,
@@ -308,11 +304,11 @@ impl HirEqInterExpr<'_, '_, '_> {
     /// Checks whether two patterns are the same.
     fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
         match (&left.kind, &right.kind) {
-            (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r),
-            (&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => {
+            (&PatKind::Box(l), &PatKind::Box(r)) => self.eq_pat(l, r),
+            (&PatKind::Struct(ref lp, la, ..), &PatKind::Struct(ref rp, ra, ..)) => {
                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat_field(l, r))
             },
-            (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => {
+            (&PatKind::TupleStruct(ref lp, la, ls), &PatKind::TupleStruct(ref rp, ra, rs)) => {
                 self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
             },
             (&PatKind::Binding(lb, li, _, ref lp), &PatKind::Binding(rb, ri, _, ref rp)) => {
@@ -323,15 +319,13 @@ impl HirEqInterExpr<'_, '_, '_> {
                 eq
             },
             (&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r),
-            (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r),
-            (&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => {
-                ls == rs && over(l, r, |l, r| self.eq_pat(l, r))
-            },
+            (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r),
+            (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
             (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
                 both(ls, rs, |a, b| self.eq_expr(a, b)) && both(le, re, |a, b| self.eq_expr(a, b)) && (li == ri)
             },
-            (&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re),
-            (&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => {
+            (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
+            (&PatKind::Slice(ls, ref li, le), &PatKind::Slice(rs, ref ri, re)) => {
                 over(ls, rs, |l, r| self.eq_pat(l, r))
                     && over(le, re, |l, r| self.eq_pat(l, r))
                     && both(li, ri, |l, r| self.eq_pat(l, r))
@@ -344,10 +338,10 @@ impl HirEqInterExpr<'_, '_, '_> {
     #[allow(clippy::similar_names)]
     fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool {
         match (left, right) {
-            (&QPath::Resolved(ref lty, ref lpath), &QPath::Resolved(ref rty, ref rpath)) => {
+            (&QPath::Resolved(ref lty, lpath), &QPath::Resolved(ref rty, rpath)) => {
                 both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
             },
-            (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => {
+            (&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => {
                 self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
             },
             (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => llang_item == rlang_item,
@@ -359,14 +353,14 @@ impl HirEqInterExpr<'_, '_, '_> {
         match (left.res, right.res) {
             (Res::Local(l), Res::Local(r)) => l == r || self.locals.get(&l) == Some(&r),
             (Res::Local(_), _) | (_, Res::Local(_)) => false,
-            _ => over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)),
+            _ => over(left.segments, right.segments, |l, r| self.eq_path_segment(l, r)),
         }
     }
 
     fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool {
         if !(left.parenthesized || right.parenthesized) {
-            over(&left.args, &right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
-                && over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r))
+            over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work
+                && over(left.bindings, right.bindings, |l, r| self.eq_type_binding(l, r))
         } else if left.parenthesized && right.parenthesized {
             over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r))
                 && both(&Some(&left.bindings[0].ty()), &Some(&right.bindings[0].ty()), |l, r| {
@@ -390,12 +384,9 @@ impl HirEqInterExpr<'_, '_, '_> {
     #[allow(clippy::similar_names)]
     fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
         match (&left.kind, &right.kind) {
-            (&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec),
-            (&TyKind::Array(ref lt, ref ll_id), &TyKind::Array(ref rt, ref rl_id)) => {
-                let cx = self.inner.cx;
-                let eval_const =
-                    |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
-                self.eq_ty(lt, rt) && eval_const(ll_id.body) == eval_const(rl_id.body)
+            (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
+            (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => {
+                self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body)
             },
             (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
                 l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
@@ -404,14 +395,14 @@ impl HirEqInterExpr<'_, '_, '_> {
                 l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty)
             },
             (&TyKind::Path(ref l), &TyKind::Path(ref r)) => self.eq_qpath(l, r),
-            (&TyKind::Tup(ref l), &TyKind::Tup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)),
+            (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
             (&TyKind::Infer, &TyKind::Infer) => true,
             _ => false,
         }
     }
 
     fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool {
-        left.ident.name == right.ident.name && self.eq_ty(&left.ty(), &right.ty())
+        left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty())
     }
 }
 
@@ -519,7 +510,7 @@ pub struct SpanlessHash<'a, 'tcx> {
     /// Context used to evaluate constant expressions.
     cx: &'a LateContext<'tcx>,
     maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>,
-    s: StableHasher,
+    s: FxHasher,
 }
 
 impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
@@ -527,7 +518,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         Self {
             cx,
             maybe_typeck_results: cx.maybe_typeck_results(),
-            s: StableHasher::new(),
+            s: FxHasher::default(),
         }
     }
 
@@ -540,17 +531,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             self.hash_stmt(s);
         }
 
-        if let Some(ref e) = b.expr {
+        if let Some(e) = b.expr {
             self.hash_expr(e);
         }
 
-        match b.rules {
-            BlockCheckMode::DefaultBlock => 0,
-            BlockCheckMode::UnsafeBlock(_) => 1,
-            BlockCheckMode::PushUnsafeBlock(_) => 2,
-            BlockCheckMode::PopUnsafeBlock(_) => 3,
-        }
-        .hash(&mut self.s);
+        std::mem::discriminant(&b.rules).hash(&mut self.s);
     }
 
     #[allow(clippy::many_single_char_names, clippy::too_many_lines)]
@@ -561,21 +546,16 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
 
         // const hashing may result in the same hash as some unrelated node, so add a sort of
         // discriminant depending on which path we're choosing next
-        simple_const.is_some().hash(&mut self.s);
-
-        if let Some(e) = simple_const {
-            return e.hash(&mut self.s);
+        simple_const.hash(&mut self.s);
+        if simple_const.is_some() {
+            return;
         }
 
         std::mem::discriminant(&e.kind).hash(&mut self.s);
 
         match e.kind {
-            ExprKind::AddrOf(kind, m, ref e) => {
-                match kind {
-                    BorrowKind::Ref => 0,
-                    BorrowKind::Raw => 1,
-                }
-                .hash(&mut self.s);
+            ExprKind::AddrOf(kind, m, e) => {
+                std::mem::discriminant(&kind).hash(&mut self.s);
                 m.hash(&mut self.s);
                 self.hash_expr(e);
             },
@@ -584,22 +564,20 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_name(i.ident.name);
                 }
             },
-            ExprKind::Assign(ref l, ref r, _) => {
+            ExprKind::Assign(l, r, _) => {
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
-            ExprKind::AssignOp(ref o, ref l, ref r) => {
-                o.node
-                    .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+            ExprKind::AssignOp(ref o, l, r) => {
+                std::mem::discriminant(&o.node).hash(&mut self.s);
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
-            ExprKind::Block(ref b, _) => {
+            ExprKind::Block(b, _) => {
                 self.hash_block(b);
             },
-            ExprKind::Binary(op, ref l, ref r) => {
-                op.node
-                    .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+            ExprKind::Binary(op, l, r) => {
+                std::mem::discriminant(&op.node).hash(&mut self.s);
                 self.hash_expr(l);
                 self.hash_expr(r);
             },
@@ -607,39 +585,35 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 if let Some(i) = i.label {
                     self.hash_name(i.ident.name);
                 }
-                if let Some(ref j) = *j {
+                if let Some(j) = *j {
                     self.hash_expr(&*j);
                 }
             },
-            ExprKind::Box(ref e) | ExprKind::DropTemps(ref e) | ExprKind::Yield(ref e, _) => {
+            ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => {
                 self.hash_expr(e);
             },
-            ExprKind::Call(ref fun, args) => {
+            ExprKind::Call(fun, args) => {
                 self.hash_expr(fun);
                 self.hash_exprs(args);
             },
-            ExprKind::Cast(ref e, ref ty) | ExprKind::Type(ref e, ref ty) => {
+            ExprKind::Cast(e, ty) | ExprKind::Type(e, ty) => {
                 self.hash_expr(e);
                 self.hash_ty(ty);
             },
             ExprKind::Closure(cap, _, eid, _, _) => {
-                match cap {
-                    CaptureBy::Value => 0,
-                    CaptureBy::Ref => 1,
-                }
-                .hash(&mut self.s);
+                std::mem::discriminant(&cap).hash(&mut self.s);
                 // closures inherit TypeckResults
                 self.hash_expr(&self.cx.tcx.hir().body(eid).value);
             },
-            ExprKind::Field(ref e, ref f) => {
+            ExprKind::Field(e, ref f) => {
                 self.hash_expr(e);
                 self.hash_name(f.name);
             },
-            ExprKind::Index(ref a, ref i) => {
+            ExprKind::Index(a, i) => {
                 self.hash_expr(a);
                 self.hash_expr(i);
             },
-            ExprKind::InlineAsm(ref asm) => {
+            ExprKind::InlineAsm(asm) => {
                 for piece in asm.template {
                     match piece {
                         InlineAsmTemplatePiece::String(s) => s.hash(&mut self.s),
@@ -694,22 +668,20 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             ExprKind::Lit(ref l) => {
                 l.node.hash(&mut self.s);
             },
-            ExprKind::Loop(ref b, ref i, ..) => {
+            ExprKind::Loop(b, ref i, ..) => {
                 self.hash_block(b);
                 if let Some(i) = *i {
                     self.hash_name(i.ident.name);
                 }
             },
-            ExprKind::If(ref cond, ref then, ref else_opt) => {
-                let c: fn(_, _, _) -> _ = ExprKind::If;
-                c.hash(&mut self.s);
+            ExprKind::If(cond, then, ref else_opt) => {
                 self.hash_expr(cond);
-                self.hash_expr(&**then);
-                if let Some(ref e) = *else_opt {
+                self.hash_expr(then);
+                if let Some(e) = *else_opt {
                     self.hash_expr(e);
                 }
             },
-            ExprKind::Match(ref e, arms, ref s) => {
+            ExprKind::Match(e, arms, ref s) => {
                 self.hash_expr(e);
 
                 for arm in arms {
@@ -717,39 +689,39 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     if let Some(ref e) = arm.guard {
                         self.hash_guard(e);
                     }
-                    self.hash_expr(&arm.body);
+                    self.hash_expr(arm.body);
                 }
 
                 s.hash(&mut self.s);
             },
-            ExprKind::MethodCall(ref path, ref _tys, args, ref _fn_span) => {
+            ExprKind::MethodCall(path, ref _tys, args, ref _fn_span) => {
                 self.hash_name(path.ident.name);
                 self.hash_exprs(args);
             },
             ExprKind::ConstBlock(ref l_id) => {
                 self.hash_body(l_id.body);
             },
-            ExprKind::Repeat(ref e, ref l_id) => {
+            ExprKind::Repeat(e, ref l_id) => {
                 self.hash_expr(e);
                 self.hash_body(l_id.body);
             },
             ExprKind::Ret(ref e) => {
-                if let Some(ref e) = *e {
+                if let Some(e) = *e {
                     self.hash_expr(e);
                 }
             },
             ExprKind::Path(ref qpath) => {
                 self.hash_qpath(qpath);
             },
-            ExprKind::Struct(ref path, fields, ref expr) => {
+            ExprKind::Struct(path, fields, ref expr) => {
                 self.hash_qpath(path);
 
                 for f in fields {
                     self.hash_name(f.ident.name);
-                    self.hash_expr(&f.expr);
+                    self.hash_expr(f.expr);
                 }
 
-                if let Some(ref e) = *expr {
+                if let Some(e) = *expr {
                     self.hash_expr(e);
                 }
             },
@@ -759,8 +731,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             ExprKind::Array(v) => {
                 self.hash_exprs(v);
             },
-            ExprKind::Unary(lop, ref le) => {
-                lop.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+            ExprKind::Unary(lop, le) => {
+                std::mem::discriminant(&lop).hash(&mut self.s);
                 self.hash_expr(le);
             },
         }
@@ -773,19 +745,19 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
     }
 
     pub fn hash_name(&mut self, n: Symbol) {
-        n.as_str().hash(&mut self.s);
+        n.hash(&mut self.s);
     }
 
     pub fn hash_qpath(&mut self, p: &QPath<'_>) {
         match *p {
-            QPath::Resolved(_, ref path) => {
+            QPath::Resolved(_, path) => {
                 self.hash_path(path);
             },
-            QPath::TypeRelative(_, ref path) => {
+            QPath::TypeRelative(_, path) => {
                 self.hash_name(path.ident.name);
             },
             QPath::LangItem(lang_item, ..) => {
-                lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&lang_item).hash(&mut self.s);
             },
         }
         // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
@@ -795,7 +767,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         std::mem::discriminant(&pat.kind).hash(&mut self.s);
         match pat.kind {
             PatKind::Binding(ann, _, _, pat) => {
-                ann.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&ann).hash(&mut self.s);
                 if let Some(pat) = pat {
                     self.hash_pat(pat);
                 }
@@ -815,11 +787,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 if let Some(e) = e {
                     self.hash_expr(e);
                 }
-                i.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s);
+                std::mem::discriminant(&i).hash(&mut self.s);
             },
-            PatKind::Ref(pat, m) => {
+            PatKind::Ref(pat, mu) => {
                 self.hash_pat(pat);
-                m.hash(&mut self.s);
+                std::mem::discriminant(&mu).hash(&mut self.s);
             },
             PatKind::Slice(l, m, r) => {
                 for pat in l {
@@ -838,7 +810,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_name(f.ident.name);
                     self.hash_pat(f.pat);
                 }
-                e.hash(&mut self.s)
+                e.hash(&mut self.s);
             },
             PatKind::Tuple(pats, e) => {
                 for pat in pats {
@@ -864,6 +836,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             _ => {
                 for seg in path.segments {
                     self.hash_name(seg.ident.name);
+                    self.hash_generic_args(seg.args().args);
                 }
             },
         }
@@ -875,7 +848,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         match &b.kind {
             StmtKind::Local(local) => {
                 self.hash_pat(local.pat);
-                if let Some(ref init) = local.init {
+                if let Some(init) = local.init {
                     self.hash_expr(init);
                 }
             },
@@ -888,7 +861,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
 
     pub fn hash_guard(&mut self, g: &Guard<'_>) {
         match g {
-            Guard::If(ref expr) | Guard::IfLet(_, ref expr) => {
+            Guard::If(expr) | Guard::IfLet(_, expr) => {
                 self.hash_expr(expr);
             },
         }
@@ -921,25 +894,24 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 self.hash_body(anon_const.body);
             },
             TyKind::Ptr(ref mut_ty) => {
-                self.hash_ty(&mut_ty.ty);
+                self.hash_ty(mut_ty.ty);
                 mut_ty.mutbl.hash(&mut self.s);
             },
             TyKind::Rptr(lifetime, ref mut_ty) => {
                 self.hash_lifetime(lifetime);
-                self.hash_ty(&mut_ty.ty);
+                self.hash_ty(mut_ty.ty);
                 mut_ty.mutbl.hash(&mut self.s);
             },
             TyKind::BareFn(bfn) => {
                 bfn.unsafety.hash(&mut self.s);
                 bfn.abi.hash(&mut self.s);
                 for arg in bfn.decl.inputs {
-                    self.hash_ty(&arg);
+                    self.hash_ty(arg);
                 }
+                std::mem::discriminant(&bfn.decl.output).hash(&mut self.s);
                 match bfn.decl.output {
-                    FnRetTy::DefaultReturn(_) => {
-                        ().hash(&mut self.s);
-                    },
-                    FnRetTy::Return(ref ty) => {
+                    FnRetTy::DefaultReturn(_) => {},
+                    FnRetTy::Return(ty) => {
                         self.hash_ty(ty);
                     },
                 }
@@ -950,24 +922,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_ty(ty);
                 }
             },
-            TyKind::Path(ref qpath) => match qpath {
-                QPath::Resolved(ref maybe_ty, ref path) => {
-                    if let Some(ref ty) = maybe_ty {
-                        self.hash_ty(ty);
-                    }
-                    for segment in path.segments {
-                        segment.ident.name.hash(&mut self.s);
-                        self.hash_generic_args(segment.args().args);
-                    }
-                },
-                QPath::TypeRelative(ref ty, ref segment) => {
-                    self.hash_ty(ty);
-                    segment.ident.name.hash(&mut self.s);
-                },
-                QPath::LangItem(lang_item, ..) => {
-                    lang_item.hash(&mut self.s);
-                },
-            },
+            TyKind::Path(ref qpath) => self.hash_qpath(qpath),
             TyKind::OpaqueDef(_, arg_list) => {
                 self.hash_generic_args(arg_list);
             },
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 9ac9500b4eb..769836aaf18 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1,10 +1,16 @@
 #![feature(box_patterns)]
 #![feature(in_band_lifetimes)]
 #![feature(iter_zip)]
-#![cfg_attr(bootstrap, feature(or_patterns))]
 #![feature(rustc_private)]
 #![recursion_limit = "512"]
+#![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)]
+// warn on the same lints as `clippy_lints`
+#![warn(trivial_casts, trivial_numeric_casts)]
+// warn on lints, that are included in `rust-lang/rust`s bootstrap
+#![warn(rust_2018_idioms, unused_lifetimes)]
+// warn on rustc internal lints
+#![warn(rustc::internal)]
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
@@ -57,7 +63,7 @@ use std::hash::BuildHasherDefault;
 
 use if_chain::if_chain;
 use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unhash::UnhashMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -322,7 +328,7 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol)
 
 /// Checks if an expression references a variable of the given name.
 pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
-    if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
+    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
         if let [p] = path.segments {
             return p.ident.name == var;
         }
@@ -332,8 +338,8 @@ pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
 
 pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
     match *path {
-        QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"),
-        QPath::TypeRelative(_, ref seg) => seg,
+        QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
+        QPath::TypeRelative(_, seg) => seg,
         QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"),
     }
 }
@@ -361,8 +367,8 @@ pub fn get_qpath_generic_tys(path: &QPath<'tcx>) -> impl Iterator<Item = &'tcx h
 
 pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
     match *path {
-        QPath::Resolved(_, ref path) => path.segments.get(0),
-        QPath::TypeRelative(_, ref seg) => Some(seg),
+        QPath::Resolved(_, path) => path.segments.get(0),
+        QPath::TypeRelative(_, seg) => Some(seg),
         QPath::LangItem(..) => None,
     }
 }
@@ -382,8 +388,8 @@ pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment
 /// ```
 pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
     match *path {
-        QPath::Resolved(_, ref path) => match_path(path, segments),
-        QPath::TypeRelative(ref ty, ref segment) => match ty.kind {
+        QPath::Resolved(_, path) => match_path(path, segments),
+        QPath::TypeRelative(ty, segment) => match ty.kind {
             TyKind::Path(ref inner_path) => {
                 if let [prefix @ .., end] = segments {
                     if match_qpath(inner_path, prefix) {
@@ -451,7 +457,7 @@ pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
 
 /// If the expression is a path to a local, returns the canonical `HirId` of the local.
 pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
-    if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind {
+    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
         if let Res::Local(id) = path.res {
             return Some(id);
         }
@@ -655,13 +661,13 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec
     let mut matched = Vec::with_capacity(methods.len());
     for method_name in methods.iter().rev() {
         // method chains are stored last -> first
-        if let ExprKind::MethodCall(ref path, _, ref args, _) = current.kind {
+        if let ExprKind::MethodCall(path, _, args, _) = current.kind {
             if path.ident.name.as_str() == *method_name {
                 if args.iter().any(|e| e.span.from_expansion()) {
                     return None;
                 }
-                matched.push(&**args); // build up `matched` backwards
-                current = &args[0] // go to parent expression
+                matched.push(args); // build up `matched` backwards
+                current = &args[0]; // go to parent expression
             } else {
                 return None;
             }
@@ -706,7 +712,7 @@ pub fn get_pat_name(pat: &Pat<'_>) -> Option<Symbol> {
     match pat.kind {
         PatKind::Binding(.., ref spname, _) => Some(spname.name),
         PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
-        PatKind::Box(ref p) | PatKind::Ref(ref p, _) => get_pat_name(&*p),
+        PatKind::Box(p) | PatKind::Ref(p, _) => get_pat_name(&*p),
         _ => None,
     }
 }
@@ -848,13 +854,31 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio
             kind: ImplItemKind::Fn(_, eid),
             ..
         }) => match cx.tcx.hir().body(eid).value.kind {
-            ExprKind::Block(ref block, _) => Some(block),
+            ExprKind::Block(block, _) => Some(block),
             _ => None,
         },
         _ => None,
     })
 }
 
+/// Gets the loop enclosing the given expression, if any.
+pub fn get_enclosing_loop(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+    let map = tcx.hir();
+    for (_, node) in map.parent_iter(expr.hir_id) {
+        match node {
+            Node::Expr(
+                e @ Expr {
+                    kind: ExprKind::Loop(..),
+                    ..
+                },
+            ) => return Some(e),
+            Node::Expr(_) | Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (),
+            _ => break,
+        }
+    }
+    None
+}
+
 /// Gets the parent node if it's an impl block.
 pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> {
     let map = tcx.hir();
@@ -947,7 +971,12 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
             let data = span.ctxt().outer_expn_data();
             let new_span = data.call_site;
 
-            if let ExpnKind::Macro { kind: MacroKind::Bang, name: mac_name, proc_macro: _ } = data.kind {
+            if let ExpnKind::Macro {
+                kind: MacroKind::Bang,
+                name: mac_name,
+                proc_macro: _,
+            } = data.kind
+            {
                 if mac_name.as_str() == name {
                     return Some(new_span);
                 }
@@ -975,7 +1004,12 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
         let data = span.ctxt().outer_expn_data();
         let new_span = data.call_site;
 
-        if let ExpnKind::Macro { kind: MacroKind::Bang, name: mac_name, proc_macro: _ } = data.kind {
+        if let ExpnKind::Macro {
+            kind: MacroKind::Bang,
+            name: mac_name,
+            proc_macro: _,
+        } = data.kind
+        {
             if mac_name.as_str() == name {
                 return Some(new_span);
             }
@@ -994,7 +1028,7 @@ pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx>
 
 /// Checks if an expression is constructing a tuple-like enum variant or struct
 pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    if let ExprKind::Call(ref fun, _) = expr.kind {
+    if let ExprKind::Call(fun, _) = expr.kind {
         if let ExprKind::Path(ref qp) = fun.kind {
             let res = cx.qpath_res(qp, fun.hir_id);
             return match res {
@@ -1024,21 +1058,21 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
     match pat.kind {
         PatKind::Wild => false,
         PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
-        PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
+        PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
         PatKind::Lit(..) | PatKind::Range(..) => true,
         PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
-        PatKind::Or(ref pats) => {
+        PatKind::Or(pats) => {
             // TODO: should be the honest check, that pats is exhaustive set
             are_refutable(cx, pats.iter().map(|pat| &**pat))
         },
-        PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
-        PatKind::Struct(ref qpath, ref fields, _) => {
+        PatKind::Tuple(pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
+        PatKind::Struct(ref qpath, fields, _) => {
             is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
         },
-        PatKind::TupleStruct(ref qpath, ref pats, _) => {
+        PatKind::TupleStruct(ref qpath, pats, _) => {
             is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
         },
-        PatKind::Slice(ref head, ref middle, ref tail) => {
+        PatKind::Slice(head, ref middle, tail) => {
             match &cx.typeck_results().node_type(pat.hir_id).kind() {
                 rustc_ty::Slice(..) => {
                     // [..] is the only irrefutable slice pattern.
@@ -1060,9 +1094,9 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
 /// the function once on the given pattern.
 pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) {
     if let PatKind::Or(pats) = pat.kind {
-        pats.iter().copied().for_each(f)
+        pats.iter().copied().for_each(f);
     } else {
-        f(pat)
+        f(pat);
     }
 }
 
@@ -1077,7 +1111,7 @@ pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
 /// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return
 /// themselves.
 pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
-    while let ExprKind::Block(ref block, ..) = expr.kind {
+    while let ExprKind::Block(block, ..) = expr.kind {
         match (block.stmts.is_empty(), block.expr.as_ref()) {
             (true, Some(e)) => expr = e,
             _ => break,
@@ -1096,7 +1130,7 @@ pub fn is_self(slf: &Param<'_>) -> bool {
 
 pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
     if_chain! {
-        if let TyKind::Path(QPath::Resolved(None, ref path)) = slf.kind;
+        if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind;
         if let Res::SelfTy(..) = path.res;
         then {
             return true
@@ -1114,7 +1148,7 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It
 pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
         if_chain! {
-            if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pat.kind;
+            if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind;
             if is_lang_ctor(cx, path, ResultOk);
             if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind;
             if path_to_local_id(arm.body, hir_id);
@@ -1133,7 +1167,7 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc
         }
     }
 
-    if let ExprKind::Match(_, ref arms, ref source) = expr.kind {
+    if let ExprKind::Match(_, arms, ref source) = expr.kind {
         // desugared from a `?` operator
         if let MatchSource::TryDesugar = *source {
             return Some(expr);
@@ -1220,12 +1254,12 @@ pub fn match_function_call<'tcx>(
     path: &[&str],
 ) -> Option<&'tcx [Expr<'tcx>]> {
     if_chain! {
-        if let ExprKind::Call(ref fun, ref args) = expr.kind;
+        if let ExprKind::Call(fun, args) = expr.kind;
         if let ExprKind::Path(ref qpath) = fun.kind;
         if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
         if match_def_path(cx, fun_def_id, path);
         then {
-            return Some(&args)
+            return Some(args)
         }
     };
     None
@@ -1282,15 +1316,15 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
     let mut conds = Vec::new();
     let mut blocks: Vec<&Block<'_>> = Vec::new();
 
-    while let ExprKind::If(ref cond, ref then_expr, ref else_expr) = expr.kind {
-        conds.push(&**cond);
-        if let ExprKind::Block(ref block, _) = then_expr.kind {
+    while let ExprKind::If(cond, then_expr, ref else_expr) = expr.kind {
+        conds.push(cond);
+        if let ExprKind::Block(block, _) = then_expr.kind {
             blocks.push(block);
         } else {
             panic!("ExprKind::If node is not an ExprKind::Block");
         }
 
-        if let Some(ref else_expr) = *else_expr {
+        if let Some(else_expr) = *else_expr {
             expr = else_expr;
         } else {
             break;
@@ -1299,8 +1333,8 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
 
     // final `else {..}`
     if !blocks.is_empty() {
-        if let ExprKind::Block(ref block, _) = expr.kind {
-            blocks.push(&**block);
+        if let ExprKind::Block(block, _) = expr.kind {
+            blocks.push(block);
         }
     }
 
@@ -1349,7 +1383,7 @@ pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> {
 // check if expr is calling method or function with #[must_use] attribute
 pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let did = match expr.kind {
-        ExprKind::Call(ref path, _) => if_chain! {
+        ExprKind::Call(path, _) => if_chain! {
             if let ExprKind::Path(ref qpath) = path.kind;
             if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id);
             then {
@@ -1362,7 +1396,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         _ => None,
     };
 
-    did.map_or(false, |did| must_use_attr(&cx.tcx.get_attrs(did)).is_some())
+    did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some())
 }
 
 /// Gets the node where an expression is either used, or it's type is unified with another branch.
@@ -1538,14 +1572,16 @@ where
     Hash: Fn(&T) -> u64,
     Eq: Fn(&T, &T) -> bool,
 {
-    if exprs.len() == 2 && eq(&exprs[0], &exprs[1]) {
-        return vec![(&exprs[0], &exprs[1])];
+    match exprs {
+        [a, b] if eq(a, b) => return vec![(a, b)],
+        _ if exprs.len() <= 2 => return vec![],
+        _ => {},
     }
 
     let mut match_expr_list: Vec<(&T, &T)> = Vec::new();
 
-    let mut map: FxHashMap<_, Vec<&_>> =
-        FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
+    let mut map: UnhashMap<u64, Vec<&_>> =
+        UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default());
 
     for expr in exprs {
         match map.entry(hash(expr)) {
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 00df04c0144..4a9c4fd0276 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -26,4 +26,5 @@ msrv_aliases! {
     1,34,0 { TRY_FROM }
     1,30,0 { ITERATOR_FIND_MAP }
     1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST }
+    1,16,0 { STR_REPEAT }
 }
diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
index 268bc5b3205..546706d51d7 100644
--- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs
+++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
@@ -52,7 +52,7 @@ impl<'a> NumericLiteral<'a> {
 
     pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> {
         if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) {
-            let (unsuffixed, suffix) = split_suffix(&src, lit_kind);
+            let (unsuffixed, suffix) = split_suffix(src, lit_kind);
             let float = matches!(lit_kind, LitKind::Float(..));
             Some(NumericLiteral::new(unsuffixed, suffix, float))
         } else {
diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs
index 5885cc83560..791688cd194 100644
--- a/src/tools/clippy/clippy_utils/src/ptr.rs
+++ b/src/tools/clippy/clippy_utils/src/ptr.rs
@@ -55,7 +55,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
         if self.abort {
             return;
         }
-        if let ExprKind::MethodCall(ref seg, _, ref args, _) = expr.kind {
+        if let ExprKind::MethodCall(seg, _, args, _) = expr.kind {
             if args.len() == 1 && match_var(&args[0], self.name) {
                 if seg.ident.name.as_str() == "capacity" {
                     self.abort = true;
@@ -79,5 +79,5 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
 }
 
 fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> {
-    get_pat_name(&arg.pat)
+    get_pat_name(arg.pat)
 }
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index a08dcf19e5b..0e6ead675c2 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -255,7 +255,7 @@ fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'t
         cursor = proj_base;
         match elem {
             ProjectionElem::Field(..) => {
-                let base_ty = Place::ty_from(place.local, &proj_base, body, tcx).ty;
+                let base_ty = Place::ty_from(place.local, proj_base, body, tcx).ty;
                 if let Some(def) = base_ty.ty_adt_def() {
                     // No union field accesses in `const fn`
                     if def.is_union() {
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 0633a19391f..efc0ec50fdc 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -2,7 +2,7 @@
 #![deny(clippy::missing_docs_in_private_items)]
 
 use crate::higher;
-use crate::source::{snippet, snippet_opt, snippet_with_macro_callsite};
+use crate::source::{snippet, snippet_opt, snippet_with_context, snippet_with_macro_callsite};
 use rustc_ast::util::parser::AssocOp;
 use rustc_ast::{ast, token};
 use rustc_ast_pretty::pprust::token_kind_to_string;
@@ -10,7 +10,7 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{EarlyContext, LateContext, LintContext};
 use rustc_span::source_map::{CharPos, Span};
-use rustc_span::{BytePos, Pos};
+use rustc_span::{BytePos, Pos, SyntaxContext};
 use std::borrow::Cow;
 use std::convert::TryInto;
 use std::fmt::Display;
@@ -90,6 +90,29 @@ impl<'a> Sugg<'a> {
         Self::hir_from_snippet(expr, snippet)
     }
 
+    /// Same as `hir`, but first walks the span up to the given context. This will result in the
+    /// macro call, rather then the expansion, if the span is from a child context. If the span is
+    /// not from a child context, it will be used directly instead.
+    ///
+    /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR
+    /// node would result in `box []`. If given the context of the address of expression, this
+    /// function will correctly get a snippet of `vec![]`.
+    pub fn hir_with_context(
+        cx: &LateContext<'_>,
+        expr: &hir::Expr<'_>,
+        ctxt: SyntaxContext,
+        default: &'a str,
+        applicability: &mut Applicability,
+    ) -> Self {
+        let (snippet, in_macro) = snippet_with_context(cx, expr.span, ctxt, default, applicability);
+
+        if in_macro {
+            Sugg::NonParen(snippet)
+        } else {
+            Self::hir_from_snippet(expr, snippet)
+        }
+    }
+
     /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
     /// function variants of `Sugg`, since these use different snippet functions.
     fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self {
@@ -289,7 +312,7 @@ fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool {
     let mut chars = sugg.as_ref().chars();
     if let Some('(') = chars.next() {
         let mut depth = 1;
-        while let Some(c) = chars.next() {
+        for c in &mut chars {
             if c == '(' {
                 depth += 1;
             } else if c == ')' {
@@ -684,7 +707,7 @@ impl<T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder
 
             if let Some(non_whitespace_offset) = non_whitespace_offset {
                 remove_span = remove_span
-                    .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")))
+                    .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large")));
             }
         }
 
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 64a80f2554f..a92d3be5d3c 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -2,9 +2,8 @@
 
 #![allow(clippy::module_name_repetitions)]
 
-use std::collections::HashMap;
-
 use rustc_ast::ast::Mutability;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{TyKind, Unsafety};
@@ -143,21 +142,18 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 // Returns whether the type has #[must_use] attribute
 pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.kind() {
-        ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(),
-        ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(),
-        ty::Slice(ref ty)
-        | ty::Array(ref ty, _)
-        | ty::RawPtr(ty::TypeAndMut { ref ty, .. })
-        | ty::Ref(_, ref ty, _) => {
+        ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(),
+        ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(),
+        ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => {
             // for the Array case we don't need to care for the len == 0 case
             // because we don't want to lint functions returning empty arrays
             is_must_use_ty(cx, *ty)
         },
-        ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
+        ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)),
         ty::Opaque(ref def_id, _) => {
             for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) {
                 if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() {
-                    if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
+                    if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() {
                         return true;
                     }
                 }
@@ -167,7 +163,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::Dynamic(binder, _) => {
             for predicate in binder.iter() {
                 if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
-                    if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
+                    if must_use_attr(cx.tcx.get_attrs(trait_ref.def_id)).is_some() {
                         return true;
                     }
                 }
@@ -184,14 +180,14 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 /// Checks if `Ty` is normalizable. This function is useful
 /// to avoid crashes on `layout_of`.
 pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
-    is_normalizable_helper(cx, param_env, ty, &mut HashMap::new())
+    is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default())
 }
 
 fn is_normalizable_helper<'tcx>(
     cx: &LateContext<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
-    cache: &mut HashMap<Ty<'tcx>, bool>,
+    cache: &mut FxHashMap<Ty<'tcx>, bool>,
 ) -> bool {
     if let Some(&cached_result) = cache.get(ty) {
         return cached_result;
@@ -306,7 +302,7 @@ pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bo
 /// Returns the base type for HIR references and pointers.
 pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
     match ty.kind {
-        TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty),
+        TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty),
         _ => ty,
     }
 }
@@ -322,3 +318,27 @@ pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
     }
     inner(ty, 0)
 }
+
+/// Returns `true` if types `a` and `b` are same types having same `Const` generic args,
+/// otherwise returns `false`
+pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+    match (&a.kind(), &b.kind()) {
+        (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
+            if did_a != did_b {
+                return false;
+            }
+
+            substs_a
+                .iter()
+                .zip(substs_b.iter())
+                .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) {
+                    (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b,
+                    (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => {
+                        same_type_and_consts(type_a, type_b)
+                    },
+                    _ => true,
+                })
+        },
+        _ => a == b,
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index 650b70c63af..2c55021ac88 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -59,7 +59,7 @@ impl<'tcx> MutVarsDelegate {
                 //FIXME: This causes false negatives. We can't get the `NodeId` from
                 //`Categorization::Upvar(_)`. So we search for any `Upvar`s in the
                 //`while`-body, not just the ones in the condition.
-                self.skip = true
+                self.skip = true;
             },
             _ => {},
         }
@@ -71,12 +71,12 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
 
     fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) {
         if let ty::BorrowKind::MutBorrow = bk {
-            self.update(&cmt)
+            self.update(cmt);
         }
     }
 
     fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
-        self.update(&cmt)
+        self.update(cmt);
     }
 
     fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {}
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index d431bdf34ee..ce00106dd4d 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -1,7 +1,7 @@
 use crate::path_to_local_id;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, walk_expr, ErasedMap, NestedVisitorMap, Visitor};
-use rustc_hir::{Arm, Block, Body, Destination, Expr, ExprKind, HirId, Stmt};
+use rustc_hir::{def::Res, Arm, Block, Body, BodyId, Destination, Expr, ExprKind, HirId, Stmt};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
 
@@ -87,7 +87,7 @@ where
         }
 
         fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
-            intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt)
+            intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt);
         }
 
         fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) {
@@ -189,35 +189,23 @@ impl<'v> Visitor<'v> for LocalUsedVisitor<'v> {
     }
 }
 
+/// A type which can be visited.
 pub trait Visitable<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V);
+    /// Calls the corresponding `visit_*` function on the visitor.
+    fn visit<V: Visitor<'tcx>>(self, visitor: &mut V);
 }
-impl Visitable<'tcx> for &'tcx Expr<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_expr(self)
-    }
-}
-impl Visitable<'tcx> for &'tcx Block<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_block(self)
-    }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Stmt<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_stmt(self)
-    }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Body<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_body(self)
-    }
-}
-impl<'tcx> Visitable<'tcx> for &'tcx Arm<'tcx> {
-    fn visit<V: Visitor<'tcx>>(self, v: &mut V) {
-        v.visit_arm(self)
-    }
+macro_rules! visitable_ref {
+    ($t:ident, $f:ident) => {
+        impl Visitable<'tcx> for &'tcx $t<'tcx> {
+            fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+                visitor.$f(self);
+            }
+        }
+    };
 }
+visitable_ref!(Block, visit_block);
 
+/// Calls the given function for each break expression.
 pub fn visit_break_exprs<'tcx>(
     node: impl Visitable<'tcx>,
     f: impl FnMut(&'tcx Expr<'tcx>, Destination, Option<&'tcx Expr<'tcx>>),
@@ -231,7 +219,7 @@ pub fn visit_break_exprs<'tcx>(
 
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             if let ExprKind::Break(dest, sub_expr) = e.kind {
-                self.0(e, dest, sub_expr)
+                self.0(e, dest, sub_expr);
             }
             walk_expr(self, e);
         }
@@ -239,3 +227,36 @@ pub fn visit_break_exprs<'tcx>(
 
     node.visit(&mut V(f));
 }
+
+/// Checks if the given resolved path is used in the given body.
+pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
+    struct V<'a, 'tcx> {
+        cx: &'a LateContext<'tcx>,
+        res: Res,
+        found: bool,
+    }
+    impl Visitor<'tcx> for V<'_, 'tcx> {
+        type Map = Map<'tcx>;
+        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+            NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+        }
+
+        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+            if self.found {
+                return;
+            }
+
+            if let ExprKind::Path(p) = &e.kind {
+                if self.cx.qpath_res(p, e.hir_id) == self.res {
+                    self.found = true;
+                }
+            } else {
+                walk_expr(self, e);
+            }
+        }
+    }
+
+    let mut v = V { cx, res, found: false };
+    v.visit_expr(&cx.tcx.hir().body(body).value);
+    v.found
+}
diff --git a/src/tools/clippy/doc/basics.md b/src/tools/clippy/doc/basics.md
index 5226875cc21..e2e307ce4f6 100644
--- a/src/tools/clippy/doc/basics.md
+++ b/src/tools/clippy/doc/basics.md
@@ -28,6 +28,8 @@ git clone git@github.com:<your-username>/rust-clippy
 If you've already cloned Clippy in the past, update it to the latest version:
 
 ```bash
+# If the upstream remote has not been added yet
+git remote add upstream https://github.com/rust-lang/rust-clippy
 # upstream has to be the remote of the rust-lang/rust-clippy repo
 git fetch upstream
 # make sure that you are on the master branch
diff --git a/src/tools/clippy/doc/release.md b/src/tools/clippy/doc/release.md
index eaa6a9af277..e0af9bf0625 100644
--- a/src/tools/clippy/doc/release.md
+++ b/src/tools/clippy/doc/release.md
@@ -94,7 +94,7 @@ After finding the Clippy commit, it can be tagged with the release number.
 # Assuming the current directory corresponds to the Clippy repository
 $ git checkout $SHA
 $ git tag rust-1.XX.0               # XX should be exchanged with the corresponding version
-$ git push upstream master --tags   # `upstream` is the `rust-lang/rust-clippy` remote
+$ git push upstream rust-1.XX.0     # `upstream` is the `rust-lang/rust-clippy` remote
 ```
 
 After this, the release should be available on the Clippy [release page].
diff --git a/src/tools/clippy/mini-macro/Cargo.toml b/src/tools/clippy/mini-macro/Cargo.toml
deleted file mode 100644
index 0d95c86aef0..00000000000
--- a/src/tools/clippy/mini-macro/Cargo.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-[package]
-name = "clippy-mini-macro-test"
-version = "0.2.0"
-authors = ["The Rust Clippy Developers"]
-license = "MIT OR Apache-2.0"
-description = "A macro to test clippy's procedural macro checks"
-repository = "https://github.com/rust-lang/rust-clippy"
-edition = "2018"
-
-[lib]
-name = "clippy_mini_macro_test"
-proc-macro = true
-
-[dependencies]
diff --git a/src/tools/clippy/mini-macro/src/lib.rs b/src/tools/clippy/mini-macro/src/lib.rs
deleted file mode 100644
index 2b793589049..00000000000
--- a/src/tools/clippy/mini-macro/src/lib.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-#![feature(proc_macro_quote)]
-#![deny(rust_2018_idioms)]
-// FIXME: Remove this attribute once the weird failure is gone.
-#![allow(unused_extern_crates)]
-extern crate proc_macro;
-
-use proc_macro::{quote, TokenStream};
-
-#[proc_macro_derive(ClippyMiniMacroTest)]
-/// # Panics
-///
-/// Panics if the macro derivation fails
-pub fn mini_macro(_: TokenStream) -> TokenStream {
-    quote!(
-        #[allow(unused)]
-        fn needless_take_by_value(s: String) {
-            println!("{}", s.len());
-        }
-        #[allow(unused)]
-        fn needless_loop(items: &[u8]) {
-            for i in 0..items.len() {
-                println!("{}", items[i]);
-            }
-        }
-        fn line_wrapper() {
-            println!("{}", line!());
-        }
-    )
-}
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 593162f09a7..e3863c46288 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-05-06"
+channel = "nightly-2021-06-03"
 components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
diff --git a/src/tools/clippy/rustc_tools_util/src/lib.rs b/src/tools/clippy/rustc_tools_util/src/lib.rs
index ff2a7de5725..5f289918a7c 100644
--- a/src/tools/clippy/rustc_tools_util/src/lib.rs
+++ b/src/tools/clippy/rustc_tools_util/src/lib.rs
@@ -100,9 +100,9 @@ pub fn get_commit_date() -> Option<String> {
 }
 
 #[must_use]
-pub fn get_channel() -> Option<String> {
+pub fn get_channel() -> String {
     match env::var("CFG_RELEASE_CHANNEL") {
-        Ok(channel) => Some(channel),
+        Ok(channel) => channel,
         Err(_) => {
             // if that failed, try to ask rustc -V, do some parsing and find out
             match std::process::Command::new("rustc")
@@ -113,16 +113,16 @@ pub fn get_channel() -> Option<String> {
             {
                 Some(rustc_output) => {
                     if rustc_output.contains("beta") {
-                        Some(String::from("beta"))
+                        String::from("beta")
                     } else if rustc_output.contains("stable") {
-                        Some(String::from("stable"))
+                        String::from("stable")
                     } else {
                         // default to nightly if we fail to parse
-                        Some(String::from("nightly"))
+                        String::from("nightly")
                     }
                 },
                 // default to nightly
-                None => Some(String::from("nightly")),
+                None => String::from("nightly"),
             }
         },
     }
diff --git a/src/tools/clippy/tests/clippy.toml b/src/tools/clippy/tests/clippy.toml
new file mode 100644
index 00000000000..5eb7ac03541
--- /dev/null
+++ b/src/tools/clippy/tests/clippy.toml
@@ -0,0 +1 @@
+# default config for tests, overrides clippy.toml at the project root
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index e1110721f6e..7d266a36bb6 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -4,8 +4,8 @@
 use compiletest_rs as compiletest;
 use compiletest_rs::common::Mode as TestMode;
 
-use std::env::{self, set_var, var};
-use std::ffi::OsStr;
+use std::env::{self, remove_var, set_var, var_os};
+use std::ffi::{OsStr, OsString};
 use std::fs;
 use std::io;
 use std::path::{Path, PathBuf};
@@ -88,9 +88,11 @@ fn default_config() -> compiletest::Config {
     config
 }
 
-fn run_mode(cfg: &mut compiletest::Config) {
+fn run_ui(cfg: &mut compiletest::Config) {
     cfg.mode = TestMode::Ui;
     cfg.src_base = Path::new("tests").join("ui");
+    // use tests/clippy.toml
+    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
     compiletest::run_tests(cfg);
 }
 
@@ -114,7 +116,7 @@ fn run_ui_toml(config: &mut compiletest::Config) {
                 continue;
             }
             let dir_path = dir.path();
-            set_var("CARGO_MANIFEST_DIR", &dir_path);
+            let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
             for file in fs::read_dir(&dir_path)? {
                 let file = file?;
                 let file_path = file.path();
@@ -145,9 +147,7 @@ fn run_ui_toml(config: &mut compiletest::Config) {
 
     let tests = compiletest::make_tests(config);
 
-    let manifest_dir = var("CARGO_MANIFEST_DIR").unwrap_or_default();
     let res = run_tests(config, tests);
-    set_var("CARGO_MANIFEST_DIR", &manifest_dir);
     match res {
         Ok(true) => {},
         Ok(false) => panic!("Some tests failed"),
@@ -208,7 +208,7 @@ fn run_ui_cargo(config: &mut compiletest::Config) {
                         Some("main.rs") => {},
                         _ => continue,
                     }
-                    set_var("CLIPPY_CONF_DIR", case.path());
+                    let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
                     let paths = compiletest::common::TestPaths {
                         file: file_path,
                         base: config.src_base.clone(),
@@ -236,10 +236,8 @@ fn run_ui_cargo(config: &mut compiletest::Config) {
     let tests = compiletest::make_tests(config);
 
     let current_dir = env::current_dir().unwrap();
-    let conf_dir = var("CLIPPY_CONF_DIR").unwrap_or_default();
     let res = run_tests(config, &config.filters, tests);
     env::set_current_dir(current_dir).unwrap();
-    set_var("CLIPPY_CONF_DIR", conf_dir);
 
     match res {
         Ok(true) => {},
@@ -260,8 +258,32 @@ fn prepare_env() {
 fn compile_test() {
     prepare_env();
     let mut config = default_config();
-    run_mode(&mut config);
+    run_ui(&mut config);
     run_ui_toml(&mut config);
     run_ui_cargo(&mut config);
     run_internal_tests(&mut config);
 }
+
+/// Restores an env var on drop
+#[must_use]
+struct VarGuard {
+    key: &'static str,
+    value: Option<OsString>,
+}
+
+impl VarGuard {
+    fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
+        let value = var_os(key);
+        set_var(key, val);
+        Self { key, value }
+    }
+}
+
+impl Drop for VarGuard {
+    fn drop(&mut self) {
+        match self.value.as_deref() {
+            None => remove_var(self.key),
+            Some(value) => set_var(self.key, value),
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 6524fd4706c..7de130c7dbe 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -22,14 +22,12 @@ fn dogfood_clippy() {
         return;
     }
     let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
-    let enable_metadata_collection = std::env::var("ENABLE_METADATA_COLLECTION").unwrap_or_else(|_| "0".to_string());
 
     let mut command = Command::new(&*CLIPPY_PATH);
     command
         .current_dir(root_dir)
         .env("CLIPPY_DOGFOOD", "1")
         .env("CARGO_INCREMENTAL", "0")
-        .env("ENABLE_METADATA_COLLECTION", &enable_metadata_collection)
         .arg("clippy")
         .arg("--all-targets")
         .arg("--all-features")
@@ -157,10 +155,9 @@ fn dogfood_subprojects() {
     if cargo::is_rustc_test_suite() {
         return;
     }
-    let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
 
     // NOTE: `path_dep` crate is omitted on purpose here
-    for d in &[
+    for project in &[
         "clippy_workspace_tests",
         "clippy_workspace_tests/src",
         "clippy_workspace_tests/subcrate",
@@ -170,34 +167,80 @@ fn dogfood_subprojects() {
         "clippy_utils",
         "rustc_tools_util",
     ] {
-        let mut command = Command::new(&*CLIPPY_PATH);
-        command
-            .current_dir(root_dir.join(d))
-            .env("CLIPPY_DOGFOOD", "1")
-            .env("CARGO_INCREMENTAL", "0")
-            .arg("clippy")
-            .arg("--all-targets")
-            .arg("--all-features")
-            .arg("--")
-            .args(&["-D", "clippy::all"])
-            .args(&["-D", "clippy::pedantic"])
-            .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
+        run_clippy_for_project(project);
+    }
 
-        // internal lints only exist if we build with the internal-lints feature
-        if cfg!(feature = "internal-lints") {
-            command.args(&["-D", "clippy::internal"]);
+    // NOTE: Since tests run in parallel we can't run cargo commands on the same workspace at the
+    // same time, so we test this immediately after the dogfood for workspaces.
+    test_no_deps_ignores_path_deps_in_workspaces();
+}
+
+#[test]
+#[ignore]
+#[cfg(feature = "metadata-collector-lint")]
+fn run_metadata_collection_lint() {
+    use std::fs::File;
+    use std::time::SystemTime;
+
+    // Setup for validation
+    let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/metadata_collection.json");
+    let start_time = SystemTime::now();
+
+    // Run collection as is
+    std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
+    run_clippy_for_project("clippy_lints");
+
+    // Check if cargo caching got in the way
+    if let Ok(file) = File::open(metadata_output_path) {
+        if let Ok(metadata) = file.metadata() {
+            if let Ok(last_modification) = metadata.modified() {
+                if last_modification > start_time {
+                    // The output file has been modified. Most likely by a hungry
+                    // metadata collection monster. So We'll return.
+                    return;
+                }
+            }
         }
+    }
 
-        let output = command.output().unwrap();
+    // Force cargo to invalidate the caches
+    filetime::set_file_mtime(
+        PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"),
+        filetime::FileTime::now(),
+    )
+    .unwrap();
 
-        println!("status: {}", output.status);
-        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
-        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
+    // Running the collection again
+    run_clippy_for_project("clippy_lints");
+}
 
-        assert!(output.status.success());
+fn run_clippy_for_project(project: &str) {
+    let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+
+    let mut command = Command::new(&*CLIPPY_PATH);
+
+    command
+        .current_dir(root_dir.join(project))
+        .env("CLIPPY_DOGFOOD", "1")
+        .env("CARGO_INCREMENTAL", "0")
+        .arg("clippy")
+        .arg("--all-targets")
+        .arg("--all-features")
+        .arg("--")
+        .args(&["-D", "clippy::all"])
+        .args(&["-D", "clippy::pedantic"])
+        .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
+
+    // internal lints only exist if we build with the internal-lints feature
+    if cfg!(feature = "internal-lints") {
+        command.args(&["-D", "clippy::internal"]);
     }
 
-    // NOTE: Since tests run in parallel we can't run cargo commands on the same workspace at the
-    // same time, so we test this immediately after the dogfood for workspaces.
-    test_no_deps_ignores_path_deps_in_workspaces();
+    let output = command.output().unwrap();
+
+    println!("status: {}", output.status);
+    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
+    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
+
+    assert!(output.status.success());
 }
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index d83080b69f5..a7be00426c4 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
index aebeaf34679..4b7b7fec78f 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
@@ -53,3 +53,22 @@ pub fn derive_use_self(_input: TokenStream) -> proc_macro::TokenStream {
         }
     }
 }
+
+#[proc_macro_derive(ClippyMiniMacroTest)]
+pub fn mini_macro(_: TokenStream) -> TokenStream {
+    quote!(
+        #[allow(unused)]
+        fn needless_take_by_value(s: String) {
+            println!("{}", s.len());
+        }
+        #[allow(unused)]
+        fn needless_loop(items: &[u8]) {
+            for i in 0..items.len() {
+                println!("{}", items[i]);
+            }
+        }
+        fn line_wrapper() {
+            println!("{}", line!());
+        }
+    )
+}
diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs
new file mode 100644
index 00000000000..780797e3c6a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs
@@ -0,0 +1,14 @@
+pub fn warn<T>(_: T) {}
+
+macro_rules! define_macro {
+    ($d:tt $lower:ident $upper:ident) => {
+        #[macro_export]
+        macro_rules! $upper {
+            ($arg:tt) => {
+                $crate::$lower($arg)
+            };
+        }
+    };
+}
+
+define_macro! {$ warn  WARNING}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7231.rs b/src/tools/clippy/tests/ui/crashes/ice-7231.rs
new file mode 100644
index 00000000000..5595d8d1d62
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-7231.rs
@@ -0,0 +1,10 @@
+// edition:2018
+#![allow(clippy::never_loop)]
+
+async fn f() {
+    loop {
+        break;
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7272.rs b/src/tools/clippy/tests/ui/crashes/ice-7272.rs
new file mode 100644
index 00000000000..57ab6ca14f8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-7272.rs
@@ -0,0 +1,12 @@
+// aux-build:ice-7272-aux.rs
+
+#![allow(clippy::no_effect)]
+
+extern crate ice_7272_aux;
+
+use ice_7272_aux::*;
+
+pub fn main() {
+    || WARNING!("Style changed!");
+    || "}{";
+}
diff --git a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs b/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
deleted file mode 100644
index c7468493380..00000000000
--- a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#[macro_use]
-extern crate clippy_mini_macro_test;
-
-#[deny(warnings)]
-fn main() {
-    let x = Foo;
-    println!("{:?}", x);
-}
-
-#[derive(ClippyMiniMacroTest, Debug)]
-struct Foo;
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs
index 2a948d60b10..cba7666c2d8 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.rs
+++ b/src/tools/clippy/tests/ui/def_id_nocore.rs
@@ -20,7 +20,7 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
     0
 }
 
-pub struct A;
+struct A;
 
 impl A {
     pub fn as_ref(self) -> &'static str {
diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs
index dbf0b03af76..4ba9f0c1fcf 100644
--- a/src/tools/clippy/tests/ui/deprecated.rs
+++ b/src/tools/clippy/tests/ui/deprecated.rs
@@ -12,5 +12,7 @@
 #[warn(clippy::unknown_clippy_lints)]
 #[warn(clippy::find_map)]
 #[warn(clippy::filter_map)]
+#[warn(clippy::pub_enum_variant_names)]
+#[warn(clippy::wrong_pub_self_convention)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr
index e5de839dbc5..03c9f438891 100644
--- a/src/tools/clippy/tests/ui/deprecated.stderr
+++ b/src/tools/clippy/tests/ui/deprecated.stderr
@@ -84,5 +84,17 @@ error: lint `clippy::filter_map` has been removed: this lint has been replaced b
 LL | #[warn(clippy::filter_map)]
    |        ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 14 previous errors
+error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items
+  --> $DIR/deprecated.rs:15:8
+   |
+LL | #[warn(clippy::pub_enum_variant_names)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items
+  --> $DIR/deprecated.rs:16:8
+   |
+LL | #[warn(clippy::wrong_pub_self_convention)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs
index 4fefc0b43f1..083f5143e6e 100644
--- a/src/tools/clippy/tests/ui/enum_variants.rs
+++ b/src/tools/clippy/tests/ui/enum_variants.rs
@@ -1,5 +1,4 @@
-#![feature(non_ascii_idents)]
-#![warn(clippy::enum_variant_names, clippy::pub_enum_variant_names)]
+#![warn(clippy::enum_variant_names)]
 #![allow(non_camel_case_types, clippy::upper_case_acronyms)]
 
 enum FakeCallType {
@@ -97,8 +96,8 @@ pub enum PubSeall {
     WithOut,
 }
 
-#[allow(clippy::pub_enum_variant_names)]
-mod allowed {
+#[allow(clippy::enum_variant_names)]
+pub mod allowed {
     pub enum PubAllowed {
         SomeThis,
         SomeThat,
diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr
index ab7fff4507a..447fbb9e1bf 100644
--- a/src/tools/clippy/tests/ui/enum_variants.stderr
+++ b/src/tools/clippy/tests/ui/enum_variants.stderr
@@ -1,5 +1,5 @@
 error: variant name ends with the enum's name
-  --> $DIR/enum_variants.rs:16:5
+  --> $DIR/enum_variants.rs:15:5
    |
 LL |     cFoo,
    |     ^^^^
@@ -7,25 +7,25 @@ LL |     cFoo,
    = note: `-D clippy::enum-variant-names` implied by `-D warnings`
 
 error: variant name starts with the enum's name
-  --> $DIR/enum_variants.rs:27:5
+  --> $DIR/enum_variants.rs:26:5
    |
 LL |     FoodGood,
    |     ^^^^^^^^
 
 error: variant name starts with the enum's name
-  --> $DIR/enum_variants.rs:28:5
+  --> $DIR/enum_variants.rs:27:5
    |
 LL |     FoodMiddle,
    |     ^^^^^^^^^^
 
 error: variant name starts with the enum's name
-  --> $DIR/enum_variants.rs:29:5
+  --> $DIR/enum_variants.rs:28:5
    |
 LL |     FoodBad,
    |     ^^^^^^^
 
 error: all variants have the same prefix: `Food`
-  --> $DIR/enum_variants.rs:26:1
+  --> $DIR/enum_variants.rs:25:1
    |
 LL | / enum Food {
 LL | |     FoodGood,
@@ -37,7 +37,7 @@ LL | | }
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: all variants have the same prefix: `CallType`
-  --> $DIR/enum_variants.rs:36:1
+  --> $DIR/enum_variants.rs:35:1
    |
 LL | / enum BadCallType {
 LL | |     CallTypeCall,
@@ -49,7 +49,7 @@ LL | | }
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: all variants have the same prefix: `Constant`
-  --> $DIR/enum_variants.rs:48:1
+  --> $DIR/enum_variants.rs:47:1
    |
 LL | / enum Consts {
 LL | |     ConstantInt,
@@ -61,7 +61,7 @@ LL | | }
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: all variants have the same prefix: `With`
-  --> $DIR/enum_variants.rs:82:1
+  --> $DIR/enum_variants.rs:81:1
    |
 LL | / enum Seallll {
 LL | |     WithOutCake,
@@ -73,7 +73,7 @@ LL | | }
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
 error: all variants have the same prefix: `Prefix`
-  --> $DIR/enum_variants.rs:88:1
+  --> $DIR/enum_variants.rs:87:1
    |
 LL | / enum NonCaps {
 LL | |     Prefix的,
@@ -84,21 +84,8 @@ LL | | }
    |
    = help: remove the prefixes and use full paths to the variants instead of glob imports
 
-error: all variants have the same prefix: `With`
-  --> $DIR/enum_variants.rs:94:1
-   |
-LL | / pub enum PubSeall {
-LL | |     WithOutCake,
-LL | |     WithOutTea,
-LL | |     WithOut,
-LL | | }
-   | |_^
-   |
-   = note: `-D clippy::pub-enum-variant-names` implied by `-D warnings`
-   = help: remove the prefixes and use full paths to the variants instead of glob imports
-
 error: all variants have the same postfix: `IData`
-  --> $DIR/enum_variants.rs:137:1
+  --> $DIR/enum_variants.rs:136:1
    |
 LL | / enum IDataRequest {
 LL | |     PutIData(String),
@@ -110,7 +97,7 @@ LL | | }
    = help: remove the postfixes and use full paths to the variants instead of glob imports
 
 error: all variants have the same postfix: `HIData`
-  --> $DIR/enum_variants.rs:143:1
+  --> $DIR/enum_variants.rs:142:1
    |
 LL | / enum HIDataRequest {
 LL | |     PutHIData(String),
@@ -121,5 +108,5 @@ LL | | }
    |
    = help: remove the postfixes and use full paths to the variants instead of glob imports
 
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index 2be2283e3fd..9e752311c67 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -48,6 +48,9 @@ fn main() {
     // See #515
     let a: Option<Box<dyn (::std::ops::Deref<Target = [i32]>)>> =
         Some(vec![1i32, 2]).map(|v| -> Box<dyn (::std::ops::Deref<Target = [i32]>)> { Box::new(v) });
+
+    // issue #7224
+    let _: Option<Vec<u32>> = Some(0).map(|_| vec![]);
 }
 
 trait TestTrait {
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index f0373f9ccf6..44be4628cbd 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -48,6 +48,9 @@ fn main() {
     // See #515
     let a: Option<Box<dyn (::std::ops::Deref<Target = [i32]>)>> =
         Some(vec![1i32, 2]).map(|v| -> Box<dyn (::std::ops::Deref<Target = [i32]>)> { Box::new(v) });
+
+    // issue #7224
+    let _: Option<Vec<u32>> = Some(0).map(|_| vec![]);
 }
 
 trait TestTrait {
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index 57ed6527966..8795d3b42c6 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -33,7 +33,7 @@ LL |     let e = Some(1u8).map(|a| generic(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
 
 error: redundant closure
-  --> $DIR/eta.rs:89:51
+  --> $DIR/eta.rs:92:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    |                                                   ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
@@ -41,43 +41,43 @@ LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings`
 
 error: redundant closure
-  --> $DIR/eta.rs:91:51
+  --> $DIR/eta.rs:94:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo());
    |                                                   ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo`
 
 error: redundant closure
-  --> $DIR/eta.rs:94:42
+  --> $DIR/eta.rs:97:42
    |
 LL |     let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear());
    |                                          ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear`
 
 error: redundant closure
-  --> $DIR/eta.rs:99:29
+  --> $DIR/eta.rs:102:29
    |
 LL |     let e = Some("str").map(|s| s.to_string());
    |                             ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string`
 
 error: redundant closure
-  --> $DIR/eta.rs:101:27
+  --> $DIR/eta.rs:104:27
    |
 LL |     let e = Some('a').map(|s| s.to_uppercase());
    |                           ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase`
 
 error: redundant closure
-  --> $DIR/eta.rs:104:65
+  --> $DIR/eta.rs:107:65
    |
 LL |     let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect();
    |                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase`
 
 error: redundant closure
-  --> $DIR/eta.rs:187:27
+  --> $DIR/eta.rs:190:27
    |
 LL |     let a = Some(1u8).map(|a| foo_ptr(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr`
 
 error: redundant closure
-  --> $DIR/eta.rs:192:27
+  --> $DIR/eta.rs:195:27
    |
 LL |     let a = Some(1u8).map(|a| closure(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.fixed b/src/tools/clippy/tests/ui/floating_point_powi.fixed
index 56762400593..85f7c531e39 100644
--- a/src/tools/clippy/tests/ui/floating_point_powi.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_powi.fixed
@@ -4,8 +4,6 @@
 fn main() {
     let one = 1;
     let x = 3f32;
-    let _ = x * x;
-    let _ = x * x;
 
     let y = 4f32;
     let _ = x.mul_add(x, y);
@@ -13,7 +11,10 @@ fn main() {
     let _ = x.mul_add(x, y).sqrt();
     let _ = y.mul_add(y, x).sqrt();
     // Cases where the lint shouldn't be applied
+    let _ = x.powi(2);
+    let _ = x.powi(1 + 1);
     let _ = x.powi(3);
+    let _ = x.powi(4) + y;
     let _ = x.powi(one + 1);
     let _ = (x.powi(2) + y.powi(2)).sqrt();
 }
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.rs b/src/tools/clippy/tests/ui/floating_point_powi.rs
index 1f800e4628d..ece61d1bec4 100644
--- a/src/tools/clippy/tests/ui/floating_point_powi.rs
+++ b/src/tools/clippy/tests/ui/floating_point_powi.rs
@@ -4,8 +4,6 @@
 fn main() {
     let one = 1;
     let x = 3f32;
-    let _ = x.powi(2);
-    let _ = x.powi(1 + 1);
 
     let y = 4f32;
     let _ = x.powi(2) + y;
@@ -13,7 +11,10 @@ fn main() {
     let _ = (x.powi(2) + y).sqrt();
     let _ = (x + y.powi(2)).sqrt();
     // Cases where the lint shouldn't be applied
+    let _ = x.powi(2);
+    let _ = x.powi(1 + 1);
     let _ = x.powi(3);
+    let _ = x.powi(4) + y;
     let _ = x.powi(one + 1);
     let _ = (x.powi(2) + y.powi(2)).sqrt();
 }
diff --git a/src/tools/clippy/tests/ui/floating_point_powi.stderr b/src/tools/clippy/tests/ui/floating_point_powi.stderr
index d5a5f1bcca1..37d840988bb 100644
--- a/src/tools/clippy/tests/ui/floating_point_powi.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_powi.stderr
@@ -1,40 +1,28 @@
-error: square can be computed more efficiently
-  --> $DIR/floating_point_powi.rs:7:13
-   |
-LL |     let _ = x.powi(2);
-   |             ^^^^^^^^^ help: consider using: `x * x`
-   |
-   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
-
-error: square can be computed more efficiently
-  --> $DIR/floating_point_powi.rs:8:13
-   |
-LL |     let _ = x.powi(1 + 1);
-   |             ^^^^^^^^^^^^^ help: consider using: `x * x`
-
-error: square can be computed more efficiently
-  --> $DIR/floating_point_powi.rs:11:13
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:9:13
    |
 LL |     let _ = x.powi(2) + y;
    |             ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
+   |
+   = note: `-D clippy::suboptimal-flops` implied by `-D warnings`
 
-error: square can be computed more efficiently
-  --> $DIR/floating_point_powi.rs:12:13
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:10:13
    |
 LL |     let _ = x + y.powi(2);
    |             ^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
 
-error: square can be computed more efficiently
-  --> $DIR/floating_point_powi.rs:13:13
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:11:13
    |
 LL |     let _ = (x.powi(2) + y).sqrt();
    |             ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)`
 
-error: square can be computed more efficiently
-  --> $DIR/floating_point_powi.rs:14:13
+error: multiply and add expressions can be calculated more efficiently and accurately
+  --> $DIR/floating_point_powi.rs:12:13
    |
 LL |     let _ = (x + y.powi(2)).sqrt();
    |             ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)`
 
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
index b5f548810e6..12db43b5343 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
@@ -6,6 +6,20 @@
 use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
 use std::iter::FromIterator;
 
+struct Foo(Vec<bool>);
+
+impl FromIterator<bool> for Foo {
+    fn from_iter<T: IntoIterator<Item = bool>>(_: T) -> Self {
+        todo!()
+    }
+}
+
+impl<'a> FromIterator<&'a bool> for Foo {
+    fn from_iter<T: IntoIterator<Item = &'a bool>>(iter: T) -> Self {
+        iter.into_iter().copied().collect::<Self>()
+    }
+}
+
 fn main() {
     let iter_expr = std::iter::repeat(5).take(5);
     let _ = iter_expr.collect::<Vec<_>>();
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
index b842b5451d1..f5ec190e0cd 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
@@ -6,6 +6,20 @@
 use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque};
 use std::iter::FromIterator;
 
+struct Foo(Vec<bool>);
+
+impl FromIterator<bool> for Foo {
+    fn from_iter<T: IntoIterator<Item = bool>>(_: T) -> Self {
+        todo!()
+    }
+}
+
+impl<'a> FromIterator<&'a bool> for Foo {
+    fn from_iter<T: IntoIterator<Item = &'a bool>>(iter: T) -> Self {
+        <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
+    }
+}
+
 fn main() {
     let iter_expr = std::iter::repeat(5).take(5);
     let _ = Vec::from_iter(iter_expr);
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
index 434734c9a21..8f08ac8c3ff 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
@@ -1,88 +1,94 @@
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:11:13
+  --> $DIR/from_iter_instead_of_collect.rs:19:9
    |
-LL |     let _ = Vec::from_iter(iter_expr);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()`
+LL |         <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.into_iter().copied().collect::<Self>()`
    |
    = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:13:13
+  --> $DIR/from_iter_instead_of_collect.rs:25:13
+   |
+LL |     let _ = Vec::from_iter(iter_expr);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()`
+
+error: usage of `FromIterator::from_iter`
+  --> $DIR/from_iter_instead_of_collect.rs:27:13
    |
 LL |     let _ = HashMap::<usize, &i8>::from_iter(vec![5, 5, 5, 5].iter().enumerate());
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::<HashMap<usize, &i8>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:18:19
+  --> $DIR/from_iter_instead_of_collect.rs:32:19
    |
 LL |     assert_eq!(a, Vec::from_iter(0..3));
    |                   ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:19:19
+  --> $DIR/from_iter_instead_of_collect.rs:33:19
    |
 LL |     assert_eq!(a, Vec::<i32>::from_iter(0..3));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<i32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:21:17
+  --> $DIR/from_iter_instead_of_collect.rs:35:17
    |
 LL |     let mut b = VecDeque::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:24:17
+  --> $DIR/from_iter_instead_of_collect.rs:38:17
    |
 LL |     let mut b = VecDeque::<i32>::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<i32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:29:21
+  --> $DIR/from_iter_instead_of_collect.rs:43:21
    |
 LL |         let mut b = collections::VecDeque::<i32>::from_iter(0..3);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::VecDeque<i32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:34:14
+  --> $DIR/from_iter_instead_of_collect.rs:48:14
    |
 LL |     let bm = BTreeMap::from_iter(values.iter().cloned());
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::<BTreeMap<_, _>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:35:19
+  --> $DIR/from_iter_instead_of_collect.rs:49:19
    |
 LL |     let mut bar = BTreeMap::from_iter(bm.range(0..2));
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::<BTreeMap<_, _>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:38:19
+  --> $DIR/from_iter_instead_of_collect.rs:52:19
    |
 LL |     let mut bts = BTreeSet::from_iter(0..3);
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<BTreeSet<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:42:17
+  --> $DIR/from_iter_instead_of_collect.rs:56:17
    |
 LL |         let _ = collections::BTreeSet::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:43:17
+  --> $DIR/from_iter_instead_of_collect.rs:57:17
    |
 LL |         let _ = collections::BTreeSet::<u32>::from_iter(0..3);
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<u32>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:46:15
+  --> $DIR/from_iter_instead_of_collect.rs:60:15
    |
 LL |     for _i in Vec::from_iter([1, 2, 3].iter()) {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<_>>()`
 
 error: usage of `FromIterator::from_iter`
-  --> $DIR/from_iter_instead_of_collect.rs:47:15
+  --> $DIR/from_iter_instead_of_collect.rs:61:15
    |
 LL |     for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<&i32>>()`
 
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/functions.stderr b/src/tools/clippy/tests/ui/functions.stderr
index 0a86568b18d..a2b8c2a384b 100644
--- a/src/tools/clippy/tests/ui/functions.stderr
+++ b/src/tools/clippy/tests/ui/functions.stderr
@@ -30,7 +30,7 @@ error: this function has too many arguments (8/7)
 LL |     fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:63:34
    |
 LL |         println!("{}", unsafe { *p });
@@ -38,49 +38,49 @@ LL |         println!("{}", unsafe { *p });
    |
    = note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings`
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:64:35
    |
 LL |         println!("{:?}", unsafe { p.as_ref() });
    |                                   ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:65:33
    |
 LL |         unsafe { std::ptr::read(p) };
    |                                 ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:76:30
    |
 LL |     println!("{}", unsafe { *p });
    |                              ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:77:31
    |
 LL |     println!("{:?}", unsafe { p.as_ref() });
    |                               ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:78:29
    |
 LL |     unsafe { std::ptr::read(p) };
    |                             ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:87:34
    |
 LL |         println!("{}", unsafe { *p });
    |                                  ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:88:35
    |
 LL |         println!("{:?}", unsafe { p.as_ref() });
    |                                   ^
 
-error: this public function dereferences a raw pointer but is not marked `unsafe`
+error: this public function might dereference a raw pointer but is not marked `unsafe`
   --> $DIR/functions.rs:89:33
    |
 LL |         unsafe { std::ptr::read(p) };
diff --git a/src/tools/clippy/tests/ui/impl.rs b/src/tools/clippy/tests/ui/impl.rs
index 1c46e3a5337..39443775015 100644
--- a/src/tools/clippy/tests/ui/impl.rs
+++ b/src/tools/clippy/tests/ui/impl.rs
@@ -33,4 +33,35 @@ impl fmt::Debug for MyStruct {
     }
 }
 
+// issue #5772
+struct WithArgs<T>(T);
+impl WithArgs<u32> {
+    fn f1() {}
+}
+impl WithArgs<u64> {
+    fn f2() {}
+}
+impl WithArgs<u64> {
+    fn f3() {}
+}
+
+// Ok, the struct is allowed to have multiple impls.
+#[allow(clippy::multiple_inherent_impl)]
+struct Allowed;
+impl Allowed {}
+impl Allowed {}
+impl Allowed {}
+
+struct AllowedImpl;
+#[allow(clippy::multiple_inherent_impl)]
+impl AllowedImpl {}
+// Ok, the first block is skipped by this lint.
+impl AllowedImpl {}
+
+struct OneAllowedImpl;
+impl OneAllowedImpl {}
+#[allow(clippy::multiple_inherent_impl)]
+impl OneAllowedImpl {}
+impl OneAllowedImpl {} // Lint, only one of the three blocks is allowed.
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/impl.stderr b/src/tools/clippy/tests/ui/impl.stderr
index aab688cc2d8..8703ecac93e 100644
--- a/src/tools/clippy/tests/ui/impl.stderr
+++ b/src/tools/clippy/tests/ui/impl.stderr
@@ -31,5 +31,33 @@ LL | |     fn first() {}
 LL | | }
    | |_^
 
-error: aborting due to 2 previous errors
+error: multiple implementations of this structure
+  --> $DIR/impl.rs:44:1
+   |
+LL | / impl WithArgs<u64> {
+LL | |     fn f3() {}
+LL | | }
+   | |_^
+   |
+note: first implementation here
+  --> $DIR/impl.rs:41:1
+   |
+LL | / impl WithArgs<u64> {
+LL | |     fn f2() {}
+LL | | }
+   | |_^
+
+error: multiple implementations of this structure
+  --> $DIR/impl.rs:65:1
+   |
+LL | impl OneAllowedImpl {} // Lint, only one of the three blocks is allowed.
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first implementation here
+  --> $DIR/impl.rs:62:1
+   |
+LL | impl OneAllowedImpl {}
+   | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed
index 51c66a46368..70d49d9f2c4 100644
--- a/src/tools/clippy/tests/ui/macro_use_imports.fixed
+++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed
@@ -1,6 +1,7 @@
 // compile-flags: --edition 2018
 // aux-build:macro_rules.rs
 // aux-build:macro_use_helper.rs
+// aux-build:proc_macro_derive.rs
 // run-rustfix
 // ignore-32bit
 
@@ -12,7 +13,7 @@
 extern crate macro_use_helper as mac;
 
 #[macro_use]
-extern crate clippy_mini_macro_test as mini_mac;
+extern crate proc_macro_derive as mini_mac;
 
 mod a {
     use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs
index 2011129bc94..68370023861 100644
--- a/src/tools/clippy/tests/ui/macro_use_imports.rs
+++ b/src/tools/clippy/tests/ui/macro_use_imports.rs
@@ -1,6 +1,7 @@
 // compile-flags: --edition 2018
 // aux-build:macro_rules.rs
 // aux-build:macro_use_helper.rs
+// aux-build:proc_macro_derive.rs
 // run-rustfix
 // ignore-32bit
 
@@ -12,7 +13,7 @@
 extern crate macro_use_helper as mac;
 
 #[macro_use]
-extern crate clippy_mini_macro_test as mini_mac;
+extern crate proc_macro_derive as mini_mac;
 
 mod a {
     #[macro_use]
diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr
index f8c86c8d917..49314b7506d 100644
--- a/src/tools/clippy/tests/ui/macro_use_imports.stderr
+++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr
@@ -1,5 +1,5 @@
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:18:5
+  --> $DIR/macro_use_imports.rs:19:5
    |
 LL |     #[macro_use]
    |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};`
@@ -7,22 +7,22 @@ LL |     #[macro_use]
    = note: `-D clippy::macro-use-imports` implied by `-D warnings`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:20:5
+  --> $DIR/macro_use_imports.rs:25:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:22:5
+  --> $DIR/macro_use_imports.rs:21:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
 
 error: `macro_use` attributes are no longer needed in the Rust 2018 edition
-  --> $DIR/macro_use_imports.rs:24:5
+  --> $DIR/macro_use_imports.rs:23:5
    |
 LL |     #[macro_use]
-   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
+   |     ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.fixed b/src/tools/clippy/tests/ui/manual_str_repeat.fixed
new file mode 100644
index 00000000000..dc140257f32
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_str_repeat.fixed
@@ -0,0 +1,66 @@
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_str_repeat)]
+
+use std::borrow::Cow;
+use std::iter::{repeat, FromIterator};
+
+fn main() {
+    let _: String = "test".repeat(10);
+    let _: String = "x".repeat(10);
+    let _: String = "'".repeat(10);
+    let _: String = "\"".repeat(10);
+
+    let x = "test";
+    let count = 10;
+    let _ = x.repeat(count + 2);
+
+    macro_rules! m {
+        ($e:expr) => {{ $e }};
+    }
+    // FIXME: macro args are fine
+    let _: String = repeat(m!("test")).take(m!(count)).collect();
+
+    let x = &x;
+    let _: String = (*x).repeat(count);
+
+    macro_rules! repeat_m {
+        ($e:expr) => {{ repeat($e) }};
+    }
+    // Don't lint, repeat is from a macro.
+    let _: String = repeat_m!("test").take(count).collect();
+
+    let x: Box<str> = Box::from("test");
+    let _: String = x.repeat(count);
+
+    #[derive(Clone)]
+    struct S;
+    impl FromIterator<Box<S>> for String {
+        fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self {
+            Self::new()
+        }
+    }
+    // Don't lint, wrong box type
+    let _: String = repeat(Box::new(S)).take(count).collect();
+
+    let _: String = Cow::Borrowed("test").repeat(count);
+
+    let x = "x".to_owned();
+    let _: String = x.repeat(count);
+
+    let x = 'x';
+    // Don't lint, not char literal
+    let _: String = repeat(x).take(count).collect();
+}
+
+fn _msrv_1_15() {
+    #![clippy::msrv = "1.15"]
+    // `str::repeat` was stabilized in 1.16. Do not lint this
+    let _: String = std::iter::repeat("test").take(10).collect();
+}
+
+fn _msrv_1_16() {
+    #![clippy::msrv = "1.16"]
+    let _: String = "test".repeat(10);
+}
diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.rs b/src/tools/clippy/tests/ui/manual_str_repeat.rs
new file mode 100644
index 00000000000..0d69c989b2e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_str_repeat.rs
@@ -0,0 +1,66 @@
+// run-rustfix
+
+#![feature(custom_inner_attributes)]
+#![warn(clippy::manual_str_repeat)]
+
+use std::borrow::Cow;
+use std::iter::{repeat, FromIterator};
+
+fn main() {
+    let _: String = std::iter::repeat("test").take(10).collect();
+    let _: String = std::iter::repeat('x').take(10).collect();
+    let _: String = std::iter::repeat('\'').take(10).collect();
+    let _: String = std::iter::repeat('"').take(10).collect();
+
+    let x = "test";
+    let count = 10;
+    let _ = repeat(x).take(count + 2).collect::<String>();
+
+    macro_rules! m {
+        ($e:expr) => {{ $e }};
+    }
+    // FIXME: macro args are fine
+    let _: String = repeat(m!("test")).take(m!(count)).collect();
+
+    let x = &x;
+    let _: String = repeat(*x).take(count).collect();
+
+    macro_rules! repeat_m {
+        ($e:expr) => {{ repeat($e) }};
+    }
+    // Don't lint, repeat is from a macro.
+    let _: String = repeat_m!("test").take(count).collect();
+
+    let x: Box<str> = Box::from("test");
+    let _: String = repeat(x).take(count).collect();
+
+    #[derive(Clone)]
+    struct S;
+    impl FromIterator<Box<S>> for String {
+        fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self {
+            Self::new()
+        }
+    }
+    // Don't lint, wrong box type
+    let _: String = repeat(Box::new(S)).take(count).collect();
+
+    let _: String = repeat(Cow::Borrowed("test")).take(count).collect();
+
+    let x = "x".to_owned();
+    let _: String = repeat(x).take(count).collect();
+
+    let x = 'x';
+    // Don't lint, not char literal
+    let _: String = repeat(x).take(count).collect();
+}
+
+fn _msrv_1_15() {
+    #![clippy::msrv = "1.15"]
+    // `str::repeat` was stabilized in 1.16. Do not lint this
+    let _: String = std::iter::repeat("test").take(10).collect();
+}
+
+fn _msrv_1_16() {
+    #![clippy::msrv = "1.16"]
+    let _: String = std::iter::repeat("test").take(10).collect();
+}
diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.stderr b/src/tools/clippy/tests/ui/manual_str_repeat.stderr
new file mode 100644
index 00000000000..c6511689716
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_str_repeat.stderr
@@ -0,0 +1,64 @@
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:10:21
+   |
+LL |     let _: String = std::iter::repeat("test").take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
+   |
+   = note: `-D clippy::manual-str-repeat` implied by `-D warnings`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:11:21
+   |
+LL |     let _: String = std::iter::repeat('x').take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"x".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:12:21
+   |
+LL |     let _: String = std::iter::repeat('/'').take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"'".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:13:21
+   |
+LL |     let _: String = std::iter::repeat('"').take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"/"".repeat(10)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:17:13
+   |
+LL |     let _ = repeat(x).take(count + 2).collect::<String>();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count + 2)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:26:21
+   |
+LL |     let _: String = repeat(*x).take(count).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*x).repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:35:21
+   |
+LL |     let _: String = repeat(x).take(count).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:47:21
+   |
+LL |     let _: String = repeat(Cow::Borrowed("test")).take(count).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Cow::Borrowed("test").repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:50:21
+   |
+LL |     let _: String = repeat(x).take(count).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)`
+
+error: manual implementation of `str::repeat` using iterators
+  --> $DIR/manual_str_repeat.rs:65:21
+   |
+LL |     let _: String = std::iter::repeat("test").take(10).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
index e7a29596b73..3717f962745 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
@@ -163,4 +163,19 @@ mod issue6965 {
     }
 }
 
+use std::rc::Rc;
+fn format_name(name: Option<&Rc<str>>) -> &str {
+    match name {
+        None => "<anon>",
+        Some(name) => name,
+    }
+}
+
+fn implicit_deref_ref() {
+    let _: &str = match Some(&"bye") {
+        None => "hi",
+        Some(s) => s,
+    };
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.rs b/src/tools/clippy/tests/ui/manual_unwrap_or.rs
index 66006b6c616..989adde1f5b 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.rs
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.rs
@@ -205,4 +205,19 @@ mod issue6965 {
     }
 }
 
+use std::rc::Rc;
+fn format_name(name: Option<&Rc<str>>) -> &str {
+    match name {
+        None => "<anon>",
+        Some(name) => name,
+    }
+}
+
+fn implicit_deref_ref() {
+    let _: &str = match Some(&"bye") {
+        None => "hi",
+        Some(s) => s,
+    };
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed
index 526e94b10bd..30bf6402253 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.fixed
+++ b/src/tools/clippy/tests/ui/match_single_binding.fixed
@@ -94,10 +94,7 @@ fn main() {
         0 => println!("Disabled branch"),
         _ => println!("Enabled branch"),
     }
-    // Lint
-    let x = 1;
-    let y = 1;
-    println!("Single branch");
+
     // Ok
     let x = 1;
     let y = 1;
diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs
index 6a2ca7c5e93..d8bb80d8b96 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.rs
+++ b/src/tools/clippy/tests/ui/match_single_binding.rs
@@ -106,15 +106,7 @@ fn main() {
         0 => println!("Disabled branch"),
         _ => println!("Enabled branch"),
     }
-    // Lint
-    let x = 1;
-    let y = 1;
-    match match y {
-        0 => 1,
-        _ => 2,
-    } {
-        _ => println!("Single branch"),
-    }
+
     // Ok
     let x = 1;
     let y = 1;
diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr
index cbbf5d29c02..795c8c3e24d 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.stderr
+++ b/src/tools/clippy/tests/ui/match_single_binding.stderr
@@ -167,16 +167,5 @@ LL |             unwrapped
 LL |         })
    |
 
-error: this match could be replaced by its body itself
-  --> $DIR/match_single_binding.rs:112:5
-   |
-LL | /     match match y {
-LL | |         0 => 1,
-LL | |         _ => 2,
-LL | |     } {
-LL | |         _ => println!("Single branch"),
-LL | |     }
-   | |_____^ help: consider using the match body instead: `println!("Single branch");`
-
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_single_binding2.fixed b/src/tools/clippy/tests/ui/match_single_binding2.fixed
index e73a85b73d7..a91fcc2125d 100644
--- a/src/tools/clippy/tests/ui/match_single_binding2.fixed
+++ b/src/tools/clippy/tests/ui/match_single_binding2.fixed
@@ -34,4 +34,20 @@ fn main() {
         },
         None => println!("nothing"),
     }
+
+    fn side_effects() {}
+
+    // Lint (scrutinee has side effects)
+    // issue #7094
+    side_effects();
+    println!("Side effects");
+
+    // Lint (scrutinee has side effects)
+    // issue #7094
+    let x = 1;
+    match x {
+        0 => 1,
+        _ => 2,
+    };
+    println!("Single branch");
 }
diff --git a/src/tools/clippy/tests/ui/match_single_binding2.rs b/src/tools/clippy/tests/ui/match_single_binding2.rs
index 7362cb390e5..476386ebabe 100644
--- a/src/tools/clippy/tests/ui/match_single_binding2.rs
+++ b/src/tools/clippy/tests/ui/match_single_binding2.rs
@@ -34,4 +34,22 @@ fn main() {
         },
         None => println!("nothing"),
     }
+
+    fn side_effects() {}
+
+    // Lint (scrutinee has side effects)
+    // issue #7094
+    match side_effects() {
+        _ => println!("Side effects"),
+    }
+
+    // Lint (scrutinee has side effects)
+    // issue #7094
+    let x = 1;
+    match match x {
+        0 => 1,
+        _ => 2,
+    } {
+        _ => println!("Single branch"),
+    }
 }
diff --git a/src/tools/clippy/tests/ui/match_single_binding2.stderr b/src/tools/clippy/tests/ui/match_single_binding2.stderr
index bc18d191aa3..4372f55af87 100644
--- a/src/tools/clippy/tests/ui/match_single_binding2.stderr
+++ b/src/tools/clippy/tests/ui/match_single_binding2.stderr
@@ -30,5 +30,39 @@ LL |             let (a, b) = get_tup();
 LL |             println!("a {:?} and b {:?}", a, b);
    |
 
-error: aborting due to 2 previous errors
+error: this match could be replaced by its scrutinee and body
+  --> $DIR/match_single_binding2.rs:42:5
+   |
+LL | /     match side_effects() {
+LL | |         _ => println!("Side effects"),
+LL | |     }
+   | |_____^
+   |
+help: consider using the scrutinee and body instead
+   |
+LL |     side_effects();
+LL |     println!("Side effects");
+   |
+
+error: this match could be replaced by its scrutinee and body
+  --> $DIR/match_single_binding2.rs:49:5
+   |
+LL | /     match match x {
+LL | |         0 => 1,
+LL | |         _ => 2,
+LL | |     } {
+LL | |         _ => println!("Single branch"),
+LL | |     }
+   | |_____^
+   |
+help: consider using the scrutinee and body instead
+   |
+LL |     match x {
+LL |         0 => 1,
+LL |         _ => 2,
+LL |     };
+LL |     println!("Single branch");
+   |
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.rs b/src/tools/clippy/tests/ui/missing-doc-impl.rs
index 57af84dcdf4..bfa9ef01b0e 100644
--- a/src/tools/clippy/tests/ui/missing-doc-impl.rs
+++ b/src/tools/clippy/tests/ui/missing-doc-impl.rs
@@ -67,7 +67,10 @@ impl PubFoo {
     pub fn foo() {}
     /// dox
     pub fn foo1() {}
-    fn foo2() {}
+    #[must_use = "yep"]
+    fn foo2() -> u32 {
+        1
+    }
     #[allow(clippy::missing_docs_in_private_items)]
     pub fn foo3() {}
 }
diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.stderr b/src/tools/clippy/tests/ui/missing-doc-impl.stderr
index 7e10404ca00..d33d512475b 100644
--- a/src/tools/clippy/tests/ui/missing-doc-impl.stderr
+++ b/src/tools/clippy/tests/ui/missing-doc-impl.stderr
@@ -94,10 +94,12 @@ LL |     pub fn foo() {}
    |     ^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:70:5
+  --> $DIR/missing-doc-impl.rs:71:5
    |
-LL |     fn foo2() {}
-   |     ^^^^^^^^^^^^
+LL | /     fn foo2() -> u32 {
+LL | |         1
+LL | |     }
+   | |_____^
 
 error: aborting due to 15 previous errors
 
diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.rs b/src/tools/clippy/tests/ui/module_name_repetitions.rs
index 669bf01a84c..f5908cb5701 100644
--- a/src/tools/clippy/tests/ui/module_name_repetitions.rs
+++ b/src/tools/clippy/tests/ui/module_name_repetitions.rs
@@ -15,12 +15,4 @@ mod foo {
     pub struct Foobar;
 }
 
-#[cfg(test)]
-mod test {
-    #[test]
-    fn it_works() {
-        assert_eq!(2 + 2, 4);
-    }
-}
-
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed
new file mode 100644
index 00000000000..5e1ea663a10
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed
@@ -0,0 +1,40 @@
+// run-rustfix
+
+#![warn(clippy::needless_bitwise_bool)]
+
+fn returns_bool() -> bool {
+    true
+}
+
+const fn const_returns_bool() -> bool {
+    false
+}
+
+fn main() {
+    let (x, y) = (false, true);
+    if x & y {
+        println!("true")
+    }
+    if returns_bool() & x {
+        println!("true")
+    }
+    if !returns_bool() & returns_bool() {
+        println!("true")
+    }
+    if y && !x {
+        println!("true")
+    }
+
+    // BELOW: lints we hope to catch as `Expr::can_have_side_effects` improves.
+    if y & !const_returns_bool() {
+        println!("true") // This is a const function, in an UnOp
+    }
+
+    if y & "abcD".is_empty() {
+        println!("true") // This is a const method call
+    }
+
+    if y & (0 < 1) {
+        println!("true") // This is a BinOp with no side effects
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs
new file mode 100644
index 00000000000..f3075fba0a2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs
@@ -0,0 +1,40 @@
+// run-rustfix
+
+#![warn(clippy::needless_bitwise_bool)]
+
+fn returns_bool() -> bool {
+    true
+}
+
+const fn const_returns_bool() -> bool {
+    false
+}
+
+fn main() {
+    let (x, y) = (false, true);
+    if x & y {
+        println!("true")
+    }
+    if returns_bool() & x {
+        println!("true")
+    }
+    if !returns_bool() & returns_bool() {
+        println!("true")
+    }
+    if y & !x {
+        println!("true")
+    }
+
+    // BELOW: lints we hope to catch as `Expr::can_have_side_effects` improves.
+    if y & !const_returns_bool() {
+        println!("true") // This is a const function, in an UnOp
+    }
+
+    if y & "abcD".is_empty() {
+        println!("true") // This is a const method call
+    }
+
+    if y & (0 < 1) {
+        println!("true") // This is a BinOp with no side effects
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr
new file mode 100644
index 00000000000..63c88ef63f5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr
@@ -0,0 +1,10 @@
+error: use of bitwise operator instead of lazy operator between booleans
+  --> $DIR/needless_bitwise_bool.rs:24:8
+   |
+LL |     if y & !x {
+   |        ^^^^^^ help: try: `y && !x`
+   |
+   = note: `-D clippy::needless-bitwise-bool` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index 5ae4a0e79b9..a87171dc3f2 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -18,7 +18,6 @@ fn main() {
     let vec = Vec::new();
     let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]`
     h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait`
-    if let Some(cake) = Some(&5) {}
     let garbl = match 42 {
         44 => &a,
         45 => {
@@ -43,19 +42,3 @@ trait Trait {}
 impl<'a> Trait for &'a str {}
 
 fn h(_: &dyn Trait) {}
-#[warn(clippy::needless_borrow)]
-#[allow(dead_code)]
-fn issue_1432() {
-    let mut v = Vec::<String>::new();
-    let _ = v.iter_mut().filter(|&ref a| a.is_empty());
-    let _ = v.iter().filter(|&a| a.is_empty());
-
-    let _ = v.iter().filter(|&a| a.is_empty());
-}
-
-#[allow(dead_code)]
-#[warn(clippy::needless_borrow)]
-#[derive(Debug)]
-enum Foo<'a> {
-    Str(&'a str),
-}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
index 1e281316c8a..059dc8ceac3 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -18,7 +18,6 @@ fn main() {
     let vec = Vec::new();
     let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]`
     h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait`
-    if let Some(ref cake) = Some(&5) {}
     let garbl = match 42 {
         44 => &a,
         45 => {
@@ -43,19 +42,3 @@ trait Trait {}
 impl<'a> Trait for &'a str {}
 
 fn h(_: &dyn Trait) {}
-#[warn(clippy::needless_borrow)]
-#[allow(dead_code)]
-fn issue_1432() {
-    let mut v = Vec::<String>::new();
-    let _ = v.iter_mut().filter(|&ref a| a.is_empty());
-    let _ = v.iter().filter(|&ref a| a.is_empty());
-
-    let _ = v.iter().filter(|&a| a.is_empty());
-}
-
-#[allow(dead_code)]
-#[warn(clippy::needless_borrow)]
-#[derive(Debug)]
-enum Foo<'a> {
-    Str(&'a str),
-}
diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr
index bea4b41b803..6eddf26db06 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -6,23 +6,11 @@ LL |     let c = x(&&a);
    |
    = note: `-D clippy::needless-borrow` implied by `-D warnings`
 
-error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow.rs:21:17
-   |
-LL |     if let Some(ref cake) = Some(&5) {}
-   |                 ^^^^^^^^ help: change this to: `cake`
-
 error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:28:15
+  --> $DIR/needless_borrow.rs:27:15
    |
 LL |         46 => &&a,
    |               ^^^ help: change this to: `&a`
 
-error: this pattern creates a reference to a reference
-  --> $DIR/needless_borrow.rs:51:31
-   |
-LL |     let _ = v.iter().filter(|&ref a| a.is_empty());
-   |                               ^^^^^ help: change this to: `a`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.rs b/src/tools/clippy/tests/ui/needless_borrow_pat.rs
new file mode 100644
index 00000000000..f0926220755
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_borrow_pat.rs
@@ -0,0 +1,151 @@
+// edition:2018
+// FIXME: run-rustfix waiting on multi-span suggestions
+
+#![warn(clippy::needless_borrow)]
+#![allow(clippy::needless_borrowed_reference)]
+
+fn f1(_: &str) {}
+macro_rules! m1 {
+    ($e:expr) => {
+        f1($e);
+    };
+}
+macro_rules! m3 {
+    ($i:ident) => {
+        Some(ref $i)
+    };
+}
+macro_rules! if_chain {
+    (if $e:expr; $($rest:tt)*) => {
+        if $e {
+            if_chain!($($rest)*)
+        }
+    };
+
+    (if let $p:pat = $e:expr; $($rest:tt)*) => {
+        if let $p = $e {
+            if_chain!($($rest)*)
+        }
+    };
+
+    (then $b:block) => {
+        $b
+    };
+}
+
+#[allow(dead_code)]
+fn main() {
+    let x = String::new();
+
+    // Ok, reference to a String.
+    let _: &String = match Some(x.clone()) {
+        Some(ref x) => x,
+        None => return,
+    };
+
+    // Ok, reference to a &mut String
+    let _: &&mut String = match Some(&mut x.clone()) {
+        Some(ref x) => x,
+        None => return,
+    };
+
+    // Ok, the pattern is from a macro
+    let _: &String = match Some(&x) {
+        m3!(x) => x,
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _: &String = match Some(&x) {
+        Some(ref x) => x,
+        None => return,
+    };
+
+    // Err, reference to a &String.
+    let _: &String = match Some(&x) {
+        Some(ref x) => *x,
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _: &String = match Some(&x) {
+        Some(ref x) => {
+            f1(x);
+            f1(*x);
+            x
+        },
+        None => return,
+    };
+
+    // Err, reference to a &String
+    match Some(&x) {
+        Some(ref x) => m1!(x),
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _ = |&ref x: &&String| {
+        let _: &String = x;
+    };
+
+    // Err, reference to a &String
+    let (ref y,) = (&x,);
+    let _: &String = *y;
+
+    let y = &&x;
+    // Ok, different y
+    let _: &String = *y;
+
+    let x = (0, 0);
+    // Err, reference to a &u32. Don't suggest adding a reference to the field access.
+    let _: u32 = match Some(&x) {
+        Some(ref x) => x.0,
+        None => return,
+    };
+
+    enum E {
+        A(&'static u32),
+        B(&'static u32),
+    }
+    // Err, reference to &u32.
+    let _: &u32 = match E::A(&0) {
+        E::A(ref x) | E::B(ref x) => *x,
+    };
+
+    // Err, reference to &String.
+    if_chain! {
+        if true;
+        if let Some(ref x) = Some(&String::new());
+        then {
+            f1(x);
+        }
+    }
+}
+
+// Err, reference to a &String
+fn f2<'a>(&ref x: &&'a String) -> &'a String {
+    let _: &String = x;
+    *x
+}
+
+trait T1 {
+    // Err, reference to a &String
+    fn f(&ref x: &&String) {
+        let _: &String = x;
+    }
+}
+
+struct S;
+impl T1 for S {
+    // Err, reference to a &String
+    fn f(&ref x: &&String) {
+        let _: &String = *x;
+    }
+}
+
+// Ok - used to error due to rustc bug
+#[allow(dead_code)]
+#[derive(Debug)]
+enum Foo<'a> {
+    Str(&'a str),
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr
new file mode 100644
index 00000000000..32913d59f7a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr
@@ -0,0 +1,112 @@
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:60:14
+   |
+LL |         Some(ref x) => x,
+   |              ^^^^^ help: try this: `x`
+   |
+   = note: `-D clippy::needless-borrow` implied by `-D warnings`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:66:14
+   |
+LL |         Some(ref x) => *x,
+   |              ^^^^^
+   |
+help: try this
+   |
+LL |         Some(x) => x,
+   |              ^     ^
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:72:14
+   |
+LL |         Some(ref x) => {
+   |              ^^^^^
+   |
+help: try this
+   |
+LL |         Some(x) => {
+LL |             f1(x);
+LL |             f1(x);
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:82:14
+   |
+LL |         Some(ref x) => m1!(x),
+   |              ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:87:15
+   |
+LL |     let _ = |&ref x: &&String| {
+   |               ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:92:10
+   |
+LL |     let (ref y,) = (&x,);
+   |          ^^^^^
+   |
+help: try this
+   |
+LL |     let (y,) = (&x,);
+LL |     let _: &String = y;
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:102:14
+   |
+LL |         Some(ref x) => x.0,
+   |              ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:112:14
+   |
+LL |         E::A(ref x) | E::B(ref x) => *x,
+   |              ^^^^^         ^^^^^
+   |
+help: try this
+   |
+LL |         E::A(x) | E::B(x) => x,
+   |              ^         ^     ^
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:118:21
+   |
+LL |         if let Some(ref x) = Some(&String::new());
+   |                     ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:126:12
+   |
+LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
+   |            ^^^^^
+   |
+help: try this
+   |
+LL | fn f2<'a>(&x: &&'a String) -> &'a String {
+LL |     let _: &String = x;
+LL |     x
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:133:11
+   |
+LL |     fn f(&ref x: &&String) {
+   |           ^^^^^ help: try this: `x`
+
+error: this pattern creates a reference to a reference
+  --> $DIR/needless_borrow_pat.rs:141:11
+   |
+LL |     fn f(&ref x: &&String) {
+   |           ^^^^^
+   |
+help: try this
+   |
+LL |     fn f(&x: &&String) {
+LL |         let _: &String = x;
+   |
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed
index af6c7bf15ea..6ecbbcb6249 100644
--- a/src/tools/clippy/tests/ui/needless_collect.fixed
+++ b/src/tools/clippy/tests/ui/needless_collect.fixed
@@ -2,7 +2,7 @@
 
 #![allow(unused, clippy::suspicious_map, clippy::iter_count)]
 
-use std::collections::{BTreeSet, HashMap, HashSet};
+use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList};
 
 #[warn(clippy::needless_collect)]
 #[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)]
@@ -13,9 +13,24 @@ fn main() {
         // Empty
     }
     sample.iter().cloned().any(|x| x == 1);
-    sample.iter().map(|x| (x, x)).count();
+    // #7164 HashMap's and BTreeMap's `len` usage should not be linted
+    sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len();
+    sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().len();
+
+    sample.iter().map(|x| (x, x)).next().is_none();
+    sample.iter().map(|x| (x, x)).next().is_none();
+
     // Notice the `HashSet`--this should not be linted
     sample.iter().collect::<HashSet<_>>().len();
     // Neither should this
     sample.iter().collect::<BTreeSet<_>>().len();
+
+    sample.iter().count();
+    sample.iter().next().is_none();
+    sample.iter().cloned().any(|x| x == 1);
+    sample.iter().any(|x| x == &1);
+
+    // `BinaryHeap` doesn't have `contains` method
+    sample.iter().count();
+    sample.iter().next().is_none();
 }
diff --git a/src/tools/clippy/tests/ui/needless_collect.rs b/src/tools/clippy/tests/ui/needless_collect.rs
index 6ae14f370b1..8dc69bcf5b3 100644
--- a/src/tools/clippy/tests/ui/needless_collect.rs
+++ b/src/tools/clippy/tests/ui/needless_collect.rs
@@ -2,7 +2,7 @@
 
 #![allow(unused, clippy::suspicious_map, clippy::iter_count)]
 
-use std::collections::{BTreeSet, HashMap, HashSet};
+use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList};
 
 #[warn(clippy::needless_collect)]
 #[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)]
@@ -13,9 +13,24 @@ fn main() {
         // Empty
     }
     sample.iter().cloned().collect::<Vec<_>>().contains(&1);
+    // #7164 HashMap's and BTreeMap's `len` usage should not be linted
     sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len();
+    sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().len();
+
+    sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().is_empty();
+    sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().is_empty();
+
     // Notice the `HashSet`--this should not be linted
     sample.iter().collect::<HashSet<_>>().len();
     // Neither should this
     sample.iter().collect::<BTreeSet<_>>().len();
+
+    sample.iter().collect::<LinkedList<_>>().len();
+    sample.iter().collect::<LinkedList<_>>().is_empty();
+    sample.iter().cloned().collect::<LinkedList<_>>().contains(&1);
+    sample.iter().collect::<LinkedList<_>>().contains(&&1);
+
+    // `BinaryHeap` doesn't have `contains` method
+    sample.iter().collect::<BinaryHeap<_>>().len();
+    sample.iter().collect::<BinaryHeap<_>>().is_empty();
 }
diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr
index 2a9539d5975..039091627a8 100644
--- a/src/tools/clippy/tests/ui/needless_collect.stderr
+++ b/src/tools/clippy/tests/ui/needless_collect.stderr
@@ -19,10 +19,52 @@ LL |     sample.iter().cloned().collect::<Vec<_>>().contains(&1);
    |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)`
 
 error: avoid using `collect()` when not needed
-  --> $DIR/needless_collect.rs:16:35
+  --> $DIR/needless_collect.rs:20:35
    |
-LL |     sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len();
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()`
+LL |     sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().is_empty();
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
 
-error: aborting due to 4 previous errors
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:21:35
+   |
+LL |     sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().is_empty();
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:28:19
+   |
+LL |     sample.iter().collect::<LinkedList<_>>().len();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:29:19
+   |
+LL |     sample.iter().collect::<LinkedList<_>>().is_empty();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:30:28
+   |
+LL |     sample.iter().cloned().collect::<LinkedList<_>>().contains(&1);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:31:19
+   |
+LL |     sample.iter().collect::<LinkedList<_>>().contains(&&1);
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &1)`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:34:19
+   |
+LL |     sample.iter().collect::<BinaryHeap<_>>().len();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()`
+
+error: avoid using `collect()` when not needed
+  --> $DIR/needless_collect.rs:35:19
+   |
+LL |     sample.iter().collect::<BinaryHeap<_>>().is_empty();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.rs b/src/tools/clippy/tests/ui/needless_collect_indirect.rs
index 2458bf1e490..2c94235b8f5 100644
--- a/src/tools/clippy/tests/ui/needless_collect_indirect.rs
+++ b/src/tools/clippy/tests/ui/needless_collect_indirect.rs
@@ -1,4 +1,4 @@
-use std::collections::{BinaryHeap, HashMap, LinkedList, VecDeque};
+use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque};
 
 fn main() {
     let sample = [1; 5];
@@ -75,3 +75,9 @@ mod issue7110 {
         buffer.len()
     }
 }
+
+fn allow_test() {
+    #[allow(clippy::needless_collect)]
+    let v = [1].iter().collect::<Vec<_>>();
+    v.into_iter().collect::<HashSet<_>>();
+}
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.fixed b/src/tools/clippy/tests/ui/needless_question_mark.fixed
index 52ddd9d2dc8..f1fc81aa12b 100644
--- a/src/tools/clippy/tests/ui/needless_question_mark.fixed
+++ b/src/tools/clippy/tests/ui/needless_question_mark.fixed
@@ -94,6 +94,11 @@ where
     Ok(x?)
 }
 
+// not quite needless
+fn deref_ref(s: Option<&String>) -> Option<&str> {
+    Some(s?)
+}
+
 fn main() {}
 
 // #6921 if a macro wraps an expr in Some(  ) and the ? is in the macro use,
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.rs b/src/tools/clippy/tests/ui/needless_question_mark.rs
index 1ea4ba0d83f..44a0c5f61b5 100644
--- a/src/tools/clippy/tests/ui/needless_question_mark.rs
+++ b/src/tools/clippy/tests/ui/needless_question_mark.rs
@@ -94,6 +94,11 @@ where
     Ok(x?)
 }
 
+// not quite needless
+fn deref_ref(s: Option<&String>) -> Option<&str> {
+    Some(s?)
+}
+
 fn main() {}
 
 // #6921 if a macro wraps an expr in Some(  ) and the ? is in the macro use,
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr
index f1f05d1af3a..02bf50d077a 100644
--- a/src/tools/clippy/tests/ui/needless_question_mark.stderr
+++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr
@@ -67,7 +67,7 @@ LL |         return Ok(t.magic?);
    |                ^^^^^^^^^^^^ help: try: `t.magic`
 
 error: question mark operator is useless here
-  --> $DIR/needless_question_mark.rs:115:27
+  --> $DIR/needless_question_mark.rs:120:27
    |
 LL |         || -> Option<_> { Some(Some($expr)?) }()
    |                           ^^^^^^^^^^^^^^^^^^ help: try: `Some($expr)`
diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs
index 8fbfcb79860..7ec845adfaa 100644
--- a/src/tools/clippy/tests/ui/no_effect.rs
+++ b/src/tools/clippy/tests/ui/no_effect.rs
@@ -91,6 +91,9 @@ fn main() {
     let s: String = "foo".into();
     FooString { s: s };
 
+    #[allow(clippy::no_effect)]
+    0;
+
     // Do not warn
     get_number();
     unsafe { unsafe_fn() };
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index 47e7460fa7a..769ccc14bc1 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -10,7 +10,11 @@ fn bad1(string: Option<&str>) -> (bool, &str) {
 fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> {
     if string.is_none() {
         None
-    } else { string.map_or(Some((false, "")), |x| Some((true, x))) }
+    } else if let Some(x) = string {
+        Some((true, x))
+    } else {
+        Some((false, ""))
+    }
 }
 
 fn unop_bad(string: &Option<&str>, mut num: Option<i32>) {
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index 7aab068800a..4ebb068d22e 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -11,17 +11,6 @@ LL | |     }
    = note: `-D clippy::option-if-let-else` implied by `-D warnings`
 
 error: use Option::map_or instead of an if let/else
-  --> $DIR/option_if_let_else.rs:17:12
-   |
-LL |       } else if let Some(x) = string {
-   |  ____________^
-LL | |         Some((true, x))
-LL | |     } else {
-LL | |         Some((false, ""))
-LL | |     }
-   | |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }`
-
-error: use Option::map_or instead of an if let/else
   --> $DIR/option_if_let_else.rs:25:13
    |
 LL |     let _ = if let Some(s) = *string { s.len() } else { 0 };
@@ -159,5 +148,5 @@ error: use Option::map_or instead of an if let/else
 LL |     let _ = if let Some(x) = optional { x + 2 } else { 5 };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
 
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs
new file mode 100644
index 00000000000..c7235e1c221
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs
@@ -0,0 +1,76 @@
+// edition:2018
+// FIXME: run-rustfix waiting on multi-span suggestions
+
+#![warn(clippy::ref_binding_to_reference)]
+#![allow(clippy::needless_borrowed_reference)]
+
+fn f1(_: &str) {}
+macro_rules! m2 {
+    ($e:expr) => {
+        f1(*$e);
+    };
+}
+macro_rules! m3 {
+    ($i:ident) => {
+        Some(ref $i)
+    };
+}
+
+#[allow(dead_code)]
+fn main() {
+    let x = String::new();
+
+    // Ok, the pattern is from a macro
+    let _: &&String = match Some(&x) {
+        m3!(x) => x,
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _: &&String = match Some(&x) {
+        Some(ref x) => x,
+        None => return,
+    };
+
+    // Err, reference to a &String
+    let _: &&String = match Some(&x) {
+        Some(ref x) => {
+            f1(x);
+            f1(*x);
+            x
+        },
+        None => return,
+    };
+
+    // Err, reference to a &String
+    match Some(&x) {
+        Some(ref x) => m2!(x),
+        None => return,
+    }
+
+    // Err, reference to a &String
+    let _ = |&ref x: &&String| {
+        let _: &&String = x;
+    };
+}
+
+// Err, reference to a &String
+fn f2<'a>(&ref x: &&'a String) -> &'a String {
+    let _: &&String = x;
+    *x
+}
+
+trait T1 {
+    // Err, reference to a &String
+    fn f(&ref x: &&String) {
+        let _: &&String = x;
+    }
+}
+
+struct S;
+impl T1 for S {
+    // Err, reference to a &String
+    fn f(&ref x: &&String) {
+        let _: &&String = x;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
new file mode 100644
index 00000000000..00aeff4fefa
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr
@@ -0,0 +1,88 @@
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:31:14
+   |
+LL |         Some(ref x) => x,
+   |              ^^^^^
+   |
+   = note: `-D clippy::ref-binding-to-reference` implied by `-D warnings`
+help: try this
+   |
+LL |         Some(x) => &x,
+   |              ^     ^^
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:37:14
+   |
+LL |         Some(ref x) => {
+   |              ^^^^^
+   |
+help: try this
+   |
+LL |         Some(x) => {
+LL |             f1(x);
+LL |             f1(x);
+LL |             &x
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:47:14
+   |
+LL |         Some(ref x) => m2!(x),
+   |              ^^^^^
+   |
+help: try this
+   |
+LL |         Some(x) => m2!(&x),
+   |              ^         ^^
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:52:15
+   |
+LL |     let _ = |&ref x: &&String| {
+   |               ^^^^^
+   |
+help: try this
+   |
+LL |     let _ = |&x: &&String| {
+LL |         let _: &&String = &x;
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:58:12
+   |
+LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
+   |            ^^^^^
+   |
+help: try this
+   |
+LL | fn f2<'a>(&x: &&'a String) -> &'a String {
+LL |     let _: &&String = &x;
+LL |     x
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:65:11
+   |
+LL |     fn f(&ref x: &&String) {
+   |           ^^^^^
+   |
+help: try this
+   |
+LL |     fn f(&x: &&String) {
+LL |         let _: &&String = &x;
+   |
+
+error: this pattern creates a reference to a reference
+  --> $DIR/ref_binding_to_reference.rs:73:11
+   |
+LL |     fn f(&ref x: &&String) {
+   |           ^^^^^
+   |
+help: try this
+   |
+LL |     fn f(&x: &&String) {
+LL |         let _: &&String = &x;
+   |
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/similar_names.rs b/src/tools/clippy/tests/ui/similar_names.rs
index 5981980988b..2b1bc1f4859 100644
--- a/src/tools/clippy/tests/ui/similar_names.rs
+++ b/src/tools/clippy/tests/ui/similar_names.rs
@@ -72,6 +72,10 @@ fn main() {
     let rx1: i32;
     let tx_cake: i32;
     let rx_cake: i32;
+
+    // names often used in win32 code (for example WindowProc)
+    let wparam: i32;
+    let lparam: i32;
 }
 
 fn foo() {
diff --git a/src/tools/clippy/tests/ui/similar_names.stderr b/src/tools/clippy/tests/ui/similar_names.stderr
index 0256f126a94..a7eb2be0778 100644
--- a/src/tools/clippy/tests/ui/similar_names.stderr
+++ b/src/tools/clippy/tests/ui/similar_names.stderr
@@ -92,13 +92,13 @@ LL |     let parsee: i32;
    |         ^^^^^^
 
 error: binding's name is too similar to existing binding
-  --> $DIR/similar_names.rs:81:16
+  --> $DIR/similar_names.rs:85:16
    |
 LL |         bpple: sprang,
    |                ^^^^^^
    |
 note: existing binding defined here
-  --> $DIR/similar_names.rs:80:16
+  --> $DIR/similar_names.rs:84:16
    |
 LL |         apple: spring,
    |                ^^^^^^
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.fixed b/src/tools/clippy/tests/ui/single_char_pattern.fixed
index fcbe9af9f56..1abd2b7883d 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.fixed
+++ b/src/tools/clippy/tests/ui/single_char_pattern.fixed
@@ -25,8 +25,8 @@ fn main() {
     x.rsplit('x');
     x.split_terminator('x');
     x.rsplit_terminator('x');
-    x.splitn(0, 'x');
-    x.rsplitn(0, 'x');
+    x.splitn(2, 'x');
+    x.rsplitn(2, 'x');
     x.matches('x');
     x.rmatches('x');
     x.match_indices('x');
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.rs b/src/tools/clippy/tests/ui/single_char_pattern.rs
index b8bc20f4070..e662bf34be2 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.rs
+++ b/src/tools/clippy/tests/ui/single_char_pattern.rs
@@ -25,8 +25,8 @@ fn main() {
     x.rsplit("x");
     x.split_terminator("x");
     x.rsplit_terminator("x");
-    x.splitn(0, "x");
-    x.rsplitn(0, "x");
+    x.splitn(2, "x");
+    x.rsplitn(2, "x");
     x.matches("x");
     x.rmatches("x");
     x.match_indices("x");
diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr
index 6d94d8a34e3..22d4b2d460f 100644
--- a/src/tools/clippy/tests/ui/single_char_pattern.stderr
+++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr
@@ -75,13 +75,13 @@ LL |     x.rsplit_terminator("x");
 error: single-character string constant used as pattern
   --> $DIR/single_char_pattern.rs:28:17
    |
-LL |     x.splitn(0, "x");
+LL |     x.splitn(2, "x");
    |                 ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
   --> $DIR/single_char_pattern.rs:29:18
    |
-LL |     x.rsplitn(0, "x");
+LL |     x.rsplitn(2, "x");
    |                  ^^^ help: try using a `char` instead: `'x'`
 
 error: single-character string constant used as pattern
diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.rs b/src/tools/clippy/tests/ui/suspicious_splitn.rs
new file mode 100644
index 00000000000..a21d94cf20b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_splitn.rs
@@ -0,0 +1,20 @@
+#![warn(clippy::suspicious_splitn)]
+
+fn main() {
+    let _ = "a,b,c".splitn(3, ',');
+    let _ = [0, 1, 2, 1, 3].splitn(3, |&x| x == 1);
+    let _ = "".splitn(0, ',');
+    let _ = [].splitn(0, |&x: &u32| x == 1);
+
+    let _ = "a,b".splitn(0, ',');
+    let _ = "a,b".rsplitn(0, ',');
+    let _ = "a,b".splitn(1, ',');
+    let _ = [0, 1, 2].splitn(0, |&x| x == 1);
+    let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1);
+    let _ = [0, 1, 2].splitn(1, |&x| x == 1);
+    let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1);
+
+    const X: usize = 0;
+    let _ = "a,b".splitn(X + 1, ',');
+    let _ = "a,b".splitn(X, ',');
+}
diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.stderr b/src/tools/clippy/tests/ui/suspicious_splitn.stderr
new file mode 100644
index 00000000000..b6220ae2393
--- /dev/null
+++ b/src/tools/clippy/tests/ui/suspicious_splitn.stderr
@@ -0,0 +1,75 @@
+error: `splitn` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:9:13
+   |
+LL |     let _ = "a,b".splitn(0, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::suspicious-splitn` implied by `-D warnings`
+   = note: the resulting iterator will always return `None`
+
+error: `rsplitn` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:10:13
+   |
+LL |     let _ = "a,b".rsplitn(0, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return `None`
+
+error: `splitn` called with `1` split
+  --> $DIR/suspicious_splitn.rs:11:13
+   |
+LL |     let _ = "a,b".splitn(1, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return the entire string followed by `None`
+
+error: `splitn` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:12:13
+   |
+LL |     let _ = [0, 1, 2].splitn(0, |&x| x == 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return `None`
+
+error: `splitn_mut` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:13:13
+   |
+LL |     let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return `None`
+
+error: `splitn` called with `1` split
+  --> $DIR/suspicious_splitn.rs:14:13
+   |
+LL |     let _ = [0, 1, 2].splitn(1, |&x| x == 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return the entire slice followed by `None`
+
+error: `rsplitn_mut` called with `1` split
+  --> $DIR/suspicious_splitn.rs:15:13
+   |
+LL |     let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return the entire slice followed by `None`
+
+error: `splitn` called with `1` split
+  --> $DIR/suspicious_splitn.rs:18:13
+   |
+LL |     let _ = "a,b".splitn(X + 1, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return the entire string followed by `None`
+
+error: `splitn` called with `0` splits
+  --> $DIR/suspicious_splitn.rs:19:13
+   |
+LL |     let _ = "a,b".splitn(X, ',');
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the resulting iterator will always return `None`
+
+error: aborting due to 9 previous errors
+
diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
index ccc3cdb2b74..2b0005bbff1 100644
--- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
+++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr
@@ -89,12 +89,6 @@ LL |     fn trait_method(&self, _foo: &Foo);
    |                                  ^^^^ help: consider passing by value instead: `Foo`
 
 error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
-  --> $DIR/trivially_copy_pass_by_ref.rs:80:37
-   |
-LL |     fn trait_method2(&self, _color: &Color);
-   |                                     ^^^^^^ help: consider passing by value instead: `Color`
-
-error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte)
   --> $DIR/trivially_copy_pass_by_ref.rs:108:21
    |
 LL |     fn foo_never(x: &i32) {
@@ -106,5 +100,5 @@ error: this argument (N byte) is passed by reference, but would be more efficien
 LL |     fn foo(x: &i32) {
    |               ^^^^ help: consider passing by value instead: `i32`
 
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.rs b/src/tools/clippy/tests/ui/unnecessary_wraps.rs
index 54f22e3ee6a..63648ef5826 100644
--- a/src/tools/clippy/tests/ui/unnecessary_wraps.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_wraps.rs
@@ -65,7 +65,7 @@ fn func10() -> Option<()> {
     unimplemented!()
 }
 
-struct A;
+pub struct A;
 
 impl A {
     // should not be linted
diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed
index 3c422cc4fee..f0c2ba7ccdf 100644
--- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed
+++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed
@@ -1,10 +1,11 @@
 // run-rustfix
+// aux-build:proc_macro_derive.rs
 
 #![warn(clippy::unseparated_literal_suffix)]
 #![allow(dead_code)]
 
 #[macro_use]
-extern crate clippy_mini_macro_test;
+extern crate proc_macro_derive;
 
 // Test for proc-macro attribute
 #[derive(ClippyMiniMacroTest)]
diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs
index 09608661e0e..f44880b4147 100644
--- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs
+++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs
@@ -1,10 +1,11 @@
 // run-rustfix
+// aux-build:proc_macro_derive.rs
 
 #![warn(clippy::unseparated_literal_suffix)]
 #![allow(dead_code)]
 
 #[macro_use]
-extern crate clippy_mini_macro_test;
+extern crate proc_macro_derive;
 
 // Test for proc-macro attribute
 #[derive(ClippyMiniMacroTest)]
diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr
index a0c0be7a9d1..ab2f75e0c56 100644
--- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr
+++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr
@@ -1,5 +1,5 @@
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:23:18
+  --> $DIR/unseparated_prefix_literals.rs:24:18
    |
 LL |     let _fail1 = 1234i32;
    |                  ^^^^^^^ help: add an underscore: `1234_i32`
@@ -7,43 +7,43 @@ LL |     let _fail1 = 1234i32;
    = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:24:18
+  --> $DIR/unseparated_prefix_literals.rs:25:18
    |
 LL |     let _fail2 = 1234u32;
    |                  ^^^^^^^ help: add an underscore: `1234_u32`
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:25:18
+  --> $DIR/unseparated_prefix_literals.rs:26:18
    |
 LL |     let _fail3 = 1234isize;
    |                  ^^^^^^^^^ help: add an underscore: `1234_isize`
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:26:18
+  --> $DIR/unseparated_prefix_literals.rs:27:18
    |
 LL |     let _fail4 = 1234usize;
    |                  ^^^^^^^^^ help: add an underscore: `1234_usize`
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:27:18
+  --> $DIR/unseparated_prefix_literals.rs:28:18
    |
 LL |     let _fail5 = 0x123isize;
    |                  ^^^^^^^^^^ help: add an underscore: `0x123_isize`
 
 error: float type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:31:19
+  --> $DIR/unseparated_prefix_literals.rs:32:19
    |
 LL |     let _failf1 = 1.5f32;
    |                   ^^^^^^ help: add an underscore: `1.5_f32`
 
 error: float type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:32:19
+  --> $DIR/unseparated_prefix_literals.rs:33:19
    |
 LL |     let _failf2 = 1f32;
    |                   ^^^^ help: add an underscore: `1_f32`
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:15:9
+  --> $DIR/unseparated_prefix_literals.rs:16:9
    |
 LL |         42usize
    |         ^^^^^^^ help: add an underscore: `42_usize`
@@ -54,7 +54,7 @@ LL |     let _ = lit_from_macro!();
    = note: this error originates in the macro `lit_from_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: integer type suffix should be separated by an underscore
-  --> $DIR/unseparated_prefix_literals.rs:40:16
+  --> $DIR/unseparated_prefix_literals.rs:41:16
    |
 LL |     assert_eq!(4897u32, 32223);
    |                ^^^^^^^ help: add an underscore: `4897_u32`
diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs
new file mode 100644
index 00000000000..4f4203f5fdb
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_async.rs
@@ -0,0 +1,15 @@
+// edition:2018
+#![warn(clippy::unused_async)]
+
+async fn foo() -> i32 {
+    4
+}
+
+async fn bar() -> i32 {
+    foo().await
+}
+
+fn main() {
+    foo();
+    bar();
+}
diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr
new file mode 100644
index 00000000000..8b834d205b1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_async.stderr
@@ -0,0 +1,13 @@
+error: unused `async` for function with no await statements
+  --> $DIR/unused_async.rs:4:1
+   |
+LL | / async fn foo() -> i32 {
+LL | |     4
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::unused-async` implied by `-D warnings`
+   = help: consider removing the `async` from this function
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed
index 1282befdfb3..631da6fe066 100644
--- a/src/tools/clippy/tests/ui/use_self.fixed
+++ b/src/tools/clippy/tests/ui/use_self.fixed
@@ -462,3 +462,33 @@ mod issue6818 {
         a: i32,
     }
 }
+
+mod issue7206 {
+    struct MyStruct<const C: char>;
+    impl From<MyStruct<'a'>> for MyStruct<'b'> {
+        fn from(_s: MyStruct<'a'>) -> Self {
+            Self
+        }
+    }
+
+    // keep linting non-`Const` generic args
+    struct S<'a> {
+        inner: &'a str,
+    }
+
+    struct S2<T> {
+        inner: T,
+    }
+
+    impl<T> S2<T> {
+        fn new() -> Self {
+            unimplemented!();
+        }
+    }
+
+    impl<'a> S2<S<'a>> {
+        fn new_again() -> Self {
+            Self::new()
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs
index 7aaac7b2414..7a10d755faa 100644
--- a/src/tools/clippy/tests/ui/use_self.rs
+++ b/src/tools/clippy/tests/ui/use_self.rs
@@ -462,3 +462,33 @@ mod issue6818 {
         a: i32,
     }
 }
+
+mod issue7206 {
+    struct MyStruct<const C: char>;
+    impl From<MyStruct<'a'>> for MyStruct<'b'> {
+        fn from(_s: MyStruct<'a'>) -> Self {
+            Self
+        }
+    }
+
+    // keep linting non-`Const` generic args
+    struct S<'a> {
+        inner: &'a str,
+    }
+
+    struct S2<T> {
+        inner: T,
+    }
+
+    impl<T> S2<T> {
+        fn new() -> Self {
+            unimplemented!();
+        }
+    }
+
+    impl<'a> S2<S<'a>> {
+        fn new_again() -> Self {
+            S2::new()
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr
index a32a9b9157d..cf6222c9b45 100644
--- a/src/tools/clippy/tests/ui/use_self.stderr
+++ b/src/tools/clippy/tests/ui/use_self.stderr
@@ -162,5 +162,11 @@ error: unnecessary structure name repetition
 LL |             A::new::<submod::B>(submod::B {})
    |             ^ help: use the applicable keyword: `Self`
 
-error: aborting due to 27 previous errors
+error: unnecessary structure name repetition
+  --> $DIR/use_self.rs:491:13
+   |
+LL |             S2::new()
+   |             ^^ help: use the applicable keyword: `Self`
+
+error: aborting due to 28 previous errors
 
diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed
index 03977de9455..76aa82068d6 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.fixed
+++ b/src/tools/clippy/tests/ui/useless_conversion.fixed
@@ -70,4 +70,23 @@ fn main() {
     let a: i32 = 1;
     let b: i32 = 1;
     let _ = (a + b) * 3;
+
+    // see #7205
+    let s: Foo<'a'> = Foo;
+    let _: Foo<'b'> = s.into();
+    let s2: Foo<'a'> = Foo;
+    let _: Foo<'a'> = s2;
+    let s3: Foo<'a'> = Foo;
+    let _ = s3;
+    let s4: Foo<'a'> = Foo;
+    let _ = vec![s4, s4, s4].into_iter();
+}
+
+#[derive(Copy, Clone)]
+struct Foo<const C: char>;
+
+impl From<Foo<'a'>> for Foo<'b'> {
+    fn from(_s: Foo<'a'>) -> Self {
+        Foo
+    }
 }
diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs
index f6e094c1661..ccee7abb404 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.rs
+++ b/src/tools/clippy/tests/ui/useless_conversion.rs
@@ -70,4 +70,23 @@ fn main() {
     let a: i32 = 1;
     let b: i32 = 1;
     let _ = i32::from(a + b) * 3;
+
+    // see #7205
+    let s: Foo<'a'> = Foo;
+    let _: Foo<'b'> = s.into();
+    let s2: Foo<'a'> = Foo;
+    let _: Foo<'a'> = s2.into();
+    let s3: Foo<'a'> = Foo;
+    let _ = Foo::<'a'>::from(s3);
+    let s4: Foo<'a'> = Foo;
+    let _ = vec![s4, s4, s4].into_iter().into_iter();
+}
+
+#[derive(Copy, Clone)]
+struct Foo<const C: char>;
+
+impl From<Foo<'a'>> for Foo<'b'> {
+    fn from(_s: Foo<'a'>) -> Self {
+        Foo
+    }
 }
diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr
index 26a33595031..e6760f700f3 100644
--- a/src/tools/clippy/tests/ui/useless_conversion.stderr
+++ b/src/tools/clippy/tests/ui/useless_conversion.stderr
@@ -70,5 +70,23 @@ error: useless conversion to the same type: `i32`
 LL |     let _ = i32::from(a + b) * 3;
    |             ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)`
 
-error: aborting due to 11 previous errors
+error: useless conversion to the same type: `Foo<'a'>`
+  --> $DIR/useless_conversion.rs:78:23
+   |
+LL |     let _: Foo<'a'> = s2.into();
+   |                       ^^^^^^^^^ help: consider removing `.into()`: `s2`
+
+error: useless conversion to the same type: `Foo<'a'>`
+  --> $DIR/useless_conversion.rs:80:13
+   |
+LL |     let _ = Foo::<'a'>::from(s3);
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3`
+
+error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>`
+  --> $DIR/useless_conversion.rs:82:13
+   |
+LL |     let _ = vec![s4, s4, s4].into_iter().into_iter();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()`
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
index 749393db124..c3e2cf0c4a4 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed
@@ -1,7 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::while_let_on_iterator)]
-#![allow(clippy::never_loop, unreachable_code, unused_mut)]
+#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)]
 
 fn base() {
     let mut iter = 1..20;
@@ -41,13 +41,6 @@ fn base() {
     // or this
     let mut iter = 1u32..20;
     while let Some(_) = iter.next() {
-        break;
-    }
-    println!("Remaining iter {:?}", iter);
-
-    // or this
-    let mut iter = 1u32..20;
-    while let Some(_) = iter.next() {
         iter = 1..20;
     }
 }
@@ -135,18 +128,6 @@ fn refutable2() {
 
 fn nested_loops() {
     let a = [42, 1337];
-    let mut y = a.iter();
-    loop {
-        // x is reused, so don't lint here
-        while let Some(_) = y.next() {}
-    }
-
-    let mut y = a.iter();
-    for _ in 0..2 {
-        while let Some(_) = y.next() {
-            // y is reused, don't lint
-        }
-    }
 
     loop {
         let mut y = a.iter();
@@ -167,10 +148,8 @@ fn issue1121() {
 }
 
 fn issue2965() {
-    // This should not cause an ICE and suggest:
-    //
-    // for _ in values.iter() {}
-    //
+    // This should not cause an ICE
+
     use std::collections::HashSet;
     let mut values = HashSet::new();
     values.insert(1);
@@ -205,13 +184,145 @@ fn issue1654() {
     }
 }
 
+fn issue6491() {
+    // Used in outer loop, needs &mut
+    let mut it = 1..40;
+    while let Some(n) = it.next() {
+        for m in &mut it {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+        println!("n still is {}", n);
+    }
+
+    // This is fine, inner loop uses a new iterator.
+    let mut it = 1..40;
+    for n in it {
+        let mut it = 1..40;
+        for m in it {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+
+        // Weird binding shouldn't change anything.
+        let (mut it, _) = (1..40, 0);
+        for m in it {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+
+        // Used after the loop, needs &mut.
+        let mut it = 1..40;
+        for m in &mut it {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+        println!("next item {}", it.next().unwrap());
+
+        println!("n still is {}", n);
+    }
+}
+
+fn issue6231() {
+    // Closure in the outer loop, needs &mut
+    let mut it = 1..40;
+    let mut opt = Some(0);
+    while let Some(n) = opt.take().or_else(|| it.next()) {
+        for m in &mut it {
+            if n % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+        println!("n still is {}", n);
+    }
+}
+
+fn issue1924() {
+    struct S<T>(T);
+    impl<T: Iterator<Item = u32>> S<T> {
+        fn f(&mut self) -> Option<u32> {
+            // Used as a field.
+            for i in &mut self.0 {
+                if !(3..=7).contains(&i) {
+                    return Some(i);
+                }
+            }
+            None
+        }
+
+        fn f2(&mut self) -> Option<u32> {
+            // Don't lint, self borrowed inside the loop
+            while let Some(i) = self.0.next() {
+                if i == 1 {
+                    return self.f();
+                }
+            }
+            None
+        }
+    }
+    impl<T: Iterator<Item = u32>> S<(S<T>, Option<u32>)> {
+        fn f3(&mut self) -> Option<u32> {
+            // Don't lint, self borrowed inside the loop
+            while let Some(i) = self.0.0.0.next() {
+                if i == 1 {
+                    return self.0.0.f();
+                }
+            }
+            while let Some(i) = self.0.0.0.next() {
+                if i == 1 {
+                    return self.f3();
+                }
+            }
+            // This one is fine, a different field is borrowed
+            for i in &mut self.0.0.0 {
+                if i == 1 {
+                    return self.0.1.take();
+                } else {
+                    self.0.1 = Some(i);
+                }
+            }
+            None
+        }
+    }
+
+    struct S2<T>(T, u32);
+    impl<T: Iterator<Item = u32>> Iterator for S2<T> {
+        type Item = u32;
+        fn next(&mut self) -> Option<u32> {
+            self.0.next()
+        }
+    }
+
+    // Don't lint, field of the iterator is accessed in the loop
+    let mut it = S2(1..40, 0);
+    while let Some(n) = it.next() {
+        if n == it.1 {
+            break;
+        }
+    }
+
+    // Needs &mut, field of the iterator is accessed after the loop
+    let mut it = S2(1..40, 0);
+    for n in &mut it {
+        if n == 0 {
+            break;
+        }
+    }
+    println!("iterator field {}", it.1);
+}
+
 fn main() {
-    base();
-    refutable();
-    refutable2();
-    nested_loops();
-    issue1121();
-    issue2965();
-    issue3670();
-    issue1654();
+    let mut it = 0..20;
+    for _ in it {
+        println!("test");
+    }
 }
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
index 30e3b82a7cc..1717006a449 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs
@@ -1,7 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::while_let_on_iterator)]
-#![allow(clippy::never_loop, unreachable_code, unused_mut)]
+#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)]
 
 fn base() {
     let mut iter = 1..20;
@@ -41,13 +41,6 @@ fn base() {
     // or this
     let mut iter = 1u32..20;
     while let Some(_) = iter.next() {
-        break;
-    }
-    println!("Remaining iter {:?}", iter);
-
-    // or this
-    let mut iter = 1u32..20;
-    while let Some(_) = iter.next() {
         iter = 1..20;
     }
 }
@@ -135,18 +128,6 @@ fn refutable2() {
 
 fn nested_loops() {
     let a = [42, 1337];
-    let mut y = a.iter();
-    loop {
-        // x is reused, so don't lint here
-        while let Some(_) = y.next() {}
-    }
-
-    let mut y = a.iter();
-    for _ in 0..2 {
-        while let Some(_) = y.next() {
-            // y is reused, don't lint
-        }
-    }
 
     loop {
         let mut y = a.iter();
@@ -167,10 +148,8 @@ fn issue1121() {
 }
 
 fn issue2965() {
-    // This should not cause an ICE and suggest:
-    //
-    // for _ in values.iter() {}
-    //
+    // This should not cause an ICE
+
     use std::collections::HashSet;
     let mut values = HashSet::new();
     values.insert(1);
@@ -205,13 +184,145 @@ fn issue1654() {
     }
 }
 
+fn issue6491() {
+    // Used in outer loop, needs &mut
+    let mut it = 1..40;
+    while let Some(n) = it.next() {
+        while let Some(m) = it.next() {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+        println!("n still is {}", n);
+    }
+
+    // This is fine, inner loop uses a new iterator.
+    let mut it = 1..40;
+    while let Some(n) = it.next() {
+        let mut it = 1..40;
+        while let Some(m) = it.next() {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+
+        // Weird binding shouldn't change anything.
+        let (mut it, _) = (1..40, 0);
+        while let Some(m) = it.next() {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+
+        // Used after the loop, needs &mut.
+        let mut it = 1..40;
+        while let Some(m) = it.next() {
+            if m % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+        println!("next item {}", it.next().unwrap());
+
+        println!("n still is {}", n);
+    }
+}
+
+fn issue6231() {
+    // Closure in the outer loop, needs &mut
+    let mut it = 1..40;
+    let mut opt = Some(0);
+    while let Some(n) = opt.take().or_else(|| it.next()) {
+        while let Some(m) = it.next() {
+            if n % 10 == 0 {
+                break;
+            }
+            println!("doing something with m: {}", m);
+        }
+        println!("n still is {}", n);
+    }
+}
+
+fn issue1924() {
+    struct S<T>(T);
+    impl<T: Iterator<Item = u32>> S<T> {
+        fn f(&mut self) -> Option<u32> {
+            // Used as a field.
+            while let Some(i) = self.0.next() {
+                if i < 3 || i > 7 {
+                    return Some(i);
+                }
+            }
+            None
+        }
+
+        fn f2(&mut self) -> Option<u32> {
+            // Don't lint, self borrowed inside the loop
+            while let Some(i) = self.0.next() {
+                if i == 1 {
+                    return self.f();
+                }
+            }
+            None
+        }
+    }
+    impl<T: Iterator<Item = u32>> S<(S<T>, Option<u32>)> {
+        fn f3(&mut self) -> Option<u32> {
+            // Don't lint, self borrowed inside the loop
+            while let Some(i) = self.0.0.0.next() {
+                if i == 1 {
+                    return self.0.0.f();
+                }
+            }
+            while let Some(i) = self.0.0.0.next() {
+                if i == 1 {
+                    return self.f3();
+                }
+            }
+            // This one is fine, a different field is borrowed
+            while let Some(i) = self.0.0.0.next() {
+                if i == 1 {
+                    return self.0.1.take();
+                } else {
+                    self.0.1 = Some(i);
+                }
+            }
+            None
+        }
+    }
+
+    struct S2<T>(T, u32);
+    impl<T: Iterator<Item = u32>> Iterator for S2<T> {
+        type Item = u32;
+        fn next(&mut self) -> Option<u32> {
+            self.0.next()
+        }
+    }
+
+    // Don't lint, field of the iterator is accessed in the loop
+    let mut it = S2(1..40, 0);
+    while let Some(n) = it.next() {
+        if n == it.1 {
+            break;
+        }
+    }
+
+    // Needs &mut, field of the iterator is accessed after the loop
+    let mut it = S2(1..40, 0);
+    while let Some(n) = it.next() {
+        if n == 0 {
+            break;
+        }
+    }
+    println!("iterator field {}", it.1);
+}
+
 fn main() {
-    base();
-    refutable();
-    refutable2();
-    nested_loops();
-    issue1121();
-    issue2965();
-    issue3670();
-    issue1654();
+    let mut it = 0..20;
+    while let Some(..) = it.next() {
+        println!("test");
+    }
 }
diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
index 6554977c798..eff559bef7e 100644
--- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
+++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr
@@ -19,28 +19,96 @@ LL |     while let Some(_) = iter.next() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:101:9
+  --> $DIR/while_let_on_iterator.rs:94:9
    |
 LL |         while let Some([..]) = it.next() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:108:9
+  --> $DIR/while_let_on_iterator.rs:101:9
    |
 LL |         while let Some([_x]) = it.next() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:121:9
+  --> $DIR/while_let_on_iterator.rs:114:9
    |
 LL |         while let Some(x @ [_]) = it.next() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:153:9
+  --> $DIR/while_let_on_iterator.rs:134:9
    |
 LL |         while let Some(_) = y.next() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y`
 
-error: aborting due to 7 previous errors
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:191:9
+   |
+LL |         while let Some(m) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:202:5
+   |
+LL |     while let Some(n) = it.next() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:204:9
+   |
+LL |         while let Some(m) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:213:9
+   |
+LL |         while let Some(m) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:222:9
+   |
+LL |         while let Some(m) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:239:9
+   |
+LL |         while let Some(m) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:254:13
+   |
+LL |             while let Some(i) = self.0.next() {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in &mut self.0`
+
+error: manual `!RangeInclusive::contains` implementation
+  --> $DIR/while_let_on_iterator.rs:255:20
+   |
+LL |                 if i < 3 || i > 7 {
+   |                    ^^^^^^^^^^^^^^ help: use: `!(3..=7).contains(&i)`
+   |
+   = note: `-D clippy::manual-range-contains` implied by `-D warnings`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:286:13
+   |
+LL |             while let Some(i) = self.0.0.0.next() {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in &mut self.0.0.0`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:315:5
+   |
+LL |     while let Some(n) = it.next() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in &mut it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:325:5
+   |
+LL |     while let Some(..) = it.next() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
+
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/write_with_newline.stderr b/src/tools/clippy/tests/ui/write_with_newline.stderr
index a14e86122ee..cecc2ea9406 100644
--- a/src/tools/clippy/tests/ui/write_with_newline.stderr
+++ b/src/tools/clippy/tests/ui/write_with_newline.stderr
@@ -51,8 +51,8 @@ LL |     write!(&mut v, "/n");
    |
 help: use `writeln!()` instead
    |
-LL |     writeln!(&mut v, );
-   |     ^^^^^^^         --
+LL |     writeln!(&mut v);
+   |     ^^^^^^^       --
 
 error: using `write!()` with a format string that ends in a single newline
   --> $DIR/write_with_newline.rs:36:5
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.rs b/src/tools/clippy/tests/ui/wrong_self_convention.rs
index cdfbdb8b0db..151dd0c27d5 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention.rs
+++ b/src/tools/clippy/tests/ui/wrong_self_convention.rs
@@ -1,6 +1,5 @@
 // edition:2018
 #![warn(clippy::wrong_self_convention)]
-#![warn(clippy::wrong_pub_self_convention)]
 #![allow(dead_code)]
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.stderr b/src/tools/clippy/tests/ui/wrong_self_convention.stderr
index 29f5ba82695..ce23317abf6 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention.stderr
+++ b/src/tools/clippy/tests/ui/wrong_self_convention.stderr
@@ -1,5 +1,5 @@
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:18:17
+  --> $DIR/wrong_self_convention.rs:17:17
    |
 LL |     fn from_i32(self) {}
    |                 ^^^^
@@ -8,7 +8,7 @@ LL |     fn from_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:24:21
+  --> $DIR/wrong_self_convention.rs:23:21
    |
 LL |     pub fn from_i64(self) {}
    |                     ^^^^
@@ -16,7 +16,7 @@ LL |     pub fn from_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:36:15
+  --> $DIR/wrong_self_convention.rs:35:15
    |
 LL |     fn as_i32(self) {}
    |               ^^^^
@@ -24,7 +24,7 @@ LL |     fn as_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:38:17
+  --> $DIR/wrong_self_convention.rs:37:17
    |
 LL |     fn into_i32(&self) {}
    |                 ^^^^^
@@ -32,7 +32,7 @@ LL |     fn into_i32(&self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:40:15
+  --> $DIR/wrong_self_convention.rs:39:15
    |
 LL |     fn is_i32(self) {}
    |               ^^^^
@@ -40,7 +40,7 @@ LL |     fn is_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:42:15
+  --> $DIR/wrong_self_convention.rs:41:15
    |
 LL |     fn to_i32(self) {}
    |               ^^^^
@@ -48,7 +48,7 @@ LL |     fn to_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:44:17
+  --> $DIR/wrong_self_convention.rs:43:17
    |
 LL |     fn from_i32(self) {}
    |                 ^^^^
@@ -56,7 +56,7 @@ LL |     fn from_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:46:19
+  --> $DIR/wrong_self_convention.rs:45:19
    |
 LL |     pub fn as_i64(self) {}
    |                   ^^^^
@@ -64,7 +64,7 @@ LL |     pub fn as_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:47:21
+  --> $DIR/wrong_self_convention.rs:46:21
    |
 LL |     pub fn into_i64(&self) {}
    |                     ^^^^^
@@ -72,7 +72,7 @@ LL |     pub fn into_i64(&self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:48:19
+  --> $DIR/wrong_self_convention.rs:47:19
    |
 LL |     pub fn is_i64(self) {}
    |                   ^^^^
@@ -80,7 +80,7 @@ LL |     pub fn is_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:49:19
+  --> $DIR/wrong_self_convention.rs:48:19
    |
 LL |     pub fn to_i64(self) {}
    |                   ^^^^
@@ -88,7 +88,7 @@ LL |     pub fn to_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:50:21
+  --> $DIR/wrong_self_convention.rs:49:21
    |
 LL |     pub fn from_i64(self) {}
    |                     ^^^^
@@ -96,7 +96,7 @@ LL |     pub fn from_i64(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:95:19
+  --> $DIR/wrong_self_convention.rs:94:19
    |
 LL |         fn as_i32(self) {}
    |                   ^^^^
@@ -104,7 +104,7 @@ LL |         fn as_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:98:25
+  --> $DIR/wrong_self_convention.rs:97:25
    |
 LL |         fn into_i32_ref(&self) {}
    |                         ^^^^^
@@ -112,7 +112,7 @@ LL |         fn into_i32_ref(&self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:100:19
+  --> $DIR/wrong_self_convention.rs:99:19
    |
 LL |         fn is_i32(self) {}
    |                   ^^^^
@@ -120,7 +120,7 @@ LL |         fn is_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:104:21
+  --> $DIR/wrong_self_convention.rs:103:21
    |
 LL |         fn from_i32(self) {}
    |                     ^^^^
@@ -128,7 +128,7 @@ LL |         fn from_i32(self) {}
    = help: consider choosing a less ambiguous name
 
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/wrong_self_convention.rs:119:19
+  --> $DIR/wrong_self_convention.rs:118:19
    |
 LL |         fn as_i32(self);
    |                   ^^^^
@@ -136,7 +136,7 @@ LL |         fn as_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:122:25
+  --> $DIR/wrong_self_convention.rs:121:25
    |
 LL |         fn into_i32_ref(&self);
    |                         ^^^^^
@@ -144,7 +144,7 @@ LL |         fn into_i32_ref(&self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `is_*` usually take `self` by reference or no `self`
-  --> $DIR/wrong_self_convention.rs:124:19
+  --> $DIR/wrong_self_convention.rs:123:19
    |
 LL |         fn is_i32(self);
    |                   ^^^^
@@ -152,7 +152,7 @@ LL |         fn is_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:128:21
+  --> $DIR/wrong_self_convention.rs:127:21
    |
 LL |         fn from_i32(self);
    |                     ^^^^
@@ -160,7 +160,7 @@ LL |         fn from_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `into_*` usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:146:25
+  --> $DIR/wrong_self_convention.rs:145:25
    |
 LL |         fn into_i32_ref(&self);
    |                         ^^^^^
@@ -168,7 +168,7 @@ LL |         fn into_i32_ref(&self);
    = help: consider choosing a less ambiguous name
 
 error: methods called `from_*` usually take no `self`
-  --> $DIR/wrong_self_convention.rs:152:21
+  --> $DIR/wrong_self_convention.rs:151:21
    |
 LL |         fn from_i32(self);
    |                     ^^^^
@@ -176,7 +176,7 @@ LL |         fn from_i32(self);
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value
-  --> $DIR/wrong_self_convention.rs:176:22
+  --> $DIR/wrong_self_convention.rs:175:22
    |
 LL |         fn to_u64_v2(&self) -> u64 {
    |                      ^^^^^
@@ -184,7 +184,7 @@ LL |         fn to_u64_v2(&self) -> u64 {
    = help: consider choosing a less ambiguous name
 
 error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention.rs:185:19
+  --> $DIR/wrong_self_convention.rs:184:19
    |
 LL |         fn to_u64(self) -> u64 {
    |                   ^^^^
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.rs b/src/tools/clippy/tests/ui/wrong_self_convention2.rs
index ae3a740d405..501bc1e6a85 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention2.rs
+++ b/src/tools/clippy/tests/ui/wrong_self_convention2.rs
@@ -1,6 +1,5 @@
 // edition:2018
 #![warn(clippy::wrong_self_convention)]
-#![warn(clippy::wrong_pub_self_convention)]
 #![allow(dead_code)]
 
 fn main() {}
@@ -23,7 +22,7 @@ mod issue6983 {
     }
 
     struct FooNoCopy;
-    // trigger lint
+    // don't trigger
     impl ToU64 for FooNoCopy {
         fn to_u64(self) -> u64 {
             2
@@ -42,3 +41,30 @@ mod issue7032 {
         }
     }
 }
+
+mod issue7179 {
+    pub struct S(i32);
+
+    impl S {
+        // don't trigger (`s` is not `self`)
+        pub fn from_be(s: Self) -> Self {
+            S(i32::from_be(s.0))
+        }
+
+        // lint
+        pub fn from_be_self(self) -> Self {
+            S(i32::from_be(self.0))
+        }
+    }
+
+    trait T {
+        // don't trigger (`s` is not `self`)
+        fn from_be(s: Self) -> Self;
+        // lint
+        fn from_be_self(self) -> Self;
+    }
+
+    trait Foo: Sized {
+        fn as_byte_slice(slice: &[Self]) -> &[u8];
+    }
+}
diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
index 0ca1a390974..0e0d066d656 100644
--- a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
+++ b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr
@@ -1,11 +1,19 @@
-error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
-  --> $DIR/wrong_self_convention2.rs:28:19
+error: methods called `from_*` usually take no `self`
+  --> $DIR/wrong_self_convention2.rs:55:29
    |
-LL |         fn to_u64(self) -> u64 {
-   |                   ^^^^
+LL |         pub fn from_be_self(self) -> Self {
+   |                             ^^^^
    |
    = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
    = help: consider choosing a less ambiguous name
 
-error: aborting due to previous error
+error: methods called `from_*` usually take no `self`
+  --> $DIR/wrong_self_convention2.rs:64:25
+   |
+LL |         fn from_be_self(self) -> Self;
+   |                         ^^^^
+   |
+   = help: consider choosing a less ambiguous name
+
+error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/util/cov.sh b/src/tools/clippy/util/cov.sh
deleted file mode 100755
index 3f9a6b06f72..00000000000
--- a/src/tools/clippy/util/cov.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/bash
-
-# This run `kcov` on Clippy. The coverage report will be at
-# `./target/cov/index.html`.
-# `compile-test` is special. `kcov` does not work directly on it so these files
-# are compiled manually.
-
-tests=$(find tests/ -maxdepth 1 -name '*.rs' ! -name compile-test.rs -exec basename {} .rs \;)
-tmpdir=$(mktemp -d)
-
-cargo test --no-run --verbose
-
-for t in $tests; do
-  kcov \
-    --verify \
-    --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
-    "$tmpdir/$t" \
-    cargo test --test "$t"
-done
-
-for t in ./tests/compile-fail/*.rs; do
-  kcov \
-    --verify \
-    --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
-    "$tmpdir/compile-fail-$(basename "$t")" \
-    cargo run -- -L target/debug -L target/debug/deps -Z no-trans "$t"
-done
-
-for t in ./tests/run-pass/*.rs; do
-  kcov \
-    --verify \
-    --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \
-    "$tmpdir/run-pass-$(basename "$t")" \
-    cargo run -- -L target/debug -L target/debug/deps -Z no-trans "$t"
-done
-
-kcov --verify --merge target/cov "$tmpdir"/*
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index f4e16483d8c..54b079a3e86 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2327,7 +2327,11 @@ impl<'test> TestCx<'test> {
         // For now, though…
         if let Some(rev) = self.revision {
             let prefixes = format!("CHECK,{}", rev);
-            filecheck.args(&["--check-prefixes", &prefixes]);
+            if self.config.llvm_version.unwrap_or(0) >= 130000 {
+                filecheck.args(&["--allow-unused-prefixes", "--check-prefixes", &prefixes]);
+            } else {
+                filecheck.args(&["--check-prefixes", &prefixes]);
+            }
         }
         self.compose_and_run(filecheck, "", None, None)
     }
diff --git a/src/tools/jsondocck/Cargo.toml b/src/tools/jsondocck/Cargo.toml
index a6efc4c9a6b..b5f1554dbe4 100644
--- a/src/tools/jsondocck/Cargo.toml
+++ b/src/tools/jsondocck/Cargo.toml
@@ -8,8 +8,7 @@ edition = "2018"
 jsonpath_lib = "0.2"
 getopts = "0.2"
 regex = "1.4"
-lazy_static = "1.4"
-shlex = "0.1"
-serde = "1.0"
+shlex = "1.0"
 serde_json = "1.0"
 fs-err = "2.5.0"
+once_cell = "1.0"
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index 216890d59ad..b8ea10f3d22 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -1,5 +1,5 @@
 use jsonpath_lib::select;
-use lazy_static::lazy_static;
+use once_cell::sync::Lazy;
 use regex::{Regex, RegexBuilder};
 use serde_json::Value;
 use std::borrow::Cow;
@@ -94,19 +94,19 @@ impl fmt::Display for CommandKind {
     }
 }
 
-lazy_static! {
-    static ref LINE_PATTERN: Regex = RegexBuilder::new(
+static LINE_PATTERN: Lazy<Regex> = Lazy::new(|| {
+    RegexBuilder::new(
         r#"
         \s(?P<invalid>!?)@(?P<negated>!?)
         (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
         (?P<args>.*)$
-    "#
+    "#,
     )
     .ignore_whitespace(true)
     .unicode(true)
     .build()
-    .unwrap();
-}
+    .unwrap()
+});
 
 fn print_err(msg: &str, lineno: usize) {
     eprintln!("Invalid command: {} on line {}", msg, lineno)
diff --git a/src/tools/linkchecker/linkcheck.sh b/src/tools/linkchecker/linkcheck.sh
index b68053c76be..9eeebf444a4 100755
--- a/src/tools/linkchecker/linkcheck.sh
+++ b/src/tools/linkchecker/linkcheck.sh
@@ -85,11 +85,11 @@ fi
 if [ ! -e "linkchecker/main.rs" ] || [ "$iterative" = "0" ]
 then
     echo "Downloading linkchecker source..."
+    nightly_hash=$(rustc +nightly -Vv | grep commit-hash | cut -f2 -d" ")
+    url="https://raw.githubusercontent.com/rust-lang/rust"
     mkdir linkchecker
-    curl -o linkchecker/Cargo.toml \
-        https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/Cargo.toml
-    curl -o linkchecker/main.rs \
-        https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/main.rs
+    curl -o linkchecker/Cargo.toml ${url}/${nightly_hash}/src/tools/linkchecker/Cargo.toml
+    curl -o linkchecker/main.rs ${url}/${nightly_hash}/src/tools/linkchecker/main.rs
 fi
 
 echo "Building book \"$book_name\"..."
@@ -106,7 +106,7 @@ else
     check_path="linkcheck/$book_name"
 fi
 echo "Running linkchecker on \"$check_path\"..."
-cargo run --manifest-path=linkchecker/Cargo.toml -- "$check_path"
+cargo run --release --manifest-path=linkchecker/Cargo.toml -- "$check_path"
 
 if [ "$iterative" = "0" ]
 then
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index c677d04917e..47960c3f6cc 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -14,18 +14,18 @@
 //! A few exceptions are allowed as there's known bugs in rustdoc, but this
 //! should catch the majority of "broken link" cases.
 
-use std::collections::hash_map::Entry;
+use std::cell::RefCell;
 use std::collections::{HashMap, HashSet};
 use std::env;
 use std::fs;
+use std::io::ErrorKind;
 use std::path::{Component, Path, PathBuf};
 use std::rc::Rc;
+use std::time::Instant;
 
 use once_cell::sync::Lazy;
 use regex::Regex;
 
-use crate::Redirect::*;
-
 // Add linkcheck exceptions here
 // If at all possible you should use intra-doc links to avoid linkcheck issues. These
 // are cases where that does not work
@@ -87,33 +87,64 @@ macro_rules! t {
 }
 
 fn main() {
-    let docs = env::args_os().nth(1).unwrap();
+    let docs = env::args_os().nth(1).expect("doc path should be first argument");
     let docs = env::current_dir().unwrap().join(docs);
-    let mut errors = false;
-    walk(&mut HashMap::new(), &docs, &docs, &mut errors);
-    if errors {
-        panic!("found some broken links");
+    let mut checker = Checker { root: docs.clone(), cache: HashMap::new() };
+    let mut report = Report {
+        errors: 0,
+        start: Instant::now(),
+        html_files: 0,
+        html_redirects: 0,
+        links_checked: 0,
+        links_ignored_external: 0,
+        links_ignored_exception: 0,
+        intra_doc_exceptions: 0,
+    };
+    checker.walk(&docs, &mut report);
+    report.report();
+    if report.errors != 0 {
+        println!("found some broken links");
+        std::process::exit(1);
     }
 }
 
-#[derive(Debug)]
-pub enum LoadError {
-    IOError(std::io::Error),
-    BrokenRedirect(PathBuf, std::io::Error),
-    IsRedirect,
+struct Checker {
+    root: PathBuf,
+    cache: Cache,
 }
 
-enum Redirect {
-    SkipRedirect,
-    FromRedirect(bool),
+struct Report {
+    errors: u32,
+    start: Instant,
+    html_files: u32,
+    html_redirects: u32,
+    links_checked: u32,
+    links_ignored_external: u32,
+    links_ignored_exception: u32,
+    intra_doc_exceptions: u32,
 }
 
-struct FileEntry {
-    source: Rc<String>,
-    ids: HashSet<String>,
+/// A cache entry.
+enum FileEntry {
+    /// An HTML file.
+    ///
+    /// This includes the contents of the HTML file, and an optional set of
+    /// HTML IDs. The IDs are used for checking fragments. The are computed
+    /// as-needed. The source is discarded (replaced with an empty string)
+    /// after the file has been checked, to conserve on memory.
+    HtmlFile { source: Rc<String>, ids: RefCell<HashSet<String>> },
+    /// This file is an HTML redirect to the given local path.
+    Redirect { target: PathBuf },
+    /// This is not an HTML file.
+    OtherFile,
+    /// This is a directory.
+    Dir,
+    /// The file doesn't exist.
+    Missing,
 }
 
-type Cache = HashMap<PathBuf, FileEntry>;
+/// A cache to speed up file access.
+type Cache = HashMap<String, FileEntry>;
 
 fn small_url_encode(s: &str) -> String {
     s.replace("<", "%3C")
@@ -130,173 +161,169 @@ fn small_url_encode(s: &str) -> String {
         .replace("\"", "%22")
 }
 
-impl FileEntry {
-    fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) {
-        if self.ids.is_empty() {
-            with_attrs_in_source(contents, " id", |fragment, i, _| {
-                let frag = fragment.trim_start_matches("#").to_owned();
-                let encoded = small_url_encode(&frag);
-                if !self.ids.insert(frag) {
-                    *errors = true;
-                    println!("{}:{}: id is not unique: `{}`", file.display(), i, fragment);
-                }
-                // Just in case, we also add the encoded id.
-                self.ids.insert(encoded);
-            });
-        }
-    }
-}
-
-fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) {
-    for entry in t!(dir.read_dir()).map(|e| t!(e)) {
-        let path = entry.path();
-        let kind = t!(entry.file_type());
-        if kind.is_dir() {
-            walk(cache, root, &path, errors);
-        } else {
-            let pretty_path = check(cache, root, &path, errors);
-            if let Some(pretty_path) = pretty_path {
-                let entry = cache.get_mut(&pretty_path).unwrap();
-                // we don't need the source anymore,
-                // so drop to reduce memory-usage
-                entry.source = Rc::new(String::new());
+impl Checker {
+    /// Primary entry point for walking the filesystem to find HTML files to check.
+    fn walk(&mut self, dir: &Path, report: &mut Report) {
+        for entry in t!(dir.read_dir()).map(|e| t!(e)) {
+            let path = entry.path();
+            let kind = t!(entry.file_type());
+            if kind.is_dir() {
+                self.walk(&path, report);
+            } else {
+                self.check(&path, report);
             }
         }
     }
-}
-
-fn is_intra_doc_exception(file: &Path, link: &str) -> bool {
-    if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
-        entry.1.is_empty() || entry.1.contains(&link)
-    } else {
-        false
-    }
-}
 
-fn is_exception(file: &Path, link: &str) -> bool {
-    if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
-        entry.1.contains(&link)
-    } else {
-        // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page
-        //
-        // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path
-        // calculated in `check` function is outside `build/<triple>/doc` dir.
-        // So the `strip_prefix` method just returns the old absolute broken path.
-        if file.ends_with("std/primitive.slice.html") {
-            if link.ends_with("primitive.slice.html") {
-                return true;
+    /// Checks a single file.
+    fn check(&mut self, file: &Path, report: &mut Report) {
+        let (pretty_path, entry) = self.load_file(file, report);
+        let source = match entry {
+            FileEntry::Missing => panic!("missing file {:?} while walking", file),
+            FileEntry::Dir => unreachable!("never with `check` path"),
+            FileEntry::OtherFile => return,
+            FileEntry::Redirect { .. } => return,
+            FileEntry::HtmlFile { source, ids } => {
+                parse_ids(&mut ids.borrow_mut(), &pretty_path, source, report);
+                source.clone()
             }
-        }
-        false
-    }
-}
-
-fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Option<PathBuf> {
-    // Ignore non-HTML files.
-    if file.extension().and_then(|s| s.to_str()) != Some("html") {
-        return None;
-    }
+        };
 
-    let res = load_file(cache, root, file, SkipRedirect);
-    let (pretty_file, contents) = match res {
-        Ok(res) => res,
-        Err(_) => return None,
-    };
-    {
-        cache.get_mut(&pretty_file).unwrap().parse_ids(&pretty_file, &contents, errors);
-    }
+        // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
+        with_attrs_in_source(&source, " href", |url, i, base| {
+            // Ignore external URLs
+            if url.starts_with("http:")
+                || url.starts_with("https:")
+                || url.starts_with("javascript:")
+                || url.starts_with("ftp:")
+                || url.starts_with("irc:")
+                || url.starts_with("data:")
+            {
+                report.links_ignored_external += 1;
+                return;
+            }
+            report.links_checked += 1;
+            let (url, fragment) = match url.split_once('#') {
+                None => (url, None),
+                Some((url, fragment)) => (url, Some(fragment)),
+            };
+            // NB: the `splitn` always succeeds, even if the delimiter is not present.
+            let url = url.splitn(2, '?').next().unwrap();
+
+            // Once we've plucked out the URL, parse it using our base url and
+            // then try to extract a file path.
+            let mut path = file.to_path_buf();
+            if !base.is_empty() || !url.is_empty() {
+                path.pop();
+                for part in Path::new(base).join(url).components() {
+                    match part {
+                        Component::Prefix(_) | Component::RootDir => {
+                            // Avoid absolute paths as they make the docs not
+                            // relocatable by making assumptions on where the docs
+                            // are hosted relative to the site root.
+                            report.errors += 1;
+                            println!(
+                                "{}:{}: absolute path - {}",
+                                pretty_path,
+                                i + 1,
+                                Path::new(base).join(url).display()
+                            );
+                            return;
+                        }
+                        Component::CurDir => {}
+                        Component::ParentDir => {
+                            path.pop();
+                        }
+                        Component::Normal(s) => {
+                            path.push(s);
+                        }
+                    }
+                }
+            }
 
-    // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
-    with_attrs_in_source(&contents, " href", |url, i, base| {
-        // Ignore external URLs
-        if url.starts_with("http:")
-            || url.starts_with("https:")
-            || url.starts_with("javascript:")
-            || url.starts_with("ftp:")
-            || url.starts_with("irc:")
-            || url.starts_with("data:")
-        {
-            return;
-        }
-        let (url, fragment) = match url.split_once('#') {
-            None => (url, None),
-            Some((url, fragment)) => (url, Some(fragment)),
-        };
-        // NB: the `splitn` always succeeds, even if the delimiter is not present.
-        let url = url.splitn(2, '?').next().unwrap();
-
-        // Once we've plucked out the URL, parse it using our base url and
-        // then try to extract a file path.
-        let mut path = file.to_path_buf();
-        if !base.is_empty() || !url.is_empty() {
-            path.pop();
-            for part in Path::new(base).join(url).components() {
-                match part {
-                    Component::Prefix(_) | Component::RootDir => {
-                        // Avoid absolute paths as they make the docs not
-                        // relocatable by making assumptions on where the docs
-                        // are hosted relative to the site root.
-                        *errors = true;
+            let (target_pretty_path, target_entry) = self.load_file(&path, report);
+            let (target_source, target_ids) = match target_entry {
+                FileEntry::Missing => {
+                    if is_exception(file, &target_pretty_path) {
+                        report.links_ignored_exception += 1;
+                    } else {
+                        report.errors += 1;
                         println!(
-                            "{}:{}: absolute path - {}",
-                            pretty_file.display(),
+                            "{}:{}: broken link - `{}`",
+                            pretty_path,
                             i + 1,
-                            Path::new(base).join(url).display()
+                            target_pretty_path
                         );
-                        return;
-                    }
-                    Component::CurDir => {}
-                    Component::ParentDir => {
-                        path.pop();
                     }
-                    Component::Normal(s) => {
-                        path.push(s);
-                    }
-                }
-            }
-        }
-
-        // Alright, if we've found a file name then this file had better
-        // exist! If it doesn't then we register and print an error.
-        if path.exists() {
-            if path.is_dir() {
-                // Links to directories show as directory listings when viewing
-                // the docs offline so it's best to avoid them.
-                *errors = true;
-                let pretty_path = path.strip_prefix(root).unwrap_or(&path);
-                println!(
-                    "{}:{}: directory link - {}",
-                    pretty_file.display(),
-                    i + 1,
-                    pretty_path.display()
-                );
-                return;
-            }
-            if let Some(extension) = path.extension() {
-                // Ignore none HTML files.
-                if extension != "html" {
                     return;
                 }
-            }
-            let res = load_file(cache, root, &path, FromRedirect(false));
-            let (pretty_path, contents) = match res {
-                Ok(res) => res,
-                Err(LoadError::IOError(err)) => {
-                    panic!("error loading {}: {}", path.display(), err);
-                }
-                Err(LoadError::BrokenRedirect(target, _)) => {
-                    *errors = true;
+                FileEntry::Dir => {
+                    // Links to directories show as directory listings when viewing
+                    // the docs offline so it's best to avoid them.
+                    report.errors += 1;
                     println!(
-                        "{}:{}: broken redirect to {}",
-                        pretty_file.display(),
+                        "{}:{}: directory link to `{}` \
+                         (directory links should use index.html instead)",
+                        pretty_path,
                         i + 1,
-                        target.display()
+                        target_pretty_path
                     );
                     return;
                 }
-                Err(LoadError::IsRedirect) => unreachable!(),
+                FileEntry::OtherFile => return,
+                FileEntry::Redirect { target } => {
+                    let t = target.clone();
+                    drop(target);
+                    let (target, redir_entry) = self.load_file(&t, report);
+                    match redir_entry {
+                        FileEntry::Missing => {
+                            report.errors += 1;
+                            println!(
+                                "{}:{}: broken redirect from `{}` to `{}`",
+                                pretty_path,
+                                i + 1,
+                                target_pretty_path,
+                                target
+                            );
+                            return;
+                        }
+                        FileEntry::Redirect { target } => {
+                            // Redirect to a redirect, this link checker
+                            // currently doesn't support this, since it would
+                            // require cycle checking, etc.
+                            report.errors += 1;
+                            println!(
+                                "{}:{}: redirect from `{}` to `{}` \
+                                 which is also a redirect (not supported)",
+                                pretty_path,
+                                i + 1,
+                                target_pretty_path,
+                                target.display()
+                            );
+                            return;
+                        }
+                        FileEntry::Dir => {
+                            report.errors += 1;
+                            println!(
+                                "{}:{}: redirect from `{}` to `{}` \
+                                 which is a directory \
+                                 (directory links should use index.html instead)",
+                                pretty_path,
+                                i + 1,
+                                target_pretty_path,
+                                target
+                            );
+                            return;
+                        }
+                        FileEntry::OtherFile => return,
+                        FileEntry::HtmlFile { source, ids } => (source, ids),
+                    }
+                }
+                FileEntry::HtmlFile { source, ids } => (source, ids),
             };
 
+            // Alright, if we've found an HTML file for the target link. If
+            // this is a fragment link, also check that the `id` exists.
             if let Some(ref fragment) = fragment {
                 // Fragments like `#1-6` are most likely line numbers to be
                 // interpreted by javascript, so we're ignoring these
@@ -309,85 +336,134 @@ fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Opti
                     return;
                 }
 
-                let entry = &mut cache.get_mut(&pretty_path).unwrap();
-                entry.parse_ids(&pretty_path, &contents, errors);
+                parse_ids(&mut target_ids.borrow_mut(), &pretty_path, target_source, report);
+
+                if target_ids.borrow().contains(*fragment) {
+                    return;
+                }
 
-                if !entry.ids.contains(*fragment) && !is_exception(file, &format!("#{}", fragment))
-                {
-                    *errors = true;
-                    print!("{}:{}: broken link fragment ", pretty_file.display(), i + 1);
-                    println!("`#{}` pointing to `{}`", fragment, pretty_path.display());
+                if is_exception(file, &format!("#{}", fragment)) {
+                    report.links_ignored_exception += 1;
+                } else {
+                    report.errors += 1;
+                    print!("{}:{}: broken link fragment ", pretty_path, i + 1);
+                    println!("`#{}` pointing to `{}`", fragment, pretty_path);
                 };
             }
-        } else {
-            let pretty_path = path.strip_prefix(root).unwrap_or(&path);
-            if !is_exception(file, pretty_path.to_str().unwrap()) {
-                *errors = true;
-                print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
-                println!("{}", pretty_path.display());
+        });
+
+        // Search for intra-doc links that rustdoc didn't warn about
+        // FIXME(#77199, 77200) Rustdoc should just warn about these directly.
+        // NOTE: only looks at one line at a time; in practice this should find most links
+        for (i, line) in source.lines().enumerate() {
+            for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) {
+                if is_intra_doc_exception(file, &broken_link[1]) {
+                    report.intra_doc_exceptions += 1;
+                } else {
+                    report.errors += 1;
+                    print!("{}:{}: broken intra-doc link - ", pretty_path, i + 1);
+                    println!("{}", &broken_link[0]);
+                }
             }
         }
-    });
-
-    // Search for intra-doc links that rustdoc didn't warn about
-    // FIXME(#77199, 77200) Rustdoc should just warn about these directly.
-    // NOTE: only looks at one line at a time; in practice this should find most links
-    for (i, line) in contents.lines().enumerate() {
-        for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) {
-            if !is_intra_doc_exception(file, &broken_link[1]) {
-                *errors = true;
-                print!("{}:{}: broken intra-doc link - ", pretty_file.display(), i + 1);
-                println!("{}", &broken_link[0]);
-            }
+        // we don't need the source anymore,
+        // so drop to reduce memory-usage
+        match self.cache.get_mut(&pretty_path).unwrap() {
+            FileEntry::HtmlFile { source, .. } => *source = Rc::new(String::new()),
+            _ => unreachable!("must be html file"),
         }
     }
-    Some(pretty_file)
-}
 
-fn load_file(
-    cache: &mut Cache,
-    root: &Path,
-    file: &Path,
-    redirect: Redirect,
-) -> Result<(PathBuf, Rc<String>), LoadError> {
-    let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file));
-
-    let (maybe_redirect, contents) = match cache.entry(pretty_file.clone()) {
-        Entry::Occupied(entry) => (None, entry.get().source.clone()),
-        Entry::Vacant(entry) => {
-            let contents = match fs::read_to_string(file) {
-                Ok(s) => Rc::new(s),
-                Err(err) => {
-                    return Err(if let FromRedirect(true) = redirect {
-                        LoadError::BrokenRedirect(file.to_path_buf(), err)
+    /// Load a file from disk, or from the cache if available.
+    fn load_file(&mut self, file: &Path, report: &mut Report) -> (String, &FileEntry) {
+        let pretty_path =
+            file.strip_prefix(&self.root).unwrap_or(&file).to_str().unwrap().to_string();
+
+        let entry =
+            self.cache.entry(pretty_path.clone()).or_insert_with(|| match fs::metadata(file) {
+                Ok(metadata) if metadata.is_dir() => FileEntry::Dir,
+                Ok(_) => {
+                    if file.extension().and_then(|s| s.to_str()) != Some("html") {
+                        FileEntry::OtherFile
                     } else {
-                        LoadError::IOError(err)
-                    });
+                        report.html_files += 1;
+                        load_html_file(file, report)
+                    }
                 }
-            };
-
-            let maybe = maybe_redirect(&contents);
-            if maybe.is_some() {
-                if let SkipRedirect = redirect {
-                    return Err(LoadError::IsRedirect);
+                Err(e) if e.kind() == ErrorKind::NotFound => FileEntry::Missing,
+                Err(e) => {
+                    panic!("unexpected read error for {}: {}", file.display(), e);
                 }
-            } else {
-                entry.insert(FileEntry { source: contents.clone(), ids: HashSet::new() });
-            }
-            (maybe, contents)
+            });
+        (pretty_path, entry)
+    }
+}
+
+impl Report {
+    fn report(&self) {
+        println!("checked links in: {:.1}s", self.start.elapsed().as_secs_f64());
+        println!("number of HTML files scanned: {}", self.html_files);
+        println!("number of HTML redirects found: {}", self.html_redirects);
+        println!("number of links checked: {}", self.links_checked);
+        println!("number of links ignored due to external: {}", self.links_ignored_external);
+        println!("number of links ignored due to exceptions: {}", self.links_ignored_exception);
+        println!("number of intra doc links ignored: {}", self.intra_doc_exceptions);
+        println!("errors found: {}", self.errors);
+    }
+}
+
+fn load_html_file(file: &Path, report: &mut Report) -> FileEntry {
+    let source = match fs::read_to_string(file) {
+        Ok(s) => Rc::new(s),
+        Err(err) => {
+            // This usually should not fail since `metadata` was already
+            // called successfully on this file.
+            panic!("unexpected read error for {}: {}", file.display(), err);
         }
     };
-    match maybe_redirect.map(|url| file.parent().unwrap().join(url)) {
-        Some(redirect_file) => load_file(cache, root, &redirect_file, FromRedirect(true)),
-        None => Ok((pretty_file, contents)),
+    match maybe_redirect(&source) {
+        Some(target) => {
+            report.html_redirects += 1;
+            let target = file.parent().unwrap().join(target);
+            FileEntry::Redirect { target }
+        }
+        None => FileEntry::HtmlFile { source: source.clone(), ids: RefCell::new(HashSet::new()) },
+    }
+}
+
+fn is_intra_doc_exception(file: &Path, link: &str) -> bool {
+    if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
+        entry.1.is_empty() || entry.1.contains(&link)
+    } else {
+        false
     }
 }
 
+fn is_exception(file: &Path, link: &str) -> bool {
+    if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
+        entry.1.contains(&link)
+    } else {
+        // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page
+        //
+        // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path
+        // calculated in `check` function is outside `build/<triple>/doc` dir.
+        // So the `strip_prefix` method just returns the old absolute broken path.
+        if file.ends_with("std/primitive.slice.html") {
+            if link.ends_with("primitive.slice.html") {
+                return true;
+            }
+        }
+        false
+    }
+}
+
+/// If the given HTML file contents is an HTML redirect, this returns the
+/// destination path given in the redirect.
 fn maybe_redirect(source: &str) -> Option<String> {
     const REDIRECT: &str = "<p>Redirecting to <a href=";
 
     let mut lines = source.lines();
-    let redirect_line = lines.nth(6)?;
+    let redirect_line = lines.nth(7)?;
 
     redirect_line.find(REDIRECT).map(|i| {
         let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
@@ -396,9 +472,9 @@ fn maybe_redirect(source: &str) -> Option<String> {
     })
 }
 
-fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(contents: &str, attr: &str, mut f: F) {
+fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(source: &str, attr: &str, mut f: F) {
     let mut base = "";
-    for (i, mut line) in contents.lines().enumerate() {
+    for (i, mut line) in source.lines().enumerate() {
         while let Some(j) = line.find(attr) {
             let rest = &line[j + attr.len()..];
             // The base tag should always be the first link in the document so
@@ -437,3 +513,18 @@ fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(contents: &str, attr: &str,
         }
     }
 }
+
+fn parse_ids(ids: &mut HashSet<String>, file: &str, source: &str, report: &mut Report) {
+    if ids.is_empty() {
+        with_attrs_in_source(source, " id", |fragment, i, _| {
+            let frag = fragment.trim_start_matches("#").to_owned();
+            let encoded = small_url_encode(&frag);
+            if !ids.insert(frag) {
+                report.errors += 1;
+                println!("{}:{}: id is not unique: `{}`", file, i, fragment);
+            }
+            // Just in case, we also add the encoded id.
+            ids.insert(encoded);
+        });
+    }
+}
diff --git a/src/tools/linkchecker/tests/basic_broken/foo.html b/src/tools/linkchecker/tests/basic_broken/foo.html
new file mode 100644
index 00000000000..cb27c55c9fe
--- /dev/null
+++ b/src/tools/linkchecker/tests/basic_broken/foo.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<a href="bar.html">test</a>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/broken_fragment_local/foo.html b/src/tools/linkchecker/tests/broken_fragment_local/foo.html
new file mode 100644
index 00000000000..66c457ad01f
--- /dev/null
+++ b/src/tools/linkchecker/tests/broken_fragment_local/foo.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<a href="#somefrag">test</a>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/broken_fragment_remote/bar.html b/src/tools/linkchecker/tests/broken_fragment_remote/bar.html
new file mode 100644
index 00000000000..7879e1ce9fd
--- /dev/null
+++ b/src/tools/linkchecker/tests/broken_fragment_remote/bar.html
@@ -0,0 +1,4 @@
+<html>
+<body>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html b/src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html
new file mode 100644
index 00000000000..7683060b3a6
--- /dev/null
+++ b/src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<a href="../bar.html#somefrag">test</a>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/broken_redir/foo.html b/src/tools/linkchecker/tests/broken_redir/foo.html
new file mode 100644
index 00000000000..bd3e3ad3343
--- /dev/null
+++ b/src/tools/linkchecker/tests/broken_redir/foo.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+  <a href="redir-bad.html">bad redir</a>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/broken_redir/redir-bad.html b/src/tools/linkchecker/tests/broken_redir/redir-bad.html
new file mode 100644
index 00000000000..3e376629f74
--- /dev/null
+++ b/src/tools/linkchecker/tests/broken_redir/redir-bad.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta http-equiv="refresh" content="0;URL=sometarget">
+</head>
+<body>
+    <p>Redirecting to <a href="sometarget">sometarget</a>...</p>
+    <script>location.replace("sometarget" + location.search + location.hash);</script>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/checks.rs b/src/tools/linkchecker/tests/checks.rs
new file mode 100644
index 00000000000..c6ec999e5cf
--- /dev/null
+++ b/src/tools/linkchecker/tests/checks.rs
@@ -0,0 +1,77 @@
+use std::path::Path;
+use std::process::{Command, ExitStatus};
+
+fn run(dirname: &str) -> (ExitStatus, String, String) {
+    let output = Command::new(env!("CARGO_BIN_EXE_linkchecker"))
+        .current_dir(Path::new(env!("CARGO_MANIFEST_DIR")).join("tests"))
+        .arg(dirname)
+        .output()
+        .unwrap();
+    let stdout = String::from_utf8(output.stdout).unwrap();
+    let stderr = String::from_utf8(output.stderr).unwrap();
+    (output.status, stdout, stderr)
+}
+
+fn broken_test(dirname: &str, expected: &str) {
+    let (status, stdout, stderr) = run(dirname);
+    assert!(!status.success());
+    if !stdout.contains(expected) {
+        panic!(
+            "stdout did not contain expected text: {}\n\
+            --- stdout:\n\
+            {}\n\
+            --- stderr:\n\
+            {}\n",
+            expected, stdout, stderr
+        );
+    }
+}
+
+fn valid_test(dirname: &str) {
+    let (status, stdout, stderr) = run(dirname);
+    if !status.success() {
+        panic!(
+            "test did not succeed as expected\n\
+            --- stdout:\n\
+            {}\n\
+            --- stderr:\n\
+            {}\n",
+            stdout, stderr
+        );
+    }
+}
+
+#[test]
+fn valid() {
+    valid_test("valid/inner");
+}
+
+#[test]
+fn basic_broken() {
+    broken_test("basic_broken", "bar.html");
+}
+
+#[test]
+fn broken_fragment_local() {
+    broken_test("broken_fragment_local", "#somefrag");
+}
+
+#[test]
+fn broken_fragment_remote() {
+    broken_test("broken_fragment_remote/inner", "#somefrag");
+}
+
+#[test]
+fn broken_redir() {
+    broken_test("broken_redir", "sometarget");
+}
+
+#[test]
+fn directory_link() {
+    broken_test("directory_link", "somedir");
+}
+
+#[test]
+fn redirect_loop() {
+    broken_test("redirect_loop", "redir-bad.html");
+}
diff --git a/src/tools/linkchecker/tests/directory_link/foo.html b/src/tools/linkchecker/tests/directory_link/foo.html
new file mode 100644
index 00000000000..40a8461b86c
--- /dev/null
+++ b/src/tools/linkchecker/tests/directory_link/foo.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+  <a href="somedir">dir link</a>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/directory_link/somedir/index.html b/src/tools/linkchecker/tests/directory_link/somedir/index.html
new file mode 100644
index 00000000000..7879e1ce9fd
--- /dev/null
+++ b/src/tools/linkchecker/tests/directory_link/somedir/index.html
@@ -0,0 +1,4 @@
+<html>
+<body>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/redirect_loop/foo.html b/src/tools/linkchecker/tests/redirect_loop/foo.html
new file mode 100644
index 00000000000..bee58b212b5
--- /dev/null
+++ b/src/tools/linkchecker/tests/redirect_loop/foo.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+  <a href="redir-bad.html">loop link</a>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/redirect_loop/redir-bad.html b/src/tools/linkchecker/tests/redirect_loop/redir-bad.html
new file mode 100644
index 00000000000..fe7780e6739
--- /dev/null
+++ b/src/tools/linkchecker/tests/redirect_loop/redir-bad.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta http-equiv="refresh" content="0;URL=redir-bad.html">
+</head>
+<body>
+    <p>Redirecting to <a href="redir-bad.html">redir-bad.html</a>...</p>
+    <script>location.replace("redir-bad.html" + location.search + location.hash);</script>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/valid/inner/bar.html b/src/tools/linkchecker/tests/valid/inner/bar.html
new file mode 100644
index 00000000000..4b500d78b76
--- /dev/null
+++ b/src/tools/linkchecker/tests/valid/inner/bar.html
@@ -0,0 +1,7 @@
+<html>
+<body>
+
+  <h2 id="barfrag">Bar</h2>
+
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/valid/inner/foo.html b/src/tools/linkchecker/tests/valid/inner/foo.html
new file mode 100644
index 00000000000..3c6a7483bcd
--- /dev/null
+++ b/src/tools/linkchecker/tests/valid/inner/foo.html
@@ -0,0 +1,14 @@
+<html>
+<body>
+  <a href="#localfrag">test local frag</a>
+  <a href="../outer.html">remote link</a>
+  <a href="../outer.html#somefrag">remote link with fragment</a>
+  <a href="bar.html">this book</a>
+  <a href="bar.html#barfrag">this book with fragment</a>
+  <a href="https://example.com/doesnotexist">external links not validated</a>
+  <a href="redir.html#redirfrag">Redirect</a>
+
+  <h2 id="localfrag">Local</h2>
+
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/valid/inner/redir-bad.html b/src/tools/linkchecker/tests/valid/inner/redir-bad.html
new file mode 100644
index 00000000000..d21336e7e73
--- /dev/null
+++ b/src/tools/linkchecker/tests/valid/inner/redir-bad.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta http-equiv="refresh" content="0;URL=xxx">
+</head>
+<body>
+    <p>Redirecting to <a href="xxx">xxx</a>...</p>
+    <script>location.replace("xxx" + location.search + location.hash);</script>
+    These files are skipped, but probably shouldn't be.
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/valid/inner/redir-target.html b/src/tools/linkchecker/tests/valid/inner/redir-target.html
new file mode 100644
index 00000000000..bd59884a01e
--- /dev/null
+++ b/src/tools/linkchecker/tests/valid/inner/redir-target.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+  <h2 id="redirfrag">Redir</h2>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/valid/inner/redir.html b/src/tools/linkchecker/tests/valid/inner/redir.html
new file mode 100644
index 00000000000..1808b23aed8
--- /dev/null
+++ b/src/tools/linkchecker/tests/valid/inner/redir.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta http-equiv="refresh" content="0;URL=redir-target.html">
+</head>
+<body>
+    <p>Redirecting to <a href="redir-target.html">redir-target.html</a>...</p>
+    <script>location.replace("redir-target.html" + location.search + location.hash);</script>
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/valid/outer.html b/src/tools/linkchecker/tests/valid/outer.html
new file mode 100644
index 00000000000..35f799f2023
--- /dev/null
+++ b/src/tools/linkchecker/tests/valid/outer.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<a id="somefrag"></a>
+</body>
+</html>
diff --git a/src/tools/miri b/src/tools/miri
-Subproject bcae3315a76876eb48e06519749cfe6e453a8e9
+Subproject 5dde0fe6de2941c9ef16bc1e9d91ecf20ac5ee8
diff --git a/src/tools/rls b/src/tools/rls
-Subproject 097d8908339e20435078233a55a1a3335fe7c2e
+Subproject 9ed6f96f2ff85753c5a6ac290ee88ecb2831ab2
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject fd109fb587904cfecc1149e068814bfd38feb83
+Subproject f4383981249d3f2964f2c667f3349f8ff15b77c
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index 298fc7519fa..c55e014e834 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -63,6 +63,13 @@ async function main(argv) {
         // This is more convenient that setting fields one by one.
         options.parseArguments([
             "--no-screenshot",
+            // This option shows what puppeteer "code" is run
+            // "--debug",
+            // This option disable the headless mode, allowing you to see what's going on.
+            // "--no-headless",
+            // The text isn't rendered by default because of a lot of small differences
+            // between hosts.
+            // "--show-text",
             "--variable", "DOC_PATH", opts["doc_folder"],
         ]);
     } catch (error) {
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index bba689d07a4..06cec1964a0 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -235,7 +235,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "ar",
     "autocfg",
     "bitflags",
-    "byteorder",
     "cfg-if",
     "cranelift-bforest",
     "cranelift-codegen",
@@ -248,9 +247,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "cranelift-native",
     "cranelift-object",
     "crc32fast",
-    "errno",
-    "errno-dragonfly",
-    "gcc",
     "gimli",
     "hashbrown",
     "indexmap",
@@ -259,17 +255,11 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
     "log",
     "mach",
     "object",
-    "proc-macro2",
-    "quote",
     "regalloc",
     "region",
     "rustc-hash",
     "smallvec",
-    "syn",
     "target-lexicon",
-    "thiserror",
-    "thiserror-impl",
-    "unicode-xid",
     "winapi",
     "winapi-i686-pc-windows-gnu",
     "winapi-x86_64-pc-windows-gnu",
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index 55f824b63f2..d6e0ebaa541 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -8,15 +8,14 @@ use std::path::Path;
 
 // A few of those error codes can't be tested but all the others can and *should* be tested!
 const EXEMPTED_FROM_TEST: &[&str] = &[
-    "E0183", "E0227", "E0279", "E0280", "E0311", "E0313", "E0314", "E0315", "E0377", "E0461",
-    "E0462", "E0464", "E0465", "E0472", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480",
-    "E0481", "E0482", "E0483", "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514",
-    "E0519", "E0523", "E0553", "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0727",
-    "E0729",
+    "E0227", "E0279", "E0280", "E0313", "E0314", "E0315", "E0377", "E0461", "E0462", "E0464",
+    "E0465", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480", "E0481", "E0482", "E0483",
+    "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514", "E0519", "E0523", "E0553",
+    "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0729",
 ];
 
 // Some error codes don't have any tests apparently...
-const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0639", "E0729"];
+const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0729"];
 
 fn check_error_code_explanation(
     f: &str,
@@ -114,13 +113,18 @@ fn extract_error_codes(
                 .expect("failed to canonicalize error explanation file path");
             match read_to_string(&path) {
                 Ok(content) => {
-                    if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str())
-                        && !check_if_error_code_is_test_in_explanation(&content, &err_code)
-                    {
+                    let has_test = check_if_error_code_is_test_in_explanation(&content, &err_code);
+                    if !has_test && !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
                         errors.push(format!(
                             "`{}` doesn't use its own error code in compile_fail example",
                             path.display(),
                         ));
+                    } else if has_test && IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) {
+                        errors.push(format!(
+                            "`{}` has a compile_fail example with its own error code, it shouldn't \
+                             be listed in IGNORE_EXPLANATION_CHECK!",
+                            path.display(),
+                        ));
                     }
                     if check_error_code_explanation(&content, error_codes, err_code) {
                         errors.push(format!(
@@ -198,6 +202,11 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
         for (err_code, nb) in &error_codes {
             if !*nb && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
                 errors.push(format!("Error code {} needs to have at least one UI test!", err_code));
+            } else if *nb && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) {
+                errors.push(format!(
+                    "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!",
+                    err_code
+                ));
             }
         }
     }
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 7b42de0ec43..f61295c8830 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -7,8 +7,8 @@ use std::path::Path;
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 1370;
-const ISSUES_ENTRY_LIMIT: usize = 2555;
+const ROOT_ENTRY_LIMIT: usize = 1371;
+const ISSUES_ENTRY_LIMIT: usize = 2559;
 
 fn check_entries(path: &Path, bad: &mut bool) {
     let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
diff --git a/src/tools/tier-check/src/main.rs b/src/tools/tier-check/src/main.rs
index 6a492bbff4d..a41e2d6e3aa 100644
--- a/src/tools/tier-check/src/main.rs
+++ b/src/tools/tier-check/src/main.rs
@@ -24,7 +24,7 @@ fn main() {
     let doc_targets_md = std::fs::read_to_string(&src).expect("failed to read input source");
     let doc_targets: HashSet<_> = doc_targets_md
         .lines()
-        .filter(|line| line.starts_with('`') && line.contains('|'))
+        .filter(|line| line.starts_with(&['`', '['][..]) && line.contains('|'))
         .map(|line| line.split('`').skip(1).next().expect("expected target code span"))
         .collect();
 
diff --git a/triagebot.toml b/triagebot.toml
index 8b6157cd4aa..c97f63f1cfd 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -79,7 +79,7 @@ trigger_labels = [
     "regression-from-stable-to-stable",
     "regression-from-stable-to-beta",
     "regression-from-stable-to-nightly",
-    "I-unsound 💥",
+    "I-unsound",
 ]
 exclude_labels = [
     "P-*",